diff options
author | Karl Berry <karl@freefriends.org> | 2014-07-15 22:56:45 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2014-07-15 22:56:45 +0000 |
commit | 6caf348b43edcfc1dce127bf0895a5fb9bd77f2d (patch) | |
tree | 7b4b79f90596e69716ad87e3293743756b2a1954 /Master/texmf-dist/tex | |
parent | d71cd04a4c07d1cdaf85a7b7c2398022cc39beab (diff) |
luaotfload (15jul14)
git-svn-id: svn://tug.org/texlive/trunk@34622 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex')
26 files changed, 19171 insertions, 12064 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua index d3de7313f07..89bf51b4d83 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua @@ -2,10 +2,10 @@ ----------------------------------------------------------------------- -- FILE: luaotfload-auxiliary.lua -- DESCRIPTION: part of luaotfload --- REQUIREMENTS: luaotfload 2.4 +-- REQUIREMENTS: luaotfload 2.5 -- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang --- VERSION: 2.4 --- CREATED: 2013-05-01 14:40:50+0200 +-- VERSION: 2.5 +-- MODIFIED: 2014-01-02 21:24:25+0100 ----------------------------------------------------------------------- -- @@ -15,28 +15,26 @@ luaotfload = luaotfload or {} luaotfload.aux = luaotfload.aux or { } -config = config or { } -config.luaotfload = config.luaotfload or { } - -local aux = luaotfload.aux -local log = luaotfload.log -local warning = luaotfload.log -local fonthashes = fonts.hashes -local identifiers = fonthashes.identifiers - -local fontid = font.id -local texsprint = tex.sprint - -local dofile = dofile -local getmetatable = getmetatable -local setmetatable = setmetatable -local utf8 = unicode.utf8 -local stringlower = string.lower -local stringformat = string.format -local stringgsub = string.gsub -local stringbyte = string.byte -local stringfind = string.find -local tablecopy = table.copy +local aux = luaotfload.aux +local log = luaotfload.log +local report = log.report +local fonthashes = fonts.hashes +local identifiers = fonthashes.identifiers +local fontnames = fonts.names + +local fontid = font.id +local texsprint = tex.sprint + +local dofile = dofile +local getmetatable = getmetatable +local setmetatable = setmetatable +local utf8 = unicode.utf8 +local stringlower = string.lower +local stringformat = string.format +local stringgsub = string.gsub +local stringbyte = string.byte +local stringfind = string.find +local tablecopy = table.copy ----------------------------------------------------------------------- --- font patches @@ -57,8 +55,8 @@ local start_rewrite_fontname = function () rewrite_fontname, "luaotfload.rewrite_fontname") rewriting = true - logs.names_report ("log", 0, "aux", - "start rewriting tfmdata.name field") + report ("log", 1, "aux", + "start rewriting tfmdata.name field") end end @@ -69,97 +67,13 @@ local stop_rewrite_fontname = function () luatexbase.remove_fromt_callback ("luaotfload.patch_font", "luaotfload.rewrite_fontname") rewriting = false - logs.names_report ("log", 0, "aux", - "stop rewriting tfmdata.name field") + report ("log", 1, "aux", + "stop rewriting tfmdata.name field") end end aux.stop_rewrite_fontname = stop_rewrite_fontname ---- as of 2.3 the compatibility hacks for TL 2013 are made optional - -if config.luaotfload.compatibility == true then - ---[[doc-- - -The font object (tfmdata) structure has changed since version 1.x, so -in case other packages haven’t been updated we put fallbacks in place -where they’d expect them. Specifically we have in mind: - - · fontspec - · unicode-math - · microtype (most likely fixed till TL2013) - ---doc]]-- - ---- fontobj -> fontobj -local add_fontdata_fallbacks = function (fontdata) - if type(fontdata) == "table" then - local fontparameters = fontdata.parameters - local metadata - if not fontdata.shared then --- that would be a tfm - --- we can’t really catch everything that - --- goes wrong; for some reason, fontspec.lua - --- just assumes it always gets an otf object, - --- so its capheight callback, which does not - --- bother to do any checks, will access - --- fontdata.shared no matter what ... - fontdata.units = fontdata.units_per_em - - else --- otf - metadata = fontdata.shared.rawdata.metadata - fontdata.name = metadata.origname or fontdata.name - fontdata.units = fontdata.units_per_em - fontdata.size = fontdata.size or fontparameters.size - local resources = fontdata.resources - --- for legacy fontspec.lua and unicode-math.lua - fontdata.shared.otfdata = { - pfminfo = { os2_capheight = metadata.pfminfo.os2_capheight }, - metadata = { ascent = metadata.ascent }, - } - --- for microtype and fontspec - --local fake_features = { } - local fake_features = table.copy(resources.features) - setmetatable(fake_features, { __index = function (tab, idx) - warning("some package (probably fontspec) is outdated") - warning( - "attempt to index " .. - "tfmdata.shared.otfdata.luatex.features (%s)", - idx) - --os.exit(1) - return tab[idx] - end, - }) - fontdata.shared.otfdata.luatex = { - unicodes = resources.unicodes, - features = fake_features, - } - end - end - return fontdata -end - -luatexbase.add_to_callback( - "luaotfload.patch_font", - add_fontdata_fallbacks, - "luaotfload.fontdata_fallbacks") - ---[[doc-- - -Additionally, the font registry is expected at fonts.identifiers -(fontspec) or fonts.ids (microtype), but in the meantime it has been -migrated to fonts.hashes.identifiers. We’ll make luaotfload satisfy -those assumptions. (Maybe it’d be more appropriate to use -font.getfont() since Hans made it a harmless wrapper [1].) - -[1] http://www.ntg.nl/pipermail/ntg-context/2013/072166.html - ---doc]]-- - -fonts.identifiers = fonts.hashes.identifiers -fonts.ids = fonts.hashes.identifiers - -end --[[doc-- This sets two dimensions apparently relied upon by the unicode-math @@ -453,7 +367,7 @@ do local load_chardef = function () - log ("Loading character metadata from %s.", chardef) + report ("both", 1, "aux", "Loading character metadata from %s.", chardef) chardata = dofile (kpse.find_file (chardef, "lua")) if chardata == nil then @@ -511,19 +425,19 @@ local provides_script = function (font_id, asked_script) --- where method: "gpos" | "gsub" for feature, data in next, featuredata do if data[asked_script] then - log(stringformat( - "font no %d (%s) defines feature %s for script %s", - font_id, fontname, feature, asked_script)) + report ("log", 1, "aux", + "font no %d (%s) defines feature %s for script %s", + font_id, fontname, feature, asked_script) return true end end end - log(stringformat( - "font no %d (%s) defines no feature for script %s", - font_id, fontname, asked_script)) + report ("log", 0, "aux", + "font no %d (%s) defines no feature for script %s", + font_id, fontname, asked_script) end end - log(stringformat("no font with id %d", font_id)) + report ("log", 0, "aux", "no font with id %d", font_id) return false end @@ -550,20 +464,22 @@ local provides_language = function (font_id, asked_script, asked_language) for feature, data in next, featuredata do local scriptdata = data[asked_script] if scriptdata and scriptdata[asked_language] then - log(stringformat("font no %d (%s) defines feature %s " - .. "for script %s with language %s", - font_id, fontname, feature, - asked_script, asked_language)) + report ("log", 1, "aux", + "font no %d (%s) defines feature %s " + .. "for script %s with language %s", + font_id, fontname, feature, + asked_script, asked_language) return true end end end - log(stringformat( - "font no %d (%s) defines no feature for script %s with language %s", - font_id, fontname, asked_script, asked_language)) + report ("log", 0, "aux", + "font no %d (%s) defines no feature " + .. "for script %s with language %s", + font_id, fontname, asked_script, asked_language) end end - log(stringformat("no font with id %d", font_id)) + report ("log", 0, "aux", "no font with id %d", font_id) return false end @@ -621,20 +537,21 @@ local provides_feature = function (font_id, asked_script, if feature then local scriptdata = feature[asked_script] if scriptdata and scriptdata[asked_language] then - log(stringformat("font no %d (%s) defines feature %s " - .. "for script %s with language %s", - font_id, fontname, asked_feature, - asked_script, asked_language)) + report ("log", 1, "aux", + "font no %d (%s) defines feature %s " + .. "for script %s with language %s", + font_id, fontname, asked_feature, + asked_script, asked_language) return true end end end - log(stringformat( - "font no %d (%s) does not define feature %s for script %s with language %s", - font_id, fontname, asked_feature, asked_script, asked_language)) + report ("log", 0, "aux", + "font no %d (%s) does not define feature %s for script %s with language %s", + font_id, fontname, asked_feature, asked_script, asked_language) end end - log(stringformat("no font with id %d", font_id)) + report ("log", 0, "aux", "no font with id %d", font_id) return false end @@ -674,8 +591,8 @@ aux.sprint_math_dimension = sprint_math_dimension --- extra database functions ----------------------------------------------------------------------- -local namesresolve = fonts.names.resolve -local namesscan_dir = fonts.names.scan_dir +local namesresolve = fontnames.resolve +local namesscan_dir = fontnames.scan_dir --[====[-- TODO -> port this to new db model @@ -747,6 +664,42 @@ end aux.resolve_fontlist = resolve_fontlist +--- index access ------------------------------------------------------ + +--- Based on a discussion on the Luatex mailing list: +--- http://tug.org/pipermail/luatex/2014-June/004881.html + +--[[doc-- + + aux.read_font_index -- Read the names index from the canonical + location and return its contents. This does not affect the behavior + of Luaotfload: The returned table is independent of what the font + resolvers use internally. Access is raw: each call to the function + will result in the entire table being re-read from disk. + +--doc]]-- + +local load_names = fontnames.load +local access_font_index = fontnames.access_font_index + +local read_font_index = function () + return load_names (true) or { } +end + +--[[doc-- + + aux.font_index -- Access Luaotfload’s internal database. If the + database hasn’t been loaded yet this will cause it to be loaded, with + all the possible side-effects like for instance creating the index + file if it doesn’t exist, reading all font files, &c. + +--doc]]-- + +local font_index = function () return access_font_index () end + +aux.read_font_index = read_font_index +aux.font_index = font_index + --- loaded fonts ------------------------------------------------------ --- just a proof of concept diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-gen.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-gen.lua index 9cf5b93172a..c19a49af39f 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-gen.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-gen.lua @@ -254,6 +254,18 @@ function caches.loaddata(paths,name) for i=1,#paths do local data = false local luaname, lucname = makefullname(paths[i],name) + if lucname and not lfs.isfile(lucname) and type(caches.compile) == "function" then + -- in case we used luatex and luajittex mixed ... lub or luc file + texio.write(string.format("(compiling luc: %s)",lucname)) + data = loadfile(luaname) + if data then + data = data() + end + if data then + caches.compile(data,luaname,lucname) + return data + end + end if lucname and lfs.isfile(lucname) then -- maybe also check for size texio.write(string.format("(load luc: %s)",lucname)) data = loadfile(lucname) @@ -341,3 +353,16 @@ end function table.setmetatableindex(t,f) setmetatable(t,{ __index = f }) end + +-- helper for plain: + +arguments = { } + +if arg then + for i=1,#arg do + local k, v = string.match(arg[i],"^%-%-([^=]+)=?(.-)$") + if k and v then + arguments[k] = v + end + end +end diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-nod.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-nod.lua index 50a1e862790..373dab5a8c7 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-nod.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-nod.lua @@ -54,22 +54,33 @@ nodes.handlers = { } local nodecodes = { } for k,v in next, node.types () do nodecodes[string.gsub(v,"_","")] = k end local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gsub(v,"_","")] = k end local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" } +local disccodes = { [0] = "discretionary", "explicit", "automatic", "regular", "first", "second" } nodes.nodecodes = nodecodes nodes.whatcodes = whatcodes nodes.whatsitcodes = whatcodes nodes.glyphcodes = glyphcodes +nodes.disccodes = disccodes local free_node = node.free local remove_node = node.remove local new_node = node.new local traverse_id = node.traverse_id -local math_code = nodecodes.math - nodes.handlers.protectglyphs = node.protect_glyphs nodes.handlers.unprotectglyphs = node.unprotect_glyphs +local math_code = nodecodes.math +local end_of_math = node.end_of_math + +function node.end_of_math(n) + if n.id == math_code and n.subtype == 1 then + return n + else + return end_of_math(n) + end +end + function nodes.remove(head, current, free_too) local t = current head, current = remove_node(head,current) diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-blacklist.cnf b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-blacklist.cnf index 5c03dc298f2..e82669b9f87 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-blacklist.cnf +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-blacklist.cnf @@ -1,12 +1,4 @@ -% Takes ages to load -LastResort.ttf % a MacOSX font, but also available for free from unicode.org -% Segfaults under LuaTeX 0.76 -lingoes.ttf -% http://tug.org/pipermail/luatex/2013-May/004239.html -Diablindall.ttf spltfgbd.ttf spltfgbi.ttf spltfgit.ttf spltfgrg.ttf -% Buggy Max OS font, see https://github.com/lualatex/luaotfload/issues/139 -Skia.ttf diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua index 13f0482bb2d..771e10fddb3 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua @@ -3591,6 +3591,10 @@ return { category="po", direction="on", }, + [0x037F]={ + category="lu", + direction="l", + }, [0x0384]={ category="sk", direction="on", @@ -5259,6 +5263,38 @@ return { category="ll", direction="l", }, + [0x0528]={ + category="lu", + direction="l", + }, + [0x0529]={ + category="ll", + direction="l", + }, + [0x052A]={ + category="lu", + direction="l", + }, + [0x052B]={ + category="ll", + direction="l", + }, + [0x052C]={ + category="lu", + direction="l", + }, + [0x052D]={ + category="ll", + direction="l", + }, + [0x052E]={ + category="lu", + direction="l", + }, + [0x052F]={ + category="ll", + direction="l", + }, [0x0531]={ category="lu", direction="l", @@ -5603,6 +5639,14 @@ return { category="pd", direction="on", }, + [0x058D]={ + category="so", + direction="on", + }, + [0x058E]={ + category="so", + direction="on", + }, [0x058F]={ category="sc", direction="et", @@ -5975,6 +6019,10 @@ return { category="cf", direction="an", }, + [0x0605]={ + category="cf", + direction="an", + }, [0x0606]={ category="sm", direction="on", @@ -6063,6 +6111,10 @@ return { category="po", direction="al", }, + [0x061C]={ + category="cf", + direction="al", + }, [0x061E]={ category="po", direction="al", @@ -8267,6 +8319,10 @@ return { category="lo", direction="al", }, + [0x08A1]={ + category="lo", + direction="al", + }, [0x08A2]={ category="lo", direction="al", @@ -8311,6 +8367,30 @@ return { category="lo", direction="al", }, + [0x08AD]={ + category="lo", + direction="al", + }, + [0x08AE]={ + category="lo", + direction="al", + }, + [0x08AF]={ + category="lo", + direction="al", + }, + [0x08B0]={ + category="lo", + direction="al", + }, + [0x08B1]={ + category="lo", + direction="al", + }, + [0x08B2]={ + category="lo", + direction="al", + }, [0x08E4]={ category="mn", direction="nsm", @@ -8419,6 +8499,10 @@ return { category="mn", direction="nsm", }, + [0x08FF]={ + category="mn", + direction="nsm", + }, [0x0900]={ category="mn", direction="nsm", @@ -8899,6 +8983,10 @@ return { category="lo", direction="l", }, + [0x0978]={ + category="lo", + direction="l", + }, [0x0979]={ category="lo", direction="l", @@ -8927,6 +9015,10 @@ return { category="lo", direction="l", }, + [0x0980]={ + category="lo", + direction="l", + }, [0x0981]={ category="mn", direction="nsm", @@ -10595,6 +10687,10 @@ return { category="so", direction="on", }, + [0x0C00]={ + category="mn", + direction="nsm", + }, [0x0C01]={ category="mc", direction="l", @@ -10783,6 +10879,10 @@ return { category="lo", direction="l", }, + [0x0C34]={ + category="lo", + direction="l", + }, [0x0C35]={ category="lo", direction="l", @@ -10967,6 +11067,10 @@ return { category="so", direction="l", }, + [0x0C81]={ + category="mn", + direction="nsm", + }, [0x0C82]={ category="mc", direction="l", @@ -11311,6 +11415,10 @@ return { category="so", direction="l", }, + [0x0D01]={ + category="mn", + direction="nsm", + }, [0x0D02]={ category="mc", direction="l", @@ -12011,6 +12119,46 @@ return { category="mc", direction="l", }, + [0x0DE6]={ + category="nd", + direction="l", + }, + [0x0DE7]={ + category="nd", + direction="l", + }, + [0x0DE8]={ + category="nd", + direction="l", + }, + [0x0DE9]={ + category="nd", + direction="l", + }, + [0x0DEA]={ + category="nd", + direction="l", + }, + [0x0DEB]={ + category="nd", + direction="l", + }, + [0x0DEC]={ + category="nd", + direction="l", + }, + [0x0DED]={ + category="nd", + direction="l", + }, + [0x0DEE]={ + category="nd", + direction="l", + }, + [0x0DEF]={ + category="nd", + direction="l", + }, [0x0DF2]={ category="mc", direction="l", @@ -20381,6 +20529,38 @@ return { category="nl", direction="l", }, + [0x16F1]={ + category="lo", + direction="l", + }, + [0x16F2]={ + category="lo", + direction="l", + }, + [0x16F3]={ + category="lo", + direction="l", + }, + [0x16F4]={ + category="lo", + direction="l", + }, + [0x16F5]={ + category="lo", + direction="l", + }, + [0x16F6]={ + category="lo", + direction="l", + }, + [0x16F7]={ + category="lo", + direction="l", + }, + [0x16F8]={ + category="lo", + direction="l", + }, [0x1700]={ category="lo", direction="l", @@ -21219,7 +21399,7 @@ return { }, [0x180E]={ category="zs", - direction="ws", + direction="bn", }, [0x1810]={ category="nd", @@ -22181,6 +22361,14 @@ return { category="lo", direction="l", }, + [0x191D]={ + category="lo", + direction="l", + }, + [0x191E]={ + category="lo", + direction="l", + }, [0x1920]={ category="mn", direction="nsm", @@ -23039,7 +23227,7 @@ return { }, [0x1A1B]={ category="mc", - direction="l", + direction="nsm", }, [0x1A1E]={ category="po", @@ -23557,6 +23745,66 @@ return { category="po", direction="l", }, + [0x1AB0]={ + category="mn", + direction="nsm", + }, + [0x1AB1]={ + category="mn", + direction="nsm", + }, + [0x1AB2]={ + category="mn", + direction="nsm", + }, + [0x1AB3]={ + category="mn", + direction="nsm", + }, + [0x1AB4]={ + category="mn", + direction="nsm", + }, + [0x1AB5]={ + category="mn", + direction="nsm", + }, + [0x1AB6]={ + category="mn", + direction="nsm", + }, + [0x1AB7]={ + category="mn", + direction="nsm", + }, + [0x1AB8]={ + category="mn", + direction="nsm", + }, + [0x1AB9]={ + category="mn", + direction="nsm", + }, + [0x1ABA]={ + category="mn", + direction="nsm", + }, + [0x1ABB]={ + category="mn", + direction="nsm", + }, + [0x1ABC]={ + category="mn", + direction="nsm", + }, + [0x1ABD]={ + category="mn", + direction="nsm", + }, + [0x1ABE]={ + category="me", + direction="nsm", + }, [0x1B00]={ category="mn", direction="nsm", @@ -24219,11 +24467,11 @@ return { }, [0x1BAC]={ category="mc", - direction="l", + direction="nsm", }, [0x1BAD]={ category="mc", - direction="l", + direction="nsm", }, [0x1BAE]={ category="lo", @@ -25197,6 +25445,14 @@ return { category="lo", direction="l", }, + [0x1CF8]={ + category="mn", + direction="nsm", + }, + [0x1CF9]={ + category="mn", + direction="nsm", + }, [0x1D00]={ category="ll", direction="l", @@ -26121,6 +26377,66 @@ return { category="mn", direction="nsm", }, + [0x1DE7]={ + category="mn", + direction="nsm", + }, + [0x1DE8]={ + category="mn", + direction="nsm", + }, + [0x1DE9]={ + category="mn", + direction="nsm", + }, + [0x1DEA]={ + category="mn", + direction="nsm", + }, + [0x1DEB]={ + category="mn", + direction="nsm", + }, + [0x1DEC]={ + category="mn", + direction="nsm", + }, + [0x1DED]={ + category="mn", + direction="nsm", + }, + [0x1DEE]={ + category="mn", + direction="nsm", + }, + [0x1DEF]={ + category="mn", + direction="nsm", + }, + [0x1DF0]={ + category="mn", + direction="nsm", + }, + [0x1DF1]={ + category="mn", + direction="nsm", + }, + [0x1DF2]={ + category="mn", + direction="nsm", + }, + [0x1DF3]={ + category="mn", + direction="nsm", + }, + [0x1DF4]={ + category="mn", + direction="nsm", + }, + [0x1DF5]={ + category="mn", + direction="nsm", + }, [0x1DFC]={ category="mn", direction="nsm", @@ -28503,6 +28819,22 @@ return { category="cf", direction="bn", }, + [0x2066]={ + category="cf", + direction="lri", + }, + [0x2067]={ + category="cf", + direction="rli", + }, + [0x2068]={ + category="cf", + direction="fsi", + }, + [0x2069]={ + category="cf", + direction="pdi", + }, [0x206A]={ category="cf", direction="bn", @@ -28811,6 +29143,18 @@ return { category="sc", direction="et", }, + [0x20BB]={ + category="sc", + direction="et", + }, + [0x20BC]={ + category="sc", + direction="et", + }, + [0x20BD]={ + category="sc", + direction="et", + }, [0x20D0]={ category="mn", direction="nsm", @@ -32063,6 +32407,34 @@ return { category="so", direction="on", }, + [0x23F4]={ + category="so", + direction="on", + }, + [0x23F5]={ + category="so", + direction="on", + }, + [0x23F6]={ + category="so", + direction="on", + }, + [0x23F7]={ + category="so", + direction="on", + }, + [0x23F8]={ + category="so", + direction="on", + }, + [0x23F9]={ + category="so", + direction="on", + }, + [0x23FA]={ + category="so", + direction="on", + }, [0x2400]={ category="so", direction="on", @@ -34951,6 +35323,10 @@ return { category="so", direction="on", }, + [0x2700]={ + category="so", + direction="on", + }, [0x2701]={ category="so", direction="on", @@ -39513,6 +39889,18 @@ return { category="sm", direction="on", }, + [0x2B4D]={ + category="so", + direction="on", + }, + [0x2B4E]={ + category="so", + direction="on", + }, + [0x2B4F]={ + category="so", + direction="on", + }, [0x2B50]={ category="so", direction="on", @@ -39553,6 +39941,454 @@ return { category="so", direction="on", }, + [0x2B5A]={ + category="so", + direction="on", + }, + [0x2B5B]={ + category="so", + direction="on", + }, + [0x2B5C]={ + category="so", + direction="on", + }, + [0x2B5D]={ + category="so", + direction="on", + }, + [0x2B5E]={ + category="so", + direction="on", + }, + [0x2B5F]={ + category="so", + direction="on", + }, + [0x2B60]={ + category="so", + direction="on", + }, + [0x2B61]={ + category="so", + direction="on", + }, + [0x2B62]={ + category="so", + direction="on", + }, + [0x2B63]={ + category="so", + direction="on", + }, + [0x2B64]={ + category="so", + direction="on", + }, + [0x2B65]={ + category="so", + direction="on", + }, + [0x2B66]={ + category="so", + direction="on", + }, + [0x2B67]={ + category="so", + direction="on", + }, + [0x2B68]={ + category="so", + direction="on", + }, + [0x2B69]={ + category="so", + direction="on", + }, + [0x2B6A]={ + category="so", + direction="on", + }, + [0x2B6B]={ + category="so", + direction="on", + }, + [0x2B6C]={ + category="so", + direction="on", + }, + [0x2B6D]={ + category="so", + direction="on", + }, + [0x2B6E]={ + category="so", + direction="on", + }, + [0x2B6F]={ + category="so", + direction="on", + }, + [0x2B70]={ + category="so", + direction="on", + }, + [0x2B71]={ + category="so", + direction="on", + }, + [0x2B72]={ + category="so", + direction="on", + }, + [0x2B73]={ + category="so", + direction="on", + }, + [0x2B76]={ + category="so", + direction="on", + }, + [0x2B77]={ + category="so", + direction="on", + }, + [0x2B78]={ + category="so", + direction="on", + }, + [0x2B79]={ + category="so", + direction="on", + }, + [0x2B7A]={ + category="so", + direction="on", + }, + [0x2B7B]={ + category="so", + direction="on", + }, + [0x2B7C]={ + category="so", + direction="on", + }, + [0x2B7D]={ + category="so", + direction="on", + }, + [0x2B7E]={ + category="so", + direction="on", + }, + [0x2B7F]={ + category="so", + direction="on", + }, + [0x2B80]={ + category="so", + direction="on", + }, + [0x2B81]={ + category="so", + direction="on", + }, + [0x2B82]={ + category="so", + direction="on", + }, + [0x2B83]={ + category="so", + direction="on", + }, + [0x2B84]={ + category="so", + direction="on", + }, + [0x2B85]={ + category="so", + direction="on", + }, + [0x2B86]={ + category="so", + direction="on", + }, + [0x2B87]={ + category="so", + direction="on", + }, + [0x2B88]={ + category="so", + direction="on", + }, + [0x2B89]={ + category="so", + direction="on", + }, + [0x2B8A]={ + category="so", + direction="on", + }, + [0x2B8B]={ + category="so", + direction="on", + }, + [0x2B8C]={ + category="so", + direction="on", + }, + [0x2B8D]={ + category="so", + direction="on", + }, + [0x2B8E]={ + category="so", + direction="on", + }, + [0x2B8F]={ + category="so", + direction="on", + }, + [0x2B90]={ + category="so", + direction="on", + }, + [0x2B91]={ + category="so", + direction="on", + }, + [0x2B92]={ + category="so", + direction="on", + }, + [0x2B93]={ + category="so", + direction="on", + }, + [0x2B94]={ + category="so", + direction="on", + }, + [0x2B95]={ + category="so", + direction="on", + }, + [0x2B98]={ + category="so", + direction="on", + }, + [0x2B99]={ + category="so", + direction="on", + }, + [0x2B9A]={ + category="so", + direction="on", + }, + [0x2B9B]={ + category="so", + direction="on", + }, + [0x2B9C]={ + category="so", + direction="on", + }, + [0x2B9D]={ + category="so", + direction="on", + }, + [0x2B9E]={ + category="so", + direction="on", + }, + [0x2B9F]={ + category="so", + direction="on", + }, + [0x2BA0]={ + category="so", + direction="on", + }, + [0x2BA1]={ + category="so", + direction="on", + }, + [0x2BA2]={ + category="so", + direction="on", + }, + [0x2BA3]={ + category="so", + direction="on", + }, + [0x2BA4]={ + category="so", + direction="on", + }, + [0x2BA5]={ + category="so", + direction="on", + }, + [0x2BA6]={ + category="so", + direction="on", + }, + [0x2BA7]={ + category="so", + direction="on", + }, + [0x2BA8]={ + category="so", + direction="on", + }, + [0x2BA9]={ + category="so", + direction="on", + }, + [0x2BAA]={ + category="so", + direction="on", + }, + [0x2BAB]={ + category="so", + direction="on", + }, + [0x2BAC]={ + category="so", + direction="on", + }, + [0x2BAD]={ + category="so", + direction="on", + }, + [0x2BAE]={ + category="so", + direction="on", + }, + [0x2BAF]={ + category="so", + direction="on", + }, + [0x2BB0]={ + category="so", + direction="on", + }, + [0x2BB1]={ + category="so", + direction="on", + }, + [0x2BB2]={ + category="so", + direction="on", + }, + [0x2BB3]={ + category="so", + direction="on", + }, + [0x2BB4]={ + category="so", + direction="on", + }, + [0x2BB5]={ + category="so", + direction="on", + }, + [0x2BB6]={ + category="so", + direction="on", + }, + [0x2BB7]={ + category="so", + direction="on", + }, + [0x2BB8]={ + category="so", + direction="on", + }, + [0x2BB9]={ + category="so", + direction="on", + }, + [0x2BBD]={ + category="so", + direction="on", + }, + [0x2BBE]={ + category="so", + direction="on", + }, + [0x2BBF]={ + category="so", + direction="on", + }, + [0x2BC0]={ + category="so", + direction="on", + }, + [0x2BC1]={ + category="so", + direction="on", + }, + [0x2BC2]={ + category="so", + direction="on", + }, + [0x2BC3]={ + category="so", + direction="on", + }, + [0x2BC4]={ + category="so", + direction="on", + }, + [0x2BC5]={ + category="so", + direction="on", + }, + [0x2BC6]={ + category="so", + direction="on", + }, + [0x2BC7]={ + category="so", + direction="on", + }, + [0x2BC8]={ + category="so", + direction="on", + }, + [0x2BCA]={ + category="so", + direction="on", + }, + [0x2BCB]={ + category="so", + direction="on", + }, + [0x2BCC]={ + category="so", + direction="on", + }, + [0x2BCD]={ + category="so", + direction="on", + }, + [0x2BCE]={ + category="so", + direction="on", + }, + [0x2BCF]={ + category="so", + direction="on", + }, + [0x2BD0]={ + category="so", + direction="on", + }, + [0x2BD1]={ + category="so", + direction="on", + }, [0x2C00]={ category="lu", direction="l", @@ -41649,6 +42485,34 @@ return { category="pd", direction="on", }, + [0x2E3C]={ + category="po", + direction="on", + }, + [0x2E3D]={ + category="po", + direction="on", + }, + [0x2E3E]={ + category="po", + direction="on", + }, + [0x2E3F]={ + category="po", + direction="on", + }, + [0x2E40]={ + category="pd", + direction="on", + }, + [0x2E41]={ + category="po", + direction="on", + }, + [0x2E42]={ + category="ps", + direction="on", + }, [0x2E80]={ category="so", direction="on", @@ -53883,6 +54747,30 @@ return { category="ll", direction="l", }, + [0xA698]={ + category="lu", + direction="l", + }, + [0xA699]={ + category="ll", + direction="l", + }, + [0xA69A]={ + category="lu", + direction="l", + }, + [0xA69B]={ + category="ll", + direction="l", + }, + [0xA69C]={ + category="lm", + direction="l", + }, + [0xA69D]={ + category="lm", + direction="l", + }, [0xA69F]={ category="mn", direction="nsm", @@ -54827,6 +55715,54 @@ return { category="ll", direction="l", }, + [0xA794]={ + category="ll", + direction="l", + }, + [0xA795]={ + category="ll", + direction="l", + }, + [0xA796]={ + category="lu", + direction="l", + }, + [0xA797]={ + category="ll", + direction="l", + }, + [0xA798]={ + category="lu", + direction="l", + }, + [0xA799]={ + category="ll", + direction="l", + }, + [0xA79A]={ + category="lu", + direction="l", + }, + [0xA79B]={ + category="ll", + direction="l", + }, + [0xA79C]={ + category="lu", + direction="l", + }, + [0xA79D]={ + category="ll", + direction="l", + }, + [0xA79E]={ + category="lu", + direction="l", + }, + [0xA79F]={ + category="ll", + direction="l", + }, [0xA7A0]={ category="lu", direction="l", @@ -54871,6 +55807,30 @@ return { category="lu", direction="l", }, + [0xA7AB]={ + category="lu", + direction="l", + }, + [0xA7AC]={ + category="lu", + direction="l", + }, + [0xA7AD]={ + category="lu", + direction="l", + }, + [0xA7B0]={ + category="lu", + direction="l", + }, + [0xA7B1]={ + category="lu", + direction="l", + }, + [0xA7F7]={ + category="lo", + direction="l", + }, [0xA7F8]={ category="lm", direction="l", @@ -56599,6 +57559,130 @@ return { category="po", direction="l", }, + [0xA9E0]={ + category="lo", + direction="l", + }, + [0xA9E1]={ + category="lo", + direction="l", + }, + [0xA9E2]={ + category="lo", + direction="l", + }, + [0xA9E3]={ + category="lo", + direction="l", + }, + [0xA9E4]={ + category="lo", + direction="l", + }, + [0xA9E5]={ + category="mn", + direction="nsm", + }, + [0xA9E6]={ + category="lm", + direction="l", + }, + [0xA9E7]={ + category="lo", + direction="l", + }, + [0xA9E8]={ + category="lo", + direction="l", + }, + [0xA9E9]={ + category="lo", + direction="l", + }, + [0xA9EA]={ + category="lo", + direction="l", + }, + [0xA9EB]={ + category="lo", + direction="l", + }, + [0xA9EC]={ + category="lo", + direction="l", + }, + [0xA9ED]={ + category="lo", + direction="l", + }, + [0xA9EE]={ + category="lo", + direction="l", + }, + [0xA9EF]={ + category="lo", + direction="l", + }, + [0xA9F0]={ + category="nd", + direction="l", + }, + [0xA9F1]={ + category="nd", + direction="l", + }, + [0xA9F2]={ + category="nd", + direction="l", + }, + [0xA9F3]={ + category="nd", + direction="l", + }, + [0xA9F4]={ + category="nd", + direction="l", + }, + [0xA9F5]={ + category="nd", + direction="l", + }, + [0xA9F6]={ + category="nd", + direction="l", + }, + [0xA9F7]={ + category="nd", + direction="l", + }, + [0xA9F8]={ + category="nd", + direction="l", + }, + [0xA9F9]={ + category="nd", + direction="l", + }, + [0xA9FA]={ + category="lo", + direction="l", + }, + [0xA9FB]={ + category="lo", + direction="l", + }, + [0xA9FC]={ + category="lo", + direction="l", + }, + [0xA9FD]={ + category="lo", + direction="l", + }, + [0xA9FE]={ + category="lo", + direction="l", + }, [0xAA00]={ category="lo", direction="l", @@ -57043,6 +58127,22 @@ return { category="mc", direction="l", }, + [0xAA7C]={ + category="mn", + direction="nsm", + }, + [0xAA7D]={ + category="mc", + direction="l", + }, + [0xAA7E]={ + category="lo", + direction="l", + }, + [0xAA7F]={ + category="lo", + direction="l", + }, [0xAA80]={ category="lo", direction="l", @@ -57551,6 +58651,206 @@ return { category="lo", direction="l", }, + [0xAB30]={ + category="ll", + direction="l", + }, + [0xAB31]={ + category="ll", + direction="l", + }, + [0xAB32]={ + category="ll", + direction="l", + }, + [0xAB33]={ + category="ll", + direction="l", + }, + [0xAB34]={ + category="ll", + direction="l", + }, + [0xAB35]={ + category="ll", + direction="l", + }, + [0xAB36]={ + category="ll", + direction="l", + }, + [0xAB37]={ + category="ll", + direction="l", + }, + [0xAB38]={ + category="ll", + direction="l", + }, + [0xAB39]={ + category="ll", + direction="l", + }, + [0xAB3A]={ + category="ll", + direction="l", + }, + [0xAB3B]={ + category="ll", + direction="l", + }, + [0xAB3C]={ + category="ll", + direction="l", + }, + [0xAB3D]={ + category="ll", + direction="l", + }, + [0xAB3E]={ + category="ll", + direction="l", + }, + [0xAB3F]={ + category="ll", + direction="l", + }, + [0xAB40]={ + category="ll", + direction="l", + }, + [0xAB41]={ + category="ll", + direction="l", + }, + [0xAB42]={ + category="ll", + direction="l", + }, + [0xAB43]={ + category="ll", + direction="l", + }, + [0xAB44]={ + category="ll", + direction="l", + }, + [0xAB45]={ + category="ll", + direction="l", + }, + [0xAB46]={ + category="ll", + direction="l", + }, + [0xAB47]={ + category="ll", + direction="l", + }, + [0xAB48]={ + category="ll", + direction="l", + }, + [0xAB49]={ + category="ll", + direction="l", + }, + [0xAB4A]={ + category="ll", + direction="l", + }, + [0xAB4B]={ + category="ll", + direction="l", + }, + [0xAB4C]={ + category="ll", + direction="l", + }, + [0xAB4D]={ + category="ll", + direction="l", + }, + [0xAB4E]={ + category="ll", + direction="l", + }, + [0xAB4F]={ + category="ll", + direction="l", + }, + [0xAB50]={ + category="ll", + direction="l", + }, + [0xAB51]={ + category="ll", + direction="l", + }, + [0xAB52]={ + category="ll", + direction="l", + }, + [0xAB53]={ + category="ll", + direction="l", + }, + [0xAB54]={ + category="ll", + direction="l", + }, + [0xAB55]={ + category="ll", + direction="l", + }, + [0xAB56]={ + category="ll", + direction="l", + }, + [0xAB57]={ + category="ll", + direction="l", + }, + [0xAB58]={ + category="ll", + direction="l", + }, + [0xAB59]={ + category="ll", + direction="l", + }, + [0xAB5A]={ + category="ll", + direction="l", + }, + [0xAB5B]={ + category="sk", + direction="l", + }, + [0xAB5C]={ + category="lm", + direction="l", + }, + [0xAB5D]={ + category="lm", + direction="l", + }, + [0xAB5E]={ + category="lm", + direction="l", + }, + [0xAB5F]={ + category="lm", + direction="l", + }, + [0xAB64]={ + category="ll", + direction="l", + }, + [0xAB65]={ + category="ll", + direction="l", + }, [0xABC0]={ category="lo", direction="l", @@ -62791,6 +64091,34 @@ return { category="mn", direction="nsm", }, + [0xFE27]={ + category="mn", + direction="nsm", + }, + [0xFE28]={ + category="mn", + direction="nsm", + }, + [0xFE29]={ + category="mn", + direction="nsm", + }, + [0xFE2A]={ + category="mn", + direction="nsm", + }, + [0xFE2B]={ + category="mn", + direction="nsm", + }, + [0xFE2C]={ + category="mn", + direction="nsm", + }, + [0xFE2D]={ + category="mn", + direction="nsm", + }, [0xFE30]={ category="po", direction="on", @@ -65919,6 +67247,14 @@ return { category="no", direction="on", }, + [0x1018B]={ + category="no", + direction="on", + }, + [0x1018C]={ + category="so", + direction="on", + }, [0x10190]={ category="so", direction="on", @@ -65967,6 +67303,10 @@ return { category="so", direction="on", }, + [0x101A0]={ + category="so", + direction="on", + }, [0x101D0]={ category="so", direction="l", @@ -66463,6 +67803,118 @@ return { category="lo", direction="l", }, + [0x102E0]={ + category="mn", + direction="nsm", + }, + [0x102E1]={ + category="no", + direction="en", + }, + [0x102E2]={ + category="no", + direction="en", + }, + [0x102E3]={ + category="no", + direction="en", + }, + [0x102E4]={ + category="no", + direction="en", + }, + [0x102E5]={ + category="no", + direction="en", + }, + [0x102E6]={ + category="no", + direction="en", + }, + [0x102E7]={ + category="no", + direction="en", + }, + [0x102E8]={ + category="no", + direction="en", + }, + [0x102E9]={ + category="no", + direction="en", + }, + [0x102EA]={ + category="no", + direction="en", + }, + [0x102EB]={ + category="no", + direction="en", + }, + [0x102EC]={ + category="no", + direction="en", + }, + [0x102ED]={ + category="no", + direction="en", + }, + [0x102EE]={ + category="no", + direction="en", + }, + [0x102EF]={ + category="no", + direction="en", + }, + [0x102F0]={ + category="no", + direction="en", + }, + [0x102F1]={ + category="no", + direction="en", + }, + [0x102F2]={ + category="no", + direction="en", + }, + [0x102F3]={ + category="no", + direction="en", + }, + [0x102F4]={ + category="no", + direction="en", + }, + [0x102F5]={ + category="no", + direction="en", + }, + [0x102F6]={ + category="no", + direction="en", + }, + [0x102F7]={ + category="no", + direction="en", + }, + [0x102F8]={ + category="no", + direction="en", + }, + [0x102F9]={ + category="no", + direction="en", + }, + [0x102FA]={ + category="no", + direction="en", + }, + [0x102FB]={ + category="no", + direction="en", + }, [0x10300]={ category="lo", direction="l", @@ -66587,6 +68039,10 @@ return { category="lo", direction="l", }, + [0x1031F]={ + category="lo", + direction="l", + }, [0x10320]={ category="no", direction="l", @@ -66711,6 +68167,178 @@ return { category="nl", direction="l", }, + [0x10350]={ + category="lo", + direction="l", + }, + [0x10351]={ + category="lo", + direction="l", + }, + [0x10352]={ + category="lo", + direction="l", + }, + [0x10353]={ + category="lo", + direction="l", + }, + [0x10354]={ + category="lo", + direction="l", + }, + [0x10355]={ + category="lo", + direction="l", + }, + [0x10356]={ + category="lo", + direction="l", + }, + [0x10357]={ + category="lo", + direction="l", + }, + [0x10358]={ + category="lo", + direction="l", + }, + [0x10359]={ + category="lo", + direction="l", + }, + [0x1035A]={ + category="lo", + direction="l", + }, + [0x1035B]={ + category="lo", + direction="l", + }, + [0x1035C]={ + category="lo", + direction="l", + }, + [0x1035D]={ + category="lo", + direction="l", + }, + [0x1035E]={ + category="lo", + direction="l", + }, + [0x1035F]={ + category="lo", + direction="l", + }, + [0x10360]={ + category="lo", + direction="l", + }, + [0x10361]={ + category="lo", + direction="l", + }, + [0x10362]={ + category="lo", + direction="l", + }, + [0x10363]={ + category="lo", + direction="l", + }, + [0x10364]={ + category="lo", + direction="l", + }, + [0x10365]={ + category="lo", + direction="l", + }, + [0x10366]={ + category="lo", + direction="l", + }, + [0x10367]={ + category="lo", + direction="l", + }, + [0x10368]={ + category="lo", + direction="l", + }, + [0x10369]={ + category="lo", + direction="l", + }, + [0x1036A]={ + category="lo", + direction="l", + }, + [0x1036B]={ + category="lo", + direction="l", + }, + [0x1036C]={ + category="lo", + direction="l", + }, + [0x1036D]={ + category="lo", + direction="l", + }, + [0x1036E]={ + category="lo", + direction="l", + }, + [0x1036F]={ + category="lo", + direction="l", + }, + [0x10370]={ + category="lo", + direction="l", + }, + [0x10371]={ + category="lo", + direction="l", + }, + [0x10372]={ + category="lo", + direction="l", + }, + [0x10373]={ + category="lo", + direction="l", + }, + [0x10374]={ + category="lo", + direction="l", + }, + [0x10375]={ + category="lo", + direction="l", + }, + [0x10376]={ + category="mn", + direction="nsm", + }, + [0x10377]={ + category="mn", + direction="nsm", + }, + [0x10378]={ + category="mn", + direction="nsm", + }, + [0x10379]={ + category="mn", + direction="nsm", + }, + [0x1037A]={ + category="mn", + direction="nsm", + }, [0x10380]={ category="lo", direction="l", @@ -67707,6 +69335,1742 @@ return { category="nd", direction="l", }, + [0x10500]={ + category="lo", + direction="l", + }, + [0x10501]={ + category="lo", + direction="l", + }, + [0x10502]={ + category="lo", + direction="l", + }, + [0x10503]={ + category="lo", + direction="l", + }, + [0x10504]={ + category="lo", + direction="l", + }, + [0x10505]={ + category="lo", + direction="l", + }, + [0x10506]={ + category="lo", + direction="l", + }, + [0x10507]={ + category="lo", + direction="l", + }, + [0x10508]={ + category="lo", + direction="l", + }, + [0x10509]={ + category="lo", + direction="l", + }, + [0x1050A]={ + category="lo", + direction="l", + }, + [0x1050B]={ + category="lo", + direction="l", + }, + [0x1050C]={ + category="lo", + direction="l", + }, + [0x1050D]={ + category="lo", + direction="l", + }, + [0x1050E]={ + category="lo", + direction="l", + }, + [0x1050F]={ + category="lo", + direction="l", + }, + [0x10510]={ + category="lo", + direction="l", + }, + [0x10511]={ + category="lo", + direction="l", + }, + [0x10512]={ + category="lo", + direction="l", + }, + [0x10513]={ + category="lo", + direction="l", + }, + [0x10514]={ + category="lo", + direction="l", + }, + [0x10515]={ + category="lo", + direction="l", + }, + [0x10516]={ + category="lo", + direction="l", + }, + [0x10517]={ + category="lo", + direction="l", + }, + [0x10518]={ + category="lo", + direction="l", + }, + [0x10519]={ + category="lo", + direction="l", + }, + [0x1051A]={ + category="lo", + direction="l", + }, + [0x1051B]={ + category="lo", + direction="l", + }, + [0x1051C]={ + category="lo", + direction="l", + }, + [0x1051D]={ + category="lo", + direction="l", + }, + [0x1051E]={ + category="lo", + direction="l", + }, + [0x1051F]={ + category="lo", + direction="l", + }, + [0x10520]={ + category="lo", + direction="l", + }, + [0x10521]={ + category="lo", + direction="l", + }, + [0x10522]={ + category="lo", + direction="l", + }, + [0x10523]={ + category="lo", + direction="l", + }, + [0x10524]={ + category="lo", + direction="l", + }, + [0x10525]={ + category="lo", + direction="l", + }, + [0x10526]={ + category="lo", + direction="l", + }, + [0x10527]={ + category="lo", + direction="l", + }, + [0x10530]={ + category="lo", + direction="l", + }, + [0x10531]={ + category="lo", + direction="l", + }, + [0x10532]={ + category="lo", + direction="l", + }, + [0x10533]={ + category="lo", + direction="l", + }, + [0x10534]={ + category="lo", + direction="l", + }, + [0x10535]={ + category="lo", + direction="l", + }, + [0x10536]={ + category="lo", + direction="l", + }, + [0x10537]={ + category="lo", + direction="l", + }, + [0x10538]={ + category="lo", + direction="l", + }, + [0x10539]={ + category="lo", + direction="l", + }, + [0x1053A]={ + category="lo", + direction="l", + }, + [0x1053B]={ + category="lo", + direction="l", + }, + [0x1053C]={ + category="lo", + direction="l", + }, + [0x1053D]={ + category="lo", + direction="l", + }, + [0x1053E]={ + category="lo", + direction="l", + }, + [0x1053F]={ + category="lo", + direction="l", + }, + [0x10540]={ + category="lo", + direction="l", + }, + [0x10541]={ + category="lo", + direction="l", + }, + [0x10542]={ + category="lo", + direction="l", + }, + [0x10543]={ + category="lo", + direction="l", + }, + [0x10544]={ + category="lo", + direction="l", + }, + [0x10545]={ + category="lo", + direction="l", + }, + [0x10546]={ + category="lo", + direction="l", + }, + [0x10547]={ + category="lo", + direction="l", + }, + [0x10548]={ + category="lo", + direction="l", + }, + [0x10549]={ + category="lo", + direction="l", + }, + [0x1054A]={ + category="lo", + direction="l", + }, + [0x1054B]={ + category="lo", + direction="l", + }, + [0x1054C]={ + category="lo", + direction="l", + }, + [0x1054D]={ + category="lo", + direction="l", + }, + [0x1054E]={ + category="lo", + direction="l", + }, + [0x1054F]={ + category="lo", + direction="l", + }, + [0x10550]={ + category="lo", + direction="l", + }, + [0x10551]={ + category="lo", + direction="l", + }, + [0x10552]={ + category="lo", + direction="l", + }, + [0x10553]={ + category="lo", + direction="l", + }, + [0x10554]={ + category="lo", + direction="l", + }, + [0x10555]={ + category="lo", + direction="l", + }, + [0x10556]={ + category="lo", + direction="l", + }, + [0x10557]={ + category="lo", + direction="l", + }, + [0x10558]={ + category="lo", + direction="l", + }, + [0x10559]={ + category="lo", + direction="l", + }, + [0x1055A]={ + category="lo", + direction="l", + }, + [0x1055B]={ + category="lo", + direction="l", + }, + [0x1055C]={ + category="lo", + direction="l", + }, + [0x1055D]={ + category="lo", + direction="l", + }, + [0x1055E]={ + category="lo", + direction="l", + }, + [0x1055F]={ + category="lo", + direction="l", + }, + [0x10560]={ + category="lo", + direction="l", + }, + [0x10561]={ + category="lo", + direction="l", + }, + [0x10562]={ + category="lo", + direction="l", + }, + [0x10563]={ + category="lo", + direction="l", + }, + [0x1056F]={ + category="po", + direction="l", + }, + [0x10600]={ + category="lo", + direction="l", + }, + [0x10601]={ + category="lo", + direction="l", + }, + [0x10602]={ + category="lo", + direction="l", + }, + [0x10603]={ + category="lo", + direction="l", + }, + [0x10604]={ + category="lo", + direction="l", + }, + [0x10605]={ + category="lo", + direction="l", + }, + [0x10606]={ + category="lo", + direction="l", + }, + [0x10607]={ + category="lo", + direction="l", + }, + [0x10608]={ + category="lo", + direction="l", + }, + [0x10609]={ + category="lo", + direction="l", + }, + [0x1060A]={ + category="lo", + direction="l", + }, + [0x1060B]={ + category="lo", + direction="l", + }, + [0x1060C]={ + category="lo", + direction="l", + }, + [0x1060D]={ + category="lo", + direction="l", + }, + [0x1060E]={ + category="lo", + direction="l", + }, + [0x1060F]={ + category="lo", + direction="l", + }, + [0x10610]={ + category="lo", + direction="l", + }, + [0x10611]={ + category="lo", + direction="l", + }, + [0x10612]={ + category="lo", + direction="l", + }, + [0x10613]={ + category="lo", + direction="l", + }, + [0x10614]={ + category="lo", + direction="l", + }, + [0x10615]={ + category="lo", + direction="l", + }, + [0x10616]={ + category="lo", + direction="l", + }, + [0x10617]={ + category="lo", + direction="l", + }, + [0x10618]={ + category="lo", + direction="l", + }, + [0x10619]={ + category="lo", + direction="l", + }, + [0x1061A]={ + category="lo", + direction="l", + }, + [0x1061B]={ + category="lo", + direction="l", + }, + [0x1061C]={ + category="lo", + direction="l", + }, + [0x1061D]={ + category="lo", + direction="l", + }, + [0x1061E]={ + category="lo", + direction="l", + }, + [0x1061F]={ + category="lo", + direction="l", + }, + [0x10620]={ + category="lo", + direction="l", + }, + [0x10621]={ + category="lo", + direction="l", + }, + [0x10622]={ + category="lo", + direction="l", + }, + [0x10623]={ + category="lo", + direction="l", + }, + [0x10624]={ + category="lo", + direction="l", + }, + [0x10625]={ + category="lo", + direction="l", + }, + [0x10626]={ + category="lo", + direction="l", + }, + [0x10627]={ + category="lo", + direction="l", + }, + [0x10628]={ + category="lo", + direction="l", + }, + [0x10629]={ + category="lo", + direction="l", + }, + [0x1062A]={ + category="lo", + direction="l", + }, + [0x1062B]={ + category="lo", + direction="l", + }, + [0x1062C]={ + category="lo", + direction="l", + }, + [0x1062D]={ + category="lo", + direction="l", + }, + [0x1062E]={ + category="lo", + direction="l", + }, + [0x1062F]={ + category="lo", + direction="l", + }, + [0x10630]={ + category="lo", + direction="l", + }, + [0x10631]={ + category="lo", + direction="l", + }, + [0x10632]={ + category="lo", + direction="l", + }, + [0x10633]={ + category="lo", + direction="l", + }, + [0x10634]={ + category="lo", + direction="l", + }, + [0x10635]={ + category="lo", + direction="l", + }, + [0x10636]={ + category="lo", + direction="l", + }, + [0x10637]={ + category="lo", + direction="l", + }, + [0x10638]={ + category="lo", + direction="l", + }, + [0x10639]={ + category="lo", + direction="l", + }, + [0x1063A]={ + category="lo", + direction="l", + }, + [0x1063B]={ + category="lo", + direction="l", + }, + [0x1063C]={ + category="lo", + direction="l", + }, + [0x1063D]={ + category="lo", + direction="l", + }, + [0x1063E]={ + category="lo", + direction="l", + }, + [0x1063F]={ + category="lo", + direction="l", + }, + [0x10640]={ + category="lo", + direction="l", + }, + [0x10641]={ + category="lo", + direction="l", + }, + [0x10642]={ + category="lo", + direction="l", + }, + [0x10643]={ + category="lo", + direction="l", + }, + [0x10644]={ + category="lo", + direction="l", + }, + [0x10645]={ + category="lo", + direction="l", + }, + [0x10646]={ + category="lo", + direction="l", + }, + [0x10647]={ + category="lo", + direction="l", + }, + [0x10648]={ + category="lo", + direction="l", + }, + [0x10649]={ + category="lo", + direction="l", + }, + [0x1064A]={ + category="lo", + direction="l", + }, + [0x1064B]={ + category="lo", + direction="l", + }, + [0x1064C]={ + category="lo", + direction="l", + }, + [0x1064D]={ + category="lo", + direction="l", + }, + [0x1064E]={ + category="lo", + direction="l", + }, + [0x1064F]={ + category="lo", + direction="l", + }, + [0x10650]={ + category="lo", + direction="l", + }, + [0x10651]={ + category="lo", + direction="l", + }, + [0x10652]={ + category="lo", + direction="l", + }, + [0x10653]={ + category="lo", + direction="l", + }, + [0x10654]={ + category="lo", + direction="l", + }, + [0x10655]={ + category="lo", + direction="l", + }, + [0x10656]={ + category="lo", + direction="l", + }, + [0x10657]={ + category="lo", + direction="l", + }, + [0x10658]={ + category="lo", + direction="l", + }, + [0x10659]={ + category="lo", + direction="l", + }, + [0x1065A]={ + category="lo", + direction="l", + }, + [0x1065B]={ + category="lo", + direction="l", + }, + [0x1065C]={ + category="lo", + direction="l", + }, + [0x1065D]={ + category="lo", + direction="l", + }, + [0x1065E]={ + category="lo", + direction="l", + }, + [0x1065F]={ + category="lo", + direction="l", + }, + [0x10660]={ + category="lo", + direction="l", + }, + [0x10661]={ + category="lo", + direction="l", + }, + [0x10662]={ + category="lo", + direction="l", + }, + [0x10663]={ + category="lo", + direction="l", + }, + [0x10664]={ + category="lo", + direction="l", + }, + [0x10665]={ + category="lo", + direction="l", + }, + [0x10666]={ + category="lo", + direction="l", + }, + [0x10667]={ + category="lo", + direction="l", + }, + [0x10668]={ + category="lo", + direction="l", + }, + [0x10669]={ + category="lo", + direction="l", + }, + [0x1066A]={ + category="lo", + direction="l", + }, + [0x1066B]={ + category="lo", + direction="l", + }, + [0x1066C]={ + category="lo", + direction="l", + }, + [0x1066D]={ + category="lo", + direction="l", + }, + [0x1066E]={ + category="lo", + direction="l", + }, + [0x1066F]={ + category="lo", + direction="l", + }, + [0x10670]={ + category="lo", + direction="l", + }, + [0x10671]={ + category="lo", + direction="l", + }, + [0x10672]={ + category="lo", + direction="l", + }, + [0x10673]={ + category="lo", + direction="l", + }, + [0x10674]={ + category="lo", + direction="l", + }, + [0x10675]={ + category="lo", + direction="l", + }, + [0x10676]={ + category="lo", + direction="l", + }, + [0x10677]={ + category="lo", + direction="l", + }, + [0x10678]={ + category="lo", + direction="l", + }, + [0x10679]={ + category="lo", + direction="l", + }, + [0x1067A]={ + category="lo", + direction="l", + }, + [0x1067B]={ + category="lo", + direction="l", + }, + [0x1067C]={ + category="lo", + direction="l", + }, + [0x1067D]={ + category="lo", + direction="l", + }, + [0x1067E]={ + category="lo", + direction="l", + }, + [0x1067F]={ + category="lo", + direction="l", + }, + [0x10680]={ + category="lo", + direction="l", + }, + [0x10681]={ + category="lo", + direction="l", + }, + [0x10682]={ + category="lo", + direction="l", + }, + [0x10683]={ + category="lo", + direction="l", + }, + [0x10684]={ + category="lo", + direction="l", + }, + [0x10685]={ + category="lo", + direction="l", + }, + [0x10686]={ + category="lo", + direction="l", + }, + [0x10687]={ + category="lo", + direction="l", + }, + [0x10688]={ + category="lo", + direction="l", + }, + [0x10689]={ + category="lo", + direction="l", + }, + [0x1068A]={ + category="lo", + direction="l", + }, + [0x1068B]={ + category="lo", + direction="l", + }, + [0x1068C]={ + category="lo", + direction="l", + }, + [0x1068D]={ + category="lo", + direction="l", + }, + [0x1068E]={ + category="lo", + direction="l", + }, + [0x1068F]={ + category="lo", + direction="l", + }, + [0x10690]={ + category="lo", + direction="l", + }, + [0x10691]={ + category="lo", + direction="l", + }, + [0x10692]={ + category="lo", + direction="l", + }, + [0x10693]={ + category="lo", + direction="l", + }, + [0x10694]={ + category="lo", + direction="l", + }, + [0x10695]={ + category="lo", + direction="l", + }, + [0x10696]={ + category="lo", + direction="l", + }, + [0x10697]={ + category="lo", + direction="l", + }, + [0x10698]={ + category="lo", + direction="l", + }, + [0x10699]={ + category="lo", + direction="l", + }, + [0x1069A]={ + category="lo", + direction="l", + }, + [0x1069B]={ + category="lo", + direction="l", + }, + [0x1069C]={ + category="lo", + direction="l", + }, + [0x1069D]={ + category="lo", + direction="l", + }, + [0x1069E]={ + category="lo", + direction="l", + }, + [0x1069F]={ + category="lo", + direction="l", + }, + [0x106A0]={ + category="lo", + direction="l", + }, + [0x106A1]={ + category="lo", + direction="l", + }, + [0x106A2]={ + category="lo", + direction="l", + }, + [0x106A3]={ + category="lo", + direction="l", + }, + [0x106A4]={ + category="lo", + direction="l", + }, + [0x106A5]={ + category="lo", + direction="l", + }, + [0x106A6]={ + category="lo", + direction="l", + }, + [0x106A7]={ + category="lo", + direction="l", + }, + [0x106A8]={ + category="lo", + direction="l", + }, + [0x106A9]={ + category="lo", + direction="l", + }, + [0x106AA]={ + category="lo", + direction="l", + }, + [0x106AB]={ + category="lo", + direction="l", + }, + [0x106AC]={ + category="lo", + direction="l", + }, + [0x106AD]={ + category="lo", + direction="l", + }, + [0x106AE]={ + category="lo", + direction="l", + }, + [0x106AF]={ + category="lo", + direction="l", + }, + [0x106B0]={ + category="lo", + direction="l", + }, + [0x106B1]={ + category="lo", + direction="l", + }, + [0x106B2]={ + category="lo", + direction="l", + }, + [0x106B3]={ + category="lo", + direction="l", + }, + [0x106B4]={ + category="lo", + direction="l", + }, + [0x106B5]={ + category="lo", + direction="l", + }, + [0x106B6]={ + category="lo", + direction="l", + }, + [0x106B7]={ + category="lo", + direction="l", + }, + [0x106B8]={ + category="lo", + direction="l", + }, + [0x106B9]={ + category="lo", + direction="l", + }, + [0x106BA]={ + category="lo", + direction="l", + }, + [0x106BB]={ + category="lo", + direction="l", + }, + [0x106BC]={ + category="lo", + direction="l", + }, + [0x106BD]={ + category="lo", + direction="l", + }, + [0x106BE]={ + category="lo", + direction="l", + }, + [0x106BF]={ + category="lo", + direction="l", + }, + [0x106C0]={ + category="lo", + direction="l", + }, + [0x106C1]={ + category="lo", + direction="l", + }, + [0x106C2]={ + category="lo", + direction="l", + }, + [0x106C3]={ + category="lo", + direction="l", + }, + [0x106C4]={ + category="lo", + direction="l", + }, + [0x106C5]={ + category="lo", + direction="l", + }, + [0x106C6]={ + category="lo", + direction="l", + }, + [0x106C7]={ + category="lo", + direction="l", + }, + [0x106C8]={ + category="lo", + direction="l", + }, + [0x106C9]={ + category="lo", + direction="l", + }, + [0x106CA]={ + category="lo", + direction="l", + }, + [0x106CB]={ + category="lo", + direction="l", + }, + [0x106CC]={ + category="lo", + direction="l", + }, + [0x106CD]={ + category="lo", + direction="l", + }, + [0x106CE]={ + category="lo", + direction="l", + }, + [0x106CF]={ + category="lo", + direction="l", + }, + [0x106D0]={ + category="lo", + direction="l", + }, + [0x106D1]={ + category="lo", + direction="l", + }, + [0x106D2]={ + category="lo", + direction="l", + }, + [0x106D3]={ + category="lo", + direction="l", + }, + [0x106D4]={ + category="lo", + direction="l", + }, + [0x106D5]={ + category="lo", + direction="l", + }, + [0x106D6]={ + category="lo", + direction="l", + }, + [0x106D7]={ + category="lo", + direction="l", + }, + [0x106D8]={ + category="lo", + direction="l", + }, + [0x106D9]={ + category="lo", + direction="l", + }, + [0x106DA]={ + category="lo", + direction="l", + }, + [0x106DB]={ + category="lo", + direction="l", + }, + [0x106DC]={ + category="lo", + direction="l", + }, + [0x106DD]={ + category="lo", + direction="l", + }, + [0x106DE]={ + category="lo", + direction="l", + }, + [0x106DF]={ + category="lo", + direction="l", + }, + [0x106E0]={ + category="lo", + direction="l", + }, + [0x106E1]={ + category="lo", + direction="l", + }, + [0x106E2]={ + category="lo", + direction="l", + }, + [0x106E3]={ + category="lo", + direction="l", + }, + [0x106E4]={ + category="lo", + direction="l", + }, + [0x106E5]={ + category="lo", + direction="l", + }, + [0x106E6]={ + category="lo", + direction="l", + }, + [0x106E7]={ + category="lo", + direction="l", + }, + [0x106E8]={ + category="lo", + direction="l", + }, + [0x106E9]={ + category="lo", + direction="l", + }, + [0x106EA]={ + category="lo", + direction="l", + }, + [0x106EB]={ + category="lo", + direction="l", + }, + [0x106EC]={ + category="lo", + direction="l", + }, + [0x106ED]={ + category="lo", + direction="l", + }, + [0x106EE]={ + category="lo", + direction="l", + }, + [0x106EF]={ + category="lo", + direction="l", + }, + [0x106F0]={ + category="lo", + direction="l", + }, + [0x106F1]={ + category="lo", + direction="l", + }, + [0x106F2]={ + category="lo", + direction="l", + }, + [0x106F3]={ + category="lo", + direction="l", + }, + [0x106F4]={ + category="lo", + direction="l", + }, + [0x106F5]={ + category="lo", + direction="l", + }, + [0x106F6]={ + category="lo", + direction="l", + }, + [0x106F7]={ + category="lo", + direction="l", + }, + [0x106F8]={ + category="lo", + direction="l", + }, + [0x106F9]={ + category="lo", + direction="l", + }, + [0x106FA]={ + category="lo", + direction="l", + }, + [0x106FB]={ + category="lo", + direction="l", + }, + [0x106FC]={ + category="lo", + direction="l", + }, + [0x106FD]={ + category="lo", + direction="l", + }, + [0x106FE]={ + category="lo", + direction="l", + }, + [0x106FF]={ + category="lo", + direction="l", + }, + [0x10700]={ + category="lo", + direction="l", + }, + [0x10701]={ + category="lo", + direction="l", + }, + [0x10702]={ + category="lo", + direction="l", + }, + [0x10703]={ + category="lo", + direction="l", + }, + [0x10704]={ + category="lo", + direction="l", + }, + [0x10705]={ + category="lo", + direction="l", + }, + [0x10706]={ + category="lo", + direction="l", + }, + [0x10707]={ + category="lo", + direction="l", + }, + [0x10708]={ + category="lo", + direction="l", + }, + [0x10709]={ + category="lo", + direction="l", + }, + [0x1070A]={ + category="lo", + direction="l", + }, + [0x1070B]={ + category="lo", + direction="l", + }, + [0x1070C]={ + category="lo", + direction="l", + }, + [0x1070D]={ + category="lo", + direction="l", + }, + [0x1070E]={ + category="lo", + direction="l", + }, + [0x1070F]={ + category="lo", + direction="l", + }, + [0x10710]={ + category="lo", + direction="l", + }, + [0x10711]={ + category="lo", + direction="l", + }, + [0x10712]={ + category="lo", + direction="l", + }, + [0x10713]={ + category="lo", + direction="l", + }, + [0x10714]={ + category="lo", + direction="l", + }, + [0x10715]={ + category="lo", + direction="l", + }, + [0x10716]={ + category="lo", + direction="l", + }, + [0x10717]={ + category="lo", + direction="l", + }, + [0x10718]={ + category="lo", + direction="l", + }, + [0x10719]={ + category="lo", + direction="l", + }, + [0x1071A]={ + category="lo", + direction="l", + }, + [0x1071B]={ + category="lo", + direction="l", + }, + [0x1071C]={ + category="lo", + direction="l", + }, + [0x1071D]={ + category="lo", + direction="l", + }, + [0x1071E]={ + category="lo", + direction="l", + }, + [0x1071F]={ + category="lo", + direction="l", + }, + [0x10720]={ + category="lo", + direction="l", + }, + [0x10721]={ + category="lo", + direction="l", + }, + [0x10722]={ + category="lo", + direction="l", + }, + [0x10723]={ + category="lo", + direction="l", + }, + [0x10724]={ + category="lo", + direction="l", + }, + [0x10725]={ + category="lo", + direction="l", + }, + [0x10726]={ + category="lo", + direction="l", + }, + [0x10727]={ + category="lo", + direction="l", + }, + [0x10728]={ + category="lo", + direction="l", + }, + [0x10729]={ + category="lo", + direction="l", + }, + [0x1072A]={ + category="lo", + direction="l", + }, + [0x1072B]={ + category="lo", + direction="l", + }, + [0x1072C]={ + category="lo", + direction="l", + }, + [0x1072D]={ + category="lo", + direction="l", + }, + [0x1072E]={ + category="lo", + direction="l", + }, + [0x1072F]={ + category="lo", + direction="l", + }, + [0x10730]={ + category="lo", + direction="l", + }, + [0x10731]={ + category="lo", + direction="l", + }, + [0x10732]={ + category="lo", + direction="l", + }, + [0x10733]={ + category="lo", + direction="l", + }, + [0x10734]={ + category="lo", + direction="l", + }, + [0x10735]={ + category="lo", + direction="l", + }, + [0x10736]={ + category="lo", + direction="l", + }, + [0x10740]={ + category="lo", + direction="l", + }, + [0x10741]={ + category="lo", + direction="l", + }, + [0x10742]={ + category="lo", + direction="l", + }, + [0x10743]={ + category="lo", + direction="l", + }, + [0x10744]={ + category="lo", + direction="l", + }, + [0x10745]={ + category="lo", + direction="l", + }, + [0x10746]={ + category="lo", + direction="l", + }, + [0x10747]={ + category="lo", + direction="l", + }, + [0x10748]={ + category="lo", + direction="l", + }, + [0x10749]={ + category="lo", + direction="l", + }, + [0x1074A]={ + category="lo", + direction="l", + }, + [0x1074B]={ + category="lo", + direction="l", + }, + [0x1074C]={ + category="lo", + direction="l", + }, + [0x1074D]={ + category="lo", + direction="l", + }, + [0x1074E]={ + category="lo", + direction="l", + }, + [0x1074F]={ + category="lo", + direction="l", + }, + [0x10750]={ + category="lo", + direction="l", + }, + [0x10751]={ + category="lo", + direction="l", + }, + [0x10752]={ + category="lo", + direction="l", + }, + [0x10753]={ + category="lo", + direction="l", + }, + [0x10754]={ + category="lo", + direction="l", + }, + [0x10755]={ + category="lo", + direction="l", + }, + [0x10760]={ + category="lo", + direction="l", + }, + [0x10761]={ + category="lo", + direction="l", + }, + [0x10762]={ + category="lo", + direction="l", + }, + [0x10763]={ + category="lo", + direction="l", + }, + [0x10764]={ + category="lo", + direction="l", + }, + [0x10765]={ + category="lo", + direction="l", + }, + [0x10766]={ + category="lo", + direction="l", + }, + [0x10767]={ + category="lo", + direction="l", + }, [0x10800]={ category="lo", direction="r", @@ -68051,6 +71415,294 @@ return { category="no", direction="r", }, + [0x10860]={ + category="lo", + direction="r", + }, + [0x10861]={ + category="lo", + direction="r", + }, + [0x10862]={ + category="lo", + direction="r", + }, + [0x10863]={ + category="lo", + direction="r", + }, + [0x10864]={ + category="lo", + direction="r", + }, + [0x10865]={ + category="lo", + direction="r", + }, + [0x10866]={ + category="lo", + direction="r", + }, + [0x10867]={ + category="lo", + direction="r", + }, + [0x10868]={ + category="lo", + direction="r", + }, + [0x10869]={ + category="lo", + direction="r", + }, + [0x1086A]={ + category="lo", + direction="r", + }, + [0x1086B]={ + category="lo", + direction="r", + }, + [0x1086C]={ + category="lo", + direction="r", + }, + [0x1086D]={ + category="lo", + direction="r", + }, + [0x1086E]={ + category="lo", + direction="r", + }, + [0x1086F]={ + category="lo", + direction="r", + }, + [0x10870]={ + category="lo", + direction="r", + }, + [0x10871]={ + category="lo", + direction="r", + }, + [0x10872]={ + category="lo", + direction="r", + }, + [0x10873]={ + category="lo", + direction="r", + }, + [0x10874]={ + category="lo", + direction="r", + }, + [0x10875]={ + category="lo", + direction="r", + }, + [0x10876]={ + category="lo", + direction="r", + }, + [0x10877]={ + category="so", + direction="r", + }, + [0x10878]={ + category="so", + direction="r", + }, + [0x10879]={ + category="no", + direction="r", + }, + [0x1087A]={ + category="no", + direction="r", + }, + [0x1087B]={ + category="no", + direction="r", + }, + [0x1087C]={ + category="no", + direction="r", + }, + [0x1087D]={ + category="no", + direction="r", + }, + [0x1087E]={ + category="no", + direction="r", + }, + [0x1087F]={ + category="no", + direction="r", + }, + [0x10880]={ + category="lo", + direction="r", + }, + [0x10881]={ + category="lo", + direction="r", + }, + [0x10882]={ + category="lo", + direction="r", + }, + [0x10883]={ + category="lo", + direction="r", + }, + [0x10884]={ + category="lo", + direction="r", + }, + [0x10885]={ + category="lo", + direction="r", + }, + [0x10886]={ + category="lo", + direction="r", + }, + [0x10887]={ + category="lo", + direction="r", + }, + [0x10888]={ + category="lo", + direction="r", + }, + [0x10889]={ + category="lo", + direction="r", + }, + [0x1088A]={ + category="lo", + direction="r", + }, + [0x1088B]={ + category="lo", + direction="r", + }, + [0x1088C]={ + category="lo", + direction="r", + }, + [0x1088D]={ + category="lo", + direction="r", + }, + [0x1088E]={ + category="lo", + direction="r", + }, + [0x1088F]={ + category="lo", + direction="r", + }, + [0x10890]={ + category="lo", + direction="r", + }, + [0x10891]={ + category="lo", + direction="r", + }, + [0x10892]={ + category="lo", + direction="r", + }, + [0x10893]={ + category="lo", + direction="r", + }, + [0x10894]={ + category="lo", + direction="r", + }, + [0x10895]={ + category="lo", + direction="r", + }, + [0x10896]={ + category="lo", + direction="r", + }, + [0x10897]={ + category="lo", + direction="r", + }, + [0x10898]={ + category="lo", + direction="r", + }, + [0x10899]={ + category="lo", + direction="r", + }, + [0x1089A]={ + category="lo", + direction="r", + }, + [0x1089B]={ + category="lo", + direction="r", + }, + [0x1089C]={ + category="lo", + direction="r", + }, + [0x1089D]={ + category="lo", + direction="r", + }, + [0x1089E]={ + category="lo", + direction="r", + }, + [0x108A7]={ + category="no", + direction="r", + }, + [0x108A8]={ + category="no", + direction="r", + }, + [0x108A9]={ + category="no", + direction="r", + }, + [0x108AA]={ + category="no", + direction="r", + }, + [0x108AB]={ + category="no", + direction="r", + }, + [0x108AC]={ + category="no", + direction="r", + }, + [0x108AD]={ + category="no", + direction="r", + }, + [0x108AE]={ + category="no", + direction="r", + }, + [0x108AF]={ + category="no", + direction="r", + }, [0x10900]={ category="lo", direction="r", @@ -68895,6 +72547,338 @@ return { category="po", direction="r", }, + [0x10A80]={ + category="lo", + direction="r", + }, + [0x10A81]={ + category="lo", + direction="r", + }, + [0x10A82]={ + category="lo", + direction="r", + }, + [0x10A83]={ + category="lo", + direction="r", + }, + [0x10A84]={ + category="lo", + direction="r", + }, + [0x10A85]={ + category="lo", + direction="r", + }, + [0x10A86]={ + category="lo", + direction="r", + }, + [0x10A87]={ + category="lo", + direction="r", + }, + [0x10A88]={ + category="lo", + direction="r", + }, + [0x10A89]={ + category="lo", + direction="r", + }, + [0x10A8A]={ + category="lo", + direction="r", + }, + [0x10A8B]={ + category="lo", + direction="r", + }, + [0x10A8C]={ + category="lo", + direction="r", + }, + [0x10A8D]={ + category="lo", + direction="r", + }, + [0x10A8E]={ + category="lo", + direction="r", + }, + [0x10A8F]={ + category="lo", + direction="r", + }, + [0x10A90]={ + category="lo", + direction="r", + }, + [0x10A91]={ + category="lo", + direction="r", + }, + [0x10A92]={ + category="lo", + direction="r", + }, + [0x10A93]={ + category="lo", + direction="r", + }, + [0x10A94]={ + category="lo", + direction="r", + }, + [0x10A95]={ + category="lo", + direction="r", + }, + [0x10A96]={ + category="lo", + direction="r", + }, + [0x10A97]={ + category="lo", + direction="r", + }, + [0x10A98]={ + category="lo", + direction="r", + }, + [0x10A99]={ + category="lo", + direction="r", + }, + [0x10A9A]={ + category="lo", + direction="r", + }, + [0x10A9B]={ + category="lo", + direction="r", + }, + [0x10A9C]={ + category="lo", + direction="r", + }, + [0x10A9D]={ + category="no", + direction="r", + }, + [0x10A9E]={ + category="no", + direction="r", + }, + [0x10A9F]={ + category="no", + direction="r", + }, + [0x10AC0]={ + category="lo", + direction="r", + }, + [0x10AC1]={ + category="lo", + direction="r", + }, + [0x10AC2]={ + category="lo", + direction="r", + }, + [0x10AC3]={ + category="lo", + direction="r", + }, + [0x10AC4]={ + category="lo", + direction="r", + }, + [0x10AC5]={ + category="lo", + direction="r", + }, + [0x10AC6]={ + category="lo", + direction="r", + }, + [0x10AC7]={ + category="lo", + direction="r", + }, + [0x10AC8]={ + category="so", + direction="r", + }, + [0x10AC9]={ + category="lo", + direction="r", + }, + [0x10ACA]={ + category="lo", + direction="r", + }, + [0x10ACB]={ + category="lo", + direction="r", + }, + [0x10ACC]={ + category="lo", + direction="r", + }, + [0x10ACD]={ + category="lo", + direction="r", + }, + [0x10ACE]={ + category="lo", + direction="r", + }, + [0x10ACF]={ + category="lo", + direction="r", + }, + [0x10AD0]={ + category="lo", + direction="r", + }, + [0x10AD1]={ + category="lo", + direction="r", + }, + [0x10AD2]={ + category="lo", + direction="r", + }, + [0x10AD3]={ + category="lo", + direction="r", + }, + [0x10AD4]={ + category="lo", + direction="r", + }, + [0x10AD5]={ + category="lo", + direction="r", + }, + [0x10AD6]={ + category="lo", + direction="r", + }, + [0x10AD7]={ + category="lo", + direction="r", + }, + [0x10AD8]={ + category="lo", + direction="r", + }, + [0x10AD9]={ + category="lo", + direction="r", + }, + [0x10ADA]={ + category="lo", + direction="r", + }, + [0x10ADB]={ + category="lo", + direction="r", + }, + [0x10ADC]={ + category="lo", + direction="r", + }, + [0x10ADD]={ + category="lo", + direction="r", + }, + [0x10ADE]={ + category="lo", + direction="r", + }, + [0x10ADF]={ + category="lo", + direction="r", + }, + [0x10AE0]={ + category="lo", + direction="r", + }, + [0x10AE1]={ + category="lo", + direction="r", + }, + [0x10AE2]={ + category="lo", + direction="r", + }, + [0x10AE3]={ + category="lo", + direction="r", + }, + [0x10AE4]={ + category="lo", + direction="r", + }, + [0x10AE5]={ + category="mn", + direction="nsm", + }, + [0x10AE6]={ + category="mn", + direction="nsm", + }, + [0x10AEB]={ + category="no", + direction="r", + }, + [0x10AEC]={ + category="no", + direction="r", + }, + [0x10AED]={ + category="no", + direction="r", + }, + [0x10AEE]={ + category="no", + direction="r", + }, + [0x10AEF]={ + category="no", + direction="r", + }, + [0x10AF0]={ + category="po", + direction="r", + }, + [0x10AF1]={ + category="po", + direction="r", + }, + [0x10AF2]={ + category="po", + direction="r", + }, + [0x10AF3]={ + category="po", + direction="r", + }, + [0x10AF4]={ + category="po", + direction="r", + }, + [0x10AF5]={ + category="po", + direction="r", + }, + [0x10AF6]={ + category="po", + direction="r", + }, [0x10B00]={ category="lo", direction="r", @@ -69367,6 +73351,122 @@ return { category="no", direction="r", }, + [0x10B80]={ + category="lo", + direction="r", + }, + [0x10B81]={ + category="lo", + direction="r", + }, + [0x10B82]={ + category="lo", + direction="r", + }, + [0x10B83]={ + category="lo", + direction="r", + }, + [0x10B84]={ + category="lo", + direction="r", + }, + [0x10B85]={ + category="lo", + direction="r", + }, + [0x10B86]={ + category="lo", + direction="r", + }, + [0x10B87]={ + category="lo", + direction="r", + }, + [0x10B88]={ + category="lo", + direction="r", + }, + [0x10B89]={ + category="lo", + direction="r", + }, + [0x10B8A]={ + category="lo", + direction="r", + }, + [0x10B8B]={ + category="lo", + direction="r", + }, + [0x10B8C]={ + category="lo", + direction="r", + }, + [0x10B8D]={ + category="lo", + direction="r", + }, + [0x10B8E]={ + category="lo", + direction="r", + }, + [0x10B8F]={ + category="lo", + direction="r", + }, + [0x10B90]={ + category="lo", + direction="r", + }, + [0x10B91]={ + category="lo", + direction="r", + }, + [0x10B99]={ + category="po", + direction="r", + }, + [0x10B9A]={ + category="po", + direction="r", + }, + [0x10B9B]={ + category="po", + direction="r", + }, + [0x10B9C]={ + category="po", + direction="r", + }, + [0x10BA9]={ + category="no", + direction="r", + }, + [0x10BAA]={ + category="no", + direction="r", + }, + [0x10BAB]={ + category="no", + direction="r", + }, + [0x10BAC]={ + category="no", + direction="r", + }, + [0x10BAD]={ + category="no", + direction="r", + }, + [0x10BAE]={ + category="no", + direction="r", + }, + [0x10BAF]={ + category="no", + direction="r", + }, [0x10C00]={ category="lo", direction="r", @@ -70215,6 +74315,10 @@ return { category="nd", direction="l", }, + [0x1107F]={ + category="mn", + direction="nsm", + }, [0x11080]={ category="mn", direction="nsm", @@ -70887,6 +74991,162 @@ return { category="po", direction="l", }, + [0x11150]={ + category="lo", + direction="l", + }, + [0x11151]={ + category="lo", + direction="l", + }, + [0x11152]={ + category="lo", + direction="l", + }, + [0x11153]={ + category="lo", + direction="l", + }, + [0x11154]={ + category="lo", + direction="l", + }, + [0x11155]={ + category="lo", + direction="l", + }, + [0x11156]={ + category="lo", + direction="l", + }, + [0x11157]={ + category="lo", + direction="l", + }, + [0x11158]={ + category="lo", + direction="l", + }, + [0x11159]={ + category="lo", + direction="l", + }, + [0x1115A]={ + category="lo", + direction="l", + }, + [0x1115B]={ + category="lo", + direction="l", + }, + [0x1115C]={ + category="lo", + direction="l", + }, + [0x1115D]={ + category="lo", + direction="l", + }, + [0x1115E]={ + category="lo", + direction="l", + }, + [0x1115F]={ + category="lo", + direction="l", + }, + [0x11160]={ + category="lo", + direction="l", + }, + [0x11161]={ + category="lo", + direction="l", + }, + [0x11162]={ + category="lo", + direction="l", + }, + [0x11163]={ + category="lo", + direction="l", + }, + [0x11164]={ + category="lo", + direction="l", + }, + [0x11165]={ + category="lo", + direction="l", + }, + [0x11166]={ + category="lo", + direction="l", + }, + [0x11167]={ + category="lo", + direction="l", + }, + [0x11168]={ + category="lo", + direction="l", + }, + [0x11169]={ + category="lo", + direction="l", + }, + [0x1116A]={ + category="lo", + direction="l", + }, + [0x1116B]={ + category="lo", + direction="l", + }, + [0x1116C]={ + category="lo", + direction="l", + }, + [0x1116D]={ + category="lo", + direction="l", + }, + [0x1116E]={ + category="lo", + direction="l", + }, + [0x1116F]={ + category="lo", + direction="l", + }, + [0x11170]={ + category="lo", + direction="l", + }, + [0x11171]={ + category="lo", + direction="l", + }, + [0x11172]={ + category="lo", + direction="l", + }, + [0x11173]={ + category="mn", + direction="nsm", + }, + [0x11174]={ + category="po", + direction="l", + }, + [0x11175]={ + category="po", + direction="l", + }, + [0x11176]={ + category="lo", + direction="l", + }, [0x11180]={ category="mn", direction="nsm", @@ -71179,6 +75439,10 @@ return { category="po", direction="l", }, + [0x111CD]={ + category="po", + direction="l", + }, [0x111D0]={ category="nd", direction="l", @@ -71219,6 +75483,1874 @@ return { category="nd", direction="l", }, + [0x111DA]={ + category="lo", + direction="l", + }, + [0x111E1]={ + category="no", + direction="l", + }, + [0x111E2]={ + category="no", + direction="l", + }, + [0x111E3]={ + category="no", + direction="l", + }, + [0x111E4]={ + category="no", + direction="l", + }, + [0x111E5]={ + category="no", + direction="l", + }, + [0x111E6]={ + category="no", + direction="l", + }, + [0x111E7]={ + category="no", + direction="l", + }, + [0x111E8]={ + category="no", + direction="l", + }, + [0x111E9]={ + category="no", + direction="l", + }, + [0x111EA]={ + category="no", + direction="l", + }, + [0x111EB]={ + category="no", + direction="l", + }, + [0x111EC]={ + category="no", + direction="l", + }, + [0x111ED]={ + category="no", + direction="l", + }, + [0x111EE]={ + category="no", + direction="l", + }, + [0x111EF]={ + category="no", + direction="l", + }, + [0x111F0]={ + category="no", + direction="l", + }, + [0x111F1]={ + category="no", + direction="l", + }, + [0x111F2]={ + category="no", + direction="l", + }, + [0x111F3]={ + category="no", + direction="l", + }, + [0x111F4]={ + category="no", + direction="l", + }, + [0x11200]={ + category="lo", + direction="l", + }, + [0x11201]={ + category="lo", + direction="l", + }, + [0x11202]={ + category="lo", + direction="l", + }, + [0x11203]={ + category="lo", + direction="l", + }, + [0x11204]={ + category="lo", + direction="l", + }, + [0x11205]={ + category="lo", + direction="l", + }, + [0x11206]={ + category="lo", + direction="l", + }, + [0x11207]={ + category="lo", + direction="l", + }, + [0x11208]={ + category="lo", + direction="l", + }, + [0x11209]={ + category="lo", + direction="l", + }, + [0x1120A]={ + category="lo", + direction="l", + }, + [0x1120B]={ + category="lo", + direction="l", + }, + [0x1120C]={ + category="lo", + direction="l", + }, + [0x1120D]={ + category="lo", + direction="l", + }, + [0x1120E]={ + category="lo", + direction="l", + }, + [0x1120F]={ + category="lo", + direction="l", + }, + [0x11210]={ + category="lo", + direction="l", + }, + [0x11211]={ + category="lo", + direction="l", + }, + [0x11213]={ + category="lo", + direction="l", + }, + [0x11214]={ + category="lo", + direction="l", + }, + [0x11215]={ + category="lo", + direction="l", + }, + [0x11216]={ + category="lo", + direction="l", + }, + [0x11217]={ + category="lo", + direction="l", + }, + [0x11218]={ + category="lo", + direction="l", + }, + [0x11219]={ + category="lo", + direction="l", + }, + [0x1121A]={ + category="lo", + direction="l", + }, + [0x1121B]={ + category="lo", + direction="l", + }, + [0x1121C]={ + category="lo", + direction="l", + }, + [0x1121D]={ + category="lo", + direction="l", + }, + [0x1121E]={ + category="lo", + direction="l", + }, + [0x1121F]={ + category="lo", + direction="l", + }, + [0x11220]={ + category="lo", + direction="l", + }, + [0x11221]={ + category="lo", + direction="l", + }, + [0x11222]={ + category="lo", + direction="l", + }, + [0x11223]={ + category="lo", + direction="l", + }, + [0x11224]={ + category="lo", + direction="l", + }, + [0x11225]={ + category="lo", + direction="l", + }, + [0x11226]={ + category="lo", + direction="l", + }, + [0x11227]={ + category="lo", + direction="l", + }, + [0x11228]={ + category="lo", + direction="l", + }, + [0x11229]={ + category="lo", + direction="l", + }, + [0x1122A]={ + category="lo", + direction="l", + }, + [0x1122B]={ + category="lo", + direction="l", + }, + [0x1122C]={ + category="mc", + direction="l", + }, + [0x1122D]={ + category="mc", + direction="l", + }, + [0x1122E]={ + category="mc", + direction="l", + }, + [0x1122F]={ + category="mn", + direction="nsm", + }, + [0x11230]={ + category="mn", + direction="nsm", + }, + [0x11231]={ + category="mn", + direction="nsm", + }, + [0x11232]={ + category="mc", + direction="l", + }, + [0x11233]={ + category="mc", + direction="l", + }, + [0x11234]={ + category="mn", + direction="nsm", + }, + [0x11235]={ + category="mc", + direction="l", + }, + [0x11236]={ + category="mn", + direction="nsm", + }, + [0x11237]={ + category="mn", + direction="nsm", + }, + [0x11238]={ + category="po", + direction="l", + }, + [0x11239]={ + category="po", + direction="l", + }, + [0x1123A]={ + category="po", + direction="l", + }, + [0x1123B]={ + category="po", + direction="l", + }, + [0x1123C]={ + category="po", + direction="l", + }, + [0x1123D]={ + category="po", + direction="l", + }, + [0x112B0]={ + category="lo", + direction="l", + }, + [0x112B1]={ + category="lo", + direction="l", + }, + [0x112B2]={ + category="lo", + direction="l", + }, + [0x112B3]={ + category="lo", + direction="l", + }, + [0x112B4]={ + category="lo", + direction="l", + }, + [0x112B5]={ + category="lo", + direction="l", + }, + [0x112B6]={ + category="lo", + direction="l", + }, + [0x112B7]={ + category="lo", + direction="l", + }, + [0x112B8]={ + category="lo", + direction="l", + }, + [0x112B9]={ + category="lo", + direction="l", + }, + [0x112BA]={ + category="lo", + direction="l", + }, + [0x112BB]={ + category="lo", + direction="l", + }, + [0x112BC]={ + category="lo", + direction="l", + }, + [0x112BD]={ + category="lo", + direction="l", + }, + [0x112BE]={ + category="lo", + direction="l", + }, + [0x112BF]={ + category="lo", + direction="l", + }, + [0x112C0]={ + category="lo", + direction="l", + }, + [0x112C1]={ + category="lo", + direction="l", + }, + [0x112C2]={ + category="lo", + direction="l", + }, + [0x112C3]={ + category="lo", + direction="l", + }, + [0x112C4]={ + category="lo", + direction="l", + }, + [0x112C5]={ + category="lo", + direction="l", + }, + [0x112C6]={ + category="lo", + direction="l", + }, + [0x112C7]={ + category="lo", + direction="l", + }, + [0x112C8]={ + category="lo", + direction="l", + }, + [0x112C9]={ + category="lo", + direction="l", + }, + [0x112CA]={ + category="lo", + direction="l", + }, + [0x112CB]={ + category="lo", + direction="l", + }, + [0x112CC]={ + category="lo", + direction="l", + }, + [0x112CD]={ + category="lo", + direction="l", + }, + [0x112CE]={ + category="lo", + direction="l", + }, + [0x112CF]={ + category="lo", + direction="l", + }, + [0x112D0]={ + category="lo", + direction="l", + }, + [0x112D1]={ + category="lo", + direction="l", + }, + [0x112D2]={ + category="lo", + direction="l", + }, + [0x112D3]={ + category="lo", + direction="l", + }, + [0x112D4]={ + category="lo", + direction="l", + }, + [0x112D5]={ + category="lo", + direction="l", + }, + [0x112D6]={ + category="lo", + direction="l", + }, + [0x112D7]={ + category="lo", + direction="l", + }, + [0x112D8]={ + category="lo", + direction="l", + }, + [0x112D9]={ + category="lo", + direction="l", + }, + [0x112DA]={ + category="lo", + direction="l", + }, + [0x112DB]={ + category="lo", + direction="l", + }, + [0x112DC]={ + category="lo", + direction="l", + }, + [0x112DD]={ + category="lo", + direction="l", + }, + [0x112DE]={ + category="lo", + direction="l", + }, + [0x112DF]={ + category="mn", + direction="nsm", + }, + [0x112E0]={ + category="mc", + direction="l", + }, + [0x112E1]={ + category="mc", + direction="l", + }, + [0x112E2]={ + category="mc", + direction="l", + }, + [0x112E3]={ + category="mn", + direction="nsm", + }, + [0x112E4]={ + category="mn", + direction="nsm", + }, + [0x112E5]={ + category="mn", + direction="nsm", + }, + [0x112E6]={ + category="mn", + direction="nsm", + }, + [0x112E7]={ + category="mn", + direction="nsm", + }, + [0x112E8]={ + category="mn", + direction="nsm", + }, + [0x112E9]={ + category="mn", + direction="nsm", + }, + [0x112EA]={ + category="mn", + direction="nsm", + }, + [0x112F0]={ + category="nd", + direction="l", + }, + [0x112F1]={ + category="nd", + direction="l", + }, + [0x112F2]={ + category="nd", + direction="l", + }, + [0x112F3]={ + category="nd", + direction="l", + }, + [0x112F4]={ + category="nd", + direction="l", + }, + [0x112F5]={ + category="nd", + direction="l", + }, + [0x112F6]={ + category="nd", + direction="l", + }, + [0x112F7]={ + category="nd", + direction="l", + }, + [0x112F8]={ + category="nd", + direction="l", + }, + [0x112F9]={ + category="nd", + direction="l", + }, + [0x11301]={ + category="mn", + direction="nsm", + }, + [0x11302]={ + category="mc", + direction="l", + }, + [0x11303]={ + category="mc", + direction="l", + }, + [0x11305]={ + category="lo", + direction="l", + }, + [0x11306]={ + category="lo", + direction="l", + }, + [0x11307]={ + category="lo", + direction="l", + }, + [0x11308]={ + category="lo", + direction="l", + }, + [0x11309]={ + category="lo", + direction="l", + }, + [0x1130A]={ + category="lo", + direction="l", + }, + [0x1130B]={ + category="lo", + direction="l", + }, + [0x1130C]={ + category="lo", + direction="l", + }, + [0x1130F]={ + category="lo", + direction="l", + }, + [0x11310]={ + category="lo", + direction="l", + }, + [0x11313]={ + category="lo", + direction="l", + }, + [0x11314]={ + category="lo", + direction="l", + }, + [0x11315]={ + category="lo", + direction="l", + }, + [0x11316]={ + category="lo", + direction="l", + }, + [0x11317]={ + category="lo", + direction="l", + }, + [0x11318]={ + category="lo", + direction="l", + }, + [0x11319]={ + category="lo", + direction="l", + }, + [0x1131A]={ + category="lo", + direction="l", + }, + [0x1131B]={ + category="lo", + direction="l", + }, + [0x1131C]={ + category="lo", + direction="l", + }, + [0x1131D]={ + category="lo", + direction="l", + }, + [0x1131E]={ + category="lo", + direction="l", + }, + [0x1131F]={ + category="lo", + direction="l", + }, + [0x11320]={ + category="lo", + direction="l", + }, + [0x11321]={ + category="lo", + direction="l", + }, + [0x11322]={ + category="lo", + direction="l", + }, + [0x11323]={ + category="lo", + direction="l", + }, + [0x11324]={ + category="lo", + direction="l", + }, + [0x11325]={ + category="lo", + direction="l", + }, + [0x11326]={ + category="lo", + direction="l", + }, + [0x11327]={ + category="lo", + direction="l", + }, + [0x11328]={ + category="lo", + direction="l", + }, + [0x1132A]={ + category="lo", + direction="l", + }, + [0x1132B]={ + category="lo", + direction="l", + }, + [0x1132C]={ + category="lo", + direction="l", + }, + [0x1132D]={ + category="lo", + direction="l", + }, + [0x1132E]={ + category="lo", + direction="l", + }, + [0x1132F]={ + category="lo", + direction="l", + }, + [0x11330]={ + category="lo", + direction="l", + }, + [0x11332]={ + category="lo", + direction="l", + }, + [0x11333]={ + category="lo", + direction="l", + }, + [0x11335]={ + category="lo", + direction="l", + }, + [0x11336]={ + category="lo", + direction="l", + }, + [0x11337]={ + category="lo", + direction="l", + }, + [0x11338]={ + category="lo", + direction="l", + }, + [0x11339]={ + category="lo", + direction="l", + }, + [0x1133C]={ + category="mn", + direction="nsm", + }, + [0x1133D]={ + category="lo", + direction="l", + }, + [0x1133E]={ + category="mc", + direction="l", + }, + [0x1133F]={ + category="mc", + direction="l", + }, + [0x11340]={ + category="mn", + direction="nsm", + }, + [0x11341]={ + category="mc", + direction="l", + }, + [0x11342]={ + category="mc", + direction="l", + }, + [0x11343]={ + category="mc", + direction="l", + }, + [0x11344]={ + category="mc", + direction="l", + }, + [0x11347]={ + category="mc", + direction="l", + }, + [0x11348]={ + category="mc", + direction="l", + }, + [0x1134B]={ + category="mc", + direction="l", + }, + [0x1134C]={ + category="mc", + direction="l", + }, + [0x1134D]={ + category="mc", + direction="l", + }, + [0x11357]={ + category="mc", + direction="l", + }, + [0x1135D]={ + category="lo", + direction="l", + }, + [0x1135E]={ + category="lo", + direction="l", + }, + [0x1135F]={ + category="lo", + direction="l", + }, + [0x11360]={ + category="lo", + direction="l", + }, + [0x11361]={ + category="lo", + direction="l", + }, + [0x11362]={ + category="mc", + direction="l", + }, + [0x11363]={ + category="mc", + direction="l", + }, + [0x11366]={ + category="mn", + direction="nsm", + }, + [0x11367]={ + category="mn", + direction="nsm", + }, + [0x11368]={ + category="mn", + direction="nsm", + }, + [0x11369]={ + category="mn", + direction="nsm", + }, + [0x1136A]={ + category="mn", + direction="nsm", + }, + [0x1136B]={ + category="mn", + direction="nsm", + }, + [0x1136C]={ + category="mn", + direction="nsm", + }, + [0x11370]={ + category="mn", + direction="nsm", + }, + [0x11371]={ + category="mn", + direction="nsm", + }, + [0x11372]={ + category="mn", + direction="nsm", + }, + [0x11373]={ + category="mn", + direction="nsm", + }, + [0x11374]={ + category="mn", + direction="nsm", + }, + [0x11480]={ + category="lo", + direction="l", + }, + [0x11481]={ + category="lo", + direction="l", + }, + [0x11482]={ + category="lo", + direction="l", + }, + [0x11483]={ + category="lo", + direction="l", + }, + [0x11484]={ + category="lo", + direction="l", + }, + [0x11485]={ + category="lo", + direction="l", + }, + [0x11486]={ + category="lo", + direction="l", + }, + [0x11487]={ + category="lo", + direction="l", + }, + [0x11488]={ + category="lo", + direction="l", + }, + [0x11489]={ + category="lo", + direction="l", + }, + [0x1148A]={ + category="lo", + direction="l", + }, + [0x1148B]={ + category="lo", + direction="l", + }, + [0x1148C]={ + category="lo", + direction="l", + }, + [0x1148D]={ + category="lo", + direction="l", + }, + [0x1148E]={ + category="lo", + direction="l", + }, + [0x1148F]={ + category="lo", + direction="l", + }, + [0x11490]={ + category="lo", + direction="l", + }, + [0x11491]={ + category="lo", + direction="l", + }, + [0x11492]={ + category="lo", + direction="l", + }, + [0x11493]={ + category="lo", + direction="l", + }, + [0x11494]={ + category="lo", + direction="l", + }, + [0x11495]={ + category="lo", + direction="l", + }, + [0x11496]={ + category="lo", + direction="l", + }, + [0x11497]={ + category="lo", + direction="l", + }, + [0x11498]={ + category="lo", + direction="l", + }, + [0x11499]={ + category="lo", + direction="l", + }, + [0x1149A]={ + category="lo", + direction="l", + }, + [0x1149B]={ + category="lo", + direction="l", + }, + [0x1149C]={ + category="lo", + direction="l", + }, + [0x1149D]={ + category="lo", + direction="l", + }, + [0x1149E]={ + category="lo", + direction="l", + }, + [0x1149F]={ + category="lo", + direction="l", + }, + [0x114A0]={ + category="lo", + direction="l", + }, + [0x114A1]={ + category="lo", + direction="l", + }, + [0x114A2]={ + category="lo", + direction="l", + }, + [0x114A3]={ + category="lo", + direction="l", + }, + [0x114A4]={ + category="lo", + direction="l", + }, + [0x114A5]={ + category="lo", + direction="l", + }, + [0x114A6]={ + category="lo", + direction="l", + }, + [0x114A7]={ + category="lo", + direction="l", + }, + [0x114A8]={ + category="lo", + direction="l", + }, + [0x114A9]={ + category="lo", + direction="l", + }, + [0x114AA]={ + category="lo", + direction="l", + }, + [0x114AB]={ + category="lo", + direction="l", + }, + [0x114AC]={ + category="lo", + direction="l", + }, + [0x114AD]={ + category="lo", + direction="l", + }, + [0x114AE]={ + category="lo", + direction="l", + }, + [0x114AF]={ + category="lo", + direction="l", + }, + [0x114B0]={ + category="mc", + direction="l", + }, + [0x114B1]={ + category="mc", + direction="l", + }, + [0x114B2]={ + category="mc", + direction="l", + }, + [0x114B3]={ + category="mn", + direction="nsm", + }, + [0x114B4]={ + category="mn", + direction="nsm", + }, + [0x114B5]={ + category="mn", + direction="nsm", + }, + [0x114B6]={ + category="mn", + direction="nsm", + }, + [0x114B7]={ + category="mn", + direction="nsm", + }, + [0x114B8]={ + category="mn", + direction="nsm", + }, + [0x114B9]={ + category="mc", + direction="l", + }, + [0x114BA]={ + category="mn", + direction="nsm", + }, + [0x114BB]={ + category="mc", + direction="l", + }, + [0x114BC]={ + category="mc", + direction="l", + }, + [0x114BD]={ + category="mc", + direction="l", + }, + [0x114BE]={ + category="mc", + direction="l", + }, + [0x114BF]={ + category="mn", + direction="nsm", + }, + [0x114C0]={ + category="mn", + direction="nsm", + }, + [0x114C1]={ + category="mc", + direction="l", + }, + [0x114C2]={ + category="mn", + direction="nsm", + }, + [0x114C3]={ + category="mn", + direction="nsm", + }, + [0x114C4]={ + category="lo", + direction="l", + }, + [0x114C5]={ + category="lo", + direction="l", + }, + [0x114C6]={ + category="po", + direction="l", + }, + [0x114C7]={ + category="lo", + direction="l", + }, + [0x114D0]={ + category="nd", + direction="l", + }, + [0x114D1]={ + category="nd", + direction="l", + }, + [0x114D2]={ + category="nd", + direction="l", + }, + [0x114D3]={ + category="nd", + direction="l", + }, + [0x114D4]={ + category="nd", + direction="l", + }, + [0x114D5]={ + category="nd", + direction="l", + }, + [0x114D6]={ + category="nd", + direction="l", + }, + [0x114D7]={ + category="nd", + direction="l", + }, + [0x114D8]={ + category="nd", + direction="l", + }, + [0x114D9]={ + category="nd", + direction="l", + }, + [0x11580]={ + category="lo", + direction="l", + }, + [0x11581]={ + category="lo", + direction="l", + }, + [0x11582]={ + category="lo", + direction="l", + }, + [0x11583]={ + category="lo", + direction="l", + }, + [0x11584]={ + category="lo", + direction="l", + }, + [0x11585]={ + category="lo", + direction="l", + }, + [0x11586]={ + category="lo", + direction="l", + }, + [0x11587]={ + category="lo", + direction="l", + }, + [0x11588]={ + category="lo", + direction="l", + }, + [0x11589]={ + category="lo", + direction="l", + }, + [0x1158A]={ + category="lo", + direction="l", + }, + [0x1158B]={ + category="lo", + direction="l", + }, + [0x1158C]={ + category="lo", + direction="l", + }, + [0x1158D]={ + category="lo", + direction="l", + }, + [0x1158E]={ + category="lo", + direction="l", + }, + [0x1158F]={ + category="lo", + direction="l", + }, + [0x11590]={ + category="lo", + direction="l", + }, + [0x11591]={ + category="lo", + direction="l", + }, + [0x11592]={ + category="lo", + direction="l", + }, + [0x11593]={ + category="lo", + direction="l", + }, + [0x11594]={ + category="lo", + direction="l", + }, + [0x11595]={ + category="lo", + direction="l", + }, + [0x11596]={ + category="lo", + direction="l", + }, + [0x11597]={ + category="lo", + direction="l", + }, + [0x11598]={ + category="lo", + direction="l", + }, + [0x11599]={ + category="lo", + direction="l", + }, + [0x1159A]={ + category="lo", + direction="l", + }, + [0x1159B]={ + category="lo", + direction="l", + }, + [0x1159C]={ + category="lo", + direction="l", + }, + [0x1159D]={ + category="lo", + direction="l", + }, + [0x1159E]={ + category="lo", + direction="l", + }, + [0x1159F]={ + category="lo", + direction="l", + }, + [0x115A0]={ + category="lo", + direction="l", + }, + [0x115A1]={ + category="lo", + direction="l", + }, + [0x115A2]={ + category="lo", + direction="l", + }, + [0x115A3]={ + category="lo", + direction="l", + }, + [0x115A4]={ + category="lo", + direction="l", + }, + [0x115A5]={ + category="lo", + direction="l", + }, + [0x115A6]={ + category="lo", + direction="l", + }, + [0x115A7]={ + category="lo", + direction="l", + }, + [0x115A8]={ + category="lo", + direction="l", + }, + [0x115A9]={ + category="lo", + direction="l", + }, + [0x115AA]={ + category="lo", + direction="l", + }, + [0x115AB]={ + category="lo", + direction="l", + }, + [0x115AC]={ + category="lo", + direction="l", + }, + [0x115AD]={ + category="lo", + direction="l", + }, + [0x115AE]={ + category="lo", + direction="l", + }, + [0x115AF]={ + category="mc", + direction="l", + }, + [0x115B0]={ + category="mc", + direction="l", + }, + [0x115B1]={ + category="mc", + direction="l", + }, + [0x115B2]={ + category="mn", + direction="nsm", + }, + [0x115B3]={ + category="mn", + direction="nsm", + }, + [0x115B4]={ + category="mn", + direction="nsm", + }, + [0x115B5]={ + category="mn", + direction="nsm", + }, + [0x115B8]={ + category="mc", + direction="l", + }, + [0x115B9]={ + category="mc", + direction="l", + }, + [0x115BA]={ + category="mc", + direction="l", + }, + [0x115BB]={ + category="mc", + direction="l", + }, + [0x115BC]={ + category="mn", + direction="nsm", + }, + [0x115BD]={ + category="mn", + direction="nsm", + }, + [0x115BE]={ + category="mc", + direction="l", + }, + [0x115BF]={ + category="mn", + direction="nsm", + }, + [0x115C0]={ + category="mn", + direction="nsm", + }, + [0x115C1]={ + category="po", + direction="l", + }, + [0x115C2]={ + category="po", + direction="l", + }, + [0x115C3]={ + category="po", + direction="l", + }, + [0x115C4]={ + category="po", + direction="l", + }, + [0x115C5]={ + category="po", + direction="l", + }, + [0x115C6]={ + category="po", + direction="l", + }, + [0x115C7]={ + category="po", + direction="l", + }, + [0x115C8]={ + category="po", + direction="l", + }, + [0x115C9]={ + category="po", + direction="l", + }, + [0x11600]={ + category="lo", + direction="l", + }, + [0x11601]={ + category="lo", + direction="l", + }, + [0x11602]={ + category="lo", + direction="l", + }, + [0x11603]={ + category="lo", + direction="l", + }, + [0x11604]={ + category="lo", + direction="l", + }, + [0x11605]={ + category="lo", + direction="l", + }, + [0x11606]={ + category="lo", + direction="l", + }, + [0x11607]={ + category="lo", + direction="l", + }, + [0x11608]={ + category="lo", + direction="l", + }, + [0x11609]={ + category="lo", + direction="l", + }, + [0x1160A]={ + category="lo", + direction="l", + }, + [0x1160B]={ + category="lo", + direction="l", + }, + [0x1160C]={ + category="lo", + direction="l", + }, + [0x1160D]={ + category="lo", + direction="l", + }, + [0x1160E]={ + category="lo", + direction="l", + }, + [0x1160F]={ + category="lo", + direction="l", + }, + [0x11610]={ + category="lo", + direction="l", + }, + [0x11611]={ + category="lo", + direction="l", + }, + [0x11612]={ + category="lo", + direction="l", + }, + [0x11613]={ + category="lo", + direction="l", + }, + [0x11614]={ + category="lo", + direction="l", + }, + [0x11615]={ + category="lo", + direction="l", + }, + [0x11616]={ + category="lo", + direction="l", + }, + [0x11617]={ + category="lo", + direction="l", + }, + [0x11618]={ + category="lo", + direction="l", + }, + [0x11619]={ + category="lo", + direction="l", + }, + [0x1161A]={ + category="lo", + direction="l", + }, + [0x1161B]={ + category="lo", + direction="l", + }, + [0x1161C]={ + category="lo", + direction="l", + }, + [0x1161D]={ + category="lo", + direction="l", + }, + [0x1161E]={ + category="lo", + direction="l", + }, + [0x1161F]={ + category="lo", + direction="l", + }, + [0x11620]={ + category="lo", + direction="l", + }, + [0x11621]={ + category="lo", + direction="l", + }, + [0x11622]={ + category="lo", + direction="l", + }, + [0x11623]={ + category="lo", + direction="l", + }, + [0x11624]={ + category="lo", + direction="l", + }, + [0x11625]={ + category="lo", + direction="l", + }, + [0x11626]={ + category="lo", + direction="l", + }, + [0x11627]={ + category="lo", + direction="l", + }, + [0x11628]={ + category="lo", + direction="l", + }, + [0x11629]={ + category="lo", + direction="l", + }, + [0x1162A]={ + category="lo", + direction="l", + }, + [0x1162B]={ + category="lo", + direction="l", + }, + [0x1162C]={ + category="lo", + direction="l", + }, + [0x1162D]={ + category="lo", + direction="l", + }, + [0x1162E]={ + category="lo", + direction="l", + }, + [0x1162F]={ + category="lo", + direction="l", + }, + [0x11630]={ + category="mc", + direction="l", + }, + [0x11631]={ + category="mc", + direction="l", + }, + [0x11632]={ + category="mc", + direction="l", + }, + [0x11633]={ + category="mn", + direction="nsm", + }, + [0x11634]={ + category="mn", + direction="nsm", + }, + [0x11635]={ + category="mn", + direction="nsm", + }, + [0x11636]={ + category="mn", + direction="nsm", + }, + [0x11637]={ + category="mn", + direction="nsm", + }, + [0x11638]={ + category="mn", + direction="nsm", + }, + [0x11639]={ + category="mn", + direction="nsm", + }, + [0x1163A]={ + category="mn", + direction="nsm", + }, + [0x1163B]={ + category="mc", + direction="l", + }, + [0x1163C]={ + category="mc", + direction="l", + }, + [0x1163D]={ + category="mn", + direction="nsm", + }, + [0x1163E]={ + category="mc", + direction="l", + }, + [0x1163F]={ + category="mn", + direction="nsm", + }, + [0x11640]={ + category="mn", + direction="nsm", + }, + [0x11641]={ + category="po", + direction="l", + }, + [0x11642]={ + category="po", + direction="l", + }, + [0x11643]={ + category="po", + direction="l", + }, + [0x11644]={ + category="lo", + direction="l", + }, + [0x11650]={ + category="nd", + direction="l", + }, + [0x11651]={ + category="nd", + direction="l", + }, + [0x11652]={ + category="nd", + direction="l", + }, + [0x11653]={ + category="nd", + direction="l", + }, + [0x11654]={ + category="nd", + direction="l", + }, + [0x11655]={ + category="nd", + direction="l", + }, + [0x11656]={ + category="nd", + direction="l", + }, + [0x11657]={ + category="nd", + direction="l", + }, + [0x11658]={ + category="nd", + direction="l", + }, + [0x11659]={ + category="nd", + direction="l", + }, [0x11680]={ category="lo", direction="l", @@ -71483,6 +77615,570 @@ return { category="nd", direction="l", }, + [0x118A0]={ + category="lu", + direction="l", + }, + [0x118A1]={ + category="lu", + direction="l", + }, + [0x118A2]={ + category="lu", + direction="l", + }, + [0x118A3]={ + category="lu", + direction="l", + }, + [0x118A4]={ + category="lu", + direction="l", + }, + [0x118A5]={ + category="lu", + direction="l", + }, + [0x118A6]={ + category="lu", + direction="l", + }, + [0x118A7]={ + category="lu", + direction="l", + }, + [0x118A8]={ + category="lu", + direction="l", + }, + [0x118A9]={ + category="lu", + direction="l", + }, + [0x118AA]={ + category="lu", + direction="l", + }, + [0x118AB]={ + category="lu", + direction="l", + }, + [0x118AC]={ + category="lu", + direction="l", + }, + [0x118AD]={ + category="lu", + direction="l", + }, + [0x118AE]={ + category="lu", + direction="l", + }, + [0x118AF]={ + category="lu", + direction="l", + }, + [0x118B0]={ + category="lu", + direction="l", + }, + [0x118B1]={ + category="lu", + direction="l", + }, + [0x118B2]={ + category="lu", + direction="l", + }, + [0x118B3]={ + category="lu", + direction="l", + }, + [0x118B4]={ + category="lu", + direction="l", + }, + [0x118B5]={ + category="lu", + direction="l", + }, + [0x118B6]={ + category="lu", + direction="l", + }, + [0x118B7]={ + category="lu", + direction="l", + }, + [0x118B8]={ + category="lu", + direction="l", + }, + [0x118B9]={ + category="lu", + direction="l", + }, + [0x118BA]={ + category="lu", + direction="l", + }, + [0x118BB]={ + category="lu", + direction="l", + }, + [0x118BC]={ + category="lu", + direction="l", + }, + [0x118BD]={ + category="lu", + direction="l", + }, + [0x118BE]={ + category="lu", + direction="l", + }, + [0x118BF]={ + category="lu", + direction="l", + }, + [0x118C0]={ + category="ll", + direction="l", + }, + [0x118C1]={ + category="ll", + direction="l", + }, + [0x118C2]={ + category="ll", + direction="l", + }, + [0x118C3]={ + category="ll", + direction="l", + }, + [0x118C4]={ + category="ll", + direction="l", + }, + [0x118C5]={ + category="ll", + direction="l", + }, + [0x118C6]={ + category="ll", + direction="l", + }, + [0x118C7]={ + category="ll", + direction="l", + }, + [0x118C8]={ + category="ll", + direction="l", + }, + [0x118C9]={ + category="ll", + direction="l", + }, + [0x118CA]={ + category="ll", + direction="l", + }, + [0x118CB]={ + category="ll", + direction="l", + }, + [0x118CC]={ + category="ll", + direction="l", + }, + [0x118CD]={ + category="ll", + direction="l", + }, + [0x118CE]={ + category="ll", + direction="l", + }, + [0x118CF]={ + category="ll", + direction="l", + }, + [0x118D0]={ + category="ll", + direction="l", + }, + [0x118D1]={ + category="ll", + direction="l", + }, + [0x118D2]={ + category="ll", + direction="l", + }, + [0x118D3]={ + category="ll", + direction="l", + }, + [0x118D4]={ + category="ll", + direction="l", + }, + [0x118D5]={ + category="ll", + direction="l", + }, + [0x118D6]={ + category="ll", + direction="l", + }, + [0x118D7]={ + category="ll", + direction="l", + }, + [0x118D8]={ + category="ll", + direction="l", + }, + [0x118D9]={ + category="ll", + direction="l", + }, + [0x118DA]={ + category="ll", + direction="l", + }, + [0x118DB]={ + category="ll", + direction="l", + }, + [0x118DC]={ + category="ll", + direction="l", + }, + [0x118DD]={ + category="ll", + direction="l", + }, + [0x118DE]={ + category="ll", + direction="l", + }, + [0x118DF]={ + category="ll", + direction="l", + }, + [0x118E0]={ + category="nd", + direction="l", + }, + [0x118E1]={ + category="nd", + direction="l", + }, + [0x118E2]={ + category="nd", + direction="l", + }, + [0x118E3]={ + category="nd", + direction="l", + }, + [0x118E4]={ + category="nd", + direction="l", + }, + [0x118E5]={ + category="nd", + direction="l", + }, + [0x118E6]={ + category="nd", + direction="l", + }, + [0x118E7]={ + category="nd", + direction="l", + }, + [0x118E8]={ + category="nd", + direction="l", + }, + [0x118E9]={ + category="nd", + direction="l", + }, + [0x118EA]={ + category="no", + direction="l", + }, + [0x118EB]={ + category="no", + direction="l", + }, + [0x118EC]={ + category="no", + direction="l", + }, + [0x118ED]={ + category="no", + direction="l", + }, + [0x118EE]={ + category="no", + direction="l", + }, + [0x118EF]={ + category="no", + direction="l", + }, + [0x118F0]={ + category="no", + direction="l", + }, + [0x118F1]={ + category="no", + direction="l", + }, + [0x118F2]={ + category="no", + direction="l", + }, + [0x118FF]={ + category="lo", + direction="l", + }, + [0x11AC0]={ + category="lo", + direction="l", + }, + [0x11AC1]={ + category="lo", + direction="l", + }, + [0x11AC2]={ + category="lo", + direction="l", + }, + [0x11AC3]={ + category="lo", + direction="l", + }, + [0x11AC4]={ + category="lo", + direction="l", + }, + [0x11AC5]={ + category="lo", + direction="l", + }, + [0x11AC6]={ + category="lo", + direction="l", + }, + [0x11AC7]={ + category="lo", + direction="l", + }, + [0x11AC8]={ + category="lo", + direction="l", + }, + [0x11AC9]={ + category="lo", + direction="l", + }, + [0x11ACA]={ + category="lo", + direction="l", + }, + [0x11ACB]={ + category="lo", + direction="l", + }, + [0x11ACC]={ + category="lo", + direction="l", + }, + [0x11ACD]={ + category="lo", + direction="l", + }, + [0x11ACE]={ + category="lo", + direction="l", + }, + [0x11ACF]={ + category="lo", + direction="l", + }, + [0x11AD0]={ + category="lo", + direction="l", + }, + [0x11AD1]={ + category="lo", + direction="l", + }, + [0x11AD2]={ + category="lo", + direction="l", + }, + [0x11AD3]={ + category="lo", + direction="l", + }, + [0x11AD4]={ + category="lo", + direction="l", + }, + [0x11AD5]={ + category="lo", + direction="l", + }, + [0x11AD6]={ + category="lo", + direction="l", + }, + [0x11AD7]={ + category="lo", + direction="l", + }, + [0x11AD8]={ + category="lo", + direction="l", + }, + [0x11AD9]={ + category="lo", + direction="l", + }, + [0x11ADA]={ + category="lo", + direction="l", + }, + [0x11ADB]={ + category="lo", + direction="l", + }, + [0x11ADC]={ + category="lo", + direction="l", + }, + [0x11ADD]={ + category="lo", + direction="l", + }, + [0x11ADE]={ + category="lo", + direction="l", + }, + [0x11ADF]={ + category="lo", + direction="l", + }, + [0x11AE0]={ + category="lo", + direction="l", + }, + [0x11AE1]={ + category="lo", + direction="l", + }, + [0x11AE2]={ + category="lo", + direction="l", + }, + [0x11AE3]={ + category="lo", + direction="l", + }, + [0x11AE4]={ + category="lo", + direction="l", + }, + [0x11AE5]={ + category="lo", + direction="l", + }, + [0x11AE6]={ + category="lo", + direction="l", + }, + [0x11AE7]={ + category="lo", + direction="l", + }, + [0x11AE8]={ + category="lo", + direction="l", + }, + [0x11AE9]={ + category="lo", + direction="l", + }, + [0x11AEA]={ + category="lo", + direction="l", + }, + [0x11AEB]={ + category="lo", + direction="l", + }, + [0x11AEC]={ + category="lo", + direction="l", + }, + [0x11AED]={ + category="lo", + direction="l", + }, + [0x11AEE]={ + category="lo", + direction="l", + }, + [0x11AEF]={ + category="lo", + direction="l", + }, + [0x11AF0]={ + category="lo", + direction="l", + }, + [0x11AF1]={ + category="lo", + direction="l", + }, + [0x11AF2]={ + category="lo", + direction="l", + }, + [0x11AF3]={ + category="lo", + direction="l", + }, + [0x11AF4]={ + category="lo", + direction="l", + }, + [0x11AF5]={ + category="lo", + direction="l", + }, + [0x11AF6]={ + category="lo", + direction="l", + }, + [0x11AF7]={ + category="lo", + direction="l", + }, + [0x11AF8]={ + category="lo", + direction="l", + }, [0x12000]={ category="lo", direction="l", @@ -74999,6 +81695,174 @@ return { category="lo", direction="l", }, + [0x1236F]={ + category="lo", + direction="l", + }, + [0x12370]={ + category="lo", + direction="l", + }, + [0x12371]={ + category="lo", + direction="l", + }, + [0x12372]={ + category="lo", + direction="l", + }, + [0x12373]={ + category="lo", + direction="l", + }, + [0x12374]={ + category="lo", + direction="l", + }, + [0x12375]={ + category="lo", + direction="l", + }, + [0x12376]={ + category="lo", + direction="l", + }, + [0x12377]={ + category="lo", + direction="l", + }, + [0x12378]={ + category="lo", + direction="l", + }, + [0x12379]={ + category="lo", + direction="l", + }, + [0x1237A]={ + category="lo", + direction="l", + }, + [0x1237B]={ + category="lo", + direction="l", + }, + [0x1237C]={ + category="lo", + direction="l", + }, + [0x1237D]={ + category="lo", + direction="l", + }, + [0x1237E]={ + category="lo", + direction="l", + }, + [0x1237F]={ + category="lo", + direction="l", + }, + [0x12380]={ + category="lo", + direction="l", + }, + [0x12381]={ + category="lo", + direction="l", + }, + [0x12382]={ + category="lo", + direction="l", + }, + [0x12383]={ + category="lo", + direction="l", + }, + [0x12384]={ + category="lo", + direction="l", + }, + [0x12385]={ + category="lo", + direction="l", + }, + [0x12386]={ + category="lo", + direction="l", + }, + [0x12387]={ + category="lo", + direction="l", + }, + [0x12388]={ + category="lo", + direction="l", + }, + [0x12389]={ + category="lo", + direction="l", + }, + [0x1238A]={ + category="lo", + direction="l", + }, + [0x1238B]={ + category="lo", + direction="l", + }, + [0x1238C]={ + category="lo", + direction="l", + }, + [0x1238D]={ + category="lo", + direction="l", + }, + [0x1238E]={ + category="lo", + direction="l", + }, + [0x1238F]={ + category="lo", + direction="l", + }, + [0x12390]={ + category="lo", + direction="l", + }, + [0x12391]={ + category="lo", + direction="l", + }, + [0x12392]={ + category="lo", + direction="l", + }, + [0x12393]={ + category="lo", + direction="l", + }, + [0x12394]={ + category="lo", + direction="l", + }, + [0x12395]={ + category="lo", + direction="l", + }, + [0x12396]={ + category="lo", + direction="l", + }, + [0x12397]={ + category="lo", + direction="l", + }, + [0x12398]={ + category="lo", + direction="l", + }, [0x12400]={ category="nl", direction="l", @@ -75395,6 +82259,54 @@ return { category="nl", direction="l", }, + [0x12463]={ + category="nl", + direction="l", + }, + [0x12464]={ + category="nl", + direction="l", + }, + [0x12465]={ + category="nl", + direction="l", + }, + [0x12466]={ + category="nl", + direction="l", + }, + [0x12467]={ + category="nl", + direction="l", + }, + [0x12468]={ + category="nl", + direction="l", + }, + [0x12469]={ + category="nl", + direction="l", + }, + [0x1246A]={ + category="nl", + direction="l", + }, + [0x1246B]={ + category="nl", + direction="l", + }, + [0x1246C]={ + category="nl", + direction="l", + }, + [0x1246D]={ + category="nl", + direction="l", + }, + [0x1246E]={ + category="nl", + direction="l", + }, [0x12470]={ category="po", direction="l", @@ -75411,6 +82323,10 @@ return { category="po", direction="l", }, + [0x12474]={ + category="po", + direction="l", + }, [0x13000]={ category="lo", direction="l", @@ -81971,6 +88887,830 @@ return { category="lo", direction="l", }, + [0x16A40]={ + category="lo", + direction="l", + }, + [0x16A41]={ + category="lo", + direction="l", + }, + [0x16A42]={ + category="lo", + direction="l", + }, + [0x16A43]={ + category="lo", + direction="l", + }, + [0x16A44]={ + category="lo", + direction="l", + }, + [0x16A45]={ + category="lo", + direction="l", + }, + [0x16A46]={ + category="lo", + direction="l", + }, + [0x16A47]={ + category="lo", + direction="l", + }, + [0x16A48]={ + category="lo", + direction="l", + }, + [0x16A49]={ + category="lo", + direction="l", + }, + [0x16A4A]={ + category="lo", + direction="l", + }, + [0x16A4B]={ + category="lo", + direction="l", + }, + [0x16A4C]={ + category="lo", + direction="l", + }, + [0x16A4D]={ + category="lo", + direction="l", + }, + [0x16A4E]={ + category="lo", + direction="l", + }, + [0x16A4F]={ + category="lo", + direction="l", + }, + [0x16A50]={ + category="lo", + direction="l", + }, + [0x16A51]={ + category="lo", + direction="l", + }, + [0x16A52]={ + category="lo", + direction="l", + }, + [0x16A53]={ + category="lo", + direction="l", + }, + [0x16A54]={ + category="lo", + direction="l", + }, + [0x16A55]={ + category="lo", + direction="l", + }, + [0x16A56]={ + category="lo", + direction="l", + }, + [0x16A57]={ + category="lo", + direction="l", + }, + [0x16A58]={ + category="lo", + direction="l", + }, + [0x16A59]={ + category="lo", + direction="l", + }, + [0x16A5A]={ + category="lo", + direction="l", + }, + [0x16A5B]={ + category="lo", + direction="l", + }, + [0x16A5C]={ + category="lo", + direction="l", + }, + [0x16A5D]={ + category="lo", + direction="l", + }, + [0x16A5E]={ + category="lo", + direction="l", + }, + [0x16A60]={ + category="nd", + direction="l", + }, + [0x16A61]={ + category="nd", + direction="l", + }, + [0x16A62]={ + category="nd", + direction="l", + }, + [0x16A63]={ + category="nd", + direction="l", + }, + [0x16A64]={ + category="nd", + direction="l", + }, + [0x16A65]={ + category="nd", + direction="l", + }, + [0x16A66]={ + category="nd", + direction="l", + }, + [0x16A67]={ + category="nd", + direction="l", + }, + [0x16A68]={ + category="nd", + direction="l", + }, + [0x16A69]={ + category="nd", + direction="l", + }, + [0x16A6E]={ + category="po", + direction="l", + }, + [0x16A6F]={ + category="po", + direction="l", + }, + [0x16AD0]={ + category="lo", + direction="l", + }, + [0x16AD1]={ + category="lo", + direction="l", + }, + [0x16AD2]={ + category="lo", + direction="l", + }, + [0x16AD3]={ + category="lo", + direction="l", + }, + [0x16AD4]={ + category="lo", + direction="l", + }, + [0x16AD5]={ + category="lo", + direction="l", + }, + [0x16AD6]={ + category="lo", + direction="l", + }, + [0x16AD7]={ + category="lo", + direction="l", + }, + [0x16AD8]={ + category="lo", + direction="l", + }, + [0x16AD9]={ + category="lo", + direction="l", + }, + [0x16ADA]={ + category="lo", + direction="l", + }, + [0x16ADB]={ + category="lo", + direction="l", + }, + [0x16ADC]={ + category="lo", + direction="l", + }, + [0x16ADD]={ + category="lo", + direction="l", + }, + [0x16ADE]={ + category="lo", + direction="l", + }, + [0x16ADF]={ + category="lo", + direction="l", + }, + [0x16AE0]={ + category="lo", + direction="l", + }, + [0x16AE1]={ + category="lo", + direction="l", + }, + [0x16AE2]={ + category="lo", + direction="l", + }, + [0x16AE3]={ + category="lo", + direction="l", + }, + [0x16AE4]={ + category="lo", + direction="l", + }, + [0x16AE5]={ + category="lo", + direction="l", + }, + [0x16AE6]={ + category="lo", + direction="l", + }, + [0x16AE7]={ + category="lo", + direction="l", + }, + [0x16AE8]={ + category="lo", + direction="l", + }, + [0x16AE9]={ + category="lo", + direction="l", + }, + [0x16AEA]={ + category="lo", + direction="l", + }, + [0x16AEB]={ + category="lo", + direction="l", + }, + [0x16AEC]={ + category="lo", + direction="l", + }, + [0x16AED]={ + category="lo", + direction="l", + }, + [0x16AF0]={ + category="mn", + direction="nsm", + }, + [0x16AF1]={ + category="mn", + direction="nsm", + }, + [0x16AF2]={ + category="mn", + direction="nsm", + }, + [0x16AF3]={ + category="mn", + direction="nsm", + }, + [0x16AF4]={ + category="mn", + direction="nsm", + }, + [0x16AF5]={ + category="po", + direction="l", + }, + [0x16B00]={ + category="lo", + direction="l", + }, + [0x16B01]={ + category="lo", + direction="l", + }, + [0x16B02]={ + category="lo", + direction="l", + }, + [0x16B03]={ + category="lo", + direction="l", + }, + [0x16B04]={ + category="lo", + direction="l", + }, + [0x16B05]={ + category="lo", + direction="l", + }, + [0x16B06]={ + category="lo", + direction="l", + }, + [0x16B07]={ + category="lo", + direction="l", + }, + [0x16B08]={ + category="lo", + direction="l", + }, + [0x16B09]={ + category="lo", + direction="l", + }, + [0x16B0A]={ + category="lo", + direction="l", + }, + [0x16B0B]={ + category="lo", + direction="l", + }, + [0x16B0C]={ + category="lo", + direction="l", + }, + [0x16B0D]={ + category="lo", + direction="l", + }, + [0x16B0E]={ + category="lo", + direction="l", + }, + [0x16B0F]={ + category="lo", + direction="l", + }, + [0x16B10]={ + category="lo", + direction="l", + }, + [0x16B11]={ + category="lo", + direction="l", + }, + [0x16B12]={ + category="lo", + direction="l", + }, + [0x16B13]={ + category="lo", + direction="l", + }, + [0x16B14]={ + category="lo", + direction="l", + }, + [0x16B15]={ + category="lo", + direction="l", + }, + [0x16B16]={ + category="lo", + direction="l", + }, + [0x16B17]={ + category="lo", + direction="l", + }, + [0x16B18]={ + category="lo", + direction="l", + }, + [0x16B19]={ + category="lo", + direction="l", + }, + [0x16B1A]={ + category="lo", + direction="l", + }, + [0x16B1B]={ + category="lo", + direction="l", + }, + [0x16B1C]={ + category="lo", + direction="l", + }, + [0x16B1D]={ + category="lo", + direction="l", + }, + [0x16B1E]={ + category="lo", + direction="l", + }, + [0x16B1F]={ + category="lo", + direction="l", + }, + [0x16B20]={ + category="lo", + direction="l", + }, + [0x16B21]={ + category="lo", + direction="l", + }, + [0x16B22]={ + category="lo", + direction="l", + }, + [0x16B23]={ + category="lo", + direction="l", + }, + [0x16B24]={ + category="lo", + direction="l", + }, + [0x16B25]={ + category="lo", + direction="l", + }, + [0x16B26]={ + category="lo", + direction="l", + }, + [0x16B27]={ + category="lo", + direction="l", + }, + [0x16B28]={ + category="lo", + direction="l", + }, + [0x16B29]={ + category="lo", + direction="l", + }, + [0x16B2A]={ + category="lo", + direction="l", + }, + [0x16B2B]={ + category="lo", + direction="l", + }, + [0x16B2C]={ + category="lo", + direction="l", + }, + [0x16B2D]={ + category="lo", + direction="l", + }, + [0x16B2E]={ + category="lo", + direction="l", + }, + [0x16B2F]={ + category="lo", + direction="l", + }, + [0x16B30]={ + category="mn", + direction="nsm", + }, + [0x16B31]={ + category="mn", + direction="nsm", + }, + [0x16B32]={ + category="mn", + direction="nsm", + }, + [0x16B33]={ + category="mn", + direction="nsm", + }, + [0x16B34]={ + category="mn", + direction="nsm", + }, + [0x16B35]={ + category="mn", + direction="nsm", + }, + [0x16B36]={ + category="mn", + direction="nsm", + }, + [0x16B37]={ + category="po", + direction="l", + }, + [0x16B38]={ + category="po", + direction="l", + }, + [0x16B39]={ + category="po", + direction="l", + }, + [0x16B3A]={ + category="po", + direction="l", + }, + [0x16B3B]={ + category="po", + direction="l", + }, + [0x16B3C]={ + category="so", + direction="l", + }, + [0x16B3D]={ + category="so", + direction="l", + }, + [0x16B3E]={ + category="so", + direction="l", + }, + [0x16B3F]={ + category="so", + direction="l", + }, + [0x16B40]={ + category="lm", + direction="l", + }, + [0x16B41]={ + category="lm", + direction="l", + }, + [0x16B42]={ + category="lm", + direction="l", + }, + [0x16B43]={ + category="lm", + direction="l", + }, + [0x16B44]={ + category="po", + direction="l", + }, + [0x16B45]={ + category="so", + direction="l", + }, + [0x16B50]={ + category="nd", + direction="l", + }, + [0x16B51]={ + category="nd", + direction="l", + }, + [0x16B52]={ + category="nd", + direction="l", + }, + [0x16B53]={ + category="nd", + direction="l", + }, + [0x16B54]={ + category="nd", + direction="l", + }, + [0x16B55]={ + category="nd", + direction="l", + }, + [0x16B56]={ + category="nd", + direction="l", + }, + [0x16B57]={ + category="nd", + direction="l", + }, + [0x16B58]={ + category="nd", + direction="l", + }, + [0x16B59]={ + category="nd", + direction="l", + }, + [0x16B5B]={ + category="no", + direction="l", + }, + [0x16B5C]={ + category="no", + direction="l", + }, + [0x16B5D]={ + category="no", + direction="l", + }, + [0x16B5E]={ + category="no", + direction="l", + }, + [0x16B5F]={ + category="no", + direction="l", + }, + [0x16B60]={ + category="no", + direction="l", + }, + [0x16B61]={ + category="no", + direction="l", + }, + [0x16B63]={ + category="lo", + direction="l", + }, + [0x16B64]={ + category="lo", + direction="l", + }, + [0x16B65]={ + category="lo", + direction="l", + }, + [0x16B66]={ + category="lo", + direction="l", + }, + [0x16B67]={ + category="lo", + direction="l", + }, + [0x16B68]={ + category="lo", + direction="l", + }, + [0x16B69]={ + category="lo", + direction="l", + }, + [0x16B6A]={ + category="lo", + direction="l", + }, + [0x16B6B]={ + category="lo", + direction="l", + }, + [0x16B6C]={ + category="lo", + direction="l", + }, + [0x16B6D]={ + category="lo", + direction="l", + }, + [0x16B6E]={ + category="lo", + direction="l", + }, + [0x16B6F]={ + category="lo", + direction="l", + }, + [0x16B70]={ + category="lo", + direction="l", + }, + [0x16B71]={ + category="lo", + direction="l", + }, + [0x16B72]={ + category="lo", + direction="l", + }, + [0x16B73]={ + category="lo", + direction="l", + }, + [0x16B74]={ + category="lo", + direction="l", + }, + [0x16B75]={ + category="lo", + direction="l", + }, + [0x16B76]={ + category="lo", + direction="l", + }, + [0x16B77]={ + category="lo", + direction="l", + }, + [0x16B7D]={ + category="lo", + direction="l", + }, + [0x16B7E]={ + category="lo", + direction="l", + }, + [0x16B7F]={ + category="lo", + direction="l", + }, + [0x16B80]={ + category="lo", + direction="l", + }, + [0x16B81]={ + category="lo", + direction="l", + }, + [0x16B82]={ + category="lo", + direction="l", + }, + [0x16B83]={ + category="lo", + direction="l", + }, + [0x16B84]={ + category="lo", + direction="l", + }, + [0x16B85]={ + category="lo", + direction="l", + }, + [0x16B86]={ + category="lo", + direction="l", + }, + [0x16B87]={ + category="lo", + direction="l", + }, + [0x16B88]={ + category="lo", + direction="l", + }, + [0x16B89]={ + category="lo", + direction="l", + }, + [0x16B8A]={ + category="lo", + direction="l", + }, + [0x16B8B]={ + category="lo", + direction="l", + }, + [0x16B8C]={ + category="lo", + direction="l", + }, + [0x16B8D]={ + category="lo", + direction="l", + }, + [0x16B8E]={ + category="lo", + direction="l", + }, + [0x16B8F]={ + category="lo", + direction="l", + }, [0x16F00]={ category="lo", direction="l", @@ -82511,6 +90251,594 @@ return { category="lo", direction="l", }, + [0x1BC00]={ + category="lo", + direction="l", + }, + [0x1BC01]={ + category="lo", + direction="l", + }, + [0x1BC02]={ + category="lo", + direction="l", + }, + [0x1BC03]={ + category="lo", + direction="l", + }, + [0x1BC04]={ + category="lo", + direction="l", + }, + [0x1BC05]={ + category="lo", + direction="l", + }, + [0x1BC06]={ + category="lo", + direction="l", + }, + [0x1BC07]={ + category="lo", + direction="l", + }, + [0x1BC08]={ + category="lo", + direction="l", + }, + [0x1BC09]={ + category="lo", + direction="l", + }, + [0x1BC0A]={ + category="lo", + direction="l", + }, + [0x1BC0B]={ + category="lo", + direction="l", + }, + [0x1BC0C]={ + category="lo", + direction="l", + }, + [0x1BC0D]={ + category="lo", + direction="l", + }, + [0x1BC0E]={ + category="lo", + direction="l", + }, + [0x1BC0F]={ + category="lo", + direction="l", + }, + [0x1BC10]={ + category="lo", + direction="l", + }, + [0x1BC11]={ + category="lo", + direction="l", + }, + [0x1BC12]={ + category="lo", + direction="l", + }, + [0x1BC13]={ + category="lo", + direction="l", + }, + [0x1BC14]={ + category="lo", + direction="l", + }, + [0x1BC15]={ + category="lo", + direction="l", + }, + [0x1BC16]={ + category="lo", + direction="l", + }, + [0x1BC17]={ + category="lo", + direction="l", + }, + [0x1BC18]={ + category="lo", + direction="l", + }, + [0x1BC19]={ + category="lo", + direction="l", + }, + [0x1BC1A]={ + category="lo", + direction="l", + }, + [0x1BC1B]={ + category="lo", + direction="l", + }, + [0x1BC1C]={ + category="lo", + direction="l", + }, + [0x1BC1D]={ + category="lo", + direction="l", + }, + [0x1BC1E]={ + category="lo", + direction="l", + }, + [0x1BC1F]={ + category="lo", + direction="l", + }, + [0x1BC20]={ + category="lo", + direction="l", + }, + [0x1BC21]={ + category="lo", + direction="l", + }, + [0x1BC22]={ + category="lo", + direction="l", + }, + [0x1BC23]={ + category="lo", + direction="l", + }, + [0x1BC24]={ + category="lo", + direction="l", + }, + [0x1BC25]={ + category="lo", + direction="l", + }, + [0x1BC26]={ + category="lo", + direction="l", + }, + [0x1BC27]={ + category="lo", + direction="l", + }, + [0x1BC28]={ + category="lo", + direction="l", + }, + [0x1BC29]={ + category="lo", + direction="l", + }, + [0x1BC2A]={ + category="lo", + direction="l", + }, + [0x1BC2B]={ + category="lo", + direction="l", + }, + [0x1BC2C]={ + category="lo", + direction="l", + }, + [0x1BC2D]={ + category="lo", + direction="l", + }, + [0x1BC2E]={ + category="lo", + direction="l", + }, + [0x1BC2F]={ + category="lo", + direction="l", + }, + [0x1BC30]={ + category="lo", + direction="l", + }, + [0x1BC31]={ + category="lo", + direction="l", + }, + [0x1BC32]={ + category="lo", + direction="l", + }, + [0x1BC33]={ + category="lo", + direction="l", + }, + [0x1BC34]={ + category="lo", + direction="l", + }, + [0x1BC35]={ + category="lo", + direction="l", + }, + [0x1BC36]={ + category="lo", + direction="l", + }, + [0x1BC37]={ + category="lo", + direction="l", + }, + [0x1BC38]={ + category="lo", + direction="l", + }, + [0x1BC39]={ + category="lo", + direction="l", + }, + [0x1BC3A]={ + category="lo", + direction="l", + }, + [0x1BC3B]={ + category="lo", + direction="l", + }, + [0x1BC3C]={ + category="lo", + direction="l", + }, + [0x1BC3D]={ + category="lo", + direction="l", + }, + [0x1BC3E]={ + category="lo", + direction="l", + }, + [0x1BC3F]={ + category="lo", + direction="l", + }, + [0x1BC40]={ + category="lo", + direction="l", + }, + [0x1BC41]={ + category="lo", + direction="l", + }, + [0x1BC42]={ + category="lo", + direction="l", + }, + [0x1BC43]={ + category="lo", + direction="l", + }, + [0x1BC44]={ + category="lo", + direction="l", + }, + [0x1BC45]={ + category="lo", + direction="l", + }, + [0x1BC46]={ + category="lo", + direction="l", + }, + [0x1BC47]={ + category="lo", + direction="l", + }, + [0x1BC48]={ + category="lo", + direction="l", + }, + [0x1BC49]={ + category="lo", + direction="l", + }, + [0x1BC4A]={ + category="lo", + direction="l", + }, + [0x1BC4B]={ + category="lo", + direction="l", + }, + [0x1BC4C]={ + category="lo", + direction="l", + }, + [0x1BC4D]={ + category="lo", + direction="l", + }, + [0x1BC4E]={ + category="lo", + direction="l", + }, + [0x1BC4F]={ + category="lo", + direction="l", + }, + [0x1BC50]={ + category="lo", + direction="l", + }, + [0x1BC51]={ + category="lo", + direction="l", + }, + [0x1BC52]={ + category="lo", + direction="l", + }, + [0x1BC53]={ + category="lo", + direction="l", + }, + [0x1BC54]={ + category="lo", + direction="l", + }, + [0x1BC55]={ + category="lo", + direction="l", + }, + [0x1BC56]={ + category="lo", + direction="l", + }, + [0x1BC57]={ + category="lo", + direction="l", + }, + [0x1BC58]={ + category="lo", + direction="l", + }, + [0x1BC59]={ + category="lo", + direction="l", + }, + [0x1BC5A]={ + category="lo", + direction="l", + }, + [0x1BC5B]={ + category="lo", + direction="l", + }, + [0x1BC5C]={ + category="lo", + direction="l", + }, + [0x1BC5D]={ + category="lo", + direction="l", + }, + [0x1BC5E]={ + category="lo", + direction="l", + }, + [0x1BC5F]={ + category="lo", + direction="l", + }, + [0x1BC60]={ + category="lo", + direction="l", + }, + [0x1BC61]={ + category="lo", + direction="l", + }, + [0x1BC62]={ + category="lo", + direction="l", + }, + [0x1BC63]={ + category="lo", + direction="l", + }, + [0x1BC64]={ + category="lo", + direction="l", + }, + [0x1BC65]={ + category="lo", + direction="l", + }, + [0x1BC66]={ + category="lo", + direction="l", + }, + [0x1BC67]={ + category="lo", + direction="l", + }, + [0x1BC68]={ + category="lo", + direction="l", + }, + [0x1BC69]={ + category="lo", + direction="l", + }, + [0x1BC6A]={ + category="lo", + direction="l", + }, + [0x1BC70]={ + category="lo", + direction="l", + }, + [0x1BC71]={ + category="lo", + direction="l", + }, + [0x1BC72]={ + category="lo", + direction="l", + }, + [0x1BC73]={ + category="lo", + direction="l", + }, + [0x1BC74]={ + category="lo", + direction="l", + }, + [0x1BC75]={ + category="lo", + direction="l", + }, + [0x1BC76]={ + category="lo", + direction="l", + }, + [0x1BC77]={ + category="lo", + direction="l", + }, + [0x1BC78]={ + category="lo", + direction="l", + }, + [0x1BC79]={ + category="lo", + direction="l", + }, + [0x1BC7A]={ + category="lo", + direction="l", + }, + [0x1BC7B]={ + category="lo", + direction="l", + }, + [0x1BC7C]={ + category="lo", + direction="l", + }, + [0x1BC80]={ + category="lo", + direction="l", + }, + [0x1BC81]={ + category="lo", + direction="l", + }, + [0x1BC82]={ + category="lo", + direction="l", + }, + [0x1BC83]={ + category="lo", + direction="l", + }, + [0x1BC84]={ + category="lo", + direction="l", + }, + [0x1BC85]={ + category="lo", + direction="l", + }, + [0x1BC86]={ + category="lo", + direction="l", + }, + [0x1BC87]={ + category="lo", + direction="l", + }, + [0x1BC88]={ + category="lo", + direction="l", + }, + [0x1BC90]={ + category="lo", + direction="l", + }, + [0x1BC91]={ + category="lo", + direction="l", + }, + [0x1BC92]={ + category="lo", + direction="l", + }, + [0x1BC93]={ + category="lo", + direction="l", + }, + [0x1BC94]={ + category="lo", + direction="l", + }, + [0x1BC95]={ + category="lo", + direction="l", + }, + [0x1BC96]={ + category="lo", + direction="l", + }, + [0x1BC97]={ + category="lo", + direction="l", + }, + [0x1BC98]={ + category="lo", + direction="l", + }, + [0x1BC99]={ + category="lo", + direction="l", + }, + [0x1BC9C]={ + category="so", + direction="l", + }, + [0x1BC9D]={ + category="mn", + direction="nsm", + }, + [0x1BC9E]={ + category="mn", + direction="nsm", + }, + [0x1BC9F]={ + category="po", + direction="l", + }, + [0x1BCA0]={ + category="cf", + direction="bn", + }, + [0x1BCA1]={ + category="cf", + direction="bn", + }, + [0x1BCA2]={ + category="cf", + direction="bn", + }, + [0x1BCA3]={ + category="cf", + direction="bn", + }, [0x1D000]={ category="so", direction="l", @@ -89059,6 +97387,858 @@ return { category="nd", direction="en", }, + [0x1E800]={ + category="lo", + direction="r", + }, + [0x1E801]={ + category="lo", + direction="r", + }, + [0x1E802]={ + category="lo", + direction="r", + }, + [0x1E803]={ + category="lo", + direction="r", + }, + [0x1E804]={ + category="lo", + direction="r", + }, + [0x1E805]={ + category="lo", + direction="r", + }, + [0x1E806]={ + category="lo", + direction="r", + }, + [0x1E807]={ + category="lo", + direction="r", + }, + [0x1E808]={ + category="lo", + direction="r", + }, + [0x1E809]={ + category="lo", + direction="r", + }, + [0x1E80A]={ + category="lo", + direction="r", + }, + [0x1E80B]={ + category="lo", + direction="r", + }, + [0x1E80C]={ + category="lo", + direction="r", + }, + [0x1E80D]={ + category="lo", + direction="r", + }, + [0x1E80E]={ + category="lo", + direction="r", + }, + [0x1E80F]={ + category="lo", + direction="r", + }, + [0x1E810]={ + category="lo", + direction="r", + }, + [0x1E811]={ + category="lo", + direction="r", + }, + [0x1E812]={ + category="lo", + direction="r", + }, + [0x1E813]={ + category="lo", + direction="r", + }, + [0x1E814]={ + category="lo", + direction="r", + }, + [0x1E815]={ + category="lo", + direction="r", + }, + [0x1E816]={ + category="lo", + direction="r", + }, + [0x1E817]={ + category="lo", + direction="r", + }, + [0x1E818]={ + category="lo", + direction="r", + }, + [0x1E819]={ + category="lo", + direction="r", + }, + [0x1E81A]={ + category="lo", + direction="r", + }, + [0x1E81B]={ + category="lo", + direction="r", + }, + [0x1E81C]={ + category="lo", + direction="r", + }, + [0x1E81D]={ + category="lo", + direction="r", + }, + [0x1E81E]={ + category="lo", + direction="r", + }, + [0x1E81F]={ + category="lo", + direction="r", + }, + [0x1E820]={ + category="lo", + direction="r", + }, + [0x1E821]={ + category="lo", + direction="r", + }, + [0x1E822]={ + category="lo", + direction="r", + }, + [0x1E823]={ + category="lo", + direction="r", + }, + [0x1E824]={ + category="lo", + direction="r", + }, + [0x1E825]={ + category="lo", + direction="r", + }, + [0x1E826]={ + category="lo", + direction="r", + }, + [0x1E827]={ + category="lo", + direction="r", + }, + [0x1E828]={ + category="lo", + direction="r", + }, + [0x1E829]={ + category="lo", + direction="r", + }, + [0x1E82A]={ + category="lo", + direction="r", + }, + [0x1E82B]={ + category="lo", + direction="r", + }, + [0x1E82C]={ + category="lo", + direction="r", + }, + [0x1E82D]={ + category="lo", + direction="r", + }, + [0x1E82E]={ + category="lo", + direction="r", + }, + [0x1E82F]={ + category="lo", + direction="r", + }, + [0x1E830]={ + category="lo", + direction="r", + }, + [0x1E831]={ + category="lo", + direction="r", + }, + [0x1E832]={ + category="lo", + direction="r", + }, + [0x1E833]={ + category="lo", + direction="r", + }, + [0x1E834]={ + category="lo", + direction="r", + }, + [0x1E835]={ + category="lo", + direction="r", + }, + [0x1E836]={ + category="lo", + direction="r", + }, + [0x1E837]={ + category="lo", + direction="r", + }, + [0x1E838]={ + category="lo", + direction="r", + }, + [0x1E839]={ + category="lo", + direction="r", + }, + [0x1E83A]={ + category="lo", + direction="r", + }, + [0x1E83B]={ + category="lo", + direction="r", + }, + [0x1E83C]={ + category="lo", + direction="r", + }, + [0x1E83D]={ + category="lo", + direction="r", + }, + [0x1E83E]={ + category="lo", + direction="r", + }, + [0x1E83F]={ + category="lo", + direction="r", + }, + [0x1E840]={ + category="lo", + direction="r", + }, + [0x1E841]={ + category="lo", + direction="r", + }, + [0x1E842]={ + category="lo", + direction="r", + }, + [0x1E843]={ + category="lo", + direction="r", + }, + [0x1E844]={ + category="lo", + direction="r", + }, + [0x1E845]={ + category="lo", + direction="r", + }, + [0x1E846]={ + category="lo", + direction="r", + }, + [0x1E847]={ + category="lo", + direction="r", + }, + [0x1E848]={ + category="lo", + direction="r", + }, + [0x1E849]={ + category="lo", + direction="r", + }, + [0x1E84A]={ + category="lo", + direction="r", + }, + [0x1E84B]={ + category="lo", + direction="r", + }, + [0x1E84C]={ + category="lo", + direction="r", + }, + [0x1E84D]={ + category="lo", + direction="r", + }, + [0x1E84E]={ + category="lo", + direction="r", + }, + [0x1E84F]={ + category="lo", + direction="r", + }, + [0x1E850]={ + category="lo", + direction="r", + }, + [0x1E851]={ + category="lo", + direction="r", + }, + [0x1E852]={ + category="lo", + direction="r", + }, + [0x1E853]={ + category="lo", + direction="r", + }, + [0x1E854]={ + category="lo", + direction="r", + }, + [0x1E855]={ + category="lo", + direction="r", + }, + [0x1E856]={ + category="lo", + direction="r", + }, + [0x1E857]={ + category="lo", + direction="r", + }, + [0x1E858]={ + category="lo", + direction="r", + }, + [0x1E859]={ + category="lo", + direction="r", + }, + [0x1E85A]={ + category="lo", + direction="r", + }, + [0x1E85B]={ + category="lo", + direction="r", + }, + [0x1E85C]={ + category="lo", + direction="r", + }, + [0x1E85D]={ + category="lo", + direction="r", + }, + [0x1E85E]={ + category="lo", + direction="r", + }, + [0x1E85F]={ + category="lo", + direction="r", + }, + [0x1E860]={ + category="lo", + direction="r", + }, + [0x1E861]={ + category="lo", + direction="r", + }, + [0x1E862]={ + category="lo", + direction="r", + }, + [0x1E863]={ + category="lo", + direction="r", + }, + [0x1E864]={ + category="lo", + direction="r", + }, + [0x1E865]={ + category="lo", + direction="r", + }, + [0x1E866]={ + category="lo", + direction="r", + }, + [0x1E867]={ + category="lo", + direction="r", + }, + [0x1E868]={ + category="lo", + direction="r", + }, + [0x1E869]={ + category="lo", + direction="r", + }, + [0x1E86A]={ + category="lo", + direction="r", + }, + [0x1E86B]={ + category="lo", + direction="r", + }, + [0x1E86C]={ + category="lo", + direction="r", + }, + [0x1E86D]={ + category="lo", + direction="r", + }, + [0x1E86E]={ + category="lo", + direction="r", + }, + [0x1E86F]={ + category="lo", + direction="r", + }, + [0x1E870]={ + category="lo", + direction="r", + }, + [0x1E871]={ + category="lo", + direction="r", + }, + [0x1E872]={ + category="lo", + direction="r", + }, + [0x1E873]={ + category="lo", + direction="r", + }, + [0x1E874]={ + category="lo", + direction="r", + }, + [0x1E875]={ + category="lo", + direction="r", + }, + [0x1E876]={ + category="lo", + direction="r", + }, + [0x1E877]={ + category="lo", + direction="r", + }, + [0x1E878]={ + category="lo", + direction="r", + }, + [0x1E879]={ + category="lo", + direction="r", + }, + [0x1E87A]={ + category="lo", + direction="r", + }, + [0x1E87B]={ + category="lo", + direction="r", + }, + [0x1E87C]={ + category="lo", + direction="r", + }, + [0x1E87D]={ + category="lo", + direction="r", + }, + [0x1E87E]={ + category="lo", + direction="r", + }, + [0x1E87F]={ + category="lo", + direction="r", + }, + [0x1E880]={ + category="lo", + direction="r", + }, + [0x1E881]={ + category="lo", + direction="r", + }, + [0x1E882]={ + category="lo", + direction="r", + }, + [0x1E883]={ + category="lo", + direction="r", + }, + [0x1E884]={ + category="lo", + direction="r", + }, + [0x1E885]={ + category="lo", + direction="r", + }, + [0x1E886]={ + category="lo", + direction="r", + }, + [0x1E887]={ + category="lo", + direction="r", + }, + [0x1E888]={ + category="lo", + direction="r", + }, + [0x1E889]={ + category="lo", + direction="r", + }, + [0x1E88A]={ + category="lo", + direction="r", + }, + [0x1E88B]={ + category="lo", + direction="r", + }, + [0x1E88C]={ + category="lo", + direction="r", + }, + [0x1E88D]={ + category="lo", + direction="r", + }, + [0x1E88E]={ + category="lo", + direction="r", + }, + [0x1E88F]={ + category="lo", + direction="r", + }, + [0x1E890]={ + category="lo", + direction="r", + }, + [0x1E891]={ + category="lo", + direction="r", + }, + [0x1E892]={ + category="lo", + direction="r", + }, + [0x1E893]={ + category="lo", + direction="r", + }, + [0x1E894]={ + category="lo", + direction="r", + }, + [0x1E895]={ + category="lo", + direction="r", + }, + [0x1E896]={ + category="lo", + direction="r", + }, + [0x1E897]={ + category="lo", + direction="r", + }, + [0x1E898]={ + category="lo", + direction="r", + }, + [0x1E899]={ + category="lo", + direction="r", + }, + [0x1E89A]={ + category="lo", + direction="r", + }, + [0x1E89B]={ + category="lo", + direction="r", + }, + [0x1E89C]={ + category="lo", + direction="r", + }, + [0x1E89D]={ + category="lo", + direction="r", + }, + [0x1E89E]={ + category="lo", + direction="r", + }, + [0x1E89F]={ + category="lo", + direction="r", + }, + [0x1E8A0]={ + category="lo", + direction="r", + }, + [0x1E8A1]={ + category="lo", + direction="r", + }, + [0x1E8A2]={ + category="lo", + direction="r", + }, + [0x1E8A3]={ + category="lo", + direction="r", + }, + [0x1E8A4]={ + category="lo", + direction="r", + }, + [0x1E8A5]={ + category="lo", + direction="r", + }, + [0x1E8A6]={ + category="lo", + direction="r", + }, + [0x1E8A7]={ + category="lo", + direction="r", + }, + [0x1E8A8]={ + category="lo", + direction="r", + }, + [0x1E8A9]={ + category="lo", + direction="r", + }, + [0x1E8AA]={ + category="lo", + direction="r", + }, + [0x1E8AB]={ + category="lo", + direction="r", + }, + [0x1E8AC]={ + category="lo", + direction="r", + }, + [0x1E8AD]={ + category="lo", + direction="r", + }, + [0x1E8AE]={ + category="lo", + direction="r", + }, + [0x1E8AF]={ + category="lo", + direction="r", + }, + [0x1E8B0]={ + category="lo", + direction="r", + }, + [0x1E8B1]={ + category="lo", + direction="r", + }, + [0x1E8B2]={ + category="lo", + direction="r", + }, + [0x1E8B3]={ + category="lo", + direction="r", + }, + [0x1E8B4]={ + category="lo", + direction="r", + }, + [0x1E8B5]={ + category="lo", + direction="r", + }, + [0x1E8B6]={ + category="lo", + direction="r", + }, + [0x1E8B7]={ + category="lo", + direction="r", + }, + [0x1E8B8]={ + category="lo", + direction="r", + }, + [0x1E8B9]={ + category="lo", + direction="r", + }, + [0x1E8BA]={ + category="lo", + direction="r", + }, + [0x1E8BB]={ + category="lo", + direction="r", + }, + [0x1E8BC]={ + category="lo", + direction="r", + }, + [0x1E8BD]={ + category="lo", + direction="r", + }, + [0x1E8BE]={ + category="lo", + direction="r", + }, + [0x1E8BF]={ + category="lo", + direction="r", + }, + [0x1E8C0]={ + category="lo", + direction="r", + }, + [0x1E8C1]={ + category="lo", + direction="r", + }, + [0x1E8C2]={ + category="lo", + direction="r", + }, + [0x1E8C3]={ + category="lo", + direction="r", + }, + [0x1E8C4]={ + category="lo", + direction="r", + }, + [0x1E8C7]={ + category="no", + direction="r", + }, + [0x1E8C8]={ + category="no", + direction="r", + }, + [0x1E8C9]={ + category="no", + direction="r", + }, + [0x1E8CA]={ + category="no", + direction="r", + }, + [0x1E8CB]={ + category="no", + direction="r", + }, + [0x1E8CC]={ + category="no", + direction="r", + }, + [0x1E8CD]={ + category="no", + direction="r", + }, + [0x1E8CE]={ + category="no", + direction="r", + }, + [0x1E8CF]={ + category="no", + direction="r", + }, + [0x1E8D0]={ + category="mn", + direction="nsm", + }, + [0x1E8D1]={ + category="mn", + direction="nsm", + }, + [0x1E8D2]={ + category="mn", + direction="nsm", + }, + [0x1E8D3]={ + category="mn", + direction="nsm", + }, + [0x1E8D4]={ + category="mn", + direction="nsm", + }, + [0x1E8D5]={ + category="mn", + direction="nsm", + }, + [0x1E8D6]={ + category="mn", + direction="nsm", + }, [0x1EE00]={ category="lo", direction="al", @@ -90323,6 +99503,10 @@ return { category="so", direction="on", }, + [0x1F0BF]={ + category="so", + direction="on", + }, [0x1F0C1]={ category="so", direction="on", @@ -90443,6 +99627,94 @@ return { category="so", direction="on", }, + [0x1F0E0]={ + category="so", + direction="on", + }, + [0x1F0E1]={ + category="so", + direction="on", + }, + [0x1F0E2]={ + category="so", + direction="on", + }, + [0x1F0E3]={ + category="so", + direction="on", + }, + [0x1F0E4]={ + category="so", + direction="on", + }, + [0x1F0E5]={ + category="so", + direction="on", + }, + [0x1F0E6]={ + category="so", + direction="on", + }, + [0x1F0E7]={ + category="so", + direction="on", + }, + [0x1F0E8]={ + category="so", + direction="on", + }, + [0x1F0E9]={ + category="so", + direction="on", + }, + [0x1F0EA]={ + category="so", + direction="on", + }, + [0x1F0EB]={ + category="so", + direction="on", + }, + [0x1F0EC]={ + category="so", + direction="on", + }, + [0x1F0ED]={ + category="so", + direction="on", + }, + [0x1F0EE]={ + category="so", + direction="on", + }, + [0x1F0EF]={ + category="so", + direction="on", + }, + [0x1F0F0]={ + category="so", + direction="on", + }, + [0x1F0F1]={ + category="so", + direction="on", + }, + [0x1F0F2]={ + category="so", + direction="on", + }, + [0x1F0F3]={ + category="so", + direction="on", + }, + [0x1F0F4]={ + category="so", + direction="on", + }, + [0x1F0F5]={ + category="so", + direction="on", + }, [0x1F100]={ category="no", direction="en", @@ -90487,6 +99759,14 @@ return { category="no", direction="en", }, + [0x1F10B]={ + category="no", + direction="on", + }, + [0x1F10C]={ + category="no", + direction="on", + }, [0x1F110]={ category="so", direction="l", @@ -91487,6 +100767,54 @@ return { category="so", direction="on", }, + [0x1F321]={ + category="so", + direction="on", + }, + [0x1F322]={ + category="so", + direction="on", + }, + [0x1F323]={ + category="so", + direction="on", + }, + [0x1F324]={ + category="so", + direction="on", + }, + [0x1F325]={ + category="so", + direction="on", + }, + [0x1F326]={ + category="so", + direction="on", + }, + [0x1F327]={ + category="so", + direction="on", + }, + [0x1F328]={ + category="so", + direction="on", + }, + [0x1F329]={ + category="so", + direction="on", + }, + [0x1F32A]={ + category="so", + direction="on", + }, + [0x1F32B]={ + category="so", + direction="on", + }, + [0x1F32C]={ + category="so", + direction="on", + }, [0x1F330]={ category="so", direction="on", @@ -91511,6 +100839,10 @@ return { category="so", direction="on", }, + [0x1F336]={ + category="so", + direction="on", + }, [0x1F337]={ category="so", direction="on", @@ -91791,6 +101123,10 @@ return { category="so", direction="on", }, + [0x1F37D]={ + category="so", + direction="on", + }, [0x1F380]={ category="so", direction="on", @@ -91871,6 +101207,54 @@ return { category="so", direction="on", }, + [0x1F394]={ + category="so", + direction="on", + }, + [0x1F395]={ + category="so", + direction="on", + }, + [0x1F396]={ + category="so", + direction="on", + }, + [0x1F397]={ + category="so", + direction="on", + }, + [0x1F398]={ + category="so", + direction="on", + }, + [0x1F399]={ + category="so", + direction="on", + }, + [0x1F39A]={ + category="so", + direction="on", + }, + [0x1F39B]={ + category="so", + direction="on", + }, + [0x1F39C]={ + category="so", + direction="on", + }, + [0x1F39D]={ + category="so", + direction="on", + }, + [0x1F39E]={ + category="so", + direction="on", + }, + [0x1F39F]={ + category="so", + direction="on", + }, [0x1F3A0]={ category="so", direction="on", @@ -92019,6 +101403,10 @@ return { category="so", direction="on", }, + [0x1F3C5]={ + category="so", + direction="on", + }, [0x1F3C6]={ category="so", direction="on", @@ -92039,6 +101427,70 @@ return { category="so", direction="on", }, + [0x1F3CB]={ + category="so", + direction="on", + }, + [0x1F3CC]={ + category="so", + direction="on", + }, + [0x1F3CD]={ + category="so", + direction="on", + }, + [0x1F3CE]={ + category="so", + direction="on", + }, + [0x1F3D4]={ + category="so", + direction="on", + }, + [0x1F3D5]={ + category="so", + direction="on", + }, + [0x1F3D6]={ + category="so", + direction="on", + }, + [0x1F3D7]={ + category="so", + direction="on", + }, + [0x1F3D8]={ + category="so", + direction="on", + }, + [0x1F3D9]={ + category="so", + direction="on", + }, + [0x1F3DA]={ + category="so", + direction="on", + }, + [0x1F3DB]={ + category="so", + direction="on", + }, + [0x1F3DC]={ + category="so", + direction="on", + }, + [0x1F3DD]={ + category="so", + direction="on", + }, + [0x1F3DE]={ + category="so", + direction="on", + }, + [0x1F3DF]={ + category="so", + direction="on", + }, [0x1F3E0]={ category="so", direction="on", @@ -92107,6 +101559,34 @@ return { category="so", direction="on", }, + [0x1F3F1]={ + category="so", + direction="on", + }, + [0x1F3F2]={ + category="so", + direction="on", + }, + [0x1F3F3]={ + category="so", + direction="on", + }, + [0x1F3F4]={ + category="so", + direction="on", + }, + [0x1F3F5]={ + category="so", + direction="on", + }, + [0x1F3F6]={ + category="so", + direction="on", + }, + [0x1F3F7]={ + category="so", + direction="on", + }, [0x1F400]={ category="so", direction="on", @@ -92359,10 +101839,18 @@ return { category="so", direction="on", }, + [0x1F43F]={ + category="so", + direction="on", + }, [0x1F440]={ category="so", direction="on", }, + [0x1F441]={ + category="so", + direction="on", + }, [0x1F442]={ category="so", direction="on", @@ -93091,6 +102579,10 @@ return { category="so", direction="on", }, + [0x1F4F8]={ + category="so", + direction="on", + }, [0x1F4F9]={ category="so", direction="on", @@ -93107,6 +102599,14 @@ return { category="so", direction="on", }, + [0x1F4FD]={ + category="so", + direction="on", + }, + [0x1F4FE]={ + category="so", + direction="on", + }, [0x1F500]={ category="so", direction="on", @@ -93355,6 +102855,14 @@ return { category="so", direction="on", }, + [0x1F53E]={ + category="so", + direction="on", + }, + [0x1F53F]={ + category="so", + direction="on", + }, [0x1F540]={ category="so", direction="on", @@ -93371,6 +102879,34 @@ return { category="so", direction="on", }, + [0x1F544]={ + category="so", + direction="on", + }, + [0x1F545]={ + category="so", + direction="on", + }, + [0x1F546]={ + category="so", + direction="on", + }, + [0x1F547]={ + category="so", + direction="on", + }, + [0x1F548]={ + category="so", + direction="on", + }, + [0x1F549]={ + category="so", + direction="on", + }, + [0x1F54A]={ + category="so", + direction="on", + }, [0x1F550]={ category="so", direction="on", @@ -93467,6 +103003,586 @@ return { category="so", direction="on", }, + [0x1F568]={ + category="so", + direction="on", + }, + [0x1F569]={ + category="so", + direction="on", + }, + [0x1F56A]={ + category="so", + direction="on", + }, + [0x1F56B]={ + category="so", + direction="on", + }, + [0x1F56C]={ + category="so", + direction="on", + }, + [0x1F56D]={ + category="so", + direction="on", + }, + [0x1F56E]={ + category="so", + direction="on", + }, + [0x1F56F]={ + category="so", + direction="on", + }, + [0x1F570]={ + category="so", + direction="on", + }, + [0x1F571]={ + category="so", + direction="on", + }, + [0x1F572]={ + category="so", + direction="on", + }, + [0x1F573]={ + category="so", + direction="on", + }, + [0x1F574]={ + category="so", + direction="on", + }, + [0x1F575]={ + category="so", + direction="on", + }, + [0x1F576]={ + category="so", + direction="on", + }, + [0x1F577]={ + category="so", + direction="on", + }, + [0x1F578]={ + category="so", + direction="on", + }, + [0x1F579]={ + category="so", + direction="on", + }, + [0x1F57B]={ + category="so", + direction="on", + }, + [0x1F57C]={ + category="so", + direction="on", + }, + [0x1F57D]={ + category="so", + direction="on", + }, + [0x1F57E]={ + category="so", + direction="on", + }, + [0x1F57F]={ + category="so", + direction="on", + }, + [0x1F580]={ + category="so", + direction="on", + }, + [0x1F581]={ + category="so", + direction="on", + }, + [0x1F582]={ + category="so", + direction="on", + }, + [0x1F583]={ + category="so", + direction="on", + }, + [0x1F584]={ + category="so", + direction="on", + }, + [0x1F585]={ + category="so", + direction="on", + }, + [0x1F586]={ + category="so", + direction="on", + }, + [0x1F587]={ + category="so", + direction="on", + }, + [0x1F588]={ + category="so", + direction="on", + }, + [0x1F589]={ + category="so", + direction="on", + }, + [0x1F58A]={ + category="so", + direction="on", + }, + [0x1F58B]={ + category="so", + direction="on", + }, + [0x1F58C]={ + category="so", + direction="on", + }, + [0x1F58D]={ + category="so", + direction="on", + }, + [0x1F58E]={ + category="so", + direction="on", + }, + [0x1F58F]={ + category="so", + direction="on", + }, + [0x1F590]={ + category="so", + direction="on", + }, + [0x1F591]={ + category="so", + direction="on", + }, + [0x1F592]={ + category="so", + direction="on", + }, + [0x1F593]={ + category="so", + direction="on", + }, + [0x1F594]={ + category="so", + direction="on", + }, + [0x1F595]={ + category="so", + direction="on", + }, + [0x1F596]={ + category="so", + direction="on", + }, + [0x1F597]={ + category="so", + direction="on", + }, + [0x1F598]={ + category="so", + direction="on", + }, + [0x1F599]={ + category="so", + direction="on", + }, + [0x1F59A]={ + category="so", + direction="on", + }, + [0x1F59B]={ + category="so", + direction="on", + }, + [0x1F59C]={ + category="so", + direction="on", + }, + [0x1F59D]={ + category="so", + direction="on", + }, + [0x1F59E]={ + category="so", + direction="on", + }, + [0x1F59F]={ + category="so", + direction="on", + }, + [0x1F5A0]={ + category="so", + direction="on", + }, + [0x1F5A1]={ + category="so", + direction="on", + }, + [0x1F5A2]={ + category="so", + direction="on", + }, + [0x1F5A3]={ + category="so", + direction="on", + }, + [0x1F5A5]={ + category="so", + direction="on", + }, + [0x1F5A6]={ + category="so", + direction="on", + }, + [0x1F5A7]={ + category="so", + direction="on", + }, + [0x1F5A8]={ + category="so", + direction="on", + }, + [0x1F5A9]={ + category="so", + direction="on", + }, + [0x1F5AA]={ + category="so", + direction="on", + }, + [0x1F5AB]={ + category="so", + direction="on", + }, + [0x1F5AC]={ + category="so", + direction="on", + }, + [0x1F5AD]={ + category="so", + direction="on", + }, + [0x1F5AE]={ + category="so", + direction="on", + }, + [0x1F5AF]={ + category="so", + direction="on", + }, + [0x1F5B0]={ + category="so", + direction="on", + }, + [0x1F5B1]={ + category="so", + direction="on", + }, + [0x1F5B2]={ + category="so", + direction="on", + }, + [0x1F5B3]={ + category="so", + direction="on", + }, + [0x1F5B4]={ + category="so", + direction="on", + }, + [0x1F5B5]={ + category="so", + direction="on", + }, + [0x1F5B6]={ + category="so", + direction="on", + }, + [0x1F5B7]={ + category="so", + direction="on", + }, + [0x1F5B8]={ + category="so", + direction="on", + }, + [0x1F5B9]={ + category="so", + direction="on", + }, + [0x1F5BA]={ + category="so", + direction="on", + }, + [0x1F5BB]={ + category="so", + direction="on", + }, + [0x1F5BC]={ + category="so", + direction="on", + }, + [0x1F5BD]={ + category="so", + direction="on", + }, + [0x1F5BE]={ + category="so", + direction="on", + }, + [0x1F5BF]={ + category="so", + direction="on", + }, + [0x1F5C0]={ + category="so", + direction="on", + }, + [0x1F5C1]={ + category="so", + direction="on", + }, + [0x1F5C2]={ + category="so", + direction="on", + }, + [0x1F5C3]={ + category="so", + direction="on", + }, + [0x1F5C4]={ + category="so", + direction="on", + }, + [0x1F5C5]={ + category="so", + direction="on", + }, + [0x1F5C6]={ + category="so", + direction="on", + }, + [0x1F5C7]={ + category="so", + direction="on", + }, + [0x1F5C8]={ + category="so", + direction="on", + }, + [0x1F5C9]={ + category="so", + direction="on", + }, + [0x1F5CA]={ + category="so", + direction="on", + }, + [0x1F5CB]={ + category="so", + direction="on", + }, + [0x1F5CC]={ + category="so", + direction="on", + }, + [0x1F5CD]={ + category="so", + direction="on", + }, + [0x1F5CE]={ + category="so", + direction="on", + }, + [0x1F5CF]={ + category="so", + direction="on", + }, + [0x1F5D0]={ + category="so", + direction="on", + }, + [0x1F5D1]={ + category="so", + direction="on", + }, + [0x1F5D2]={ + category="so", + direction="on", + }, + [0x1F5D3]={ + category="so", + direction="on", + }, + [0x1F5D4]={ + category="so", + direction="on", + }, + [0x1F5D5]={ + category="so", + direction="on", + }, + [0x1F5D6]={ + category="so", + direction="on", + }, + [0x1F5D7]={ + category="so", + direction="on", + }, + [0x1F5D8]={ + category="so", + direction="on", + }, + [0x1F5D9]={ + category="so", + direction="on", + }, + [0x1F5DA]={ + category="so", + direction="on", + }, + [0x1F5DB]={ + category="so", + direction="on", + }, + [0x1F5DC]={ + category="so", + direction="on", + }, + [0x1F5DD]={ + category="so", + direction="on", + }, + [0x1F5DE]={ + category="so", + direction="on", + }, + [0x1F5DF]={ + category="so", + direction="on", + }, + [0x1F5E0]={ + category="so", + direction="on", + }, + [0x1F5E1]={ + category="so", + direction="on", + }, + [0x1F5E2]={ + category="so", + direction="on", + }, + [0x1F5E3]={ + category="so", + direction="on", + }, + [0x1F5E4]={ + category="so", + direction="on", + }, + [0x1F5E5]={ + category="so", + direction="on", + }, + [0x1F5E6]={ + category="so", + direction="on", + }, + [0x1F5E7]={ + category="so", + direction="on", + }, + [0x1F5E8]={ + category="so", + direction="on", + }, + [0x1F5E9]={ + category="so", + direction="on", + }, + [0x1F5EA]={ + category="so", + direction="on", + }, + [0x1F5EB]={ + category="so", + direction="on", + }, + [0x1F5EC]={ + category="so", + direction="on", + }, + [0x1F5ED]={ + category="so", + direction="on", + }, + [0x1F5EE]={ + category="so", + direction="on", + }, + [0x1F5EF]={ + category="so", + direction="on", + }, + [0x1F5F0]={ + category="so", + direction="on", + }, + [0x1F5F1]={ + category="so", + direction="on", + }, + [0x1F5F2]={ + category="so", + direction="on", + }, + [0x1F5F3]={ + category="so", + direction="on", + }, + [0x1F5F4]={ + category="so", + direction="on", + }, + [0x1F5F5]={ + category="so", + direction="on", + }, + [0x1F5F6]={ + category="so", + direction="on", + }, + [0x1F5F7]={ + category="so", + direction="on", + }, + [0x1F5F8]={ + category="so", + direction="on", + }, + [0x1F5F9]={ + category="so", + direction="on", + }, + [0x1F5FA]={ + category="so", + direction="on", + }, [0x1F5FB]={ category="so", direction="on", @@ -93747,6 +103863,14 @@ return { category="so", direction="on", }, + [0x1F641]={ + category="so", + direction="on", + }, + [0x1F642]={ + category="so", + direction="on", + }, [0x1F645]={ category="so", direction="on", @@ -93791,6 +103915,198 @@ return { category="so", direction="on", }, + [0x1F650]={ + category="so", + direction="on", + }, + [0x1F651]={ + category="so", + direction="on", + }, + [0x1F652]={ + category="so", + direction="on", + }, + [0x1F653]={ + category="so", + direction="on", + }, + [0x1F654]={ + category="so", + direction="on", + }, + [0x1F655]={ + category="so", + direction="on", + }, + [0x1F656]={ + category="so", + direction="on", + }, + [0x1F657]={ + category="so", + direction="on", + }, + [0x1F658]={ + category="so", + direction="on", + }, + [0x1F659]={ + category="so", + direction="on", + }, + [0x1F65A]={ + category="so", + direction="on", + }, + [0x1F65B]={ + category="so", + direction="on", + }, + [0x1F65C]={ + category="so", + direction="on", + }, + [0x1F65D]={ + category="so", + direction="on", + }, + [0x1F65E]={ + category="so", + direction="on", + }, + [0x1F65F]={ + category="so", + direction="on", + }, + [0x1F660]={ + category="so", + direction="on", + }, + [0x1F661]={ + category="so", + direction="on", + }, + [0x1F662]={ + category="so", + direction="on", + }, + [0x1F663]={ + category="so", + direction="on", + }, + [0x1F664]={ + category="so", + direction="on", + }, + [0x1F665]={ + category="so", + direction="on", + }, + [0x1F666]={ + category="so", + direction="on", + }, + [0x1F667]={ + category="so", + direction="on", + }, + [0x1F668]={ + category="so", + direction="on", + }, + [0x1F669]={ + category="so", + direction="on", + }, + [0x1F66A]={ + category="so", + direction="on", + }, + [0x1F66B]={ + category="so", + direction="on", + }, + [0x1F66C]={ + category="so", + direction="on", + }, + [0x1F66D]={ + category="so", + direction="on", + }, + [0x1F66E]={ + category="so", + direction="on", + }, + [0x1F66F]={ + category="so", + direction="on", + }, + [0x1F670]={ + category="so", + direction="on", + }, + [0x1F671]={ + category="so", + direction="on", + }, + [0x1F672]={ + category="so", + direction="on", + }, + [0x1F673]={ + category="so", + direction="on", + }, + [0x1F674]={ + category="so", + direction="on", + }, + [0x1F675]={ + category="so", + direction="on", + }, + [0x1F676]={ + category="so", + direction="on", + }, + [0x1F677]={ + category="so", + direction="on", + }, + [0x1F678]={ + category="so", + direction="on", + }, + [0x1F679]={ + category="so", + direction="on", + }, + [0x1F67A]={ + category="so", + direction="on", + }, + [0x1F67B]={ + category="so", + direction="on", + }, + [0x1F67C]={ + category="so", + direction="on", + }, + [0x1F67D]={ + category="so", + direction="on", + }, + [0x1F67E]={ + category="so", + direction="on", + }, + [0x1F67F]={ + category="so", + direction="on", + }, [0x1F680]={ category="so", direction="on", @@ -94071,6 +104387,114 @@ return { category="so", direction="on", }, + [0x1F6C6]={ + category="so", + direction="on", + }, + [0x1F6C7]={ + category="so", + direction="on", + }, + [0x1F6C8]={ + category="so", + direction="on", + }, + [0x1F6C9]={ + category="so", + direction="on", + }, + [0x1F6CA]={ + category="so", + direction="on", + }, + [0x1F6CB]={ + category="so", + direction="on", + }, + [0x1F6CC]={ + category="so", + direction="on", + }, + [0x1F6CD]={ + category="so", + direction="on", + }, + [0x1F6CE]={ + category="so", + direction="on", + }, + [0x1F6CF]={ + category="so", + direction="on", + }, + [0x1F6E0]={ + category="so", + direction="on", + }, + [0x1F6E1]={ + category="so", + direction="on", + }, + [0x1F6E2]={ + category="so", + direction="on", + }, + [0x1F6E3]={ + category="so", + direction="on", + }, + [0x1F6E4]={ + category="so", + direction="on", + }, + [0x1F6E5]={ + category="so", + direction="on", + }, + [0x1F6E6]={ + category="so", + direction="on", + }, + [0x1F6E7]={ + category="so", + direction="on", + }, + [0x1F6E8]={ + category="so", + direction="on", + }, + [0x1F6E9]={ + category="so", + direction="on", + }, + [0x1F6EA]={ + category="so", + direction="on", + }, + [0x1F6EB]={ + category="so", + direction="on", + }, + [0x1F6EC]={ + category="so", + direction="on", + }, + [0x1F6F0]={ + category="so", + direction="on", + }, + [0x1F6F1]={ + category="so", + direction="on", + }, + [0x1F6F2]={ + category="so", + direction="on", + }, + [0x1F6F3]={ + category="so", + direction="on", + }, [0x1F700]={ category="so", direction="on", @@ -94535,6 +104959,938 @@ return { category="so", direction="on", }, + [0x1F780]={ + category="so", + direction="on", + }, + [0x1F781]={ + category="so", + direction="on", + }, + [0x1F782]={ + category="so", + direction="on", + }, + [0x1F783]={ + category="so", + direction="on", + }, + [0x1F784]={ + category="so", + direction="on", + }, + [0x1F785]={ + category="so", + direction="on", + }, + [0x1F786]={ + category="so", + direction="on", + }, + [0x1F787]={ + category="so", + direction="on", + }, + [0x1F788]={ + category="so", + direction="on", + }, + [0x1F789]={ + category="so", + direction="on", + }, + [0x1F78A]={ + category="so", + direction="on", + }, + [0x1F78B]={ + category="so", + direction="on", + }, + [0x1F78C]={ + category="so", + direction="on", + }, + [0x1F78D]={ + category="so", + direction="on", + }, + [0x1F78E]={ + category="so", + direction="on", + }, + [0x1F78F]={ + category="so", + direction="on", + }, + [0x1F790]={ + category="so", + direction="on", + }, + [0x1F791]={ + category="so", + direction="on", + }, + [0x1F792]={ + category="so", + direction="on", + }, + [0x1F793]={ + category="so", + direction="on", + }, + [0x1F794]={ + category="so", + direction="on", + }, + [0x1F795]={ + category="so", + direction="on", + }, + [0x1F796]={ + category="so", + direction="on", + }, + [0x1F797]={ + category="so", + direction="on", + }, + [0x1F798]={ + category="so", + direction="on", + }, + [0x1F799]={ + category="so", + direction="on", + }, + [0x1F79A]={ + category="so", + direction="on", + }, + [0x1F79B]={ + category="so", + direction="on", + }, + [0x1F79C]={ + category="so", + direction="on", + }, + [0x1F79D]={ + category="so", + direction="on", + }, + [0x1F79E]={ + category="so", + direction="on", + }, + [0x1F79F]={ + category="so", + direction="on", + }, + [0x1F7A0]={ + category="so", + direction="on", + }, + [0x1F7A1]={ + category="so", + direction="on", + }, + [0x1F7A2]={ + category="so", + direction="on", + }, + [0x1F7A3]={ + category="so", + direction="on", + }, + [0x1F7A4]={ + category="so", + direction="on", + }, + [0x1F7A5]={ + category="so", + direction="on", + }, + [0x1F7A6]={ + category="so", + direction="on", + }, + [0x1F7A7]={ + category="so", + direction="on", + }, + [0x1F7A8]={ + category="so", + direction="on", + }, + [0x1F7A9]={ + category="so", + direction="on", + }, + [0x1F7AA]={ + category="so", + direction="on", + }, + [0x1F7AB]={ + category="so", + direction="on", + }, + [0x1F7AC]={ + category="so", + direction="on", + }, + [0x1F7AD]={ + category="so", + direction="on", + }, + [0x1F7AE]={ + category="so", + direction="on", + }, + [0x1F7AF]={ + category="so", + direction="on", + }, + [0x1F7B0]={ + category="so", + direction="on", + }, + [0x1F7B1]={ + category="so", + direction="on", + }, + [0x1F7B2]={ + category="so", + direction="on", + }, + [0x1F7B3]={ + category="so", + direction="on", + }, + [0x1F7B4]={ + category="so", + direction="on", + }, + [0x1F7B5]={ + category="so", + direction="on", + }, + [0x1F7B6]={ + category="so", + direction="on", + }, + [0x1F7B7]={ + category="so", + direction="on", + }, + [0x1F7B8]={ + category="so", + direction="on", + }, + [0x1F7B9]={ + category="so", + direction="on", + }, + [0x1F7BA]={ + category="so", + direction="on", + }, + [0x1F7BB]={ + category="so", + direction="on", + }, + [0x1F7BC]={ + category="so", + direction="on", + }, + [0x1F7BD]={ + category="so", + direction="on", + }, + [0x1F7BE]={ + category="so", + direction="on", + }, + [0x1F7BF]={ + category="so", + direction="on", + }, + [0x1F7C0]={ + category="so", + direction="on", + }, + [0x1F7C1]={ + category="so", + direction="on", + }, + [0x1F7C2]={ + category="so", + direction="on", + }, + [0x1F7C3]={ + category="so", + direction="on", + }, + [0x1F7C4]={ + category="so", + direction="on", + }, + [0x1F7C5]={ + category="so", + direction="on", + }, + [0x1F7C6]={ + category="so", + direction="on", + }, + [0x1F7C7]={ + category="so", + direction="on", + }, + [0x1F7C8]={ + category="so", + direction="on", + }, + [0x1F7C9]={ + category="so", + direction="on", + }, + [0x1F7CA]={ + category="so", + direction="on", + }, + [0x1F7CB]={ + category="so", + direction="on", + }, + [0x1F7CC]={ + category="so", + direction="on", + }, + [0x1F7CD]={ + category="so", + direction="on", + }, + [0x1F7CE]={ + category="so", + direction="on", + }, + [0x1F7CF]={ + category="so", + direction="on", + }, + [0x1F7D0]={ + category="so", + direction="on", + }, + [0x1F7D1]={ + category="so", + direction="on", + }, + [0x1F7D2]={ + category="so", + direction="on", + }, + [0x1F7D3]={ + category="so", + direction="on", + }, + [0x1F7D4]={ + category="so", + direction="on", + }, + [0x1F800]={ + category="so", + direction="on", + }, + [0x1F801]={ + category="so", + direction="on", + }, + [0x1F802]={ + category="so", + direction="on", + }, + [0x1F803]={ + category="so", + direction="on", + }, + [0x1F804]={ + category="so", + direction="on", + }, + [0x1F805]={ + category="so", + direction="on", + }, + [0x1F806]={ + category="so", + direction="on", + }, + [0x1F807]={ + category="so", + direction="on", + }, + [0x1F808]={ + category="so", + direction="on", + }, + [0x1F809]={ + category="so", + direction="on", + }, + [0x1F80A]={ + category="so", + direction="on", + }, + [0x1F80B]={ + category="so", + direction="on", + }, + [0x1F810]={ + category="so", + direction="on", + }, + [0x1F811]={ + category="so", + direction="on", + }, + [0x1F812]={ + category="so", + direction="on", + }, + [0x1F813]={ + category="so", + direction="on", + }, + [0x1F814]={ + category="so", + direction="on", + }, + [0x1F815]={ + category="so", + direction="on", + }, + [0x1F816]={ + category="so", + direction="on", + }, + [0x1F817]={ + category="so", + direction="on", + }, + [0x1F818]={ + category="so", + direction="on", + }, + [0x1F819]={ + category="so", + direction="on", + }, + [0x1F81A]={ + category="so", + direction="on", + }, + [0x1F81B]={ + category="so", + direction="on", + }, + [0x1F81C]={ + category="so", + direction="on", + }, + [0x1F81D]={ + category="so", + direction="on", + }, + [0x1F81E]={ + category="so", + direction="on", + }, + [0x1F81F]={ + category="so", + direction="on", + }, + [0x1F820]={ + category="so", + direction="on", + }, + [0x1F821]={ + category="so", + direction="on", + }, + [0x1F822]={ + category="so", + direction="on", + }, + [0x1F823]={ + category="so", + direction="on", + }, + [0x1F824]={ + category="so", + direction="on", + }, + [0x1F825]={ + category="so", + direction="on", + }, + [0x1F826]={ + category="so", + direction="on", + }, + [0x1F827]={ + category="so", + direction="on", + }, + [0x1F828]={ + category="so", + direction="on", + }, + [0x1F829]={ + category="so", + direction="on", + }, + [0x1F82A]={ + category="so", + direction="on", + }, + [0x1F82B]={ + category="so", + direction="on", + }, + [0x1F82C]={ + category="so", + direction="on", + }, + [0x1F82D]={ + category="so", + direction="on", + }, + [0x1F82E]={ + category="so", + direction="on", + }, + [0x1F82F]={ + category="so", + direction="on", + }, + [0x1F830]={ + category="so", + direction="on", + }, + [0x1F831]={ + category="so", + direction="on", + }, + [0x1F832]={ + category="so", + direction="on", + }, + [0x1F833]={ + category="so", + direction="on", + }, + [0x1F834]={ + category="so", + direction="on", + }, + [0x1F835]={ + category="so", + direction="on", + }, + [0x1F836]={ + category="so", + direction="on", + }, + [0x1F837]={ + category="so", + direction="on", + }, + [0x1F838]={ + category="so", + direction="on", + }, + [0x1F839]={ + category="so", + direction="on", + }, + [0x1F83A]={ + category="so", + direction="on", + }, + [0x1F83B]={ + category="so", + direction="on", + }, + [0x1F83C]={ + category="so", + direction="on", + }, + [0x1F83D]={ + category="so", + direction="on", + }, + [0x1F83E]={ + category="so", + direction="on", + }, + [0x1F83F]={ + category="so", + direction="on", + }, + [0x1F840]={ + category="so", + direction="on", + }, + [0x1F841]={ + category="so", + direction="on", + }, + [0x1F842]={ + category="so", + direction="on", + }, + [0x1F843]={ + category="so", + direction="on", + }, + [0x1F844]={ + category="so", + direction="on", + }, + [0x1F845]={ + category="so", + direction="on", + }, + [0x1F846]={ + category="so", + direction="on", + }, + [0x1F847]={ + category="so", + direction="on", + }, + [0x1F850]={ + category="so", + direction="on", + }, + [0x1F851]={ + category="so", + direction="on", + }, + [0x1F852]={ + category="so", + direction="on", + }, + [0x1F853]={ + category="so", + direction="on", + }, + [0x1F854]={ + category="so", + direction="on", + }, + [0x1F855]={ + category="so", + direction="on", + }, + [0x1F856]={ + category="so", + direction="on", + }, + [0x1F857]={ + category="so", + direction="on", + }, + [0x1F858]={ + category="so", + direction="on", + }, + [0x1F859]={ + category="so", + direction="on", + }, + [0x1F860]={ + category="so", + direction="on", + }, + [0x1F861]={ + category="so", + direction="on", + }, + [0x1F862]={ + category="so", + direction="on", + }, + [0x1F863]={ + category="so", + direction="on", + }, + [0x1F864]={ + category="so", + direction="on", + }, + [0x1F865]={ + category="so", + direction="on", + }, + [0x1F866]={ + category="so", + direction="on", + }, + [0x1F867]={ + category="so", + direction="on", + }, + [0x1F868]={ + category="so", + direction="on", + }, + [0x1F869]={ + category="so", + direction="on", + }, + [0x1F86A]={ + category="so", + direction="on", + }, + [0x1F86B]={ + category="so", + direction="on", + }, + [0x1F86C]={ + category="so", + direction="on", + }, + [0x1F86D]={ + category="so", + direction="on", + }, + [0x1F86E]={ + category="so", + direction="on", + }, + [0x1F86F]={ + category="so", + direction="on", + }, + [0x1F870]={ + category="so", + direction="on", + }, + [0x1F871]={ + category="so", + direction="on", + }, + [0x1F872]={ + category="so", + direction="on", + }, + [0x1F873]={ + category="so", + direction="on", + }, + [0x1F874]={ + category="so", + direction="on", + }, + [0x1F875]={ + category="so", + direction="on", + }, + [0x1F876]={ + category="so", + direction="on", + }, + [0x1F877]={ + category="so", + direction="on", + }, + [0x1F878]={ + category="so", + direction="on", + }, + [0x1F879]={ + category="so", + direction="on", + }, + [0x1F87A]={ + category="so", + direction="on", + }, + [0x1F87B]={ + category="so", + direction="on", + }, + [0x1F87C]={ + category="so", + direction="on", + }, + [0x1F87D]={ + category="so", + direction="on", + }, + [0x1F87E]={ + category="so", + direction="on", + }, + [0x1F87F]={ + category="so", + direction="on", + }, + [0x1F880]={ + category="so", + direction="on", + }, + [0x1F881]={ + category="so", + direction="on", + }, + [0x1F882]={ + category="so", + direction="on", + }, + [0x1F883]={ + category="so", + direction="on", + }, + [0x1F884]={ + category="so", + direction="on", + }, + [0x1F885]={ + category="so", + direction="on", + }, + [0x1F886]={ + category="so", + direction="on", + }, + [0x1F887]={ + category="so", + direction="on", + }, + [0x1F890]={ + category="so", + direction="on", + }, + [0x1F891]={ + category="so", + direction="on", + }, + [0x1F892]={ + category="so", + direction="on", + }, + [0x1F893]={ + category="so", + direction="on", + }, + [0x1F894]={ + category="so", + direction="on", + }, + [0x1F895]={ + category="so", + direction="on", + }, + [0x1F896]={ + category="so", + direction="on", + }, + [0x1F897]={ + category="so", + direction="on", + }, + [0x1F898]={ + category="so", + direction="on", + }, + [0x1F899]={ + category="so", + direction="on", + }, + [0x1F89A]={ + category="so", + direction="on", + }, + [0x1F89B]={ + category="so", + direction="on", + }, + [0x1F89C]={ + category="so", + direction="on", + }, + [0x1F89D]={ + category="so", + direction="on", + }, + [0x1F89E]={ + category="so", + direction="on", + }, + [0x1F89F]={ + category="so", + direction="on", + }, + [0x1F8A0]={ + category="so", + direction="on", + }, + [0x1F8A1]={ + category="so", + direction="on", + }, + [0x1F8A2]={ + category="so", + direction="on", + }, + [0x1F8A3]={ + category="so", + direction="on", + }, + [0x1F8A4]={ + category="so", + direction="on", + }, + [0x1F8A5]={ + category="so", + direction="on", + }, + [0x1F8A6]={ + category="so", + direction="on", + }, + [0x1F8A7]={ + category="so", + direction="on", + }, + [0x1F8A8]={ + category="so", + direction="on", + }, + [0x1F8A9]={ + category="so", + direction="on", + }, + [0x1F8AA]={ + category="so", + direction="on", + }, + [0x1F8AB]={ + category="so", + direction="on", + }, + [0x1F8AC]={ + category="so", + direction="on", + }, + [0x1F8AD]={ + category="so", + direction="on", + }, [0x2F800]={ category="lo", direction="l", diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua index b8ecb875c7d..9be29746c4b 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua @@ -1,9 +1,9 @@ if not modules then modules = { } end modules ['luaotfload-colors'] = { - version = "2.4", - comment = "companion to luaotfload.lua (font color)", + version = "2.5", + comment = "companion to luaotfload-main.lua (font color)", author = "Khaled Hosny, Elie Roux, Philipp Gesang", copyright = "Luaotfload Development Team", - license = "GNU GPL v2" + license = "GNU GPL v2.0" } --[[doc-- @@ -19,14 +19,8 @@ explanation: http://tug.org/pipermail/luatex/2013-May/004305.html --doc]]-- - -local color_callback = config.luaotfload.color_callback -if not color_callback then - --- maybe this would be better as a method: "early" | "late" - color_callback = "pre_linebreak_filter" --- color_callback = "pre_output_filter" --- old behavior, breaks expansion -end - +local log = luaotfload.log +local logreport = log.report local newnode = node.new local nodetype = node.id @@ -34,6 +28,9 @@ local traverse_nodes = node.traverse local insert_node_before = node.insert_before local insert_node_after = node.insert_after +local texset = tex.set +local texget = tex.get + local stringformat = string.format local stringgsub = string.gsub local stringfind = string.find @@ -86,8 +83,9 @@ local sanitize_color_expression = function (digits) digits = tostring(digits) local sanitized = lpegmatch(valid_digits, digits) if not sanitized then - luaotfload.warning( - "%q is not a valid rgb[a] color expression", digits) + logreport("both", 0, "color", + "%q is not a valid rgb[a] color expression", + digits) return nil end return sanitized @@ -276,20 +274,24 @@ local color_handler = function (head) local new_head = node_colorize(head, nil, nil) -- now append our page resources if res then - res["1"] = true - local tpr, t = tex.pdfpageresources, "" + res["1"] = true + local tpr = texget("pdfpageresources") + local t = "" for k in pairs(res) do local str = stringformat("/TransGs%s<</ca %s/CA %s>>", k, k, k) if not stringfind(tpr,str) then t = t .. str end end + print"" if t ~= "" then + print(">>", tpr, "<<") if not stringfind(tpr,"/ExtGState<<.*>>") then tpr = tpr.."/ExtGState<<>>" end tpr = stringgsub(tpr,"/ExtGState<<","%1"..t) - tex.pdfpageresources = tpr + texset("global", "pdfpageresources", tpr) + print(">>", tpr, "<<") end res = nil -- reset res end @@ -300,6 +302,11 @@ local color_callback_activated = 0 --- unit -> unit add_color_callback = function ( ) + local color_callback = config.luaotfload.run.color_callback + if not color_callback then + color_callback = "pre_linebreak_filter" + end + if color_callback_activated == 0 then luatexbase.add_to_callback(color_callback, color_handler, diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua new file mode 100644 index 00000000000..dfa222c9070 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua @@ -0,0 +1,704 @@ +#!/usr/bin/env texlua +------------------------------------------------------------------------------- +-- FILE: luaotfload-configuration.lua +-- DESCRIPTION: config file reader +-- REQUIREMENTS: Luaotfload 2.5 or above +-- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> +-- VERSION: same as Luaotfload +-- MODIFIED: 2014-07-13 14:19:32+0200 +------------------------------------------------------------------------------- +-- + +if not modules then modules = { } end modules ["luaotfload-configuration"] = { + version = "2.5", + comment = "part of Luaotfload", + author = "Philipp Gesang", + copyright = "Luaotfload Development Team", + license = "GNU GPL v2.0" +} + +luaotfload = luaotfload or { } +config = config or { } +config.luaotfload = { } + +local status_file = "luaotfload-status" +local luaotfloadstatus = require (status_file) + +local string = string +local stringsub = string.sub +local stringexplode = string.explode +local stringstrip = string.strip +local stringfind = string.find + +local table = table +local tableappend = table.append +local tablecopy = table.copy +local tableconcat = table.concat +local tabletohash = table.tohash + +local math = math +local mathfloor = math.floor + +local io = io +local ioloaddata = io.loaddata +local iopopen = io.popen + +local os = os +local osgetenv = os.getenv + +local lpeg = require "lpeg" +local lpegmatch = lpeg.match +local commasplitter = lpeg.splitat "," +local equalssplitter = lpeg.splitat "=" + +local kpse = kpse +local kpseexpand_path = kpse.expand_path +local kpselookup = kpse.lookup + +local lfs = lfs +local lfsisfile = lfs.isfile +local lfsisdir = lfs.isdir + +local file = file +local filejoin = file.join +local filereplacesuffix = file.replacesuffix + + +local parsers = luaotfload.parsers + +local log = luaotfload.log +local logreport = log.report + +local config_parser = parsers.config +local stripslashes = parsers.stripslashes + +local getwritablepath = caches.getwritablepath + +------------------------------------------------------------------------------- +--- SETTINGS +------------------------------------------------------------------------------- + +local path_t = 0 +local kpse_t = 1 + +local val_home = kpseexpand_path "~" +local val_xdg_config_home = kpseexpand_path "$XDG_CONFIG_HOME" + +if val_xdg_config_home == "" then val_xdg_config_home = "~/.config" end + +local config_paths = { + --- needs adapting for those other OS + { path_t, "./luaotfload.conf" }, + { path_t, "./luaotfloadrc" }, + { path_t, filejoin (val_xdg_config_home, "luaotfload/luaotfload.conf") }, + { path_t, filejoin (val_xdg_config_home, "luaotfload/luaotfloadrc") }, + { path_t, filejoin (val_home, ".luaotfloadrc") }, + { kpse_t, "luaotfloadrc" }, + { kpse_t, "luaotfload.conf" }, +} + +local valid_formats = tabletohash { + "otf", "ttc", "ttf", "dfont", "afm", "pfb", "pfa", +} + +local feature_presets = { + arab = tabletohash { + "ccmp", "locl", "isol", "fina", "fin2", + "fin3", "medi", "med2", "init", "rlig", + "calt", "liga", "cswh", "mset", "curs", + "kern", "mark", "mkmk", + }, + deva = tabletohash { + "ccmp", "locl", "init", "nukt", "akhn", + "rphf", "blwf", "half", "pstf", "vatu", + "pres", "blws", "abvs", "psts", "haln", + "calt", "blwm", "abvm", "dist", "kern", + "mark", "mkmk", + }, + khmr = tabletohash { + "ccmp", "locl", "pref", "blwf", "abvf", + "pstf", "pres", "blws", "abvs", "psts", + "clig", "calt", "blwm", "abvm", "dist", + "kern", "mark", "mkmk", + }, + thai = tabletohash { + "ccmp", "locl", "liga", "kern", "mark", + "mkmk", + }, +} + + + +------------------------------------------------------------------------------- +--- DEFAULTS +------------------------------------------------------------------------------- + +local default_config = { + db = { + formats = "otf,ttf,ttc,dfont", + scan_local = false, + skip_read = false, + strip = true, + update_live = true, + compress = true, + max_fonts = 2^51, + }, + run = { + resolver = "cached", + definer = "patch", + log_level = 0, + color_callback = "pre_linebreak_filter", + }, + misc = { + bisect = false, + version = luaotfload.version, + statistics = false, + termwidth = nil, + }, + paths = { + names_dir = "names", + cache_dir = "fonts", + index_file = "luaotfload-names.lua", + lookups_file = "luaotfload-lookup-cache.lua", + lookup_path_lua = nil, + lookup_path_luc = nil, + index_path_lua = nil, + index_path_luc = nil, + }, + default_features = { + global = { mode = "node" }, + dflt = tabletohash { + "ccmp", "locl", "rlig", "liga", "clig", + "kern", "mark", "mkmk", 'itlc', + }, + + arab = feature_presets.arab, + syrc = feature_presets.arab, + mong = feature_presets.arab, + nko = feature_presets.arab, + + deva = feature_presets.deva, + beng = feature_presets.deva, + guru = feature_presets.deva, + gujr = feature_presets.deva, + orya = feature_presets.deva, + taml = feature_presets.deva, + telu = feature_presets.deva, + knda = feature_presets.deva, + mlym = feature_presets.deva, + sinh = feature_presets.deva, + + khmr = feature_presets.khmr, + tibt = feature_presets.khmr, + thai = feature_presets.thai, + lao = feature_presets.thai, + + hang = tabletohash { "ccmp", "ljmo", "vjmo", "tjmo", }, + }, +} + +------------------------------------------------------------------------------- +--- RECONFIGURATION TASKS +------------------------------------------------------------------------------- + +--[[doc-- + + Procedures to be executed in order to put the new configuration into effect. + +--doc]]-- + +local reconf_tasks = nil + +local min_terminal_width = 40 + +--- The “termwidth” value is only considered when printing +--- short status messages, e.g. when building the database +--- online. +local check_termwidth = function () + if config.luaotfload.misc.termwidth == nil then + local tw = 79 + if not ( os.type == "windows" --- Assume broken terminal. + or osgetenv "TERM" == "dumb") + then + local p = iopopen "tput cols" + if p then + result = tonumber (p:read "*all") + p:close () + if result then + tw = result + else + logreport ("log", 2, "db", "tput returned non-number.") + end + else + logreport ("log", 2, "db", "Shell escape disabled or tput executable missing.") + logreport ("log", 2, "db", "Assuming 79 cols terminal width.") + end + end + config.luaotfload.misc.termwidth = tw + end + return true +end + +local set_font_filter = function () + local names = fonts.names + if names and names.set_font_filter then + local formats = config.luaotfload.db.formats + if not formats or formats == "" then + formats = default_config.db.formats + end + names.set_font_filter (formats) + end + return true +end + +local set_name_resolver = function () + local names = fonts.names + if names and names.resolve_cached then + --- replace the resolver from luatex-fonts + if config.luaotfload.db.resolver == "cached" then + logreport ("both", 2, "cache", "Caching of name: lookups active.") + names.resolvespec = names.resolve_cached + else + names.resolvespec = names.resolve_name + end + end + return true +end + +local set_loglevel = function () + log.set_loglevel (config.luaotfload.run.log_level) + return true +end + +local build_cache_paths = function () + local paths = config.luaotfload.paths + local prefix = getwritablepath (paths.names_dir, "") + + if not prefix then + luaotfload.error ("Impossible to find a suitable writeable cache...") + return false + end + + prefix = lpegmatch (stripslashes, prefix) + logreport ("log", 0, "conf", "Root cache directory is %s.", prefix) + + local index_file = filejoin (prefix, paths.index_file) + local lookups_file = filejoin (prefix, paths.lookups_file) + + paths.prefix = prefix + paths.index_path_lua = filereplacesuffix (index_file, "lua") + paths.index_path_luc = filereplacesuffix (index_file, "luc") + paths.lookup_path_lua = filereplacesuffix (lookups_file, "lua") + paths.lookup_path_luc = filereplacesuffix (lookups_file, "luc") + return true +end + + +local set_default_features = function () + local default_features = config.luaotfload.default_features + luaotfload.features = luaotfload.features or { + global = { }, + defaults = { }, + } + current_features = luaotfload.features + for var, val in next, default_features do + if var == "global" then + current_features.global = val + else + current_features.defaults[var] = val + end + end + return true +end + + +reconf_tasks = { + { "Set the log level" , set_loglevel }, + { "Build cache paths" , build_cache_paths }, + { "Check terminal dimensions" , check_termwidth }, + { "Set the font filter" , set_font_filter }, + { "Install font name resolver", set_name_resolver }, + { "Set default features" , set_default_features }, +} + +------------------------------------------------------------------------------- +--- OPTION SPECIFICATION +------------------------------------------------------------------------------- + +local string_t = "string" +local table_t = "table" +local number_t = "number" +local boolean_t = "boolean" +local function_t = "function" + +local tointeger = function (n) + n = tonumber (n) + if n then + return mathfloor (n + 0.5) + end +end + +local toarray = function (s) + local fields = { lpegmatch (commasplitter, s) } + local ret = { } + for i = 1, #fields do + local field = stringstrip (fields[i]) + if field and field ~= "" then + ret[#ret + 1] = field + end + end + return ret +end + +local tohash = function (s) + local result = { } + local fields = toarray (s) + for _, field in next, fields do + local var, val + if stringfind (field, "=") then + local tmp + var, tmp = lpegmatch (equalssplitter, field) + if tmp == "true" or tmp == "yes" then val = true else val = tmp end + else + var, val = field, true + end + result[var] = val + end + return result +end + +local option_spec = { + db = { + formats = { + in_t = string_t, + out_t = string_t, + transform = function (f) + local fields = toarray (f) + + --- check validity + if not fields then + logreport ("both", 0, "conf", + "Expected list of identifiers, got %q.", f) + return nil + end + + --- strip dupes + local known = { } + local result = { } + for i = 1, #fields do + local field = fields[i] + if known[field] ~= true then + --- yet unknown, tag as seen + known[field] = true + --- include in output if valid + if valid_formats[field] == true then + result[#result + 1] = field + else + logreport ("both", 4, "conf", + "Invalid font format identifier %q, ignoring.", + field) + end + end + end + if #result == 0 then + --- force defaults + return nil + end + return tableconcat (result, ",") + end + }, + scan_local = { in_t = boolean_t, }, + skip_read = { in_t = boolean_t, }, + strip = { in_t = boolean_t, }, + update_live = { in_t = boolean_t, }, + compress = { in_t = boolean_t, }, + max_fonts = { + in_t = number_t, + out_t = number_t, --- TODO int_t from 5.3.x on + transform = tointeger, + }, + }, + run = { + resolver = { + in_t = string_t, + out_t = string_t, + transform = function (r) return r == "normal" and r or "cached" end, + }, + definer = { + in_t = string_t, + out_t = string_t, + transform = function (d) return d == "generic" and d or "patch" end, + }, + log_level = { + in_t = number_t, + out_t = number_t, --- TODO int_t from 5.3.x on + transform = tointeger, + }, + color_callback = { + in_t = string_t, + out_t = string_t, + transform = function (cb) + --- These are the two that make sense. + return cb == "pre_output_filter" and cb or "pre_linebreak_filter" + end, + }, + }, + misc = { + bisect = { in_t = boolean_t, }, --- doesn’t make sense in a config file + version = { in_t = string_t, }, + statistics = { in_t = boolean_t, }, + termwidth = { + in_t = number_t, + out_t = number_t, + transform = function (w) + w = tointeger (w) + if w < min_terminal_width then + return min_terminal_width + end + return w + end, + }, + }, + paths = { + names_dir = { in_t = string_t, }, + cache_dir = { in_t = string_t, }, + index_file = { in_t = string_t, }, + lookups_file = { in_t = string_t, }, + lookup_path_lua = { in_t = string_t, }, + lookup_path_luc = { in_t = string_t, }, + index_path_lua = { in_t = string_t, }, + index_path_luc = { in_t = string_t, }, + }, + default_features = { + __default = { in_t = string_t, out_t = table_t, transform = tohash, }, + }, +} + +------------------------------------------------------------------------------- +--- MAIN FUNCTIONALITY +------------------------------------------------------------------------------- + +--[[doc-- + + tilde_expand -- Rudimentary tilde expansion; covers just the “substitute ‘~’ + by the current users’s $HOME” part. + +--doc]]-- + +local tilde_expand = function (p) + if #p > 2 then + if stringsub (p, 1, 2) == "~/" then + local homedir = osgetenv "HOME" + if homedir and lfsisdir (homedir) then + p = filejoin (homedir, stringsub (p, 3)) + end + end + end + return p +end + +local resolve_config_path = function () + for i = 1, #config_paths do + local t, p = unpack (config_paths[i]) + local fullname + if t == kpse_t then + fullname = kpse.lookup (p) + logreport ("both", 6, "conf", "kpse lookup: %s -> %s.", p, fullname) + elseif t == path_t then + local expanded = tilde_expand (p) + if lfsisfile (expanded) then + fullname = expanded + end + logreport ("both", 6, "conf", "path lookup: %s -> %s.", p, fullname) + end + if fullname then + logreport ("both", 3, "conf", "Reading configuration file at %q.", fullname) + return fullname + end + end + logreport ("both", 2, "conf", "No configuration file found.") + return false +end + +local add_config_paths = function (t) + if not next (t) then + return + end + local result = { } + for i = 1, #t do + local path = t[i] + result[#result + 1] = { path_t, path } + end + config_paths = tableappend (result, config_paths) +end + +local process_options = function (opts) + local new = { } + for i = 1, #opts do + local section = opts[i] + local title = section.section.title + local vars = section.variables + + if not title then --- trigger warning: arrow code ahead + logreport ("both", 2, "conf", "Section %d lacks a title; skipping.", i) + elseif not vars then + logreport ("both", 2, "conf", "Section %d (%s) lacks a variable section; skipping.", i, title) + else + local spec = option_spec[title] + if not spec then + logreport ("both", 2, "conf", "Section %d (%s) unknown; skipping.", i, title) + else + local newsection = new[title] + if not newsection then + newsection = { } + new[title] = newsection + end + + for var, val in next, vars do + local vspec = spec[var] or spec.__default + local t_val = type (val) + if not vspec then + logreport ("both", 2, "conf", + "Section %d (%s): invalid configuration variable %q (%q); ignoring.", + i, title, + var, tostring (val)) + elseif t_val ~= vspec.in_t then + logreport ("both", 2, "conf", + "Section %d (%s): type mismatch of input value %q (%q, %s != %s); ignoring.", + i, title, + var, tostring (val), t_val, vspec.in_t) + else --- type matches + local transform = vspec.transform + if transform then + local dval + local t_transform = type (transform) + if t_transform == function_t then + dval = transform (val) + elseif t_transform == table_t then + dval = transform[val] + end + if dval then + local out_t = vspec.out_t + if out_t then + local t_dval = type (dval) + if t_dval == out_t then + newsection[var] = dval + else + logreport ("both", 2, "conf", + "Section %d (%s): type mismatch of derived value of %q (%q, %s != %s); ignoring.", + i, title, + var, tostring (dval), t_dval, out_t) + end + else + newsection[var] = dval + end + else + logreport ("both", 2, "conf", + "Section %d (%s): value of %q could not be derived via %s from input %q; ignoring.", + i, title, var, t_transform, tostring (val)) + end + else --- insert as is + newsection[var] = val + end + end + end + end + end + end + return new +end + +local apply +apply = function (old, new) + if not new then + if not old then + return false + end + return tablecopy (old) + elseif not old then + return tablecopy (new) + end + local result = tablecopy (old) + for name, section in next, new do + local t_section = type (section) + if t_section ~= table_t then + logreport ("both", 1, "conf", + "Error applying configuration: entry %s is %s, expected table.", + section, t_section) + --- ignore + else + local currentsection = result[name] + for var, val in next, section do + currentsection[var] = val + end + end + end + result.status = luaotfloadstatus + return result +end + +local reconfigure = function () + for i = 1, #reconf_tasks do + local name, task = unpack (reconf_tasks[i]) + logreport ("both", 3, "conf", "Launch post-configuration task %q.", name) + if not task () then + logreport ("both", 0, "conf", "Post-configuration task %q failed.", name) + return false + end + end + return true +end + +local read = function (extra) + if extra then + add_config_paths (extra) + end + + local readme = resolve_config_path () + if readme == false then + logreport ("both", 2, "conf", "No configuration file.") + return false + end + + local raw = ioloaddata (readme) + if not raw then + logreport ("both", 2, "conf", "Error reading the configuration file %q.", readme) + return false + end + + local parsed = lpegmatch (parsers.config, raw) + if not parsed then + logreport ("both", 2, "conf", "Error parsing configuration file %q.", readme) + return false + end + + local ret, msg = process_options (parsed) + if not ret then + logreport ("both", 2, "conf", "File %q is not a valid configuration file.", readme) + logreport ("both", 2, "conf", "Error: %s", msg) + return false + end + return ret +end + +local apply_defaults = function () + local defaults = default_config + local vars = read () + --- Side-effects galore ... + config.luaotfload = apply (defaults, vars) + return reconfigure () +end + +------------------------------------------------------------------------------- +--- EXPORTS +------------------------------------------------------------------------------- + +luaotfload.default_config = default_config + +config.actions = { + read = read, + apply = apply, + apply_defaults = apply_defaults, + reconfigure = reconfigure, +} + diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua index cb3ec330e35..7a01ca626bf 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua @@ -1,9 +1,9 @@ if not modules then modules = { } end modules ['luaotfload-database'] = { - version = "2.4", - comment = "companion to luaotfload.lua", + version = "2.5", + comment = "companion to luaotfload-main.lua", author = "Khaled Hosny, Elie Roux, Philipp Gesang", copyright = "Luaotfload Development Team", - license = "GNU GPL v2" + license = "GNU GPL v2.0" } --[[doc-- @@ -36,13 +36,20 @@ if not modules then modules = { } end modules ['luaotfload-database'] = { --doc]]-- -local lpeg = require "lpeg" +local lpeg = require "lpeg" +local P, Cc, lpegmatch = lpeg.P, lpeg.Cc, lpeg.match -local P, R, S, lpegmatch - = lpeg.P, lpeg.R, lpeg.S, lpeg.match +local parsers = luaotfload.parsers +local read_fonts_conf = parsers.read_fonts_conf +local stripslashes = parsers.stripslashes +local splitcomma = parsers.splitcomma + +local log = luaotfload.log +local report = log.report +local report_status = log.names_status +local report_status_start = log.names_status_start +local report_status_stop = log.names_status_stop -local C, Cc, Cf, Cg, Cs, Ct - = lpeg.C, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Cs, lpeg.Ct --- Luatex builtins local load = load @@ -60,7 +67,6 @@ local iolines = io.lines local ioopen = io.open local iopopen = io.popen local kpseexpand_path = kpse.expand_path -local kpseexpand_var = kpse.expand_var local kpsefind_file = kpse.find_file local kpselookup = kpse.lookup local kpsereadable_file = kpse.readable_file @@ -70,6 +76,7 @@ local lfscurrentdir = lfs.currentdir local lfsdir = lfs.dir local mathabs = math.abs local mathmin = math.min +local osgetenv = os.getenv local osgettimeofday = os.gettimeofday local osremove = os.remove local stringfind = string.find @@ -106,12 +113,12 @@ local stringis_empty = string.is_empty local stringsplit = string.split local stringstrip = string.strip local tableappend = table.append +local tablecontains = table.contains local tablecopy = table.copy local tablefastcopy = table.fastcopy local tabletofile = table.tofile local tabletohash = table.tohash local tableserialize = table.serialize -local runasscript = caches == nil --- the font loader namespace is “fonts”, same as in Context --- we need to put some fallbacks into place for when running --- as a script @@ -119,80 +126,19 @@ fonts = fonts or { } fonts.names = fonts.names or { } fonts.definers = fonts.definers or { } -local luaotfloadconfig = config.luaotfload --- always present -luaotfloadconfig.resolver = luaotfloadconfig.resolver or "normal" -luaotfloadconfig.formats = luaotfloadconfig.formats or "otf,ttf,ttc,dfont" -luaotfloadconfig.strip = luaotfloadconfig.strip == true - ---- this option allows for disabling updates ---- during a TeX run -luaotfloadconfig.update_live = luaotfloadconfig.update_live ~= false -luaotfloadconfig.compress = luaotfloadconfig.compress ~= false - local names = fonts.names local name_index = nil --> upvalue for names.data local lookup_cache = nil --> for names.lookups -names.version = 2.41 +names.version = 2.51 names.data = nil --- contains the loaded database names.lookups = nil --- contains the lookup cache -names.path = { index = { }, lookups = { } } -names.path.globals = { - prefix = "", --- writable_path/names_dir - names_dir = luaotfloadconfig.names_dir or "names", - index_file = luaotfloadconfig.index_file - or "luaotfload-names.lua", - lookups_file = "luaotfload-lookup-cache.lua", -} - --- string -> (string * string) local make_luanames = function (path) return filereplacesuffix(path, "lua"), filereplacesuffix(path, "luc") end -local report = logs.names_report -local report_status = logs.names_status -local report_status_start = logs.names_status_start -local report_status_stop = logs.names_status_stop - ---- The “termwidth” value is only considered when printing ---- short status messages, e.g. when building the database ---- online. -if not luaotfloadconfig.termwidth then - local tw = 79 - if not ( os.type == "windows" --- Assume broken terminal. - or os.getenv "TERM" == "dumb") - then - local p = iopopen "tput cols" - if p then - result = tonumber (p:read "*all") - p:close () - if result then - tw = result - else - report ("log", 2, "db", "tput returned non-number.") - end - else - report ("log", 2, "db", "Shell escape disabled or tput executable missing.") - report ("log", 2, "db", "Assuming 79 cols terminal width.") - end - end - luaotfloadconfig.termwidth = tw -end - -names.patterns = { } -local patterns = names.patterns - -local trailingslashes = P"/"^1 * P(-1) -local stripslashes = C((1 - trailingslashes)^0) -patterns.stripslashes = stripslashes - -local comma = P"," -local noncomma = 1-comma -local splitcomma = Ct((C(noncomma^1) + comma)^1) -patterns.splitcomma = splitcomma - local format_precedence = { "otf", "ttc", "ttf", "dfont", "afm", "pfb", @@ -208,47 +154,9 @@ local set_location_precedence = function (precedence) end --[[doc-- - We use the functions in the cache.* namespace that come with the - fontloader (see luat-basics-gen). it’s safe to use for the most part - since most checks and directory creations are already done. It - uses TEXMFCACHE or TEXMFVAR as starting points. - - There is one quirk, though: ``getwritablepath()`` will always - assume that files in subdirectories of the cache tree are writable. - It gives no feedback at all if it fails to open a file in write - mode. This may cause trouble when the index or lookup cache were - created by different user. ---doc]]-- - -if not runasscript then - local globals = names.path.globals - local names_dir = globals.names_dir - prefix = getwritablepath (names_dir, "") - if not prefix then - luaotfload.error - ("Impossible to find a suitable writeable cache...") - else - prefix = lpegmatch (stripslashes, prefix) - report ("log", 0, "db", - "Root cache directory is %s.", prefix) - end - - globals.prefix = prefix - local lookup_path = names.path.lookups - local index = names.path.index - local lookups_file = filejoin (prefix, globals.lookups_file) - local index_file = filejoin (prefix, globals.index_file) - lookup_path.lua, lookup_path.luc = make_luanames (lookups_file) - index.lua, index.luc = make_luanames (index_file) -else --- running as script, inject some dummies - caches = { } - logs = { report = function () end } -end + Auxiliary functions - ---[[doc-- -Auxiliary functions --doc]]-- --- fontnames contain all kinds of garbage; as a precaution we @@ -343,7 +251,6 @@ This is a sketch of the luaotfload db: status : filestatus; mappings : fontentry list; meta : metadata; - names : namedata; // TODO: check for relevance after db is finalized } and familytable = { local : (format, familyentry) hash; // specified with include dir @@ -351,21 +258,24 @@ This is a sketch of the luaotfload db: system : (format, familyentry) hash; } and familyentry = { - regular : sizes; - italic : sizes; - bold : sizes; - bolditalic : sizes; + r : sizes; // regular + i : sizes; // italic + b : sizes; // bold + bi : sizes; // bold italic } and sizes = { default : int; // points into mappings or names optical : (int, int) list; // design size -> index entry } and metadata = { + created : string // creation time formats : string list; // { "otf", "ttf", "ttc", "dfont" } - statistics : TODO; - version : float; + local : bool; (* set if local fonts were added to the db *) + modified : string // modification time + statistics : TODO; // created when built with "--stats" + version : float; // index version } - and filemap = { + and filemap = { // created by generate_filedata() base : { local : (string, int) hash; // basename -> idx system : (string, int) hash; @@ -378,36 +288,36 @@ This is a sketch of the luaotfload db: }; full : (int, string) hash; // idx -> full path } - and fontentry = { - barename : string; - familyname : string; - filename : string; - fontname : string; // <- metadata - fullname : string; // <- metadata - sanitized : { - family : string; - fontstyle_name : string; // <- new in 2.4 - fontname : string; // <- metadata - fullname : string; // <- namedata.names - metafamily : string; - pfullname : string; - prefmodifiers : string; - psname : string; - subfamily : string; - }; - size : int list; - slant : int; - subfont : int; - location : local | system | texmf; - weight : int; - width : int; - units_per_em : int; // mainly 1000, but also 2048 or 256 + and fontentry = { // finalized by collect_families() + basename : string; // file name without path "foo.otf" + conflicts : { barename : int; basename : int }; // filename conflict with font at index; happens with subfonts + familyname : string; // sanitized name of the font family the font belongs to, usually from the names table + fontname : string; // sanitized name of the font + fontstyle_name : string; // the fontstyle_name field returned by fontloader.info() + format : string; // "otf" | "ttf" | "dfont" | "pfa" | "pfb" | "afm" + fullname : string; // sanitized full name of the font including style modifiers + fullpath : string; // path to font in filesystem + index : int; // index in the mappings table + italicangle : float; // italic angle; non-zero with oblique faces + location : string; // "texmf" | "system" | "local" + metafamily : string; // alternative family identifier if appropriate, sanitized + plainname : string; // unsanitized font name + prefmodifiers : string; // sanitized preferred subfamily (names table 14) + psname : string; // PostScript name + size : (false | float * float * float); // if available, size info from the size table converted from decipoints + splainname : string; // sanitized version of the “plainname” field + splitstyle : string; // style information obtained by splitting the full name at the last dash + subfamily : string; // sanitized subfamily (names table 2) + subfont : (int | bool); // integer if font is part of a TrueType collection ("ttc") + version : string; // font version string + weight : int; // usWeightClass } and filestatus = (string, // fullname { index : int list; // pointer into mappings timestamp : int; }) dict -beware that this is a reconstruction and may be incomplete. +beware that this is a reconstruction and may be incomplete or out of +date. Last update: 2014-04-06, describing version 2.51. mtx-fonts has in names.tma: @@ -444,7 +354,10 @@ mtx-fonts has in names.tma: --doc]]-- -local initialize_namedata = function (formats) --- returns dbobj +--- string list -> string option -> dbobj + +local initialize_namedata = function (formats, created) + local now = os.date "%F %T" return { --families = { }, status = { }, -- was: status; map abspath -> mapping @@ -452,7 +365,10 @@ local initialize_namedata = function (formats) --- returns dbobj names = { }, -- files = { }, -- created later meta = { + created = created or now, formats = formats, + ["local"] = false, + modified = now, statistics = { }, version = names.version, }, @@ -536,29 +452,32 @@ local load_lua_file = function (path) end --- define locals in scope -local crude_file_lookup -local crude_file_lookup_verbose +local access_font_index +local collect_families +local font_file_lookup local find_closest local flush_lookup_cache -local ot_fullinfo -local t1_fullinfo -local load_names +local generate_filedata +local get_font_filter +local group_modifiers local load_lookups +local load_names +local getmetadata +local order_design_sizes +local ot_fullinfo local read_blacklist -local read_fonts_conf local reload_db -local resolve_name local resolve_cached local resolve_fullpath -local save_names +local resolve_name local save_lookups -local update_names -local get_font_filter +local save_names local set_font_filter +local t1_fullinfo +local update_names --- state of the database local fonts_reloaded = false -local fonts_read = 0 --- limit output when approximate font matching (luaotfload-tool -F) local fuzzy_limit = 1 --- display closest only @@ -566,15 +485,17 @@ local fuzzy_limit = 1 --- display closest only --- bool? -> dbobj load_names = function (dry_run) local starttime = osgettimeofday () - local foundname, data = load_lua_file (names.path.index.lua) + local foundname, data = load_lua_file (config.luaotfload.paths.index_path_lua) if data then - report ("both", 2, "db", - "Font names database loaded", "%s", foundname) + report ("log", 0, "db", + "Font names database loaded from %s", foundname) + report ("term", 3, "db", + "Font names database loaded from %s", foundname) report ("info", 3, "db", "Loading took %0.f ms.", 1000 * (osgettimeofday () - starttime)) - local db_version, nms_version + local db_version, names_version if data.meta then db_version = data.meta.version else @@ -583,11 +504,11 @@ load_names = function (dry_run) --- an earlier index version broke. db_version = data.version or -42 --- invalid end - nms_version = names.version - if db_version ~= nms_version then + names_version = names.version + if db_version ~= names_version then report ("both", 0, "db", [[Version mismatch; expected %4.3f, got %4.3f.]], - nms_version, db_version) + names_version, db_version) if not fonts_reloaded then report ("both", 0, "db", [[Force rebuild.]]) data = update_names ({ }, true, false) @@ -611,11 +532,29 @@ load_names = function (dry_run) return data end +--[[doc-- + + access_font_index -- Provide a reference of the index table. Will + cause the index to be loaded if not present. + +--doc]]-- + +access_font_index = function () + if not name_index then name_index = load_names () end + return name_index +end + +getmetadata = function () + if not name_index then name_index = load_names() end + return tablefastcopy (name_index.meta) +end + --- unit -> unit load_lookups = function ( ) - local foundname, data = load_lua_file(names.path.lookups.lua) + local foundname, data = load_lua_file(config.luaotfload.paths.lookup_path_lua) if data then - report("both", 3, "cache", + report("log", 0, "cache", "Lookup cache loaded from %s.", foundname) + report("term", 3, "cache", "Lookup cache loaded from %s.", foundname) else report("both", 1, "cache", @@ -650,57 +589,10 @@ local style_category = { i = "italic", } -local type1_formats = { "tfm", "ofm", } +local type1_metrics = { "tfm", "ofm", } local dummy_findfile = resolvers.findfile -- from basics-gen ---- filemap -> string -> string -> (string | bool) -local verbose_lookup = function (data, kind, filename) - local found = data[kind][filename] - if found ~= nil then - found = data.full[found] - if found == nil then --> texmf - report("info", 0, "db", - "Crude file lookup: req=%s; hit=%s => kpse.", - filename, kind) - found = dummy_findfile(filename) - else - report("info", 0, "db", - "Crude file lookup: req=%s; hit=%s; ret=%s.", - filename, kind, found) - end - return found - end - return false -end - ---- string -> (string * string * bool) -crude_file_lookup_verbose = function (filename) - if not name_index then name_index = load_names() end - local mappings = name_index.mappings - local files = name_index.files - local found - - --- look up in db first ... - found = verbose_lookup(files, "bare", filename) - if found then - return found, nil, true - end - found = verbose_lookup(files, "base", filename) - if found then - return found, nil, true - end - - --- ofm and tfm, returns pair - for i=1, #type1_formats do - local format = type1_formats[i] - if resolvers.findfile(filename, format) then - return file.addsuffix(filename, format), format, true - end - end - return filename, nil, false -end - local lookup_filename = function (filename) if not name_index then name_index = load_names () end local files = name_index.files @@ -736,8 +628,18 @@ local lookup_filename = function (filename) end end ---- string -> (string * string * bool) -crude_file_lookup = function (filename) +--[[doc-- + + font_file_lookup -- The ``file:`` are ultimately delegated here. + The lookups are kind of a blunt instrument since they try locating + the file using every conceivable method, which is quite + inefficient. Nevertheless, resolving files that way is rarely the + bottleneck. + +--doc]]-- + +--- string -> string * string * bool +font_file_lookup = function (filename) local found = lookup_filename (filename) if not found then @@ -748,21 +650,37 @@ crude_file_lookup = function (filename) return found, nil, true end - for i=1, #type1_formats do - local format = type1_formats[i] + for i=1, #type1_metrics do + local format = type1_metrics[i] if resolvers.findfile(filename, format) then return file.addsuffix(filename, format), format, true end end + if not fonts_reloaded and config.luaotfload.db.update_live == true then + return reload_db (stringformat ("File not found: %s.", filename), + font_file_lookup, + filename) + end return filename, nil, false end --[[doc-- -Existence of the resolved file name is verified differently depending -on whether the index entry has a texmf flag set. + + get_font_file -- Look up the file of an entry in the mappings + table. If the index is valid, pass on the name and subfont index + after verifing the existence of the resolved file. This + verification differs depending the index entry’s ``location`` + field: + + * ``texmf`` fonts are verified using the (slow) function + ``kpse.lookup()``; + * other locations are tested by resolving the full path and + checking for the presence of a file there. + --doc]]-- +--- int -> bool * (string * int) option local get_font_file = function (index) local entry = name_index.mappings [index] if not entry then @@ -809,29 +727,20 @@ We’ll just store successful name: lookups in a separate cache file. type lookup_cache = (string, (string * num)) dict -Complete, needs testing: - × 1) add cache to dbobj - × 2) wrap lookups in cached versions - × 3) make caching optional (via the config table) for debugging - × 4) make names_update() cache aware (nil if “force”) - × 5) add logging - × 6) add cache control to luaotfload-tool - × 7) incr db version (now 2.203) - × 8) save cache only at the end of a run - -The spec is modified in place (ugh), so we’ll have to catalogue what -fields actually influence its behavior. +The spec is expected to be modified in place (ugh), so we’ll have to +catalogue what fields actually influence its behavior. Idk what the “spec” resolver is for. lookup inspects modifies + ---------- ----------------- --------------------------- file: name forced, name - name:* name, style, sub, resolved, sub, name, forced + name:[*] name, style, sub, resolved, sub, name, forced optsize, size spec: name, sub resolved, sub, name, forced -* name: contains both the name resolver from luatex-fonts and - resolve_name() below +[*] name: contains both the name resolver from luatex-fonts and + resolve_name() below From my reading of font-def.lua, what a resolver does is basically rewrite the “name” field of the specification record @@ -1178,13 +1087,11 @@ resolve_name = function (specification) name, style) end - if not resolved then - resolved = specification.name, false - end if not resolved then - if not fonts_reloaded then - return reload_db ("Font not found.", + if not fonts_reloaded and config.luaotfload.db.update_live == true then + return reload_db (stringformat ("Font %s not found.", + specification.name or "<?>"), resolve_name, specification) end @@ -1225,7 +1132,7 @@ reload_db = function (why, caller, ...) local namedata = name_index local formats = tableconcat (namedata.meta.formats, ",") - report ("both", 1, "db", + report ("both", 0, "db", "Reload initiated (formats: %s); reason: %q.", formats, why) @@ -1277,7 +1184,7 @@ find_closest = function (name, limit) if not name_index then name_index = load_names () end if not name_index or type (name_index) ~= "table" then if not fonts_reloaded then - return reload_db("no database", find_closest, name) + return reload_db("Font index missing.", find_closest, name) end return false end @@ -1345,10 +1252,18 @@ end --- find_closest() <http://www.ntg.nl/pipermail/ntg-context/2013/075885.html> regarding the omission of ``fontloader.close()``. + TODO -- check if fontloader.info() is ready for prime in 0.78+ + -- fields /tables needed: + -- names + -- postscriptname + -- validation_state + -- .. + --doc]]-- local load_font_file = function (filename, subfont) local rawfont, _msg = fontloaderopen (filename, subfont) + --local rawfont, _msg = fontloaderinfo (filename, subfont) if not rawfont then report ("log", 1, "db", "ERROR: failed to open %s.", filename) return @@ -1379,42 +1294,87 @@ local get_size_info = function (metadata) return false end -local get_english_names = function (names, basename) - +local get_english_names = function (metadata) + local names = metadata.names local english_names if names then --inspect(names) for _, raw_namedata in next, names do if raw_namedata.lang == "English (US)" then - english_names = raw_namedata.names + return raw_namedata.names end end - else - -- no names table, probably a broken font - report("log", 1, "db", - "Broken font %s rejected due to missing names table.", + end + + -- no (English) names table, probably a broken font + report("both", 3, "db", + "%s: missing or broken English names table.", basename) + return { fontname = metadata.fontname, + fullname = metadata.fullname, } +end + +--[[-- + In case of broken PS names we set some dummies. However, we cannot + directly modify the font data as returned by fontloader.open() because + it is a userdata object. + + For this reason we copy what is necessary whilst keeping the table + structure the same as in the tfmdata. +--]]-- +local get_raw_info = function (metadata, basename) + local fullname + local fontname = metadata.fontname + local fullname = metadata.fullname + local psname + + local validation_state = metadata.validation_state + if (validation_state and tablecontains (validation_state, "bad_ps_fontname")) + or not fontname + then + --- Broken names table, e.g. avkv.ttf with UTF-16 strings; + --- we put some dummies in place like the fontloader + --- (font-otf.lua) does. + report("both", 3, "db", + "%s has invalid postscript font names, using dummies.", basename) + fontname = "bad-fontname-" .. basename + fullname = "bad-fullname-" .. basename end - return english_names or { } + return { + familyname = metadata.familyname, + fontname = fontname, + fontstyle_name = metadata.fontstyle_name, + fullname = fullname, + italicangle = metadata.italicangle, + names = metadata.names, + pfminfo = metadata.pfminfo, + units_per_em = metadata.units_per_em, + version = metadata.version, + design_size = metadata.design_size, + design_range_top = metadata.design_range_top, + design_range_bottom = metadata.design_range_bottom, + } end -local organize_namedata = function (metadata, +local organize_namedata = function (rawinfo, english_names, basename, info) local default_name = english_names.compatfull or english_names.fullname or english_names.postscriptname - or metadata.fullname - or metadata.fontname - or info.fullname --- TODO check if fontloader.info() is ready for prime + or rawinfo.fullname + or rawinfo.fontname + or info.fullname or info.fontname local default_family = english_names.preffamily or english_names.family - or metadata.familyname + or rawinfo.familyname or info.familyname +-- local default_modifier = english_names.prefmodifiers +-- or english_names.subfamily local fontnames = { --- see --- https://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html @@ -1445,9 +1405,9 @@ local organize_namedata = function (metadata, }, metadata = { - fullname = metadata.fullname, - fontname = metadata.fontname, - familyname = metadata.familyname, + fullname = rawinfo.fullname, + fontname = rawinfo.fontname, + familyname = rawinfo.familyname, }, info = { @@ -1458,14 +1418,14 @@ local organize_namedata = function (metadata, } -- see http://www.microsoft.com/typography/OTSPEC/features_pt.htm#size - if metadata.fontstyle_name then + if rawinfo.fontstyle_name then --- not present in all fonts, often differs from the preferred --- subfamily as well as subfamily fields, e.g. with --- LMSans10-BoldOblique: --- subfamily: “Bold Italic” --- prefmodifiers: “10 Bold Oblique” --- fontstyle_name: “Bold Oblique” - for _, name in next, metadata.fontstyle_name do + for _, name in next, rawinfo.fontstyle_name do if name.lang == 1033 then --- I hate magic numbers fontnames.fontstyle_name = name.name end @@ -1474,11 +1434,10 @@ local organize_namedata = function (metadata, return { sanitized = sanitize_fontnames (fontnames), - fontname = metadata.fontname, - fullname = metadata.fullname, - familyname = metadata.familyname, + fontname = rawinfo.fontname, + fullname = rawinfo.fullname, + familyname = rawinfo.familyname, } - end @@ -1498,23 +1457,16 @@ local organize_styledata = function (fontname, metadata, english_names, info) - local pfminfo = metadata.pfminfo + local pfminfo = metadata.pfminfo or { } local names = metadata.names return { - -- see http://www.microsoft.com/typography/OTSPEC/features_pt.htm#size + --- see http://www.microsoft.com/typography/OTSPEC/features_pt.htm#size size = get_size_info (metadata), - weight = { - pfminfo.weight, -- integer (multiple of 100?) - sanitize_fontname (info.weight), -- style name - }, + weight = pfminfo.weight or 400, split = split_fontname (fontname), width = pfminfo.width, italicangle = metadata.italicangle, --- italicangle = { --- metadata.italicangle, -- float --- info.italicangle, -- truncated to integer point size? --- }, --- this is for querying, see www.ntg.nl/maps/40/07.pdf for details units_per_em = metadata.units_per_em, version = metadata.version, @@ -1541,13 +1493,18 @@ ot_fullinfo = function (filename, return nil end - local english_names = get_english_names (metadata.names, basename) - local namedata = organize_namedata (metadata, + local rawinfo = get_raw_info (metadata, basename) + --- Closing the file manually is a tad faster and more memory + --- efficient than having it closed by the gc + fontloaderclose (metadata) + + local english_names = get_english_names (rawinfo) + local namedata = organize_namedata (rawinfo, english_names, basename, info) local style = organize_styledata (namedata.fontname, - metadata, + rawinfo, english_names, info) @@ -1559,11 +1516,8 @@ ot_fullinfo = function (filename, format = format, names = namedata, style = style, - version = metadata.version, + version = rawinfo.version, } - --- Closing the file manually is a tad faster and more memory - --- efficient than having it closed by the gc - fontloaderclose (metadata) return res end @@ -1626,8 +1580,7 @@ t1_fullinfo = function (filename, _subfont, location, basename, format) size = false, splitstyle = splitstyle, fontstyle_name = style ~= "" and style or weight, - weight = { metadata.pfminfo.weight, - weight }, + weight = metadata.pfminfo.weight or 400, italicangle = italicangle, } end @@ -1946,13 +1899,16 @@ read_blacklist = function () local whitelist = { } if files and type(files) == "table" then - for _,v in next, files do - for line in iolines(v) do + for _, path in next, files do + for line in iolines (path) do line = stringstrip(line) -- to get rid of lines like " % foo" - local first_chr = stringsub(line, 1, 1) --- faster than find + local first_chr = stringsub(line, 1, 1) if first_chr == "%" or stringis_empty(line) then -- comment or empty line elseif first_chr == "-" then + report ("both", 3, "db", + "Whitelisted file %q via %q.", + line, path) whitelist[#whitelist+1] = stringsub(line, 2, -1) else local cmt = stringfind(line, "%%") @@ -1960,7 +1916,9 @@ read_blacklist = function () line = stringsub(line, 1, cmt - 1) end line = stringstrip(line) - report("log", 2, "db", "Blacklisted file %q.", line) + report ("both", 3, "db", + "Blacklisted file %q via %q.", + line, path) blacklist[#blacklist+1] = line end end @@ -2033,9 +1991,6 @@ do get_font_filter = function (formats) return tablefastcopy (current_formats) end - - --- initialize - set_font_filter (luaotfloadconfig.formats) end local process_dir_tree @@ -2138,7 +2093,7 @@ end --- indicates the number of characters already consumed on the --- line. local truncate_string = function (str, restrict) - local tw = luaotfloadconfig.termwidth + local tw = config.luaotfload.misc.termwidth local wd = tw - restrict local len = utf8len (str) if wd - len < 0 then @@ -2148,73 +2103,44 @@ local truncate_string = function (str, restrict) return str end ---[[doc-- - scan_dir() scans a directory and populates the list of fonts - with all the fonts it finds. +--[[doc-- - · dirname : name of the directory to scan - · currentnames : current font db object - · targetnames : font db object to fill - · dry_run : don’t touch anything + collect_font_filenames_dir -- Traverse the directory root at + ``dirname`` looking for font files. Returns a list of {*filename*; + *location*} pairs. --doc]]-- ---- string -> dbobj -> dbobj -> bool -> bool -> (int * int) - -local scan_dir = function (dirname, currentnames, targetnames, - dry_run, location) +--- string -> string -> string * string list +local collect_font_filenames_dir = function (dirname, location) if lpegmatch (p_blacklist, dirname) then report ("both", 4, "db", "Skipping blacklisted directory %s.", dirname) --- ignore - return 0, 0 + return { } end - local found = find_font_files (dirname, location ~= "texmf") + local found = find_font_files (dirname, location ~= "texmf" and location ~= "local") if not found then report ("both", 4, "db", "No such directory: %q; skipping.", dirname) - return 0, 0 + return { } end - report ("both", 4, "db", "Scanning directory %s.", dirname) - local n_new = 0 --- total of fonts collected - local n_found = #found - local max_fonts = luaotfloadconfig.max_fonts - - report ("both", 4, "db", "%d font files detected.", n_found) - for j=1, n_found do - if max_fonts and fonts_read >= max_fonts then - break - end + local nfound = #found + local files = { } + report ("both", 4, "db", + "%d font files detected in %s.", + nfound, dirname) + for j = 1, nfound do local fullname = found[j] - fullname = path_normalize(fullname) - local new - - if dry_run == true then - local truncated = truncate_string (fullname, 43) - report ("log", 2, "db", - "Would have been loading %s.", fullname) - report_status ("term", "db", - "Would have been loading %s", truncated) - else - local truncated = truncate_string (fullname, 32) - report ("log", 2, "db", "Loading font %s.", fullname) - report_status ("term", "db", "Loading font %s", truncated) - local new = read_font_names (fullname, currentnames, - targetnames, texmf) - if new == true then - fonts_read = fonts_read + 1 - n_new = n_new + 1 - end - end + files[#files + 1] = { path_normalize (fullname), location } end - report ("both", 4, "db", "Done. %d fonts indexed in %q.", - n_found, dirname) - return n_found, n_new + return files end + --- string list -> string list local filter_out_pwd = function (dirs) local result = { } @@ -2233,27 +2159,29 @@ end local path_separator = ostype == "windows" and ";" or ":" --[[doc-- - scan_texmf_fonts() scans all fonts in the texmf tree through the - kpathsea variables OPENTYPEFONTS and TTFONTS of texmf.cnf. + + collect_font_filenames_texmf -- Scan texmf tree for font files + relying on the kpathsea variables $OPENTYPEFONTS and $TTFONTS of + texmf.cnf. The current working directory comes as “.” (texlive) or absolute path (miktex) and will always be filtered out. ---doc]]-- ---- dbobj -> dbobj -> bool? -> (int * int) + Returns a list of { *filename*; *location* } pairs. + +--doc]]-- -local scan_texmf_fonts = function (currentnames, targetnames, dry_run) +--- unit -> string * string list +local collect_font_filenames_texmf = function () - local n_scanned, n_new, fontdirs = 0, 0 local osfontdir = kpseexpand_path "$OSFONTDIR" if stringis_empty (osfontdir) then - report ("info", 1, "db", "Scanning TEXMF fonts...") + report ("info", 1, "db", "Scanning TEXMF for fonts...") else - report ("info", 1, "db", "Scanning TEXMF and OS fonts...") - if logs.get_loglevel () > 3 then + report ("info", 1, "db", "Scanning TEXMF and $OSFONTDIR for fonts...") + if log.get_loglevel () > 3 then local osdirs = filesplitpath (osfontdir) - report ("info", 0, "db", - "$OSFONTDIR has %d entries:", #osdirs) + report ("info", 0, "db", "$OSFONTDIR has %d entries:", #osdirs) for i = 1, #osdirs do report ("info", 0, "db", "[%d] %s", i, osdirs[i]) end @@ -2264,255 +2192,22 @@ local scan_texmf_fonts = function (currentnames, targetnames, dry_run) fontdirs = fontdirs .. path_separator .. kpseexpand_path "$TTFONTS" fontdirs = fontdirs .. path_separator .. kpseexpand_path "$T1FONTS" - if not stringis_empty (fontdirs) then - local tasks = filter_out_pwd (filesplitpath (fontdirs)) - report ("info", 3, "db", - "Initiating scan of %d directories.", #tasks) - report_status_start (2, 4) - for _, d in next, tasks do - local found, new = scan_dir (d, currentnames, targetnames, - dry_run, "texmf") - n_scanned = n_scanned + found - n_new = n_new + new - end - report_status_stop ("term", "db", "Scanned %d files, %d new.", n_scanned, n_new) - end - - return n_scanned, n_new -end - ---[[ - For the OS fonts, there are several options: - - if OSFONTDIR is set (which is the case under windows by default but - not on the other OSs), it scans it at the same time as the texmf tree, - in the scan_texmf_fonts. - - if not: - - under Windows and Mac OSX, we take a look at some hardcoded directories - - under Unix, we read /etc/fonts/fonts.conf and read the directories in it - - This means that if you have fonts in fancy directories, you need to set them - in OSFONTDIR. -]] - -local read_fonts_conf -do --- closure for read_fonts_conf() - - local alpha = R("az", "AZ") - local digit = R"09" - local tag_name = C(alpha^1) - local whitespace = S" \n\r\t\v" - local ws = whitespace^1 - local comment = P"<!--" * (1 - P"--")^0 * P"-->" - - ---> header specifica - local xml_declaration = P"<?xml" * (1 - P"?>")^0 * P"?>" - local xml_doctype = P"<!DOCTYPE" * ws - * "fontconfig" * (1 - P">")^0 * P">" - local header = xml_declaration^-1 - * (xml_doctype + comment + ws)^0 - - ---> enforce root node - local root_start = P"<" * ws^-1 * P"fontconfig" * ws^-1 * P">" - local root_stop = P"</" * ws^-1 * P"fontconfig" * ws^-1 * P">" - - local dquote, squote = P[["]], P"'" - local xml_namestartchar = S":_" + alpha --- ascii only, funk the rest - local xml_namechar = S":._" + alpha + digit - local xml_name = ws^-1 - * C(xml_namestartchar * xml_namechar^0) - local xml_attvalue = dquote * C((1 - S[[%&"]])^1) * dquote * ws^-1 - + squote * C((1 - S[[%&']])^1) * squote * ws^-1 - local xml_attr = Cg(xml_name * P"=" * xml_attvalue) - local xml_attr_list = Cf(Ct"" * xml_attr^1, rawset) - - --[[doc-- - scan_node creates a parser for a given xml tag. - --doc]]-- - --- string -> bool -> lpeg_t - local scan_node = function (tag) - --- Node attributes go into a table with the index “attributes” - --- (relevant for “prefix="xdg"” and the likes). - local p_tag = P(tag) - local with_attributes = P"<" * p_tag - * Cg(xml_attr_list, "attributes")^-1 - * ws^-1 - * P">" - local plain = P"<" * p_tag * ws^-1 * P">" - local node_start = plain + with_attributes - local node_stop = P"</" * p_tag * ws^-1 * P">" - --- there is no nesting, the earth is flat ... - local node = node_start - * Cc(tag) * C(comment + (1 - node_stop)^1) - * node_stop - return Ct(node) -- returns {string, string [, attributes = { key = val }] } - end - - --[[doc-- - At the moment, the interesting tags are “dir” for - directory declarations, and “include” for including - further configuration files. - - spec: http://freedesktop.org/software/fontconfig/fontconfig-user.html - --doc]]-- - local include_node = scan_node"include" - local dir_node = scan_node"dir" - - local element = dir_node - + include_node - + comment --> ignore - + P(1-root_stop) --> skip byte - - local root = root_start * Ct(element^0) * root_stop - local p_cheapxml = header * root - - --lpeg.print(p_cheapxml) ---> 757 rules with v0.10 - - --[[doc-- - fonts_conf_scanner() handles configuration files. - It is called on an abolute path to a config file (e.g. - /home/luser/.config/fontconfig/fonts.conf) and returns a list - of the nodes it managed to extract from the file. - --doc]]-- - --- string -> path list - local fonts_conf_scanner = function (path) - local fh = ioopen(path, "r") - if not fh then - report("both", 3, "db", "Cannot open fontconfig file %s.", path) - return - end - local raw = fh:read"*all" - fh:close() - - local confdata = lpegmatch(p_cheapxml, raw) - if not confdata then - report("both", 3, "db", "Cannot scan fontconfig file %s.", path) - return - end - return confdata - end - - local p_conf = P".conf" * P(-1) - local p_filter = (1 - p_conf)^1 * p_conf - - local conf_filter = function (path) - if lpegmatch (p_filter, path) then - return true - end - return false + if stringis_empty (fontdirs) then + return { } end - --[[doc-- - read_fonts_conf_indeed() is called with six arguments; the - latter three are tables that represent the state and are - always returned. - The first three are - · the path to the file - · the expanded $HOME - · the expanded $XDG_CONFIG_DIR - --doc]]-- - --- string -> string -> string -> tab -> tab -> (tab * tab * tab) - local read_fonts_conf_indeed - read_fonts_conf_indeed = function (start, home, xdg_home, - acc, done, dirs_done) - - local paths = fonts_conf_scanner(start) - if not paths then --- nothing to do - return acc, done, dirs_done - end - - for i=1, #paths do - local pathobj = paths[i] - local kind, path = pathobj[1], pathobj[2] - local attributes = pathobj.attributes - if attributes and attributes.prefix == "xdg" then - --- this prepends the xdg root (usually ~/.config) - path = filejoin(xdg_home, path) - end - - if kind == "dir" then - if stringsub(path, 1, 1) == "~" then - path = filejoin(home, stringsub(path, 2)) - end - --- We exclude paths with texmf in them, as they should be - --- found anyway; also duplicates are ignored by checking - --- if they are elements of dirs_done. - --- - --- FIXME does this mean we cannot access paths from - --- distributions (e.g. Context minimals) installed - --- separately? - if not (stringfind(path, "texmf") or dirs_done[path]) then - acc[#acc+1] = path - dirs_done[path] = true - end + local tasks = filter_out_pwd (filesplitpath (fontdirs)) + report ("info", 3, "db", + "Initiating scan of %d directories.", #tasks) - elseif kind == "include" then - --- here the path can be four things: a directory or a file, - --- in absolute or relative path. - if stringsub(path, 1, 1) == "~" then - path = filejoin(home, stringsub(path, 2)) - elseif --- if the path is relative, we make it absolute - not ( lfsisfile(path) or lfsisdir(path) ) - then - path = filejoin(filedirname(start), path) - end - if lfsisfile(path) - and kpsereadable_file(path) - and not done[path] - then - --- we exclude path with texmf in them, as they should - --- be found otherwise - acc = read_fonts_conf_indeed( - path, home, xdg_home, - acc, done, dirs_done) - elseif lfsisdir(path) then --- arrow code ahead - local config_files = find_files (path, conf_filter) - for _, filename in next, config_files do - if not done[filename] then - acc = read_fonts_conf_indeed( - filename, home, xdg_home, - acc, done, dirs_done) - end - end - end --- match “kind” - end --- iterate paths - end - - --inspect(acc) - --inspect(done) - return acc, done, dirs_done - end --- read_fonts_conf_indeed() - - --[[doc-- - read_fonts_conf() sets up an accumulator and two sets - for tracking what’s been done. - - Also, the environment variables HOME and XDG_CONFIG_HOME -- - which are constants anyways -- are expanded so don’t have to - repeat that over and over again as with the old parser. - Now they’re just passed on to every call of - read_fonts_conf_indeed(). - - read_fonts_conf() is also the only reference visible outside - the closure. - --doc]]-- - --- list -> list - read_fonts_conf = function (path_list) - local home = kpseexpand_path"~" --- could be os.getenv"HOME" - local xdg_home = kpseexpand_path"$XDG_CONFIG_HOME" - if xdg_home == "" then xdg_home = filejoin(home, ".config") end - local acc = { } ---> list: paths collected - local done = { } ---> set: files inspected - local dirs_done = { } ---> set: dirs in list - for i=1, #path_list do --- we keep the state between files - acc, done, dirs_done = read_fonts_conf_indeed( - path_list[i], home, xdg_home, - acc, done, dirs_done) - end - return acc + local files = { } + for _, dir in next, tasks do + files = tableappend (files, collect_font_filenames_dir (dir, "texmf")) end -end --- read_fonts_conf closure + report ("term", 3, "db", "Collected %d files.", #files) + return files +end ---- TODO stuff those paths into some writable table --- unit -> string list local function get_os_dirs () if os.name == 'macosx' then @@ -2523,14 +2218,14 @@ local function get_os_dirs () "/Network/Library/Fonts", } elseif os.type == "windows" or os.type == "msdos" then - local windir = os.getenv("WINDIR") + local windir = osgetenv("WINDIR") return { filejoin(windir, 'Fonts') } else local fonts_conves = { --- plural, much? "/usr/local/etc/fonts/fonts.conf", "/etc/fonts/fonts.conf", } - local os_dirs = read_fonts_conf(fonts_conves) + local os_dirs = read_fonts_conf(fonts_conves, find_files) return os_dirs end return {} @@ -2538,51 +2233,118 @@ end --[[doc-- - scan_os_fonts() scans the OS fonts through - - fontconfig for Unix (reads the fonts.conf file[s] and scans the - directories) - - a static set of directories for Windows and MacOSX + retrieve_namedata -- Scan the list of collected fonts and populate + the list of namedata. + + · dirname : name of the directory to scan + · currentnames : current font db object + · targetnames : font db object to fill + · dry_run : don’t touch anything - **NB**: If $OSFONTDIR is nonempty, as it appears to be by default - on Windows setups, the system fonts will have already been - processed while scanning the TEXMF. Thus, this function is - never called. + Returns the number of fonts that were actually added to the index. --doc]]-- ---- dbobj -> dbobj -> bool? -> (int * int) -local scan_os_fonts = function (currentnames, - targetnames, - dry_run) +--- string * string list -> dbobj -> dbobj -> bool? -> int +local retrieve_namedata = function (files, currentnames, targetnames, dry_run) + + local nfiles = #files + local nnew = 0 + + report ("info", 1, "db", "Scanning %d collected font files ...", nfiles) + + local bylocation = { texmf = { 0, 0 } + , ["local"] = { 0, 0 } + , system = { 0, 0 } + } + report_status_start (2, 4) + for i = 1, nfiles do + local fullname, location = unpack (files[i]) + local count = bylocation[location] + count[1] = count[1] + 1 + if dry_run == true then + local truncated = truncate_string (fullname, 43) + report ("log", 2, "db", "Would have been loading %s.", fullname) + report_status ("term", "db", "Would have been loading %s", truncated) + --- skip the read_font_names part + else + local truncated = truncate_string (fullname, 32) + report ("log", 2, "db", "Loading font %s.", fullname) + report_status ("term", "db", "Loading font %s", truncated) + local new = read_font_names (fullname, currentnames, + targetnames, location) + if new == true then + nnew = nnew + 1 + count[2] = count[2] + 1 + end + end + end + report_status_stop ("term", "db", "Scanned %d files, %d new.", nfiles, nnew) + for location, count in next, bylocation do + report ("term", 4, "db", " * %s: %d files, %d new", + location, count[1], count[2]) + end + return nnew +end + +--- unit -> string * string list +local collect_font_filenames_system = function () local n_scanned, n_new = 0, 0 - report ("info", 1, "db", "Scanning OS fonts...") + report ("info", 1, "db", "Scanning system fonts...") report ("info", 2, "db", "Searching in static system directories...") - report_status_start (2, 4) - for _, d in next, get_os_dirs () do - local found, new = scan_dir (d, currentnames, - targetnames, dry_run) - n_scanned = n_scanned + found - n_new = n_new + new + local files = { } + for _, dir in next, get_os_dirs () do + tableappend (files, collect_font_filenames_dir (dir, "system")) end - report_status_stop ("term", "db", "Scanned %d files, %d new.", n_scanned, n_new) - - return n_scanned, n_new + report ("term", 3, "db", "Collected %d files.", #files) + return files end ---- unit -> (bool, lookup_cache) +--- unit -> bool flush_lookup_cache = function () lookup_cache = { } collectgarbage "collect" - return true, lookup_cache + return true +end + +--[[doc-- + + collect_font_filenames_local -- Scan $PWD (during a TeX run) + for font files. + + Side effect: This sets the “local” flag in the subtable “meta” to + prevent the merged table from being saved to disk. + + TODO the local tree could be cached in $PWD. + +--doc]]-- + +--- unit -> string * string list +local collect_font_filenames_local = function () + local pwd = lfscurrentdir () + report ("both", 1, "db", "Scanning for fonts in $PWD (%q) ...", pwd) + + local files = collect_font_filenames_dir (pwd, "local") + local nfiles = #files + if nfiles > 0 then + targetnames.meta["local"] = true --- prevent saving to disk + report ("term", 1, "db", "Found %d files.", pwd) + else + report ("term", 1, "db", + "Couldn’t find a thing here. What a waste.", pwd) + end + report ("term", 3, "db", "Collected %d files.", #files) + return files end +--- dbobj -> dbobj -> int * int --- fontentry list -> filemap -local generate_filedata = function (mappings) +generate_filedata = function (mappings) report ("both", 2, "db", "Creating filename map.") @@ -2715,11 +2477,16 @@ do local splitfontname = lpeg.splitat "-" local choose_exact = function (field) + --- only clean matches, without guessing if italic_synonym [field] then return "i" - elseif field == "bold" then + end + + if field == "bold" then return "b" - elseif field == "bolditalic" or field == "boldoblique" then + end + + if field == "bolditalic" or field == "boldoblique" then return "bi" end @@ -2741,19 +2508,30 @@ do style = choose_exact (subfamily) end end --- if not style and splitstyle then --- style = choose_exact (splitstyle) --- end return style end + pick_fallback_style = function (italicangle, weight) + --- more aggressive, but only to determine bold faces + if weight > 500 then --- bold spectrum matches + if italicangle == 0 then + return tostring (weight) + else + return tostring (weight) .. "i" + end + end + return false + end + --- we use only exact matches here since there are constructs --- like “regularitalic” (Cabin, Bodoni Old Fashion) check_regular = function (fontstyle_name, prefmodifiers, subfamily, - splitstyle) + splitstyle, + italicangle, + weight) if fontstyle_name then return regular_synonym [fontstyle_name] @@ -2763,6 +2541,8 @@ do return regular_synonym [subfamily] elseif splitstyle then return regular_synonym [splitstyle] + elseif italicangle == 0 and weight == 400 then + return true end return nil @@ -2786,7 +2566,7 @@ local pull_values = function (entry) --- pull name info ... entry.psname = english.psname - entry.fontname = info.fontname + entry.fontname = info.fontname or metadata.fontname entry.fullname = english.fullname or info.fullname entry.splainname = metadata.fullname entry.prefmodifiers = english.prefmodifiers @@ -2806,7 +2586,7 @@ local pull_values = function (entry) entry.splitstyle = style.split entry.weight = style.weight - if luaotfloadconfig.strip == true then + if config.luaotfload.db.strip == true then entry.file = nil entry.names = nil entry.style = nil @@ -2814,7 +2594,7 @@ local pull_values = function (entry) end local add_family = function (name, subtable, modifier, entry) - if not name then + if not name then --- probably borked font return end local familytable = subtable [name] @@ -2823,33 +2603,28 @@ local add_family = function (name, subtable, modifier, entry) subtable [name] = familytable end - --- the style table is treated as an unordered list - local styletable = familytable [modifier] - if not styletable then - styletable = { } - familytable [modifier] = styletable - end + local size = entry.size - if not entry.prefmodifiers then --- default size for this style/family combo - styletable.default = entry.index - end + familytable [#familytable + 1] = { + index = entry.index, + modifier = modifier, + } +end - local size = entry.size --- dsnsize * high * low - if size then - styletable [#styletable + 1] = { - size [1], - size [2], - size [3], - entry.index, - } - else - styletable.default = entry.index +local get_subtable = function (families, entry) + local location = entry.location + local format = entry.format + local subtable = families [location] [format] + if not subtable then + subtable = { } + families [location] [format] = subtable end + return subtable end -local collect_families = function (mappings) +collect_families = function (mappings) - report ("info", 2, "db", "Analyzing families, sizes, and styles.") + report ("info", 2, "db", "Analyzing families.") local families = { ["local"] = { }, @@ -2865,14 +2640,7 @@ local collect_families = function (mappings) pull_values (entry) end - local location = entry.location - local format = entry.format - - local subtable = families [location] [format] - if not subtable then - subtable = { } - families [location] [format] = subtable - end + local subtable = get_subtable (families, entry) local familyname = entry.familyname local metafamily = entry.metafamily @@ -2893,7 +2661,9 @@ local collect_families = function (mappings) modifier = check_regular (fontstyle_name, prefmodifiers, subfamily, - splitstyle) + splitstyle, + italicangle, + weight) end if modifier then @@ -2921,6 +2691,11 @@ local collect_families = function (mappings) -- if metafamily and metafamily ~= familyname then -- add_family (metafamily, subtable, modifier, entry) -- end + elseif weight > 500 then -- in bold spectrum + modifier = pick_fallback_style (italicangle, weight) + if modifier then + add_family (familyname, subtable, modifier, entry) + end end end @@ -2928,11 +2703,121 @@ local collect_families = function (mappings) return families end +--[[doc-- + + group_modifiers -- For not-quite-bold faces, determine whether + they can fill in for a missing bold face slot in a matching family. + + Some families like Lucida do not contain real bold / bold italic + members. Instead, they have semibold variants at weight 600 which + we must add in a separate pass. + +--doc]]-- + +local bold_spectrum_low = 501 --- 500 is medium, 900 heavy/black +local bold_weight = 700 +local style_categories = { "r", "b", "i", "bi" } +local bold_categories = { "b", "bi" } + +group_modifiers = function (mappings, families) + report ("info", 2, "db", "Analyzing shapes, weights, and styles.") + for location, location_data in next, families do + for format, format_data in next, location_data do + for familyname, collected in next, format_data do + local styledata = { } --- will replace the “collected” table + --- First, fill in the ordinary style data that + --- fits neatly into the four relevant modifier + --- categories. + for _, modifier in next, style_categories do + local entries + for key, info in next, collected do + if info.modifier == modifier then + if not entries then + entries = { } + end + local index = info.index + local entry = mappings [index] + local size = entry.size + if size then + entries [#entries + 1] = { + size [1], + size [2], + size [3], + index, + } + else + entries.default = index + end + collected [key] = nil + end + styledata [modifier] = entries + end + end + + --- At this point the family set may still lack + --- entries for bold or bold italic. We will fill + --- those in using the modifier with the numeric + --- weight that is closest to bold (700). + if next (collected) then --- there are uncategorized entries + for _, modifier in next, bold_categories do + if not styledata [modifier] then + local closest + local minimum = 2^51 + for key, info in next, collected do + local info_modifier = tonumber (info.modifier) and "b" or "bi" + if modifier == info_modifier then + local index = info.index + local entry = mappings [index] + local weight = entry.weight + local diff = weight < 700 and 700 - weight or weight - 700 + if diff < minimum then + minimum = diff + closest = weight + end + end + end + if closest then + --- We know there is a substitute face for the modifier. + --- Now we scan the list again to extract the size data + --- in case the shape is available at multiple sizes. + local entries = { } + for key, info in next, collected do + local info_modifier = tonumber (info.modifier) and "b" or "bi" + if modifier == info_modifier then + local index = info.index + local entry = mappings [index] + local size = entry.size + if entry.weight == closest then + if size then + entries [#entries + 1] = { + size [1], + size [2], + size [3], + index, + } + else + entries.default = index + end + end + end + end + styledata [modifier] = entries + end + end + end + end + format_data [familyname] = styledata + end + end + end + return families +end + local cmp_sizes = function (a, b) return a [1] < b [1] end -local order_design_sizes = function (families) +order_design_sizes = function (families) report ("info", 2, "db", "Ordering design sizes.") @@ -2949,27 +2834,89 @@ local order_design_sizes = function (families) return families end -local retrieve_namedata = function (currentnames, - targetnames, - dry_run, - n_rawnames, - n_newnames) +--[[doc-- - local rawnames, new = scan_texmf_fonts (currentnames, - targetnames, - dry_run) + collect_font_filenames -- Scan the three search path categories for + font files. This constitutes the first pass of the update mode. + +--doc]]-- - n_rawnames = n_rawnames + rawnames - n_newnames = n_newnames + new +--- unit -> string * bool list +local collect_font_filenames = function () - rawnames, new = scan_os_fonts (currentnames, targetnames, dry_run) + report ("info", 4, "db", "Scanning the filesystem for font files.") - n_rawnames = n_rawnames + rawnames - n_newnames = n_newnames + new + local filenames = { } + local bisect = config.luaotfload.misc.bisect + local max_fonts = config.luaotfload.db.max_fonts --- XXX revisit for lua 5.3 wrt integers - return n_rawnames, n_newnames + tableappend (filenames, collect_font_filenames_texmf ()) + tableappend (filenames, collect_font_filenames_system ()) + if config.luaotfload.db.scan_local == true then + tableappend (filenames, collect_font_filenames_local ()) + end + --- Now drop everything above max_fonts. + if max_fonts < #filenames then + filenames = { unpack (filenames, 1, max_fonts) } + end + --- And choose the requested slice if in bisect mode. + if bisect then + return { unpack (filenames, bisect[1], bisect[2]) } + end + return filenames end +--[[doc-- + + nth_font_file -- Return the filename of the nth font. + +--doc]]-- + +--- int -> string +local nth_font_filename = function (n) + report ("info", 4, "db", "Picking font file no. %d.", n) + if not p_blacklist then + read_blacklist () + end + local filenames = collect_font_filenames () + return filenames[n] and filenames[n][1] or "<error>" +end + +--[[doc-- + + font_slice -- Return the fonts in the range from lo to hi. + +--doc]]-- + +local font_slice = function (lo, hi) + report ("info", 4, "db", "Retrieving font files nos. %d--%d.", lo, hi) + if not p_blacklist then + read_blacklist () + end + local filenames = collect_font_filenames () + local result = { } + for i = lo, hi do + result[#result + 1] = filenames[i][1] + end + return result +end + +--[[doc + + count_font_files -- Return the number of files found by + collect_font_filenames. This function is exported primarily + for use with luaotfload-tool.lua in bisect mode. + +--doc]]-- + +--- unit -> int +local count_font_files = function () + report ("info", 4, "db", "Counting font files.") + if not p_blacklist then + read_blacklist () + end + return #collect_font_filenames () +end --- dbobj -> stats @@ -3053,7 +3000,7 @@ local collect_statistics = function (mappings) local n_fullname = setsize (fullname) local n_family = setsize (family) - if logs.get_loglevel () > 1 then + if log.get_loglevel () > 1 then local pprint_top = function (hash, n, set) local freqs = { } @@ -3142,18 +3089,16 @@ end --- dbobj? -> bool? -> bool? -> dbobj update_names = function (currentnames, force, dry_run) - local targetnames - if luaotfloadconfig.update_live == false then + if config.luaotfload.db.update_live == false then report ("info", 2, "db", "Skipping database update.") --- skip all db updates return currentnames or name_index end - local starttime = osgettimeofday () - local n_rawnames, n_newnames = 0, 0 + local starttime = osgettimeofday () --[[ The main function, scans everything @@ -3163,10 +3108,7 @@ update_names = function (currentnames, force, dry_run) report("both", 1, "db", "Updating the font names database" .. (force and " forcefully." or ".")) - --- pass 1 get raw data: read font files (normal case) or reuse - --- information present in index - - if luaotfloadconfig.skip_read == true then + if config.luaotfload.db.skip_read == true then --- the difference to a “dry run” is that we don’t search --- for font files entirely. we also ignore the “force” --- parameter since it concerns only the font files. @@ -3188,22 +3130,28 @@ update_names = function (currentnames, force, dry_run) end end - targetnames = initialize_namedata (get_font_filter ()) + targetnames = initialize_namedata (get_font_filter (), + currentnames.meta and currentnames.meta.created) read_blacklist () - local n_raw, n_new= retrieve_namedata (currentnames, - targetnames, - dry_run, - n_rawnames, - n_newnames) + --- pass 1: Collect the names of all fonts we are going to process. + local font_filenames = collect_font_filenames () + + --- pass 2: read font files (normal case) or reuse information + --- present in index + + n_new = retrieve_namedata (font_filenames, + currentnames, + targetnames, + dry_run) report ("info", 3, "db", - "Scanned %d font files; %d new entries.", - n_rawnames, n_newnames) + "Found %d font files; %d new entries.", + #font_filenames, n_new) end - --- pass 2 (optional): collect some stats about the raw font info - if luaotfloadconfig.statistics == true then + --- pass 3 (optional): collect some stats about the raw font info + if config.luaotfload.misc.statistics == true then targetnames.meta.statistics = collect_statistics (targetnames.mappings) end @@ -3212,13 +3160,17 @@ update_names = function (currentnames, force, dry_run) --- non-texmf entries are redirected there and the mapping --- needs to be 100% consistent - --- pass 3: build filename table + --- pass 4: build filename table targetnames.files = generate_filedata (targetnames.mappings) - --- pass 4: build family lookup table - targetnames.families = collect_families (targetnames.mappings) + --- pass 5: build family lookup table + targetnames.families = collect_families (targetnames.mappings) + + --- pass 6: arrange style and size info + targetnames.families = group_modifiers (targetnames.mappings, + targetnames.families) - --- pass 5: order design size tables + --- pass 7: order design size tables targetnames.families = order_design_sizes (targetnames.families) @@ -3229,25 +3181,29 @@ update_names = function (currentnames, force, dry_run) if dry_run ~= true then - save_names () - - local success, _lookups = flush_lookup_cache () - if success then - local success = save_lookups () - if success then - logs.names_report ("info", 2, "cache", - "Lookup cache emptied.") - return targetnames + if n_new == 0 then + report ("info", 2, "db", "No new fonts found, skip saving to disk.") + else + local success, reason = save_names () + if not success then + report ("both", 0, "db", + "Failed to save database to disk: %s", + reason) end end + + if flush_lookup_cache () and save_lookups () then + report ("both", 2, "cache", "Lookup cache emptied.") + return targetnames + end end return targetnames end --- unit -> bool save_lookups = function ( ) - local path = names.path.lookups - local luaname, lucname = path.lua, path.luc + local paths = config.luaotfload.paths + local luaname, lucname = paths.lookup_path_lua, paths.lookup_path_luc if fileiswritable (luaname) and fileiswritable (lucname) then tabletofile (luaname, lookup_cache, true) osremove (lucname) @@ -3271,17 +3227,22 @@ save_lookups = function ( ) end --- save_names() is usually called without the argument ---- dbobj? -> bool +--- dbobj? -> bool * string option save_names = function (currentnames) if not currentnames then currentnames = name_index end - local path = names.path.index - local luaname, lucname = path.lua, path.luc + if not currentnames or type (currentnames) ~= "table" then + return false, "invalid names table" + elseif currentnames.meta and currentnames.meta["local"] then + return false, "table contains local entries" + end + local paths = config.luaotfload.paths + local luaname, lucname = paths.index_path_lua, paths.index_path_luc if fileiswritable (luaname) and fileiswritable (lucname) then osremove (lucname) local gzname = luaname .. ".gz" - if luaotfloadconfig.compress then + if config.luaotfload.db.compress then local serialized = tableserialize (currentnames, true) save_gzipped (gzname, serialized) caches.compile (currentnames, "", lucname) @@ -3399,7 +3360,7 @@ end local getwritablecachepath = function ( ) --- fonts.handlers.otf doesn’t exist outside a Luatex run, --- so we have to improvise - local writable = getwritablepath (luaotfloadconfig.cache_dir) + local writable = getwritablepath (config.luaotfload.paths.cache_dir) if writable then return writable end @@ -3407,7 +3368,7 @@ end local getreadablecachepaths = function ( ) local readables = caches.getreadablepaths - (luaotfloadconfig.cache_dir) + (config.luaotfload.paths.cache_dir) local result = { } if readables then for i=1, #readables do @@ -3424,7 +3385,7 @@ end local purge_cache = function ( ) local writable_path = getwritablecachepath () local luanames, lucnames, rest = collect_cache(writable_path) - if logs.get_loglevel() > 1 then + if log.get_loglevel() > 1 then print_cache("writable path", writable_path, luanames, lucnames, rest) end local success = purge_from_cache("writable path", writable_path, luanames, false) @@ -3435,7 +3396,7 @@ end local erase_cache = function ( ) local writable_path = getwritablecachepath () local luanames, lucnames, rest, all = collect_cache(writable_path) - if logs.get_loglevel() > 1 then + if log.get_loglevel() > 1 then print_cache("writable path", writable_path, luanames, lucnames, rest) end local success = purge_from_cache("writable path", writable_path, all, true) @@ -3472,36 +3433,31 @@ end --- export functionality to the namespace “fonts.names” ----------------------------------------------------------------------- -names.scan_dir = scan_dir names.set_font_filter = set_font_filter names.flush_lookup_cache = flush_lookup_cache names.save_lookups = save_lookups names.load = load_names +names.access_font_index = access_font_index names.data = function () return name_index end names.save = save_names names.update = update_names -names.crude_file_lookup = crude_file_lookup -names.crude_file_lookup_verbose = crude_file_lookup_verbose +names.font_file_lookup = font_file_lookup names.read_blacklist = read_blacklist names.sanitize_fontname = sanitize_fontname names.getfilename = resolve_fullpath +names.getmetadata = getmetadata names.set_location_precedence = set_location_precedence +names.count_font_files = count_font_files +names.nth_font_filename = nth_font_filename +names.font_slice = font_slice +names.resolve_cached = resolve_cached +names.resolve_name = resolve_name --- font cache names.purge_cache = purge_cache names.erase_cache = erase_cache names.show_cache = show_cache ---- replace the resolver from luatex-fonts -if luaotfloadconfig.resolver == "cached" then - report("both", 2, "cache", "Caching of name: lookups active.") - names.resolvespec = resolve_cached - names.resolve_name = resolve_cached -else - names.resolvespec = resolve_name - names.resolve_name = resolve_name -end - names.find_closest = find_closest -- for testing purpose diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua index 68ed18c456b..80e461ccac5 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua @@ -4,13 +4,11 @@ -- DESCRIPTION: functionality accessible by the --diagnose option -- REQUIREMENTS: luaotfload-tool.lua -- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> --- VERSION: 2.4 --- CREATED: 2013-07-28 10:01:18+0200 +-- VERSION: 2.5 +-- MODIFIED: 2014-01-02 21:23:06+0100 ----------------------------------------------------------------------- -- local names = fonts.names -local luatexstatus = status -local status = config.luaotfload.status local kpse = require "kpse" local kpseexpand_path = kpse.expand_path @@ -49,10 +47,15 @@ local lpeg = require "lpeg" local C, Cg, Ct = lpeg.C, lpeg.Cg, lpeg.Ct local lpegmatch = lpeg.match +local report = luaotfload.log.report local out = function (...) - logs.names_report (false, 0, "diagnose", ...) + report (false, 0, "diagnose", ...) end +local parsers = luaotfload.parsers +local stripslashes = parsers.stripslashes +local splitcomma = parsers.splitcomma + local check_index = function (errcnt) out "================= font names ==================" @@ -94,8 +97,9 @@ local check_index = function (errcnt) return errcnt end -local verify_files = function (errcnt, status) +local verify_files = function (errcnt) out "================ verify files =================" + local status = config.luaotfload.status local hashes = status.hashes local notes = status.notes if not hashes or #hashes == 0 then @@ -163,8 +167,6 @@ local analyze_permissions = function (raw) return lpegmatch (p_permissions, raw) end -local stripslashes = names.patterns.stripslashes - local get_permissions = function (t, location) if stringsub (location, #location) == "/" then --- strip trailing slashes (lfs idiosyncrasy on Win) @@ -238,19 +240,23 @@ local check_conformance = function (spec, permissions, errcnt) return errcnt end -local path = names.path - -local desired_permissions = { - { "d", {"r","w"}, function () return caches.getwritablepath () end }, - { "d", {"r","w"}, path.globals.prefix }, - { "f", {"r","w"}, path.index.lua .. ".gz" }, - { "f", {"r","w"}, path.index.luc }, - { "f", {"r","w"}, path.lookups.lua }, - { "f", {"r","w"}, path.lookups.luc }, -} +local desired_permissions +local init_desired_permissions = function () + inspect(config.luaotfload.paths) + local paths = config.luaotfload.paths + desired_permissions = { + { "d", {"r","w"}, function () return caches.getwritablepath () end }, + { "d", {"r","w"}, paths.prefix }, + { "f", {"r","w"}, paths.index_path_lua .. ".gz" }, + { "f", {"r","w"}, paths.index_path_luc }, + { "f", {"r","w"}, paths.lookup_path_lua }, + { "f", {"r","w"}, paths.lookup_path_luc }, + } +end local check_permissions = function (errcnt) out [[=============== file permissions ==============]] + if not desired_permissions then init_desired_permissions () end for i = 1, #desired_permissions do local t, spec, path = unpack (desired_permissions[i]) if type (path) == "function" then @@ -334,8 +340,7 @@ else end out ("Requesting <%s>.", request) - local response, code, headers, status - = https.request (request) + local response, code, headers, status = https.request (request) if status ~= alright then out "Request failed!" return false @@ -605,8 +610,6 @@ local anamneses = { "permissions" } -local splitcomma = names.patterns.splitcomma - local diagnose = function (job) local errcnt = 0 local asked = job.asked_diagnostics @@ -628,7 +631,7 @@ local diagnose = function (job) end if asked.files == true then - errcnt = verify_files (errcnt, status) + errcnt = verify_files (errcnt) asked.files = nil end @@ -638,6 +641,7 @@ local diagnose = function (job) end if asked.repository == true then + local status = config.luaotfload.status check_upstream (status.notes.revision) asked.repository = nil end @@ -663,7 +667,7 @@ local diagnose = function (job) carefully and get a clean version from CTAN or github: - × http://ctan.org/tex-archive/macros/luatex/generic/luaotfload + × http://www.ctan.org/pkg/luaotfload × https://github.com/lualatex/luaotfload/releases If you are uncertain as to how to proceed, then diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua index 4b2f20619ff..1fb6d7c6785 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua @@ -1,15 +1,26 @@ if not modules then modules = { } end modules ["features"] = { - version = "2.4", - comment = "companion to luaotfload.lua", + version = "2.5", + comment = "companion to luaotfload-main.lua", author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -local type, next = type, next +local type = type +local next = next local tonumber = tonumber local tostring = tostring + +local lpeg = require "lpeg" local lpegmatch = lpeg.match +local P = lpeg.P +local R = lpeg.R +local C = lpeg.C + +local table = table +local tabletohash = table.tohash +local setmetatableindex = table.setmetatableindex +local insert = table.insert ---[[ begin included font-ltx.lua ]] --- this appears to be based in part on luatex-fonts-def.lua @@ -43,7 +54,8 @@ function fonts.definers.getspecification(str) return "", str, "", ":", str end -local report = logs.names_report +local log = luaotfload.log +local report = log.report local stringfind = string.find local stringlower = string.lower @@ -53,58 +65,6 @@ local stringformat = string.format local stringis_empty = string.is_empty local mathceil = math.ceil -local defaults = { - dflt = { - "ccmp", "locl", "rlig", "liga", "clig", - "kern", "mark", "mkmk", 'itlc', - }, - arab = { - "ccmp", "locl", "isol", "fina", "fin2", - "fin3", "medi", "med2", "init", "rlig", - "calt", "liga", "cswh", "mset", "curs", - "kern", "mark", "mkmk", - }, - deva = { - "ccmp", "locl", "init", "nukt", "akhn", - "rphf", "blwf", "half", "pstf", "vatu", - "pres", "blws", "abvs", "psts", "haln", - "calt", "blwm", "abvm", "dist", "kern", - "mark", "mkmk", - }, - khmr = { - "ccmp", "locl", "pref", "blwf", "abvf", - "pstf", "pres", "blws", "abvs", "psts", - "clig", "calt", "blwm", "abvm", "dist", - "kern", "mark", "mkmk", - }, - thai = { - "ccmp", "locl", "liga", "kern", "mark", - "mkmk", - }, - hang = { - "ccmp", "ljmo", "vjmo", "tjmo", - }, -} - -local global_defaults = { mode = "node" } - -defaults.beng = defaults.deva -defaults.guru = defaults.deva -defaults.gujr = defaults.deva -defaults.orya = defaults.deva -defaults.taml = defaults.deva -defaults.telu = defaults.deva -defaults.knda = defaults.deva -defaults.mlym = defaults.deva -defaults.sinh = defaults.deva - -defaults.syrc = defaults.arab -defaults.mong = defaults.arab -defaults.nko = defaults.arab - -defaults.tibt = defaults.khmr - -defaults.lao = defaults.thai ---[[ begin excerpt from font-ott.lua ]] @@ -749,7 +709,7 @@ local verbosebaselines = swapped(baselines) --doc]]-- -local support_incomplete = table.tohash({ +local support_incomplete = tabletohash({ "deva", "beng", "guru", "gujr", "orya", "taml", "telu", "knda", "mlym", "sinh", @@ -764,6 +724,8 @@ local support_incomplete = table.tohash({ --- (string, string) dict -> (string, string) dict local set_default_features = function (speclist) + local default_features = luaotfload.features + speclist = speclist or { } speclist[""] = nil --- invalid options stub @@ -788,32 +750,31 @@ local set_default_features = function (speclist) or "dflt" if support_incomplete[script] then report("log", 0, "load", - "support for the requested script: " - .. "%q may be incomplete", script) + "Support for the requested script: " + .. "%q may be incomplete.", script) end else script = "dflt" end speclist.script = script - report("log", 0, "load", - "auto-selecting default features for script: %s", + report("log", 1, "load", + "Auto-selecting default features for script: %s.", script) - local requested = defaults[script] + local requested = default_features.defaults[script] if not requested then - report("log", 0, "load", - "no defaults for script %q, falling back to \"dflt\"", + report("log", 1, "load", + "No default features for script %q, falling back to \"dflt\".", script) - requested = defaults.dflt + requested = default_features.defaults.dflt end - for i=1, #requested do - local feat = requested[i] - if speclist[feat] ~= false then speclist[feat] = true end + for feat, state in next, requested do + if not speclist[feat] then speclist[feat] = state end end - for feat, state in next, global_defaults do + for feat, state in next, default_features.global do --- This is primarily intended for setting node --- mode unless “base” is requested, as stated --- in the manual. @@ -822,259 +783,6 @@ local set_default_features = function (speclist) return speclist end ------------------------------------------------------------------------ ---- request syntax parser 2.2 ------------------------------------------------------------------------ ---- the luaotfload font request syntax (see manual) ---- has a canonical form: ---- ---- \font<csname>=<prefix>:<identifier>:<features> ---- ---- where ---- <csname> is the control sequence that activates the font ---- <prefix> is either “file” or “name”, determining the lookup ---- <identifer> is either a file name (no path) or a font ---- name, depending on the lookup ---- <features> is a list of switches or options, separated by ---- semicolons or commas; a switch is of the form “+” foo ---- or “-” foo, options are of the form lhs “=” rhs ---- ---- however, to ensure backward compatibility we also have ---- support for Xetex-style requests. ---- ---- for the Xetex emulation see: ---- · The XeTeX Reference Guide by Will Robertson, 2011 ---- · The XeTeX Companion by Michel Goosens, 2010 ---- · About XeTeX by Jonathan Kew, 2005 ---- ---- ---- caueat emptor. ---- the request is parsed into one of **four** different ---- lookup categories: the regular ones, file and name, ---- as well as the Xetex compatibility ones, path and anon. ---- (maybe a better choice of identifier would be “ambig”.) ---- ---- according to my reconstruction, the correct chaining ---- of the lookups for each category is as follows: ---- ---- | File -> ( db/filename lookup ) ---- ---- | Name -> ( db/name lookup, ---- db/filename lookup ) ---- ---- | Path -> ( db/filename lookup, ---- fullpath lookup ) ---- ---- | Anon -> ( kpse.find_file(), // <- for tfm, ofm ---- db/name lookup, ---- db/filename lookup, ---- fullpath lookup ) ---- ---- caching of successful lookups is essential. we now ---- as of v2.2 have an experimental lookup cache that is ---- stored in a separate file. it pertains only to name: ---- lookups, and is described in more detail in ---- luaotfload-database.lua. ---- ------------------------------------------------------------------------ - ---[[doc-- - - One further incompatibility between Xetex and Luatex-Fonts consists - in their option list syntax: apparently, Xetex requires key-value - options to be prefixed by a "+" (ascii “plus”) character. We - silently accept this as well, dropping the first byte if it is a - plus or minus character. - - Reference: https://github.com/lualatex/luaotfload/issues/79#issuecomment-18104483 - ---doc]]-- - -local handle_normal_option = function (key, val) - val = stringlower(val) - --- the former “toboolean()” handler - if val == "true" then - val = true - elseif val == "false" then - val = false - end - return key, val -end - ---[[doc-- - - Xetex style indexing begins at zero which we just increment before - passing it along to the font loader. Ymmv. - ---doc]]-- - -local handle_xetex_option = function (key, val) - val = stringlower(val) - local numeric = tonumber(val) --- decimal only; keeps colors intact - if numeric then --- ugh - if mathceil(numeric) == numeric then -- integer, possible index - val = tostring(numeric + 1) - end - elseif val == "true" then - val = true - elseif val == "false" then - val = false - end - return key, val -end - ---[[doc-- - - Instead of silently ignoring invalid options we emit a warning to - the log. - - Note that we have to return a pair to please rawset(). This creates - an entry on the resulting features hash which will later be removed - during set_default_features(). - ---doc]]-- - -local handle_invalid_option = function (opt) - report("log", 0, "load", "font option %q unknown.", opt) - return "", false -end - ---[[doc-- - - Dirty test if a file: request is actually a path: lookup; don’t - ask! Note this fails on Windows-style absolute paths. These will - *really* have to use the correct request. - ---doc]]-- - -local check_garbage = function (_,i, garbage) - if stringfind(garbage, "/") then - report("log", 0, "load", --- ffs use path! - "warning: path in file: lookups is deprecated; ") - report("log", 0, "load", "use bracket syntax instead!") - report("log", 0, "load", - "position: %d; full match: %q", - i, garbage) - return true - end - return false -end - -local lpegmatch = lpeg.match -local P, S, R = lpeg.P, lpeg.S, lpeg.R -local C, Cc, Cf, Cg, Cmt, Cs, Ct - = lpeg.C, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Cmt, lpeg.Cs, lpeg.Ct - ---- terminals and low-level classes ----------------------------------- ---- note we could use the predefined ones from lpeg.patterns -local dot = P"." -local colon = P":" -local featuresep = S",;" -local slash = P"/" -local equals = P"=" -local lbrk, rbrk = P"[", P"]" - -local spacing = S" \t\v" -local ws = spacing^0 - -local digit = R"09" -local alpha = R("az", "AZ") -local anum = alpha + digit -local decimal = digit^1 * (dot * digit^0)^-1 - ---- modifiers --------------------------------------------------------- ---[[doc-- - The slash notation: called “modifiers” (Kew) or “font options” - (Robertson, Goosens) - we only support the shorthands for italic / bold / bold italic - shapes, as well as setting optical size, the rest is ignored. ---doc]]-- -local style_modifier = (P"BI" + P"IB" + P"bi" + P"ib" + S"biBI") - / stringlower -local size_modifier = S"Ss" * P"=" --- optical size - * Cc"optsize" * C(decimal) -local other_modifier = P"AAT" + P"aat" --- apple stuff; unsupported - + P"ICU" + P"icu" --- not applicable - + P"GR" + P"gr" --- sil stuff; unsupported -local garbage_modifier = ((1 - colon - slash)^0 * Cc(false)) -local modifier = slash * (other_modifier --> ignore - + Cs(style_modifier) --> collect - + Ct(size_modifier) --> collect - + garbage_modifier) --> warn -local modifier_list = Cg(Ct(modifier^0), "modifiers") - ---- lookups ----------------------------------------------------------- -local fontname = C((1-S":(/")^1) --- like luatex-fonts -local unsupported = Cmt((1-S":(")^1, check_garbage) -local prefixed = P"name:" * ws * Cg(fontname, "name") ---- initially we intended file: to emulate the behavior of ---- luatex-fonts, i.e. no paths allowed. after all, we do have XeTeX ---- emulation with the path lookup and it interferes with db lookups. ---- turns out fontspec and other widely used packages rely on file: ---- with paths already, so we’ll add a less strict rule here. anyways, ---- we’ll emit a warning. - + P"file:" * ws * Cg(unsupported, "path") - + P"file:" * ws * Cg(fontname, "file") ---- EXPERIMENTAL: kpse lookup - + P"kpse:" * ws * Cg(fontname, "kpse") ---- EXPERIMENTAL: custom lookup - + P"my:" * ws * Cg(fontname, "my") -local unprefixed = Cg(fontname, "anon") -local path_lookup = lbrk * Cg(C((1-rbrk)^1), "path") * rbrk - ---- features ---------------------------------------------------------- -local field_char = anum + S"+-." --- sic! -local field = field_char^1 ---- assignments are “lhs=rhs” ---- or “+lhs=rhs” (Xetex-style) ---- switches are “+key” | “-key” -local normal_option = C(field) * ws * equals * ws * C(field) * ws -local xetex_option = P"+" * ws * normal_option -local ignore_option = (1 - equals - featuresep)^1 - * equals - * (1 - featuresep)^1 -local assignment = xetex_option / handle_xetex_option - + normal_option / handle_normal_option - + ignore_option / handle_invalid_option -local switch = P"+" * ws * C(field) * Cc(true) - + P"-" * ws * C(field) * Cc(false) - + C(field) * Cc(true) --- default -local feature_expr = ws * Cg(assignment + switch) * ws -local option = feature_expr -local feature_list = Cf(Ct"" - * option - * (featuresep * option^-1)^0 - , rawset) - * featuresep^-1 - ---- other ------------------------------------------------------------- ---- This rule is present in the original parser. It sets the “sub” ---- field of the specification which allows addressing a specific ---- font inside a TTC container. Neither in Luatex-Fonts nor in ---- Luaotfload is this documented, so we might as well silently drop ---- it. However, as backward compatibility is one of our prime goals we ---- just insert it here and leave it undocumented until someone cares ---- to ask. (Note: afair subfonts are numbered, but this rule matches a ---- string; I won’t mess with it though until someone reports a ---- problem.) ---- local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim ---- Note to self: subfonts apparently start at index 0. Tested with ---- Cambria.ttc that includes “Cambria Math” at 0 and “Cambria” at 1. ---- Other values cause luatex to segfault. -local subfont = P"(" * Cg((1 - S"()")^1, "sub") * P")" ---- top-level rules --------------------------------------------------- ---- \font\foo=<specification>:<features> -local features = Cg(feature_list, "features") -local specification = (prefixed + unprefixed) - * subfont^-1 - * modifier_list^-1 -local font_request = Ct(path_lookup * (colon^-1 * features)^-1 - + specification * (colon * features)^-1) - --- lpeg.print(font_request) ---- new parser: 657 rules ---- old parser: 230 rules - local import_values = { --- That’s what the 1.x parser did, not quite as graciously, --- with an array of branch expressions. @@ -1138,7 +846,7 @@ end --- spec -> spec local handle_request = function (specification) - local request = lpegmatch(font_request, + local request = lpegmatch(luaotfload.parsers.font_request, specification.specification) if not request then --- happens when called with an absolute path @@ -1230,7 +938,6 @@ local report_otf = logs.reporter("fonts","otf loading") local otf = fonts.handlers.otf local registerotffeature = otf.features.register -local setmetatableindex = table.setmetatableindex --[[HH-- @@ -1286,6 +993,7 @@ local function addfeature(data,feature,specifications) local subtables = specification.subtables or { specification.data } or { } local featuretype = types[specification.type or "substitution"] local featureflags = specification.flags or noflags + local featureorder = specification.order or { feature } local added = false local featurename = stringformat("ctx_%s_%s",feature,s) local st = { } @@ -1346,17 +1054,23 @@ local function addfeature(data,feature,specifications) -- script = { lang1, lang2, lang3 } or script = { lang1 = true, ... } for k, v in next, askedfeatures do if v[1] then - askedfeatures[k] = table.tohash(v) + askedfeatures[k] = tabletohash(v) end end - sequences[#sequences+1] = { + local sequence = { chain = 0, features = { [feature] = askedfeatures }, flags = featureflags, name = featurename, + order = featureorder, subtables = st, type = featuretype, } + if specification.prepend then + insert(sequences,1,sequence) + else + insert(sequences,sequence) + end -- register in metadata (merge as there can be a few) if not gsubfeatures then gsubfeatures = { } @@ -1386,6 +1100,7 @@ local function addfeature(data,feature,specifications) end end + otf.enhancers.addfeature = addfeature local extrafeatures = { } @@ -1414,6 +1129,8 @@ local tlig = { [0x0060] = 0x2018, -- quoteright }, flags = { }, + order = { "tlig" }, + prepend = true, }, { type = "ligature", @@ -1432,6 +1149,8 @@ local tlig = { [0x00BB] = {0x003E, 0x003E}, -- RIGHT-POINTING DOUBLE ANGLE QUOTATION MARK }, flags = { }, + order = { "tlig" }, + prepend = true, }, { type = "ligature", @@ -1443,6 +1162,8 @@ local tlig = { [0x00BF] = {0x003F, 0x0060}, -- questiondown }, flags = { }, + order = { "tlig" }, + prepend = true, }, } @@ -1494,6 +1215,7 @@ local anum_specification = { features = { arab = { far = true, urd = true, snd = true } }, data = anum_persian, flags = { }, + order = { "anum" }, valid = valid, }, { @@ -1501,23 +1223,16 @@ local anum_specification = { features = { arab = { ["*"] = true } }, data = anum_arabic, flags = { }, + order = { "anum" }, valid = valid, }, } ---[[doc-- - - Below the specifications as given in the removed font-otc.lua. - The rest was identical to what this file had from the beginning. - Both make the “anum.tex” test pass anyways. - ---doc]]-- - -otf.addfeature("anum",anum_specification) +otf.addfeature ("anum", anum_specification) registerotffeature { - name = 'anum', - description = 'arabic digits', + name = "anum", + description = "arabic digits", } -- vim:tw=71:sw=4:ts=4:expandtab diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fontloader.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fontloader.lua index 177324145e3..2f26be70e21 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fontloader.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fontloader.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 12/24/13 17:52:44 +-- merge date : 07/06/14 22:50:12 do -- begin closure to overcome local limits and interference @@ -82,6 +82,9 @@ function optionalrequire(...) return result end end +if lua then + lua.mask=load([[τεχ = 1]]) and "utf" or "ascii" +end end -- closure @@ -101,7 +104,9 @@ local byte,char,gmatch,format=string.byte,string.char,string.gmatch,string.forma local floor=math.floor local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print -setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end) +if setinspector then + setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end) +end lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns local anything=P(1) @@ -120,7 +125,7 @@ local uppercase=R("AZ") local underscore=P("_") local hexdigit=digit+lowercase+uppercase local cr,lf,crlf=P("\r"),P("\n"),P("\r\n") -local newline=crlf+S("\r\n") +local newline=P("\r")*(P("\n")+P(true))+P("\n") local escaped=P("\\")*anything local squote=P("'") local dquote=P('"') @@ -142,8 +147,8 @@ patterns.utfbom_32_le=utfbom_32_le patterns.utfbom_16_be=utfbom_16_be patterns.utfbom_16_le=utfbom_16_le patterns.utfbom_8=utfbom_8 -patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n") -patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000") +patterns.utf_16_be_nl=P("\000\r\000\n")+P("\000\r")+P("\000\n") +patterns.utf_16_le_nl=P("\r\000\n\000")+P("\r\000")+P("\n\000") patterns.utf8one=R("\000\127") patterns.utf8two=R("\194\223")*utf8next patterns.utf8three=R("\224\239")*utf8next*utf8next @@ -170,9 +175,11 @@ patterns.spacer=spacer patterns.whitespace=whitespace patterns.nonspacer=nonspacer patterns.nonwhitespace=nonwhitespace -local stripper=spacer^0*C((spacer^0*nonspacer^1)^0) +local stripper=spacer^0*C((spacer^0*nonspacer^1)^0) +local fullstripper=whitespace^0*C((whitespace^0*nonwhitespace^1)^0) local collapser=Cs(spacer^0/""*nonspacer^0*((spacer^0/" "*nonspacer^1)^0)) patterns.stripper=stripper +patterns.fullstripper=fullstripper patterns.collapser=collapser patterns.lowercase=lowercase patterns.uppercase=uppercase @@ -210,9 +217,12 @@ patterns.integer=sign^-1*digit^1 patterns.unsigned=digit^0*period*digit^1 patterns.float=sign^-1*patterns.unsigned patterns.cunsigned=digit^0*comma*digit^1 +patterns.cpunsigned=digit^0*(period+comma)*digit^1 patterns.cfloat=sign^-1*patterns.cunsigned +patterns.cpfloat=sign^-1*patterns.cpunsigned patterns.number=patterns.float+patterns.integer patterns.cnumber=patterns.cfloat+patterns.integer +patterns.cpnumber=patterns.cpfloat+patterns.integer patterns.oct=zero*octdigit^1 patterns.octal=patterns.oct patterns.HEX=zero*P("X")*(digit+uppercase)^1 @@ -395,7 +405,7 @@ function lpeg.replacer(one,two,makefunction,isutf) return pattern end end -function lpeg.finder(lst,makefunction) +function lpeg.finder(lst,makefunction,isutf) local pattern if type(lst)=="table" then pattern=P(false) @@ -411,7 +421,11 @@ function lpeg.finder(lst,makefunction) else pattern=P(lst) end - pattern=(1-pattern)^0*pattern + if isutf then + pattern=((utf8char or 1)-pattern)^0*pattern + else + pattern=(1-pattern)^0*pattern + end if makefunction then return function(str) return lpegmatch(pattern,str) @@ -625,21 +639,22 @@ function lpeg.append(list,pp,delayed,checked) end return p end -local function make(t) - local p +local function make(t,hash) + local p=P(false) local keys=sortedkeys(t) for i=1,#keys do local k=keys[i] local v=t[k] - if not p then + local h=hash[v] + if h then if next(v) then - p=P(k)*make(v) + p=p+P(k)*(make(v,hash)+P(true)) else - p=P(k) + p=p+P(k)*P(true) end else if next(v) then - p=p+P(k)*make(v) + p=p+P(k)*make(v,hash) else p=p+P(k) end @@ -649,16 +664,37 @@ local function make(t) end function lpeg.utfchartabletopattern(list) local tree={} - for i=1,#list do - local t=tree - for c in gmatch(list[i],".") do - if not t[c] then - t[c]={} + local hash={} + local n=#list + if n==0 then + for s in next,list do + local t=tree + for c in gmatch(s,".") do + local tc=t[c] + if not tc then + tc={} + t[c]=tc + end + t=tc end - t=t[c] + hash[t]=s + end + else + for i=1,n do + local t=tree + local s=list[i] + for c in gmatch(s,".") do + local tc=t[c] + if not tc then + tc={} + t[c]=tc + end + t=tc + end + hash[t]=s end end - return make(tree) + return make(tree,hash) end patterns.containseol=lpeg.finder(eol) local function nextstep(n,step,result) @@ -748,11 +784,15 @@ function string.limit(str,n,sentinel) end end local stripper=patterns.stripper +local fullstripper=patterns.fullstripper local collapser=patterns.collapser local longtostring=patterns.longtostring function string.strip(str) return lpegmatch(stripper,str) or "" end +function string.fullstrip(str) + return lpegmatch(fullstripper,str) or "" +end function string.collapsespaces(str) return lpegmatch(collapser,str) or "" end @@ -886,6 +926,36 @@ local function sortedkeys(tab) return {} end end +local function sortedhashonly(tab) + if tab then + local srt,s={},0 + for key,_ in next,tab do + if type(key)=="string" then + s=s+1 + srt[s]=key + end + end + sort(srt) + return srt + else + return {} + end +end +local function sortedindexonly(tab) + if tab then + local srt,s={},0 + for key,_ in next,tab do + if type(key)=="number" then + s=s+1 + srt[s]=key + end + end + sort(srt) + return srt + else + return {} + end +end local function sortedhashkeys(tab,cmp) if tab then local srt,s={},0 @@ -911,6 +981,8 @@ function table.allkeys(t) return sortedkeys(keys) end table.sortedkeys=sortedkeys +table.sortedhashonly=sortedhashonly +table.sortedindexonly=sortedindexonly table.sortedhashkeys=sortedhashkeys local function nothing() end local function sortedhash(t,cmp) @@ -923,14 +995,14 @@ local function sortedhash(t,cmp) end local n=0 local m=#s - local function kv(s) + local function kv() if n<m then n=n+1 local k=s[n] return k,t[k] end end - return kv,s + return kv else return nothing end @@ -1095,7 +1167,7 @@ local function simple_table(t) if tv=="number" then nt=nt+1 if hexify then - tt[nt]=format("0x%04X",v) + tt[nt]=format("0x%X",v) else tt[nt]=tostring(v) end @@ -1126,7 +1198,7 @@ local function do_serialize(root,name,depth,level,indexed) local tn=type(name) if tn=="number" then if hexify then - handle(format("%s[0x%04X]={",depth,name)) + handle(format("%s[0x%X]={",depth,name)) else handle(format("%s[%s]={",depth,name)) end @@ -1165,7 +1237,7 @@ local function do_serialize(root,name,depth,level,indexed) if compact and first and tk=="number" and k>=first and k<=last then if tv=="number" then if hexify then - handle(format("%s 0x%04X,",depth,v)) + handle(format("%s 0x%X,",depth,v)) else handle(format("%s %s,",depth,v)) end @@ -1206,25 +1278,25 @@ local function do_serialize(root,name,depth,level,indexed) elseif tv=="number" then if tk=="number" then if hexify then - handle(format("%s [0x%04X]=0x%04X,",depth,k,v)) + handle(format("%s [0x%X]=0x%X,",depth,k,v)) else handle(format("%s [%s]=%s,",depth,k,v)) end elseif tk=="boolean" then if hexify then - handle(format("%s [%s]=0x%04X,",depth,k and "true" or "false",v)) + handle(format("%s [%s]=0x%X,",depth,k and "true" or "false",v)) else handle(format("%s [%s]=%s,",depth,k and "true" or "false",v)) end elseif noquotes and not reserved[k] and lpegmatch(propername,k) then if hexify then - handle(format("%s %s=0x%04X,",depth,k,v)) + handle(format("%s %s=0x%X,",depth,k,v)) else handle(format("%s %s=%s,",depth,k,v)) end else if hexify then - handle(format("%s [%q]=0x%04X,",depth,k,v)) + handle(format("%s [%q]=0x%X,",depth,k,v)) else handle(format("%s [%q]=%s,",depth,k,v)) end @@ -1233,7 +1305,7 @@ local function do_serialize(root,name,depth,level,indexed) if reduce and tonumber(v) then if tk=="number" then if hexify then - handle(format("%s [0x%04X]=%s,",depth,k,v)) + handle(format("%s [0x%X]=%s,",depth,k,v)) else handle(format("%s [%s]=%s,",depth,k,v)) end @@ -1247,7 +1319,7 @@ local function do_serialize(root,name,depth,level,indexed) else if tk=="number" then if hexify then - handle(format("%s [0x%04X]=%q,",depth,k,v)) + handle(format("%s [0x%X]=%q,",depth,k,v)) else handle(format("%s [%s]=%q,",depth,k,v)) end @@ -1263,7 +1335,7 @@ local function do_serialize(root,name,depth,level,indexed) if not next(v) then if tk=="number" then if hexify then - handle(format("%s [0x%04X]={},",depth,k)) + handle(format("%s [0x%X]={},",depth,k)) else handle(format("%s [%s]={},",depth,k)) end @@ -1279,7 +1351,7 @@ local function do_serialize(root,name,depth,level,indexed) if st then if tk=="number" then if hexify then - handle(format("%s [0x%04X]={ %s },",depth,k,concat(st,", "))) + handle(format("%s [0x%X]={ %s },",depth,k,concat(st,", "))) else handle(format("%s [%s]={ %s },",depth,k,concat(st,", "))) end @@ -1299,7 +1371,7 @@ local function do_serialize(root,name,depth,level,indexed) elseif tv=="boolean" then if tk=="number" then if hexify then - handle(format("%s [0x%04X]=%s,",depth,k,v and "true" or "false")) + handle(format("%s [0x%X]=%s,",depth,k,v and "true" or "false")) else handle(format("%s [%s]=%s,",depth,k,v and "true" or "false")) end @@ -1315,7 +1387,7 @@ local function do_serialize(root,name,depth,level,indexed) local f=getinfo(v).what=="C" and dump(dummy) or dump(v) if tk=="number" then if hexify then - handle(format("%s [0x%04X]=load(%q),",depth,k,f)) + handle(format("%s [0x%X]=load(%q),",depth,k,f)) else handle(format("%s [%s]=load(%q),",depth,k,f)) end @@ -1330,7 +1402,7 @@ local function do_serialize(root,name,depth,level,indexed) else if tk=="number" then if hexify then - handle(format("%s [0x%04X]=%q,",depth,k,tostring(v))) + handle(format("%s [0x%X]=%q,",depth,k,tostring(v))) else handle(format("%s [%s]=%q,",depth,k,tostring(v))) end @@ -1384,7 +1456,7 @@ local function serialize(_handle,root,name,specification) end elseif tname=="number" then if hexify then - handle(format("[0x%04X]={",name)) + handle(format("[0x%X]={",name)) else handle("["..name.."]={") end @@ -1636,7 +1708,9 @@ function table.print(t,...) serialize(print,t,...) end end -setinspector(function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) +if setinspector then + setinspector(function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) +end function table.sub(t,i,j) return { unpack(t,i,j) } end @@ -1689,6 +1763,44 @@ function table.values(t,s) return {} end end +function table.filtered(t,pattern,sort,cmp) + if t and type(pattern)=="string" then + if sort then + local s + if cmp then + s=sortedhashkeys(t,function(a,b) return cmp(t,a,b) end) + else + s=sortedkeys(t) + end + local n=0 + local m=#s + local function kv(s) + while n<m do + n=n+1 + local k=s[n] + if find(k,pattern) then + return k,t[k] + end + end + end + return kv,s + else + local n=next(t) + local function iterator() + while n do + local k=n + n=next(t,k) + if find(k,pattern) then + return k,t[k] + end + end + end + return iterator,t + end + else + return nothing + end +end end -- closure @@ -1706,7 +1818,7 @@ local byte,find,gsub,format=string.byte,string.find,string.gsub,string.format local concat=table.concat local floor=math.floor local type=type -if string.find(os.getenv("PATH"),";") then +if string.find(os.getenv("PATH"),";",1,true) then io.fileseparator,io.pathseparator="\\",";" else io.fileseparator,io.pathseparator="/",":" @@ -2508,15 +2620,28 @@ local unpack,concat=table.unpack,table.concat local P,V,C,S,R,Ct,Cs,Cp,Carg,Cc=lpeg.P,lpeg.V,lpeg.C,lpeg.S,lpeg.R,lpeg.Ct,lpeg.Cs,lpeg.Cp,lpeg.Carg,lpeg.Cc local patterns,lpegmatch=lpeg.patterns,lpeg.match local utfchar,utfbyte=utf.char,utf.byte -local loadstripped=_LUAVERSION<5.2 and load or function(str) - return load(dump(load(str),true)) +local loadstripped=nil +if _LUAVERSION<5.2 then + loadstripped=function(str,shortcuts) + return load(str) + end +else + loadstripped=function(str,shortcuts) + if shortcuts then + return load(dump(load(str),true),nil,nil,shortcuts) + else + return load(dump(load(str),true)) + end + end end if not number then number={} end local stripper=patterns.stripzeros local function points(n) + n=tonumber(n) return (not n or n==0) and "0pt" or lpegmatch(stripper,format("%.5fpt",n/65536)) end local function basepoints(n) + n=tonumber(n) return (not n or n==0) and "0bp" or lpegmatch(stripper,format("%.5fbp",n*(7200/7227)/65536)) end number.points=points @@ -2579,11 +2704,40 @@ local pattern=Carg(1)/function(t) function strings.tabtospace(str,tab) return lpegmatch(pattern,str,1,tab or 7) end -function strings.striplong(str) - str=gsub(str,"^%s*","") - str=gsub(str,"[\n\r]+ *","\n") - return str +local newline=patterns.newline +local endofstring=patterns.endofstring +local whitespace=patterns.whitespace +local spacer=patterns.spacer +local space=spacer^0 +local nospace=space/"" +local endofline=nospace*newline +local stripend=(whitespace^1*endofstring)/"" +local normalline=(nospace*((1-space*(newline+endofstring))^1)*nospace) +local stripempty=endofline^1/"" +local normalempty=endofline^1 +local singleempty=endofline*(endofline^0/"") +local doubleempty=endofline*endofline^-1*(endofline^0/"") +local stripstart=stripempty^0 +local p_prune_normal=Cs (stripstart*(stripend+normalline+normalempty )^0 ) +local p_prune_collapse=Cs (stripstart*(stripend+normalline+doubleempty )^0 ) +local p_prune_noempty=Cs (stripstart*(stripend+normalline+singleempty )^0 ) +local p_retain_normal=Cs ((normalline+normalempty )^0 ) +local p_retain_collapse=Cs ((normalline+doubleempty )^0 ) +local p_retain_noempty=Cs ((normalline+singleempty )^0 ) +local striplinepatterns={ + ["prune"]=p_prune_normal, + ["prune and collapse"]=p_prune_collapse, + ["prune and no empty"]=p_prune_noempty, + ["retain"]=p_retain_normal, + ["retain and collapse"]=p_retain_collapse, + ["retain and no empty"]=p_retain_noempty, + ["collapse"]=patterns.collapser, +} +strings.striplinepatterns=striplinepatterns +function strings.striplines(str,how) + return str and lpegmatch(how and striplinepatterns[how] or p_prune_collapse,str) or str end +strings.striplong=strings.striplines function strings.nice(str) str=gsub(str,"[:%-+_]+"," ") return str @@ -2659,31 +2813,58 @@ function number.sparseexponent(f,n) end return tostring(n) end -local preamble=[[ -local type = type -local tostring = tostring -local tonumber = tonumber -local format = string.format -local concat = table.concat -local signed = number.signed -local points = number.points -local basepoints = number.basepoints -local utfchar = utf.char -local utfbyte = utf.byte -local lpegmatch = lpeg.match -local nspaces = string.nspaces -local tracedchar = string.tracedchar -local autosingle = string.autosingle -local autodouble = string.autodouble -local sequenced = table.sequenced -local formattednumber = number.formatted -local sparseexponent = number.sparseexponent -]] local template=[[ %s %s return function(%s) return %s end ]] +local preamble,environment="",{} +if _LUAVERSION<5.2 then + preamble=[[ +local lpeg=lpeg +local type=type +local tostring=tostring +local tonumber=tonumber +local format=string.format +local concat=table.concat +local signed=number.signed +local points=number.points +local basepoints= number.basepoints +local utfchar=utf.char +local utfbyte=utf.byte +local lpegmatch=lpeg.match +local nspaces=string.nspaces +local tracedchar=string.tracedchar +local autosingle=string.autosingle +local autodouble=string.autodouble +local sequenced=table.sequenced +local formattednumber=number.formatted +local sparseexponent=number.sparseexponent + ]] +else + environment={ + global=global or _G, + lpeg=lpeg, + type=type, + tostring=tostring, + tonumber=tonumber, + format=string.format, + concat=table.concat, + signed=number.signed, + points=number.points, + basepoints=number.basepoints, + utfchar=utf.char, + utfbyte=utf.byte, + lpegmatch=lpeg.match, + nspaces=string.nspaces, + tracedchar=string.tracedchar, + autosingle=string.autosingle, + autodouble=string.autodouble, + sequenced=table.sequenced, + formattednumber=number.formatted, + sparseexponent=number.sparseexponent, + } +end local arguments={ "a1" } setmetatable(arguments,{ __index=function(t,k) local v=t[k-1]..",a"..k @@ -2722,7 +2903,7 @@ local format_i=function(f) if f and f~="" then return format("format('%%%si',a%s)",f,n) else - return format("format('%%i',a%s)",n) + return format("format('%%i',a%s)",n) end end local format_d=format_i @@ -2734,6 +2915,14 @@ local format_f=function(f) n=n+1 return format("format('%%%sf',a%s)",f,n) end +local format_F=function() + n=n+1 + if not f or f=="" then + return format("(((a%s > -0.0000000005 and a%s < 0.0000000005) and '0') or format((a%s %% 1 == 0) and '%%i' or '%%.9f',a%s))",n,n,n,n) + else + return format("format((a%s %% 1 == 0) and '%%i' or '%%%sf',a%s)",n,f,n) + end +end local format_g=function(f) n=n+1 return format("format('%%%sg',a%s)",f,n) @@ -2948,7 +3137,7 @@ local builder=Cs { "start", ( P("%")/""*( V("!") -+V("s")+V("q")+V("i")+V("d")+V("f")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o") ++V("s")+V("q")+V("i")+V("d")+V("f")+V("F")+V("g")+V("G")+V("e")+V("E")+V("x")+V("X")+V("o") +V("c")+V("C")+V("S") +V("Q") +V("N") @@ -2968,6 +3157,7 @@ local builder=Cs { "start", ["i"]=(prefix_any*P("i"))/format_i, ["d"]=(prefix_any*P("d"))/format_d, ["f"]=(prefix_any*P("f"))/format_f, + ["F"]=(prefix_any*P("F"))/format_F, ["g"]=(prefix_any*P("g"))/format_g, ["G"]=(prefix_any*P("G"))/format_G, ["e"]=(prefix_any*P("e"))/format_e, @@ -3005,8 +3195,8 @@ local builder=Cs { "start", ["!"]=Carg(2)*prefix_any*P("!")*C((1-P("!"))^1)*P("!")/format_extension, } local direct=Cs ( - P("%")/""*Cc([[local format = string.format return function(str) return format("%]])*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*Cc([[",str) end]])*P(-1) - ) + P("%")*(S("+- .")+R("09"))^0*S("sqidfgGeExXo")*P(-1)/[[local format = string.format return function(str) return format("%0",str) end]] +) local function make(t,str) local f local p @@ -3015,10 +3205,10 @@ local function make(t,str) f=loadstripped(p)() else n=0 - p=lpegmatch(builder,str,1,"..",t._extensions_) + p=lpegmatch(builder,str,1,t._connector_,t._extensions_) if n>0 then p=format(template,preamble,t._preamble_,arguments[n],p) - f=loadstripped(p)() + f=loadstripped(p,t._environment_)() else f=function() return str end end @@ -3030,10 +3220,22 @@ local function use(t,fmt,...) return t[fmt](...) end strings.formatters={} -function strings.formatters.new() - local t={ _extensions_={},_preamble_="",_type_="formatter" } - setmetatable(t,{ __index=make,__call=use }) - return t +if _LUAVERSION<5.2 then + function strings.formatters.new(noconcat) + local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_=preamble,_environment_={} } + setmetatable(t,{ __index=make,__call=use }) + return t + end +else + function strings.formatters.new(noconcat) + local e={} + for k,v in next,environment do + e[k]=v + end + local t={ _type_="formatter",_connector_=noconcat and "," or "..",_extensions_={},_preamble_="",_environment_=e } + setmetatable(t,{ __index=make,__call=use }) + return t + end end local formatters=strings.formatters.new() string.formatters=formatters @@ -3041,8 +3243,12 @@ string.formatter=function(str,...) return formatters[str](...) end local function add(t,name,template,preamble) if type(t)=="table" and t._type_=="formatter" then t._extensions_[name]=template or "%s" - if preamble then + if type(preamble)=="string" then t._preamble_=preamble.."\n"..t._preamble_ + elseif type(preamble)=="table" then + for k,v in next,preamble do + t._environment_[k]=v + end end end end @@ -3051,9 +3257,24 @@ patterns.xmlescape=Cs((P("<")/"<"+P(">")/">"+P("&")/"&"+P('"')/"" patterns.texescape=Cs((C(S("#$%\\{}"))/"\\%1"+P(1))^0) patterns.luaescape=Cs(((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0) patterns.luaquoted=Cs(Cc('"')*((1-S('"\n'))^1+P('"')/'\\"'+P('\n')/'\\n"')^0*Cc('"')) -add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],[[local xmlescape = lpeg.patterns.xmlescape]]) -add(formatters,"tex",[[lpegmatch(texescape,%s)]],[[local texescape = lpeg.patterns.texescape]]) -add(formatters,"lua",[[lpegmatch(luaescape,%s)]],[[local luaescape = lpeg.patterns.luaescape]]) +if _LUAVERSION<5.2 then + add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],"local xmlescape = lpeg.patterns.xmlescape") + add(formatters,"tex",[[lpegmatch(texescape,%s)]],"local texescape = lpeg.patterns.texescape") + add(formatters,"lua",[[lpegmatch(luaescape,%s)]],"local luaescape = lpeg.patterns.luaescape") +else + add(formatters,"xml",[[lpegmatch(xmlescape,%s)]],{ xmlescape=lpeg.patterns.xmlescape }) + add(formatters,"tex",[[lpegmatch(texescape,%s)]],{ texescape=lpeg.patterns.texescape }) + add(formatters,"lua",[[lpegmatch(luaescape,%s)]],{ luaescape=lpeg.patterns.luaescape }) +end +local dquote=patterns.dquote +local equote=patterns.escaped+dquote/'\\"'+1 +local space=patterns.space +local cquote=Cc('"') +local pattern=Cs(dquote*(equote-P(-2))^0*dquote) ++Cs(cquote*(equote-space)^0*space*equote^0*cquote) +function string.optionalquoted(str) + return lpegmatch(pattern,str) or str +end end -- closure @@ -3250,6 +3471,17 @@ function caches.loaddata(paths,name) for i=1,#paths do local data=false local luaname,lucname=makefullname(paths[i],name) + if lucname and not lfs.isfile(lucname) and type(caches.compile)=="function" then + texio.write(string.format("(compiling luc: %s)",lucname)) + data=loadfile(luaname) + if data then + data=data() + end + if data then + caches.compile(data,luaname,lucname) + return data + end + end if lucname and lfs.isfile(lucname) then texio.write(string.format("(load luc: %s)",lucname)) data=loadfile(lucname) @@ -3305,6 +3537,15 @@ end function table.setmetatableindex(t,f) setmetatable(t,{ __index=f }) end +arguments={} +if arg then + for i=1,#arg do + local k,v=string.match(arg[i],"^%-%-([^=]+)=?(.-)$") + if k and v then + arguments[k]=v + end + end +end end -- closure @@ -3473,9 +3714,17 @@ local free_node=node.free local remove_node=node.remove local new_node=node.new local traverse_id=node.traverse_id -local math_code=nodecodes.math nodes.handlers.protectglyphs=node.protect_glyphs nodes.handlers.unprotectglyphs=node.unprotect_glyphs +local math_code=nodecodes.math +local end_of_math=node.end_of_math +function node.end_of_math(n) + if n.id==math_code and n.subtype==1 then + return n + else + return end_of_math(n) + end +end function nodes.remove(head,current,free_too) local t=current head,current=remove_node(head,current) @@ -3769,14 +4018,15 @@ constructors.sharefonts=false constructors.nofsharedfonts=0 local sharednames={} function constructors.trytosharefont(target,tfmdata) - if constructors.sharefonts then + if constructors.sharefonts then local characters=target.characters local n=1 local t={ target.psname } local u=sortedkeys(characters) for i=1,#u do + local k=u[i] n=n+1;t[n]=k - n=n+1;t[n]=characters[u[i]].index or k + n=n+1;t[n]=characters[k].index or k end local h=md5.HEX(concat(t," ")) local s=sharednames[h] @@ -4006,6 +4256,7 @@ function constructors.scale(tfmdata,specification) if changed then local c=changed[unicode] if c then + local ligatures=character.ligatures description=descriptions[c] or descriptions[unicode] or character character=characters[c] or character index=description.index or c @@ -4017,6 +4268,9 @@ function constructors.scale(tfmdata,specification) touni=tounicode[i] end end + if ligatures and not character.ligatures then + character.ligatures=ligatures + end else description=descriptions[unicode] or character index=description.index or unicode @@ -4694,6 +4948,7 @@ end local fonts=fonts fonts.encodings={} fonts.encodings.agl={} +fonts.encodings.known={} setmetatable(fonts.encodings.agl,{ __index=function(t,k) if k=="unicodes" then texio.write(" <loading (extended) adobe glyph list>") @@ -5620,7 +5875,6 @@ unify=function(data,filename) if unicode then krn[unicode]=kern else - print(unicode,name) end end description.kerns=krn @@ -6405,7 +6659,7 @@ local type,next,tonumber,tostring=type,next,tonumber,tostring local abs=math.abs local insert=table.insert local lpegmatch=lpeg.match -local reversed,concat,remove=table.reversed,table.concat,table.remove +local reversed,concat,remove,sortedkeys=table.reversed,table.concat,table.remove,table.sortedkeys local ioflush=io.flush local fastcopy,tohash,derivetable=table.fastcopy,table.tohash,table.derive local formatters=string.formatters @@ -6427,7 +6681,7 @@ local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf otf.glists={ "gsub","gpos" } -otf.version=2.749 +otf.version=2.756 otf.cache=containers.define("fonts","otf",otf.version,true) local fontdata=fonts.hashes.identifiers local chardata=characters and characters.data @@ -6579,6 +6833,7 @@ local valid_fields=table.tohash { "upos", "use_typo_metrics", "uwidth", + "validation_state", "version", "vert_base", "weight", @@ -6969,15 +7224,22 @@ actions["prepare glyphs"]=function(data,filename,raw) local glyph=cidglyphs[index] if glyph then local unicode=glyph.unicode +if unicode>=0x00E000 and unicode<=0x00F8FF then + unicode=-1 +elseif unicode>=0x0F0000 and unicode<=0x0FFFFD then + unicode=-1 +elseif unicode>=0x100000 and unicode<=0x10FFFD then + unicode=-1 +end local name=glyph.name or cidnames[index] - if not unicode or unicode==-1 or unicode>=criterium then + if not unicode or unicode==-1 then unicode=cidunicodes[index] end if unicode and descriptions[unicode] then report_otf("preventing glyph %a at index %H to overload unicode %U",name or "noname",index,unicode) unicode=-1 end - if not unicode or unicode==-1 or unicode>=criterium then + if not unicode or unicode==-1 then if not name then name=format("u%06X",private) end @@ -7023,7 +7285,7 @@ actions["prepare glyphs"]=function(data,filename,raw) if glyph then local unicode=glyph.unicode local name=glyph.name - if not unicode or unicode==-1 or unicode>=criterium then + if not unicode or unicode==-1 then unicode=private unicodes[name]=private if trace_private then @@ -7045,7 +7307,6 @@ actions["prepare glyphs"]=function(data,filename,raw) } local altuni=glyph.altuni if altuni then - local d for i=1,#altuni do local a=altuni[i] local u=a.unicode @@ -7058,15 +7319,8 @@ actions["prepare glyphs"]=function(data,filename,raw) vv={ [u]=unicode } variants[v]=vv end - elseif d then - d[#d+1]=u - else - d={ u } end end - if d then - duplicates[unicode]=d - end end else report_otf("potential problem: glyph %U is used but empty",index) @@ -7084,47 +7338,45 @@ actions["check encoding"]=function(data,filename,raw) local duplicates=resources.duplicates local mapdata=raw.map or {} local unicodetoindex=mapdata and mapdata.map or {} + local indextounicode=mapdata and mapdata.backmap or {} local encname=lower(data.enc_name or mapdata.enc_name or "") - local criterium=0xFFFF + local criterium=0xFFFF + local privateoffset=constructors.privateoffset if find(encname,"unicode") then if trace_loading then report_otf("checking embedded unicode map %a",encname) end - for unicode,index in next,unicodetoindex do - if unicode<=criterium and not descriptions[unicode] then - local parent=indices[index] - if not parent then - report_otf("weird, unicode %U points to nowhere with index %H",unicode,index) + local reported={} + for maybeunicode,index in next,unicodetoindex do + if descriptions[maybeunicode] then + else + local unicode=indices[index] + if not unicode then + elseif maybeunicode==unicode then + elseif unicode>privateoffset then else - local parentdescription=descriptions[parent] - if parentdescription then - local altuni=parentdescription.altuni - if not altuni then - altuni={ { unicode=unicode } } - parentdescription.altuni=altuni - duplicates[parent]={ unicode } + local d=descriptions[unicode] + if d then + local c=d.copies + if c then + c[maybeunicode]=true else - local done=false - for i=1,#altuni do - if altuni[i].unicode==unicode then - done=true - break - end - end - if not done then - insert(altuni,{ unicode=unicode }) - insert(duplicates[parent],unicode) - end - end - if trace_loading then - report_otf("weird, unicode %U points to nowhere with index %H",unicode,index) + d.copies={ [maybeunicode]=true } end - else - report_otf("weird, unicode %U points to %U with index %H",unicode,index) + elseif index and not reported[index] then + report_otf("missing index %i",index) + reported[index]=true end end end end + for unicode,data in next,descriptions do + local d=data.copies + if d then + duplicates[unicode]=sortedkeys(d) + data.copies=nil + end + end elseif properties.cidinfo then report_otf("warning: no unicode map, used cidmap %a",properties.cidinfo.usedname) else @@ -7132,6 +7384,7 @@ actions["check encoding"]=function(data,filename,raw) end if mapdata then mapdata.map={} + mapdata.backmap={} end end actions["add duplicates"]=function(data,filename,raw) @@ -7142,28 +7395,37 @@ actions["add duplicates"]=function(data,filename,raw) local indices=resources.indices local duplicates=resources.duplicates for unicode,d in next,duplicates do - for i=1,#d do - local u=d[i] - if not descriptions[u] then - local description=descriptions[unicode] - local duplicate=table.copy(description) - duplicate.comment=format("copy of U+%05X",unicode) - descriptions[u]=duplicate - local n=0 - for _,description in next,descriptions do - if kerns then - local kerns=description.kerns - for _,k in next,kerns do - local ku=k[unicode] - if ku then - k[u]=ku - n=n+1 + local nofduplicates=#d + if nofduplicates>4 then + if trace_loading then + report_otf("ignoring excessive duplicates of %U (n=%s)",unicode,nofduplicates) + end + else + for i=1,nofduplicates do + local u=d[i] + if not descriptions[u] then + local description=descriptions[unicode] + local n=0 + for _,description in next,descriptions do + if kerns then + local kerns=description.kerns + for _,k in next,kerns do + local ku=k[unicode] + if ku then + k[u]=ku + n=n+1 + end end end end - end - if trace_loading then - report_otf("duplicating %U to %U with index %H (%s kerns)",unicode,u,description.index,n) + if u>0 then + local duplicate=table.copy(description) + duplicate.comment=format("copy of U+%05X",unicode) + descriptions[u]=duplicate + if trace_loading then + report_otf("duplicating %U to %U with index %H (%s kerns)",unicode,u,description.index,n) + end + end end end end @@ -7358,10 +7620,16 @@ actions["reorganize subtables"]=function(data,filename,raw) report_otf("skipping weird lookup number %s",k) elseif features then local f={} + local o={} for i=1,#features do local df=features[i] local tag=strip(lower(df.tag)) - local ft=f[tag] if not ft then ft={} f[tag]=ft end + local ft=f[tag] + if not ft then + ft={} + f[tag]=ft + o[#o+1]=tag + end local dscripts=df.scripts for i=1,#dscripts do local d=dscripts[i] @@ -7381,6 +7649,7 @@ actions["reorganize subtables"]=function(data,filename,raw) subtables=subtables, markclass=markclass, features=f, + order=o, } else lookups[name]={ @@ -7616,6 +7885,14 @@ actions["reorganize lookups"]=function(data,filename,raw) rule.current=s_hashed(names,s_h_cache) end rule.glyphs=nil + local lookups=rule.lookups + if lookups then + for i=1,#names do + if not lookups[i] then + lookups[i]="" + end + end + end end end end @@ -7887,6 +8164,11 @@ actions["check metadata"]=function(data,filename,raw) ttftables[i].data="deleted" end end + if metadata.validation_state and table.contains(metadata.validation_state,"bad_ps_fontname") then + local name=file.nameonly(filename) + metadata.fontname="bad-fontname-"..name + metadata.fullname="bad-fullname-"..name + end end actions["cleanup tables"]=function(data,filename,raw) data.resources.indices=nil @@ -8184,6 +8466,24 @@ local function otftotfm(specification) local features=specification.features.normal local rawdata=otf.load(filename,sub,features and features.featurefile) if rawdata and next(rawdata) then + local descriptions=rawdata.descriptions + local duplicates=rawdata.resources.duplicates + if duplicates then + local nofduplicates,nofduplicated=0,0 + for parent,list in next,duplicates do + for i=1,#list do + local unicode=list[i] + if not descriptions[unicode] then + descriptions[unicode]=descriptions[parent] + nofduplicated=nofduplicated+1 + end + end + nofduplicates=nofduplicates+#list + end + if trace_otf and nofduplicated~=nofduplicates then + report_otf("%i extra duplicates copied out of %i",nofduplicated,nofduplicates) + end + end rawdata.lookuphash={} tfmdata=copytotfm(rawdata,cache_id) if tfmdata and next(tfmdata) then @@ -8341,13 +8641,14 @@ local function gref(descriptions,n) return f_unicode(n) end elseif n then - local num,nam={},{} - for i=2,#n do + local num,nam,j={},{},0 + for i=1,#n do local ni=n[i] if tonumber(ni) then + j=j+1 local di=descriptions[ni] - num[i]=f_unicode(ni) - nam[i]=di and di.name or "-" + num[j]=f_unicode(ni) + nam[j]=di and di.name or "-" end end return f_unilist(num,nam) @@ -8430,8 +8731,8 @@ local function finalize_ligatures(tfmdata,ligatures) local ligature=ligatures[i] if ligature then local unicode,lookupdata=ligature[1],ligature[2] - if trace then - trace_ligatures_detail("building % a into %a",lookupdata,unicode) + if trace_ligatures_detail then + report_prepare("building % a into %a",lookupdata,unicode) end local size=#lookupdata local firstcode=lookupdata[1] @@ -8443,8 +8744,8 @@ local function finalize_ligatures(tfmdata,ligatures) local firstdata=characters[firstcode] if not firstdata then firstcode=private - if trace then - trace_ligatures_detail("defining %a as %a",firstname,firstcode) + if trace_ligatures_detail then + report_prepare("defining %a as %a",firstname,firstcode) end unicodes[firstname]=firstcode firstdata={ intermediate=true,ligatures={} } @@ -8467,8 +8768,8 @@ local function finalize_ligatures(tfmdata,ligatures) break end end - if trace then - trace_ligatures_detail("codes (%a,%a) + (%a,%a) -> %a",firstname,firstcode,secondname,secondcode,target) + if trace_ligatures_detail then + report_prepare("codes (%a,%a) + (%a,%a) -> %a",firstname,firstcode,secondname,secondcode,target) end local firstligs=firstdata.ligatures if firstligs then @@ -8479,6 +8780,8 @@ local function finalize_ligatures(tfmdata,ligatures) firstcode=target firstname=secondname end + elseif trace_ligatures_detail then + report_prepare("no glyph (%a,%a) for building %a",firstname,firstcode,target) end if okay then ligatures[i]=false @@ -8488,12 +8791,14 @@ local function finalize_ligatures(tfmdata,ligatures) end alldone=done==0 end - if trace then - for k,v in next,characters do - if v.ligatures then table.print(v,k) end + if trace_ligatures_detail then + for k,v in table.sortedhash(characters) do + if v.ligatures then + table.print(v,k) + end end end - tfmdata.resources.private=private + resources.private=private end end local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplist) @@ -8712,7 +9017,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis end changed[unicode]=data elseif lookuptype=="alternate" then - local replacement=data[alternate] + local replacement=data[alternate] if replacement then changed[unicode]=replacement if trace_alternatives then @@ -8803,8 +9108,9 @@ basemethods.shared={ basemethod="independent" local function featuresinitializer(tfmdata,value) if true then - local t=trace_preparing and os.clock() + local starttime=trace_preparing and os.clock() local features=tfmdata.shared.features + local fullname=trace_preparing and tfmdata.properties.fullname if features then applybasemethod("initializehashes",tfmdata) local collectlookups=otf.collectlookups @@ -8814,26 +9120,34 @@ local function featuresinitializer(tfmdata,value) local language=properties.language local basesubstitutions=rawdata.resources.features.gsub local basepositionings=rawdata.resources.features.gpos - if basesubstitutions then - for feature,data in next,basesubstitutions do - local value=features[feature] - if value then - local validlookups,lookuplist=collectlookups(rawdata,feature,script,language) - if validlookups then - applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist) - registerbasefeature(feature,value) - end - end - end - end - if basepositionings then - for feature,data in next,basepositionings do - local value=features[feature] - if value then - local validlookups,lookuplist=collectlookups(rawdata,feature,script,language) - if validlookups then - applybasemethod("preparepositionings",tfmdata,feature,features[feature],validlookups,lookuplist) - registerbasefeature(feature,value) + if basesubstitutions or basepositionings then + local sequences=tfmdata.resources.sequences + for s=1,#sequences do + local sequence=sequences[s] + local sfeatures=sequence.features + if sfeatures then + local order=sequence.order + if order then + for i=1,#order do + local feature=order[i] + if features[feature] then + local validlookups,lookuplist=collectlookups(rawdata,feature,script,language) + if not validlookups then + elseif basesubstitutions and basesubstitutions[feature] then + if trace_preparing then + report_prepare("filtering base feature %a for %a",feature,fullname) + end + applybasemethod("preparesubstitutions",tfmdata,feature,value,validlookups,lookuplist) + registerbasefeature(feature,value) + elseif basepositionings and basepositionings[feature] then + if trace_preparing then + report_prepare("filtering base feature %a for %a",feature,fullname) + end + applybasemethod("preparepositionings",tfmdata,feature,features[feature],validlookups,lookuplist) + registerbasefeature(feature,value) + end + end + end end end end @@ -8841,7 +9155,7 @@ local function featuresinitializer(tfmdata,value) registerbasehash(tfmdata) end if trace_preparing then - report_prepare("preparation time is %0.3f seconds for %a",os.clock()-t,tfmdata.properties.fullname) + report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,fullname) end end end @@ -8881,26 +9195,12 @@ nodes.injections=nodes.injections or {} local injections=nodes.injections local nodecodes=nodes.nodecodes local glyph_code=nodecodes.glyph -local disc_code=nodecodes.disc local kern_code=nodecodes.kern -local nuts=nodes.nuts -local nodepool=nuts.pool +local nodepool=nodes.pool local newkern=nodepool.kern -local tonode=nuts.tonode -local tonut=nuts.tonut -local getfield=nuts.getfield -local getnext=nuts.getnext -local getprev=nuts.getprev -local getid=nuts.getid -local getattr=nuts.getattr -local getfont=nuts.getfont -local getsubtype=nuts.getsubtype -local getchar=nuts.getchar -local setfield=nuts.setfield -local setattr=nuts.setattr -local traverse_id=nuts.traverse_id -local insert_node_before=nuts.insert_before -local insert_node_after=nuts.insert_after +local traverse_id=node.traverse_id +local insert_node_before=node.insert_before +local insert_node_after=node.insert_after local a_kernpair=attributes.private('kernpair') local a_ligacomp=attributes.private('ligacomp') local a_markbase=attributes.private('markbase') @@ -8919,21 +9219,21 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2]) local ws,wn=tfmstart.width,tfmnext.width local bound=#cursives+1 - setattr(start,a_cursbase,bound) - setattr(nxt,a_curscurs,bound) + start[a_cursbase]=bound + nxt[a_curscurs]=bound cursives[bound]={ rlmode,dx,dy,ws,wn } return dx,dy,bound end function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr) local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4] if x~=0 or w~=0 or y~=0 or h~=0 then - local bound=getattr(current,a_kernpair) + local bound=current[a_kernpair] if bound then local kb=kerns[bound] kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h else bound=#kerns+1 - setattr(current,a_kernpair,bound) + current[a_kernpair]=bound kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width } end return x,y,w,h,bound @@ -8944,35 +9244,35 @@ function injections.setkern(current,factor,rlmode,x,tfmchr) local dx=factor*x if dx~=0 then local bound=#kerns+1 - setattr(current,a_kernpair,bound) + current[a_kernpair]=bound kerns[bound]={ rlmode,dx } return dx,bound else return 0,0 end end -function injections.setmark(start,base,factor,rlmode,ba,ma,index,baseismark) - local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2]) - local bound=getattr(base,a_markbase) +function injections.setmark(start,base,factor,rlmode,ba,ma) + local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2]) + local bound=base[a_markbase] local index=1 if bound then local mb=marks[bound] if mb then index=#mb+1 mb[index]={ dx,dy,rlmode } - setattr(start,a_markmark,bound) - setattr(start,a_markdone,index) + start[a_markmark]=bound + start[a_markdone]=index return dx,dy,bound else - report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound) + report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound) end end index=index or 1 bound=#marks+1 - setattr(base,a_markbase,bound) - setattr(start,a_markmark,bound) - setattr(start,a_markdone,index) - marks[bound]={ [index]={ dx,dy,rlmode,baseismark } } + base[a_markbase]=bound + start[a_markmark]=bound + start[a_markdone]=index + marks[bound]={ [index]={ dx,dy,rlmode } } return dx,dy,bound end local function dir(n) @@ -8981,15 +9281,15 @@ end local function trace(head) report_injections("begin run") for n in traverse_id(glyph_code,head) do - if getsubtype(n)<256 then - local kp=getattr(n,a_kernpair) - local mb=getattr(n,a_markbase) - local mm=getattr(n,a_markmark) - local md=getattr(n,a_markdone) - local cb=getattr(n,a_cursbase) - local cc=getattr(n,a_curscurs) - local char=getchar(n) - report_injections("font %s, char %U, glyph %c",getfont(n),char,char) + if n.subtype<256 then + local kp=n[a_kernpair] + local mb=n[a_markbase] + local mm=n[a_markmark] + local md=n[a_markdone] + local cb=n[a_cursbase] + local cc=n[a_curscurs] + local char=n.char + report_injections("font %s, char %U, glyph %c",n.font,char,char) if kp then local k=kerns[kp] if k[3] then @@ -9030,23 +9330,21 @@ local function show_result(head) local current=head local skipping=false while current do - local id=getid(current) + local id=current.id if id==glyph_code then - report_injections("char: %C, width %p, xoffset %p, yoffset %p", - getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset")) + report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset) skipping=false elseif id==kern_code then - report_injections("kern: %p",getfield(current,"kern")) + report_injections("kern: %p",current.kern) skipping=false elseif not skipping then report_injections() skipping=true end - current=getnext(current) + current=current.next end end function injections.handler(head,where,keep) - head=tonut(head) local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns) if has_marks or has_cursives then if trace_injections then @@ -9056,18 +9354,17 @@ function injections.handler(head,where,keep) if has_kerns then local nf,tm=nil,nil for n in traverse_id(glyph_code,head) do - if getsubtype(n)<256 then + if n.subtype<256 then nofvalid=nofvalid+1 valid[nofvalid]=n - local f=getfont(n) - if f~=nf then - nf=f - tm=fontdata[nf].resources.marks + if n.font~=nf then + nf=n.font + tm=fontdata[nf].resources.marks end if tm then - mk[n]=tm[getchar(n)] + mk[n]=tm[n.char] end - local k=getattr(n,a_kernpair) + local k=n[a_kernpair] if k then local kk=kerns[k] if kk then @@ -9087,16 +9384,15 @@ function injections.handler(head,where,keep) else local nf,tm=nil,nil for n in traverse_id(glyph_code,head) do - if getsubtype(n)<256 then + if n.subtype<256 then nofvalid=nofvalid+1 valid[nofvalid]=n - local f=getfont(n) - if f~=nf then - nf=f - tm=fontdata[nf].resources.marks + if n.font~=nf then + nf=n.font + tm=fontdata[nf].resources.marks end if tm then - mk[n]=tm[getchar(n)] + mk[n]=tm[n.char] end end end @@ -9105,7 +9401,7 @@ function injections.handler(head,where,keep) local cx={} if has_kerns and next(ky) then for n,k in next,ky do - setfield(n,"yoffset",k) + n.yoffset=k end end if has_cursives then @@ -9114,9 +9410,9 @@ function injections.handler(head,where,keep) for i=1,nofvalid do local n=valid[i] if not mk[n] then - local n_cursbase=getattr(n,a_cursbase) + local n_cursbase=n[a_cursbase] if p_cursbase then - local n_curscurs=getattr(n,a_curscurs) + local n_curscurs=n[a_curscurs] if p_cursbase==n_curscurs then local c=cursives[n_curscurs] if c then @@ -9139,20 +9435,20 @@ function injections.handler(head,where,keep) end end elseif maxt>0 then - local ny=getfield(n,"yoffset") + local ny=n.yoffset for i=maxt,1,-1 do ny=ny+d[i] local ti=t[i] - setfield(ti,"yoffset",getfield(ti,"yoffset")+ny) + ti.yoffset=ti.yoffset+ny end maxt=0 end if not n_cursbase and maxt>0 then - local ny=getfield(n,"yoffset") + local ny=n.yoffset for i=maxt,1,-1 do ny=ny+d[i] local ti=t[i] - setfield(ti,"yoffset",ny) + ti.yoffset=ny end maxt=0 end @@ -9160,11 +9456,11 @@ function injections.handler(head,where,keep) end end if maxt>0 then - local ny=getfield(n,"yoffset") + local ny=n.yoffset for i=maxt,1,-1 do ny=ny+d[i] local ti=t[i] - setfield(ti,"yoffset",ny) + ti.yoffset=ny end maxt=0 end @@ -9175,66 +9471,57 @@ function injections.handler(head,where,keep) if has_marks then for i=1,nofvalid do local p=valid[i] - local p_markbase=getattr(p,a_markbase) + local p_markbase=p[a_markbase] if p_markbase then local mrks=marks[p_markbase] local nofmarks=#mrks - for n in traverse_id(glyph_code,getnext(p)) do - local n_markmark=getattr(n,a_markmark) + for n in traverse_id(glyph_code,p.next) do + local n_markmark=n[a_markmark] if p_markbase==n_markmark then - local index=getattr(n,a_markdone) or 1 + local index=n[a_markdone] or 1 local d=mrks[index] if d then local rlmode=d[3] local k=wx[p] - local px=getfield(p,"xoffset") - local ox=0 if k then local x=k[2] local w=k[4] if w then if rlmode and rlmode>=0 then - ox=px-getfield(p,"width")+d[1]-(w-x) + n.xoffset=p.xoffset-p.width+d[1]-(w-x) else - ox=px-d[1]-x + n.xoffset=p.xoffset-d[1]-x end else if rlmode and rlmode>=0 then - ox=px-getfield(p,"width")+d[1] + n.xoffset=p.xoffset-p.width+d[1] else - ox=px-d[1]-x + n.xoffset=p.xoffset-d[1]-x end end else - local wp=getfield(p,"width") - local wn=getfield(n,"width") if rlmode and rlmode>=0 then - ox=px-wp+d[1] + n.xoffset=p.xoffset-p.width+d[1] else - ox=px-d[1] + n.xoffset=p.xoffset-d[1] end - if wn~=0 then - insert_node_before(head,n,newkern(-wn/2)) - insert_node_after(head,n,newkern(-wn/2)) + local w=n.width + if w~=0 then + insert_node_before(head,n,newkern(-w/2)) + insert_node_after(head,n,newkern(-w/2)) end end - setfield(n,"xoffset",ox) - local py=getfield(p,"yoffset") - local oy=0 if mk[p] then - oy=py+d[2] + n.yoffset=p.yoffset+d[2] else - oy=getfield(n,"yoffset")+py+d[2] + n.yoffset=n.yoffset+p.yoffset+d[2] end - setfield(n,"yoffset",oy) if nofmarks==1 then break else nofmarks=nofmarks-1 end end - elseif not n_markmark then - break else end end @@ -9286,7 +9573,6 @@ function injections.handler(head,where,keep) if not keep then kerns={} end -head=tonode(head) return head,true elseif not keep then kerns,cursives,marks={},{},{} @@ -9296,14 +9582,14 @@ head=tonode(head) trace(head) end for n in traverse_id(glyph_code,head) do - if getsubtype(n)<256 then - local k=getattr(n,a_kernpair) + if n.subtype<256 then + local k=n[a_kernpair] if k then local kk=kerns[k] if kk then local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4] if y and y~=0 then - setfield(n,"yoffset",y) + n.yoffset=y end if w then local wx=w-x @@ -9334,10 +9620,10 @@ head=tonode(head) if not keep then kerns={} end - return tonode(head),true + return head,true else end - return tonode(head),false + return head,false end end -- closure @@ -9511,6 +9797,7 @@ local isolated={ [0x0856]=true,[0x0858]=true,[0x0857]=true, [0x07FA]=true, [zwnj]=true, + [0x08AD]=true, } local final={ [0x0622]=true,[0x0623]=true,[0x0624]=true,[0x0625]=true, @@ -9528,15 +9815,16 @@ local final={ [0x06D3]=true,[0x06D5]=true,[0x06EE]=true,[0x06EF]=true, [0x0759]=true,[0x075A]=true,[0x075B]=true,[0x076B]=true, [0x076C]=true,[0x0771]=true,[0x0773]=true,[0x0774]=true, - [0x0778]=true,[0x0779]=true, + [0x0778]=true,[0x0779]=true, [0x08AA]=true,[0x08AB]=true,[0x08AC]=true, [0xFEF5]=true,[0xFEF7]=true,[0xFEF9]=true,[0xFEFB]=true, - [0x0710]=true,[0x0715]=true,[0x0716]=true,[0x0717]=true, - [0x0718]=true,[0x0719]=true,[0x0728]=true,[0x072A]=true, - [0x072C]=true,[0x071E]=true, + [0x0710]=true,[0x0715]=true,[0x0716]=true,[0x0717]=true, + [0x0718]=true,[0x0719]=true,[0x0728]=true,[0x072A]=true, + [0x072C]=true,[0x071E]=true, [0x072F]=true,[0x074D]=true, [0x0840]=true,[0x0849]=true,[0x0854]=true,[0x0846]=true, - [0x084F]=true + [0x084F]=true, + [0x08AE]=true,[0x08B1]=true,[0x08B2]=true, } local medial={ [0x0626]=true,[0x0628]=true,[0x062A]=true,[0x062B]=true, @@ -9596,8 +9884,8 @@ local medial={ [0x07D2]=true,[0x07D0]=true,[0x07CF]=true,[0x07CD]=true, [0x07CB]=true,[0x07D3]=true,[0x07E4]=true,[0x07D5]=true, [0x07E6]=true, - [tatweel]=true, - [zwj]=true, + [tatweel]=true,[zwj]=true, + [0x08A1]=true,[0x08AF]=true,[0x08B0]=true, } local arab_warned={} local function warning(current,what) @@ -9752,25 +10040,12 @@ registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive") registertracker("otf.actions","otf.replacements,otf.positions") registertracker("otf.injections","nodes.injections") registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing") -local nuts=nodes.nuts -local tonode=nuts.tonode -local tonut=nuts.tonut -local getfield=nuts.getfield -local getnext=nuts.getnext -local getprev=nuts.getprev -local getid=nuts.getid -local getattr=nuts.getattr -local getfont=nuts.getfont -local getsubtype=nuts.getsubtype -local getchar=nuts.getchar -local setfield=nuts.setfield -local setattr=nuts.setattr -local insert_node_after=nuts.insert_after -local delete_node=nuts.delete -local copy_node=nuts.copy -local find_node_tail=nuts.tail -local flush_node_list=nuts.flush_list -local end_of_math=nuts.end_of_math +local insert_node_after=node.insert_after +local delete_node=nodes.delete +local copy_node=node.copy +local find_node_tail=node.tail or node.slide +local flush_node_list=node.flush_list +local end_of_math=node.end_of_math local setmetatableindex=table.setmetatableindex local zwnj=0x200C local zwj=0x200D @@ -9881,83 +10156,83 @@ local function pref(kind,lookupname) return formatters["feature %a, lookup %a"](kind,lookupname) end local function copy_glyph(g) - local components=getfield(g,"components") + local components=g.components if components then - setfield(g,"components",nil) + g.components=nil local n=copy_node(g) - setfield(g,"components",components) + g.components=components return n else return copy_node(g) end end local function markstoligature(kind,lookupname,head,start,stop,char) - if start==stop and getchar(start)==char then + if start==stop and start.char==char then return head,start else - local prev=getprev(start) - local next=getnext(stop) - setfield(start,"prev",nil) - setfield(stop,"next",nil) + local prev=start.prev + local next=stop.next + start.prev=nil + stop.next=nil local base=copy_glyph(start) if head==start then head=base end - setfield(base,"char",char) - setfield(base,"subtype",ligature_code) - setfield(base,"components",start) + base.char=char + base.subtype=ligature_code + base.components=start if prev then - setfield(prev,"next",base) + prev.next=base end if next then - setfield(next,"prev",base) + next.prev=base end - setfield(base,"next",next) - setfield(base,"prev",prev) + base.next=next + base.prev=prev return head,base end end local function getcomponentindex(start) - if getid(start)~=glyph_code then + if start.id~=glyph_code then return 0 - elseif getsubtype(start)==ligature_code then + elseif start.subtype==ligature_code then local i=0 - local components=getfield(start,"components") + local components=start.components while components do i=i+getcomponentindex(components) - components=getnext(components) + components=components.next end return i - elseif not marks[getchar(start)] then + elseif not marks[start.char] then return 1 else return 0 end end local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) - if start==stop and getchar(start)==char then - setfield(start,"char",char) + if start==stop and start.char==char then + start.char=char return head,start end - local prev=getprev(start) - local next=getnext(stop) - setfield(start,"prev",nil) - setfield(stop,"next",nil) + local prev=start.prev + local next=stop.next + start.prev=nil + stop.next=nil local base=copy_glyph(start) if start==head then head=base end - setfield(base,"char",char) - setfield(base,"subtype",ligature_code) - setfield(base,"components",start) + base.char=char + base.subtype=ligature_code + base.components=start if prev then - setfield(prev,"next",base) + prev.next=base end if next then - setfield(next,"prev",base) + next.prev=base end - setfield(base,"next",next) - setfield(base,"prev",prev) + base.next=next + base.prev=prev if not discfound then local deletemarks=markflag~="mark" local components=start @@ -9966,42 +10241,42 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun local head=base local current=base while start do - local char=getchar(start) + local char=start.char if not marks[char] then baseindex=baseindex+componentindex componentindex=getcomponentindex(start) elseif not deletemarks then - setattr(start,a_ligacomp,baseindex+(getattr(start,a_ligacomp) or componentindex)) + start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex) if trace_marks then - logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp)) + logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp]) end head,current=insert_node_after(head,current,copy_node(start)) elseif trace_marks then logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char)) end - start=getnext(start) + start=start.next end - local start=getnext(current) - while start and getid(start)==glyph_code do - local char=getchar(start) + local start=current.next + while start and start.id==glyph_code do + local char=start.char if marks[char] then - setattr(start,a_ligacomp,baseindex+(getattr(start,a_ligacomp) or componentindex)) + start[a_ligacomp]=baseindex+(start[a_ligacomp] or componentindex) if trace_marks then - logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),getattr(start,a_ligacomp)) + logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp]) end else break end - start=getnext(start) + start=start.next end end return head,base end function handlers.gsub_single(head,start,kind,lookupname,replacement) if trace_singles then - logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) + logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement)) end - setfield(start,"char",replacement) + start.char=replacement return head,start,true end local function get_alternative_glyph(start,alternatives,value,trace_alternatives) @@ -10027,7 +10302,7 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives return false,trace_alternatives and formatters["invalid value %a, %s"](value,"out of range") end elseif value==0 then - return getchar(start),trace_alternatives and formatters["invalid value %a, %s"](value,"no change") + return start.char,trace_alternatives and formatters["invalid value %a, %s"](value,"no change") elseif value<1 then return alternatives[1],trace_alternatives and formatters["invalid value %a, taking %a"](value,1) else @@ -10038,25 +10313,25 @@ end local function multiple_glyphs(head,start,multiple,ignoremarks) local nofmultiples=#multiple if nofmultiples>0 then - setfield(start,"char",multiple[1]) + start.char=multiple[1] if nofmultiples>1 then - local sn=getnext(start) + local sn=start.next for k=2,nofmultiples do local n=copy_node(start) - setfield(n,"char",multiple[k]) - setfield(n,"next",sn) - setfield(n,"prev",start) + n.char=multiple[k] + n.next=sn + n.prev=start if sn then - setfield(sn,"prev",n) + sn.prev=n end - setfield(start,"next",n) + start.next=n start=n end end return head,start,true else if trace_multiples then - logprocess("no multiple for %s",gref(getchar(start))) + logprocess("no multiple for %s",gref(start.char)) end return head,start,false end @@ -10066,34 +10341,34 @@ function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence local choice,comment=get_alternative_glyph(start,alternative,value,trace_alternatives) if choice then if trace_alternatives then - logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(getchar(start)),choice,gref(choice),comment) + logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment) end - setfield(start,"char",choice) + start.char=choice else if trace_alternatives then - logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(getchar(start)),comment) + logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment) end end return head,start,true end function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence) if trace_multiples then - logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(getchar(start)),gref(multiple)) + logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple)) end return multiple_glyphs(head,start,multiple,sequence.flags[1]) end function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) - local s,stop,discfound=getnext(start),nil,false - local startchar=getchar(start) + local s,stop,discfound=start.next,nil,false + local startchar=start.char if marks[startchar] then while s do - local id=getid(s) - if id==glyph_code and getfont(s)==currentfont and getsubtype(s)<256 then - local lg=ligature[getchar(s)] + local id=s.id + if id==glyph_code and s.font==currentfont and s.subtype<256 then + local lg=ligature[s.char] if lg then stop=s ligature=lg - s=getnext(s) + s=s.next else break end @@ -10105,9 +10380,9 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) local lig=ligature.ligature if lig then if trace_ligatures then - local stopchar=getchar(stop) + local stopchar=stop.char head,start=markstoligature(kind,lookupname,head,start,stop,lig) - logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start))) + logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char)) else head,start=markstoligature(kind,lookupname,head,start,stop,lig) end @@ -10118,18 +10393,18 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) else local skipmark=sequence.flags[1] while s do - local id=getid(s) - if id==glyph_code and getsubtype(s)<256 then - if getfont(s)==currentfont then - local char=getchar(s) + local id=s.id + if id==glyph_code and s.subtype<256 then + if s.font==currentfont then + local char=s.char if skipmark and marks[char] then - s=getnext(s) + s=s.next else local lg=ligature[char] if lg then stop=s ligature=lg - s=getnext(s) + s=s.next else break end @@ -10139,7 +10414,7 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) end elseif id==disc_code then discfound=true - s=getnext(s) + s=s.next else break end @@ -10148,35 +10423,36 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) if lig then if stop then if trace_ligatures then - local stopchar=getchar(stop) + local stopchar=stop.char head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound) - logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(getchar(start))) + logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char)) else head,start=toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound) end + return head,start,true else - setfield(start,"char",lig) + start.char=lig if trace_ligatures then logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) end + return head,start,true end - return head,start,true else end end return head,start,false end function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence) - local markchar=getchar(start) + local markchar=start.char if marks[markchar] then - local base=getprev(start) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - local basechar=getchar(base) + local base=start.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + local basechar=base.char if marks[basechar] then while true do - base=getprev(base) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - basechar=getchar(base) + base=base.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + basechar=base.char if not marks[basechar] then break end @@ -10225,16 +10501,16 @@ function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence return head,start,false end function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence) - local markchar=getchar(start) + local markchar=start.char if marks[markchar] then - local base=getprev(start) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - local basechar=getchar(base) + local base=start.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + local basechar=base.char if marks[basechar] then while true do - base=getprev(base) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - basechar=getchar(base) + base=base.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + basechar=base.char if not marks[basechar] then break end @@ -10246,7 +10522,7 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ end end end - local index=getattr(start,a_ligacomp) + local index=start[a_ligacomp] local baseanchors=descriptions[basechar] if baseanchors then baseanchors=baseanchors.anchors @@ -10291,22 +10567,22 @@ function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequ return head,start,false end function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence) - local markchar=getchar(start) + local markchar=start.char if marks[markchar] then - local base=getprev(start) - local slc=getattr(start,a_ligacomp) + local base=start.prev + local slc=start[a_ligacomp] if slc then while base do - local blc=getattr(base,a_ligacomp) + local blc=base[a_ligacomp] if blc and blc~=slc then - base=getprev(base) + base=base.prev else break end end end - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - local basechar=getchar(base) + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + local basechar=base.char local baseanchors=descriptions[basechar] if baseanchors then baseanchors=baseanchors.anchors @@ -10344,20 +10620,20 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence return head,start,false end function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) - local alreadydone=cursonce and getattr(start,a_cursbase) + local alreadydone=cursonce and start[a_cursbase] if not alreadydone then local done=false - local startchar=getchar(start) + local startchar=start.char if marks[startchar] then if trace_cursive then logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar)) end else - local nxt=getnext(start) - while not done and nxt and getid(nxt)==glyph_code and getfont(nxt)==currentfont and getsubtype(nxt)<256 do - local nextchar=getchar(nxt) + local nxt=start.next + while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do + local nextchar=nxt.char if marks[nextchar] then - nxt=getnext(nxt) + nxt=nxt.next else local entryanchors=descriptions[nextchar] if entryanchors then @@ -10391,13 +10667,13 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) return head,start,done else if trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone) + logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone) end return head,start,false end end function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence) - local startchar=getchar(start) + local startchar=start.char local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) if trace_kerns then logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) @@ -10405,33 +10681,33 @@ function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence) return head,start,false end function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) - local snext=getnext(start) + local snext=start.next if not snext then return head,start,false else local prev,done=start,false local factor=tfmdata.parameters.factor local lookuptype=lookuptypes[lookupname] - while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do - local nextchar=getchar(snext) + while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do + local nextchar=snext.char local krn=kerns[nextchar] if not krn and marks[nextchar] then prev=snext - snext=getnext(snext) + snext=snext.next else if not krn then elseif type(krn)=="table" then if lookuptype=="pair" then local a,b=krn[2],krn[3] if a and #a>0 then - local startchar=getchar(start) + local startchar=start.char local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) if trace_kerns then logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) end end if b and #b>0 then - local startchar=getchar(start) + local startchar=start.char local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) if trace_kerns then logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) @@ -10444,7 +10720,7 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) elseif krn~=0 then local k=setkern(snext,factor,rlmode,krn) if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) + logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar)) end done=true end @@ -10479,13 +10755,13 @@ function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,looku return head,start,false end function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements) - local char=getchar(start) + local char=start.char local replacement=replacements[char] if replacement then if trace_singles then logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement)) end - setfield(start,"char",replacement) + start.char=replacement return head,start,true else return head,start,false @@ -10498,8 +10774,8 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," ")) end while current do - if getid(current)==glyph_code then - local currentchar=getchar(current) + if current.id==glyph_code then + local currentchar=current.char local lookupname=subtables[1] local replacement=lookuphash[lookupname] if not replacement then @@ -10516,21 +10792,21 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo if trace_singles then logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement)) end - setfield(current,"char",replacement) + current.char=replacement end end return head,start,true elseif current==stop then break else - current=getnext(current) + current=current.next end end return head,start,false end chainmores.gsub_single=chainprocs.gsub_single function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) - local startchar=getchar(start) + local startchar=start.char local subtables=currentlookup.subtables local lookupname=subtables[1] local replacements=lookuphash[lookupname] @@ -10559,8 +10835,8 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext local subtables=currentlookup.subtables local value=featurevalue==true and tfmdata.shared.features[kind] or featurevalue while current do - if getid(current)==glyph_code then - local currentchar=getchar(current) + if current.id==glyph_code then + local currentchar=current.char local lookupname=subtables[1] local alternatives=lookuphash[lookupname] if not alternatives then @@ -10575,7 +10851,7 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext if trace_alternatives then logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment) end - setfield(start,"char",choice) + start.char=choice else if trace_alternatives then logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment) @@ -10589,14 +10865,14 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext elseif current==stop then break else - current=getnext(current) + current=current.next end end return head,start,false end chainmores.gsub_alternate=chainprocs.gsub_alternate function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex) - local startchar=getchar(start) + local startchar=start.char local subtables=currentlookup.subtables local lookupname=subtables[1] local ligatures=lookuphash[lookupname] @@ -10611,20 +10887,20 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) end else - local s=getnext(start) + local s=start.next local discfound=false local last=stop local nofreplacements=0 local skipmark=currentlookup.flags[1] while s do - local id=getid(s) + local id=s.id if id==disc_code then - s=getnext(s) + s=s.next discfound=true else - local schar=getchar(s) + local schar=s.char if skipmark and marks[schar] then - s=getnext(s) + s=s.next else local lg=ligatures[schar] if lg then @@ -10632,7 +10908,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, if s==stop then break else - s=getnext(s) + s=s.next end else break @@ -10649,7 +10925,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, if start==stop then logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2)) else - logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop)),gref(l2)) + logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2)) end end head,start=toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound) @@ -10658,7 +10934,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, if start==stop then logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) else - logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(getchar(stop))) + logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char)) end end end @@ -10667,7 +10943,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end chainmores.gsub_ligature=chainprocs.gsub_ligature function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) - local markchar=getchar(start) + local markchar=start.char if marks[markchar] then local subtables=currentlookup.subtables local lookupname=subtables[1] @@ -10676,14 +10952,14 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext markanchors=markanchors[markchar] end if markanchors then - local base=getprev(start) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - local basechar=getchar(base) + local base=start.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + local basechar=base.char if marks[basechar] then while true do - base=getprev(base) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - basechar=getchar(base) + base=base.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + basechar=base.char if not marks[basechar] then break end @@ -10730,7 +11006,7 @@ function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext return head,start,false end function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) - local markchar=getchar(start) + local markchar=start.char if marks[markchar] then local subtables=currentlookup.subtables local lookupname=subtables[1] @@ -10739,14 +11015,14 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon markanchors=markanchors[markchar] end if markanchors then - local base=getprev(start) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - local basechar=getchar(base) + local base=start.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + local basechar=base.char if marks[basechar] then while true do - base=getprev(base) - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - basechar=getchar(base) + base=base.prev + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + basechar=base.char if not marks[basechar] then break end @@ -10758,7 +11034,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon end end end - local index=getattr(start,a_ligacomp) + local index=start[a_ligacomp] local baseanchors=descriptions[basechar].anchors if baseanchors then local baseanchors=baseanchors['baselig'] @@ -10797,7 +11073,7 @@ function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcon return head,start,false end function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) - local markchar=getchar(start) + local markchar=start.char if marks[markchar] then local subtables=currentlookup.subtables local lookupname=subtables[1] @@ -10806,20 +11082,20 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext markanchors=markanchors[markchar] end if markanchors then - local base=getprev(start) - local slc=getattr(start,a_ligacomp) + local base=start.prev + local slc=start[a_ligacomp] if slc then while base do - local blc=getattr(base,a_ligacomp) + local blc=base[a_ligacomp] if blc and blc~=slc then - base=getprev(base) + base=base.prev else break end end end - if base and getid(base)==glyph_code and getfont(base)==currentfont and getsubtype(base)<256 then - local basechar=getchar(base) + if base and base.id==glyph_code and base.font==currentfont and base.subtype<256 then + local basechar=base.char local baseanchors=descriptions[basechar].anchors if baseanchors then baseanchors=baseanchors['basemark'] @@ -10855,9 +11131,9 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext return head,start,false end function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) - local alreadydone=cursonce and getattr(start,a_cursbase) + local alreadydone=cursonce and start[a_cursbase] if not alreadydone then - local startchar=getchar(start) + local startchar=start.char local subtables=currentlookup.subtables local lookupname=subtables[1] local exitanchors=lookuphash[lookupname] @@ -10871,11 +11147,11 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar)) end else - local nxt=getnext(start) - while not done and nxt and getid(nxt)==glyph_code and getfont(nxt)==currentfont and getsubtype(nxt)<256 do - local nextchar=getchar(nxt) + local nxt=start.next + while not done and nxt and nxt.id==glyph_code and nxt.font==currentfont and nxt.subtype<256 do + local nextchar=nxt.char if marks[nextchar] then - nxt=getnext(nxt) + nxt=nxt.next else local entryanchors=descriptions[nextchar] if entryanchors then @@ -10909,7 +11185,7 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l return head,start,done else if trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(getchar(start)),alreadydone) + logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone) end return head,start,false end @@ -10917,7 +11193,7 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l return head,start,false end function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) - local startchar=getchar(start) + local startchar=start.char local subtables=currentlookup.subtables local lookupname=subtables[1] local kerns=lookuphash[lookupname] @@ -10934,9 +11210,9 @@ function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lo end chainmores.gpos_single=chainprocs.gpos_single function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) - local snext=getnext(start) + local snext=start.next if snext then - local startchar=getchar(start) + local startchar=start.char local subtables=currentlookup.subtables local lookupname=subtables[1] local kerns=lookuphash[lookupname] @@ -10946,26 +11222,26 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look local lookuptype=lookuptypes[lookupname] local prev,done=start,false local factor=tfmdata.parameters.factor - while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do - local nextchar=getchar(snext) + while snext and snext.id==glyph_code and snext.font==currentfont and snext.subtype<256 do + local nextchar=snext.char local krn=kerns[nextchar] if not krn and marks[nextchar] then prev=snext - snext=getnext(snext) + snext=snext.next else if not krn then elseif type(krn)=="table" then if lookuptype=="pair" then local a,b=krn[2],krn[3] if a and #a>0 then - local startchar=getchar(start) + local startchar=start.char local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) if trace_kerns then logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) end end if b and #b>0 then - local startchar=getchar(start) + local startchar=start.char local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) if trace_kerns then logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) @@ -10977,7 +11253,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look if a and a~=0 then local k=setkern(snext,factor,rlmode,a) if trace_kerns then - logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) + logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar)) end end if b and b~=0 then @@ -10988,7 +11264,7 @@ function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,look elseif krn~=0 then local k=setkern(snext,factor,rlmode,krn) if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) + logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar)) end done=true end @@ -11009,10 +11285,6 @@ local function show_skip(kind,chainname,char,ck,class) logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2]) end end -local quit_on_no_replacement=true -directives.register("otf.chain.quitonnoreplacement",function(value) - quit_on_no_replacement=value -end) local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash) local flags=sequence.flags local done=false @@ -11030,7 +11302,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq local seq=ck[3] local s=#seq if s==1 then - match=getid(current)==glyph_code and getfont(current)==currentfont and getsubtype(current)<256 and seq[1][getchar(current)] + match=current.id==glyph_code and current.font==currentfont and current.subtype<256 and seq[1][current.char] else local f,l=ck[4],ck[5] if f==1 and f==l then @@ -11038,13 +11310,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if f==l then else local n=f+1 - last=getnext(last) + last=last.next while n<=l do if last then - local id=getid(last) + local id=last.id if id==glyph_code then - if getfont(last)==currentfont and getsubtype(last)<256 then - local char=getchar(last) + if last.font==currentfont and last.subtype<256 then + local char=last.char local ccd=descriptions[char] if ccd then local class=ccd.class @@ -11053,10 +11325,10 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if trace_skips then show_skip(kind,chainname,char,ck,class) end - last=getnext(last) + last=last.next elseif seq[n][char] then if n<l then - last=getnext(last) + last=last.next end n=n+1 else @@ -11072,7 +11344,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq break end elseif id==disc_code then - last=getnext(last) + last=last.next else match=false break @@ -11085,15 +11357,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end if match and f>1 then - local prev=getprev(start) + local prev=start.prev if prev then local n=f-1 while n>=1 do if prev then - local id=getid(prev) + local id=prev.id if id==glyph_code then - if getfont(prev)==currentfont and getsubtype(prev)<256 then - local char=getchar(prev) + if prev.font==currentfont and prev.subtype<256 then + local char=prev.char local ccd=descriptions[char] if ccd then local class=ccd.class @@ -11123,7 +11395,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq match=false break end - prev=getprev(prev) + prev=prev.prev elseif seq[n][32] then n=n -1 else @@ -11143,15 +11415,15 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end if match and s>l then - local current=last and getnext(last) + local current=last and last.next if current then local n=l+1 while n<=s do if current then - local id=getid(current) + local id=current.id if id==glyph_code then - if getfont(current)==currentfont and getsubtype(current)<256 then - local char=getchar(current) + if current.font==currentfont and current.subtype<256 then + local char=current.char local ccd=descriptions[char] if ccd then local class=ccd.class @@ -11181,7 +11453,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq match=false break end - current=getnext(current) + current=current.next elseif seq[n][32] then n=n+1 else @@ -11204,7 +11476,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if match then if trace_contexts then local rule,lookuptype,f,l=ck[1],ck[2],ck[4],ck[5] - local char=getchar(start) + local char=start.char if ck[9] then logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a", cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10]) @@ -11238,12 +11510,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq repeat if skipped then while true do - local char=getchar(start) + local char=start.char local ccd=descriptions[char] if ccd then local class=ccd.class if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then - start=getnext(start) + start=start.next else break end @@ -11273,7 +11545,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end if start then - start=getnext(start) + start=start.next else end until i>nofchainlookups @@ -11283,7 +11555,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if replacements then head,start,done=chainprocs.reversesub(head,start,last,kind,chainname,ck,lookuphash,replacements) else - done=quit_on_no_replacement + done=true if trace_contexts then logprocess("%s: skipping match",cref(kind,chainname)) end @@ -11352,14 +11624,20 @@ local autofeatures=fonts.analyzers.features local function initialize(sequence,script,language,enabled) local features=sequence.features if features then - for kind,scripts in next,features do - local valid=enabled[kind] - if valid then - local languages=scripts[script] or scripts[wildcard] - if languages and (languages[language] or languages[wildcard]) then - return { valid,autofeatures[kind] or false,sequence.chain or 0,kind,sequence } + local order=sequence.order + if order then + for i=1,#order do + local kind=order[i] + local valid=enabled[kind] + if valid then + local scripts=features[kind] + local languages=scripts[script] or scripts[wildcard] + if languages and (languages[language] or languages[wildcard]) then + return { valid,autofeatures[kind] or false,sequence.chain or 0,kind,sequence } + end end end + else end end return false @@ -11386,12 +11664,12 @@ function otf.dataset(tfmdata,font) } rs[language]=rl local sequences=tfmdata.resources.sequences -for s=1,#sequences do - local v=enabled and initialize(sequences[s],script,language,enabled) - if v then - rl[#rl+1]=v - end -end + for s=1,#sequences do + local v=enabled and initialize(sequences[s],script,language,enabled) + if v then + rl[#rl+1]=v + end + end end return rl end @@ -11400,7 +11678,6 @@ local function featuresprocessor(head,font,attr) if not lookuphash then return head,false end - head=tonut(head) if trace_steps then checkstep(head) end @@ -11433,10 +11710,10 @@ local function featuresprocessor(head,font,attr) local handler=handlers[typ] local start=find_node_tail(head) while start do - local id=getid(start) + local id=start.id if id==glyph_code then - if getfont(start)==font and getsubtype(start)<256 then - local a=getattr(start,0) + if start.font==font and start.subtype<256 then + local a=start[0] if a then a=a==attr else @@ -11447,7 +11724,7 @@ local function featuresprocessor(head,font,attr) local lookupname=subtables[i] local lookupcache=lookuphash[lookupname] if lookupcache then - local lookupmatch=lookupcache[getchar(start)] + local lookupmatch=lookupcache[start.char] if lookupmatch then head,start,success=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) if success then @@ -11458,15 +11735,15 @@ local function featuresprocessor(head,font,attr) report_missing_cache(typ,lookupname) end end - if start then start=getprev(start) end + if start then start=start.prev end else - start=getprev(start) + start=start.prev end else - start=getprev(start) + start=start.prev end else - start=getprev(start) + start=start.prev end end else @@ -11484,16 +11761,16 @@ local function featuresprocessor(head,font,attr) local head=start local done=false while start do - local id=getid(start) - if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then - local a=getattr(start,0) + local id=start.id + if id==glyph_code and start.font==font and start.subtype<256 then + local a=start[0] if a then - a=(a==attr) and (not attribute or getattr(start,a_state)==attribute) + a=(a==attr) and (not attribute or start[a_state]==attribute) else - a=not attribute or getattr(start,a_state)==attribute + a=not attribute or start[a_state]==attribute end if a then - local lookupmatch=lookupcache[getchar(start)] + local lookupmatch=lookupcache[start.char] if lookupmatch then local ok head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) @@ -11501,12 +11778,12 @@ local function featuresprocessor(head,font,attr) done=true end end - if start then start=getnext(start) end + if start then start=start.next end else - start=getnext(start) + start=start.next end else - start=getnext(start) + start=start.next end end if done then @@ -11515,18 +11792,18 @@ local function featuresprocessor(head,font,attr) end end local function kerndisc(disc) - local prev=getprev(disc) - local next=getnext(disc) + local prev=disc.prev + local next=disc.next if prev and next then - setfield(prev,"next",next) - local a=getattr(prev,0) + prev.next=next + local a=prev[0] if a then - a=(a==attr) and (not attribute or getattr(prev,a_state)==attribute) + a=(a==attr) and (not attribute or prev[a_state]==attribute) else - a=not attribute or getattr(prev,a_state)==attribute + a=not attribute or prev[a_state]==attribute end if a then - local lookupmatch=lookupcache[getchar(prev)] + local lookupmatch=lookupcache[prev.char] if lookupmatch then local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) if ok then @@ -11535,22 +11812,22 @@ local function featuresprocessor(head,font,attr) end end end - setfield(prev,"next",disc) + prev.next=disc end return next end while start do - local id=getid(start) + local id=start.id if id==glyph_code then - if getfont(start)==font and getsubtype(start)<256 then - local a=getattr(start,0) + if start.font==font and start.subtype<256 then + local a=start[0] if a then - a=(a==attr) and (not attribute or getattr(start,a_state)==attribute) + a=(a==attr) and (not attribute or start[a_state]==attribute) else - a=not attribute or getattr(start,a_state)==attribute + a=not attribute or start[a_state]==attribute end if a then - local lookupmatch=lookupcache[getchar(start)] + local lookupmatch=lookupcache[start.char] if lookupmatch then local ok head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) @@ -11558,38 +11835,38 @@ local function featuresprocessor(head,font,attr) success=true end end - if start then start=getnext(start) end + if start then start=start.next end else - start=getnext(start) + start=start.next end else - start=getnext(start) + start=start.next end elseif id==disc_code then - if getsubtype(start)==discretionary_code then - local pre=getfield(start,"pre") + if start.subtype==discretionary_code then + local pre=start.pre if pre then local new=subrun(pre) - if new then setfield(start,"pre",new) end + if new then start.pre=new end end - local post=getfield(start,"post") + local post=start.post if post then local new=subrun(post) - if new then setfield(start,"post",new) end + if new then start.post=new end end - local replace=getfield(start,"replace") + local replace=start.replace if replace then local new=subrun(replace) - if new then setfield(start,"replace",new) end + if new then start.replace=new end end elseif typ=="gpos_single" or typ=="gpos_pair" then kerndisc(start) end - start=getnext(start) + start=start.next elseif id==whatsit_code then - local subtype=getsubtype(start) + local subtype=start.subtype if subtype==dir_code then - local dir=getfield(start,"dir") + local dir=start.dir if dir=="+TRT" or dir=="+TLT" then topstack=topstack+1 dirstack[topstack]=dir @@ -11608,7 +11885,7 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) end elseif subtype==localpar_code then - local dir=getfield(start,"dir") + local dir=start.dir if dir=="TRT" then rlparmode=-1 elseif dir=="TLT" then @@ -11621,11 +11898,11 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) end end - start=getnext(start) + start=start.next elseif id==math_code then - start=getnext(end_of_math(start)) + start=end_of_math(start).next else - start=getnext(start) + start=start.next end end end @@ -11634,20 +11911,20 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then local head=start local done=false while start do - local id=getid(start) - if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then - local a=getattr(start,0) + local id=start.id + if id==glyph_code and start.id==font and start.subtype<256 then + local a=start[0] if a then - a=(a==attr) and (not attribute or getattr(start,a_state)==attribute) + a=(a==attr) and (not attribute or start[a_state]==attribute) else - a=not attribute or getattr(start,a_state)==attribute + a=not attribute or start[a_state]==attribute end if a then for i=1,ns do local lookupname=subtables[i] local lookupcache=lookuphash[lookupname] if lookupcache then - local lookupmatch=lookupcache[getchar(start)] + local lookupmatch=lookupcache[start.char] if lookupmatch then local ok head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) @@ -11662,12 +11939,12 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then report_missing_cache(typ,lookupname) end end - if start then start=getnext(start) end + if start then start=start.next end else - start=getnext(start) + start=start.next end else - start=getnext(start) + start=start.next end end if done then @@ -11676,22 +11953,22 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then end end local function kerndisc(disc) - local prev=getprev(disc) - local next=getnext(disc) + local prev=disc.prev + local next=disc.next if prev and next then - setfield(prev,"next",next) - local a=getattr(prev,0) + prev.next=next + local a=prev[0] if a then - a=(a==attr) and (not attribute or getattr(prev,a_state)==attribute) + a=(a==attr) and (not attribute or prev[a_state]==attribute) else - a=not attribute or getattr(prev,a_state)==attribute + a=not attribute or prev[a_state]==attribute end if a then for i=1,ns do local lookupname=subtables[i] local lookupcache=lookuphash[lookupname] if lookupcache then - local lookupmatch=lookupcache[getchar(prev)] + local lookupmatch=lookupcache[prev.char] if lookupmatch then local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) if ok then @@ -11704,26 +11981,26 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then end end end - setfield(prev,"next",disc) + prev.next=disc end return next end while start do - local id=getid(start) + local id=start.id if id==glyph_code then - if getfont(start)==font and getsubtype(start)<256 then - local a=getattr(start,0) + if start.font==font and start.subtype<256 then + local a=start[0] if a then - a=(a==attr) and (not attribute or getattr(start,a_state)==attribute) + a=(a==attr) and (not attribute or start[a_state]==attribute) else - a=not attribute or getattr(start,a_state)==attribute + a=not attribute or start[a_state]==attribute end if a then for i=1,ns do local lookupname=subtables[i] local lookupcache=lookuphash[lookupname] if lookupcache then - local lookupmatch=lookupcache[getchar(start)] + local lookupmatch=lookupcache[start.char] if lookupmatch then local ok head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) @@ -11738,38 +12015,38 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then report_missing_cache(typ,lookupname) end end - if start then start=getnext(start) end + if start then start=start.next end else - start=getnext(start) + start=start.next end else - start=getnext(start) + start=start.next end elseif id==disc_code then - if getsubtype(start)==discretionary_code then - local pre=getfield(start,"pre") + if start.subtype==discretionary_code then + local pre=start.pre if pre then local new=subrun(pre) - if new then setfield(start,"pre",new) end + if new then start.pre=new end end - local post=getfield(start,"post") + local post=start.post if post then local new=subrun(post) - if new then setfield(start,"post",new) end + if new then start.post=new end end - local replace=getfield(start,"replace") + local replace=start.replace if replace then local new=subrun(replace) - if new then setfield(start,"replace",new) end + if new then start.replace=new end end elseif typ=="gpos_single" or typ=="gpos_pair" then kerndisc(start) end - start=getnext(start) + start=start.next elseif id==whatsit_code then - local subtype=getsubtype(start) + local subtype=start.subtype if subtype==dir_code then - local dir=getfield(start,"dir") + local dir=start.dir if dir=="+TRT" or dir=="+TLT" then topstack=topstack+1 dirstack[topstack]=dir @@ -11788,7 +12065,7 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) end elseif subtype==localpar_code then - local dir=getfield(start,"dir") + local dir=start.dir if dir=="TRT" then rlparmode=-1 elseif dir=="TLT" then @@ -11801,11 +12078,11 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) end end - start=getnext(start) + start=start.next elseif id==math_code then - start=getnext(end_of_math(start)) + start=end_of_math(start).next else - start=getnext(start) + start=start.next end end end @@ -11817,7 +12094,6 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then registerstep(head) end end - head=tonode(head) return head,done end local function generic(lookupdata,lookupname,unicode,lookuphash) @@ -12420,6 +12696,14 @@ local function packdata(data) features[script]=pack_normal(feature) end end + local order=sequence.order + if order then + sequence.order=pack_indexed(order) + end + local markclass=sequence.markclass + if markclass then + sequence.markclass=pack_boolean(markclass) + end end end local lookups=resources.lookups @@ -12832,6 +13116,20 @@ local function unpackdata(data) end end end + local order=feature.order + if order then + local tv=tables[order] + if tv then + feature.order=tv + end + end + local markclass=feature.markclass + if markclass then + local tv=tables[markclass] + if tv then + feature.markclass=tv + end + end end end local lookups=resources.lookups diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-inj.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-inj.lua new file mode 100644 index 00000000000..ae48150a6ca --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-inj.lua @@ -0,0 +1,526 @@ +if not modules then modules = { } end modules ['node-inj'] = { + version = 1.001, + comment = "companion to node-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- This is very experimental (this will change when we have luatex > .50 and +-- a few pending thingies are available. Also, Idris needs to make a few more +-- test fonts. Btw, future versions of luatex will have extended glyph properties +-- that can be of help. Some optimizations can go away when we have faster machines. + +-- todo: make a special one for context + +local next = next +local utfchar = utf.char + +local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end) + +local report_injections = logs.reporter("nodes","injections") + +local attributes, nodes, node = attributes, nodes, node + +fonts = fonts +local fontdata = fonts.hashes.identifiers + +nodes.injections = nodes.injections or { } +local injections = nodes.injections + +local nodecodes = nodes.nodecodes +local glyph_code = nodecodes.glyph +local kern_code = nodecodes.kern +local nodepool = nodes.pool +local newkern = nodepool.kern + +local traverse_id = node.traverse_id +local insert_node_before = node.insert_before +local insert_node_after = node.insert_after + +local a_kernpair = attributes.private('kernpair') +local a_ligacomp = attributes.private('ligacomp') +local a_markbase = attributes.private('markbase') +local a_markmark = attributes.private('markmark') +local a_markdone = attributes.private('markdone') +local a_cursbase = attributes.private('cursbase') +local a_curscurs = attributes.private('curscurs') +local a_cursdone = attributes.private('cursdone') + +-- This injector has been tested by Idris Samawi Hamid (several arabic fonts as well as +-- the rather demanding Husayni font), Khaled Hosny (latin and arabic) and Kaj Eigner +-- (arabic, hebrew and thai) and myself (whatever font I come across). I'm pretty sure +-- that this code is not 100% okay but examples are needed to figure things out. + +function injections.installnewkern(nk) + newkern = nk or newkern +end + +local cursives = { } +local marks = { } +local kerns = { } + +-- Currently we do gpos/kern in a bit inofficial way but when we have the extra fields in +-- glyphnodes to manipulate ht/dp/wd explicitly I will provide an alternative; also, we +-- can share tables. + +-- For the moment we pass the r2l key ... volt/arabtype tests .. idris: this needs +-- checking with husayni (volt and fontforge). + +function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) + local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2]) + local ws, wn = tfmstart.width, tfmnext.width + local bound = #cursives + 1 + start[a_cursbase] = bound + nxt[a_curscurs] = bound + cursives[bound] = { rlmode, dx, dy, ws, wn } + return dx, dy, bound +end + +function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr) + local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4] + -- dy = y - h + if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then + local bound = current[a_kernpair] + if bound then + local kb = kerns[bound] + -- inefficient but singles have less, but weird anyway, needs checking + kb[2], kb[3], kb[4], kb[5] = (kb[2] or 0) + x, (kb[3] or 0) + y, (kb[4] or 0)+ w, (kb[5] or 0) + h + else + bound = #kerns + 1 + current[a_kernpair] = bound + kerns[bound] = { rlmode, x, y, w, h, r2lflag, tfmchr.width } + end + return x, y, w, h, bound + end + return x, y, w, h -- no bound +end + +function injections.setkern(current,factor,rlmode,x,tfmchr) + local dx = factor*x + if dx ~= 0 then + local bound = #kerns + 1 + current[a_kernpair] = bound + kerns[bound] = { rlmode, dx } + return dx, bound + else + return 0, 0 + end +end + +function injections.setmark(start,base,factor,rlmode,ba,ma,index,baseismark) -- ba=baseanchor, ma=markanchor + local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) -- the index argument is no longer used but when this + local bound = base[a_markbase] -- fails again we should pass it + local index = 1 + if bound then + local mb = marks[bound] + if mb then + -- if not index then index = #mb + 1 end + index = #mb + 1 + mb[index] = { dx, dy, rlmode } + start[a_markmark] = bound + start[a_markdone] = index + return dx, dy, bound + else + report_injections("possible problem, %U is base mark without data (id %a)",base.char,bound) + end + end +-- index = index or 1 + index = index or 1 + bound = #marks + 1 + base[a_markbase] = bound + start[a_markmark] = bound + start[a_markdone] = index + marks[bound] = { [index] = { dx, dy, rlmode, baseismark } } + return dx, dy, bound +end + +local function dir(n) + return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset" +end + +local function trace(head) + report_injections("begin run") + for n in traverse_id(glyph_code,head) do + if n.subtype < 256 then + local kp = n[a_kernpair] + local mb = n[a_markbase] + local mm = n[a_markmark] + local md = n[a_markdone] + local cb = n[a_cursbase] + local cc = n[a_curscurs] + local char = n.char + report_injections("font %s, char %U, glyph %c",n.font,char,char) + if kp then + local k = kerns[kp] + if k[3] then + report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5]) + else + report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2]) + end + end + if mb then + report_injections(" markbase: bound %a",mb) + end + if mm then + local m = marks[mm] + if mb then + local m = m[mb] + if m then + report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2]) + else + report_injections(" markmark: bound %a, missing index",mm) + end + else + m = m[1] + report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2]) + end + end + if cb then + report_injections(" cursbase: bound %a",cb) + end + if cc then + local c = cursives[cc] + report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3]) + end + end + end + report_injections("end run") +end + +-- todo: reuse tables (i.e. no collection), but will be extra fields anyway +-- todo: check for attribute + +-- We can have a fast test on a font being processed, so we can check faster for marks etc +-- but I'll make a context variant anyway. + +local function show_result(head) + local current = head + local skipping = false + while current do + local id = current.id + if id == glyph_code then + report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset) + skipping = false + elseif id == kern_code then + report_injections("kern: %p",current.kern) + skipping = false + elseif not skipping then + report_injections() + skipping = true + end + current = current.next + end +end + +function injections.handler(head,where,keep) + local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns) + if has_marks or has_cursives then + if trace_injections then + trace(head) + end + -- in the future variant we will not copy items but refs to tables + local done, ky, rl, valid, cx, wx, mk, nofvalid = false, { }, { }, { }, { }, { }, { }, 0 + if has_kerns then -- move outside loop + local nf, tm = nil, nil + for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts + if n.subtype < 256 then + nofvalid = nofvalid + 1 + valid[nofvalid] = n + if n.font ~= nf then + nf = n.font + tm = fontdata[nf].resources.marks + end + if tm then + mk[n] = tm[n.char] + end + local k = n[a_kernpair] + if k then + local kk = kerns[k] + if kk then + local x, y, w, h = kk[2] or 0, kk[3] or 0, kk[4] or 0, kk[5] or 0 + local dy = y - h + if dy ~= 0 then + ky[n] = dy + end + if w ~= 0 or x ~= 0 then + wx[n] = kk + end + rl[n] = kk[1] -- could move in test + end + end + end + end + else + local nf, tm = nil, nil + for n in traverse_id(glyph_code,head) do + if n.subtype < 256 then + nofvalid = nofvalid + 1 + valid[nofvalid] = n + if n.font ~= nf then + nf = n.font + tm = fontdata[nf].resources.marks + end + if tm then + mk[n] = tm[n.char] + end + end + end + end + if nofvalid > 0 then + -- we can assume done == true because we have cursives and marks + local cx = { } + if has_kerns and next(ky) then + for n, k in next, ky do + n.yoffset = k + end + end + -- todo: reuse t and use maxt + if has_cursives then + local p_cursbase, p = nil, nil + -- since we need valid[n+1] we can also use a "while true do" + local t, d, maxt = { }, { }, 0 + for i=1,nofvalid do -- valid == glyphs + local n = valid[i] + if not mk[n] then + local n_cursbase = n[a_cursbase] + if p_cursbase then + local n_curscurs = n[a_curscurs] + if p_cursbase == n_curscurs then + local c = cursives[n_curscurs] + if c then + local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5] + if rlmode >= 0 then + dx = dx - ws + else + dx = dx + wn + end + if dx ~= 0 then + cx[n] = dx + rl[n] = rlmode + end + -- if rlmode and rlmode < 0 then + dy = -dy + -- end + maxt = maxt + 1 + t[maxt] = p + d[maxt] = dy + else + maxt = 0 + end + end + elseif maxt > 0 then + local ny = n.yoffset + for i=maxt,1,-1 do + ny = ny + d[i] + local ti = t[i] + ti.yoffset = ti.yoffset + ny + end + maxt = 0 + end + if not n_cursbase and maxt > 0 then + local ny = n.yoffset + for i=maxt,1,-1 do + ny = ny + d[i] + local ti = t[i] + ti.yoffset = ny + end + maxt = 0 + end + p_cursbase, p = n_cursbase, n + end + end + if maxt > 0 then + local ny = n.yoffset + for i=maxt,1,-1 do + ny = ny + d[i] + local ti = t[i] + ti.yoffset = ny + end + maxt = 0 + end + if not keep then + cursives = { } + end + end + if has_marks then + for i=1,nofvalid do + local p = valid[i] + local p_markbase = p[a_markbase] + if p_markbase then + local mrks = marks[p_markbase] + local nofmarks = #mrks + for n in traverse_id(glyph_code,p.next) do + local n_markmark = n[a_markmark] + if p_markbase == n_markmark then + local index = n[a_markdone] or 1 + local d = mrks[index] + if d then + local rlmode = d[3] + -- + local k = wx[p] + if k then + local x = k[2] + local w = k[4] + if w then + if rlmode and rlmode >= 0 then + -- kern(x) glyph(p) kern(w-x) mark(n) + n.xoffset = p.xoffset - p.width + d[1] - (w-x) + else + -- kern(w-x) glyph(p) kern(x) mark(n) + n.xoffset = p.xoffset - d[1] - x + end + else + if rlmode and rlmode >= 0 then + -- okay for husayni + n.xoffset = p.xoffset - p.width + d[1] + else + -- needs checking: is x ok here? + n.xoffset = p.xoffset - d[1] - x + end + end + else + if rlmode and rlmode >= 0 then + n.xoffset = p.xoffset - p.width + d[1] + else + n.xoffset = p.xoffset - d[1] + end + local w = n.width + if w ~= 0 then + insert_node_before(head,n,newkern(-w/2)) + insert_node_after(head,n,newkern(-w/2)) + end + end + -- -- + if mk[p] then + n.yoffset = p.yoffset + d[2] + else + n.yoffset = n.yoffset + p.yoffset + d[2] + end + -- + if nofmarks == 1 then + break + else + nofmarks = nofmarks - 1 + end + end + else + -- KE: there can be <mark> <mkmk> <mark> sequences in ligatures + end + end + end + end + if not keep then + marks = { } + end + end + -- todo : combine + if next(wx) then + for n, k in next, wx do + -- only w can be nil (kernclasses), can be sped up when w == nil + local x = k[2] + local w = k[4] + if w then + local rl = k[1] -- r2l = k[6] + local wx = w - x + if rl < 0 then -- KE: don't use r2l here + if wx ~= 0 then + insert_node_before(head,n,newkern(wx)) -- type 0/2 + end + if x ~= 0 then + insert_node_after (head,n,newkern(x)) -- type 0/2 + end + else + if x ~= 0 then + insert_node_before(head,n,newkern(x)) -- type 0/2 + end + if wx ~= 0 then + insert_node_after (head,n,newkern(wx)) -- type 0/2 + end + end + elseif x ~= 0 then + -- this needs checking for rl < 0 but it is unlikely that a r2l script + -- uses kernclasses between glyphs so we're probably safe (KE has a + -- problematic font where marks interfere with rl < 0 in the previous + -- case) + insert_node_before(head,n,newkern(x)) -- a real font kern, type 0 + end + end + end + if next(cx) then + for n, k in next, cx do + if k ~= 0 then + local rln = rl[n] + if rln and rln < 0 then + insert_node_before(head,n,newkern(-k)) -- type 0/2 + else + insert_node_before(head,n,newkern(k)) -- type 0/2 + end + end + end + end + if not keep then + kerns = { } + end + -- if trace_injections then + -- show_result(head) + -- end + return head, true + elseif not keep then + kerns, cursives, marks = { }, { }, { } + end + elseif has_kerns then + if trace_injections then + trace(head) + end + for n in traverse_id(glyph_code,head) do + if n.subtype < 256 then + local k = n[a_kernpair] + if k then + local kk = kerns[k] + if kk then + local rl, x, y, w = kk[1], kk[2] or 0, kk[3], kk[4] + if y and y ~= 0 then + n.yoffset = y -- todo: h ? + end + if w then + -- copied from above + -- local r2l = kk[6] + local wx = w - x + if rl < 0 then -- KE: don't use r2l here + if wx ~= 0 then + insert_node_before(head,n,newkern(wx)) + end + if x ~= 0 then + insert_node_after (head,n,newkern(x)) + end + else + if x ~= 0 then + insert_node_before(head,n,newkern(x)) + end + if wx ~= 0 then + insert_node_after(head,n,newkern(wx)) + end + end + else + -- simple (e.g. kernclass kerns) + if x ~= 0 then + insert_node_before(head,n,newkern(x)) + end + end + end + end + end + end + if not keep then + kerns = { } + end + -- if trace_injections then + -- show_result(head) + -- end + return head, true + else + -- no tracing needed + end + return head, false +end diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-otn.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-otn.lua new file mode 100644 index 00000000000..c57be5f0278 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-otn.lua @@ -0,0 +1,2848 @@ +if not modules then modules = { } end modules ['font-otn'] = { + version = 1.001, + comment = "companion to font-ini.mkiv", + author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "see context related readme files", +} + +-- preprocessors = { "nodes" } + +-- this is still somewhat preliminary and it will get better in due time; +-- much functionality could only be implemented thanks to the husayni font +-- of Idris Samawi Hamid to who we dedicate this module. + +-- in retrospect it always looks easy but believe it or not, it took a lot +-- of work to get proper open type support done: buggy fonts, fuzzy specs, +-- special made testfonts, many skype sessions between taco, idris and me, +-- torture tests etc etc ... unfortunately the code does not show how much +-- time it took ... + +-- todo: +-- +-- kerning is probably not yet ok for latin around dics nodes (interesting challenge) +-- extension infrastructure (for usage out of context) +-- sorting features according to vendors/renderers +-- alternative loop quitters +-- check cursive and r2l +-- find out where ignore-mark-classes went +-- default features (per language, script) +-- handle positions (we need example fonts) +-- handle gpos_single (we might want an extra width field in glyph nodes because adding kerns might interfere) +-- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests) +-- remove some optimizations (when I have a faster machine) +-- +-- maybe redo the lot some way (more context specific) + +--[[ldx-- +<p>This module is a bit more split up that I'd like but since we also want to test +with plain <l n='tex'/> it has to be so. This module is part of <l n='context'/> +and discussion about improvements and functionality mostly happens on the +<l n='context'/> mailing list.</p> + +<p>The specification of OpenType is kind of vague. Apart from a lack of a proper +free specifications there's also the problem that Microsoft and Adobe +may have their own interpretation of how and in what order to apply features. +In general the Microsoft website has more detailed specifications and is a +better reference. There is also some information in the FontForge help files.</p> + +<p>Because there is so much possible, fonts might contain bugs and/or be made to +work with certain rederers. These may evolve over time which may have the side +effect that suddenly fonts behave differently.</p> + +<p>After a lot of experiments (mostly by Taco, me and Idris) we're now at yet another +implementation. Of course all errors are mine and of course the code can be +improved. There are quite some optimizations going on here and processing speed +is currently acceptable. Not all functions are implemented yet, often because I +lack the fonts for testing. Many scripts are not yet supported either, but I will +look into them as soon as <l n='context'/> users ask for it.</p> + +<p>Because there are different interpretations possible, I will extend the code +with more (configureable) variants. I can also add hooks for users so that they can +write their own extensions.</p> + +<p>Glyphs are indexed not by unicode but in their own way. This is because there is no +relationship with unicode at all, apart from the fact that a font might cover certain +ranges of characters. One character can have multiple shapes. However, at the +<l n='tex'/> end we use unicode so and all extra glyphs are mapped into a private +space. This is needed because we need to access them and <l n='tex'/> has to include +then in the output eventually.</p> + +<p>The raw table as it coms from <l n='fontforge'/> gets reorganized in to fit out needs. +In <l n='context'/> that table is packed (similar tables are shared) and cached on disk +so that successive runs can use the optimized table (after loading the table is +unpacked). The flattening code used later is a prelude to an even more compact table +format (and as such it keeps evolving).</p> + +<p>This module is sparsely documented because it is a moving target. The table format +of the reader changes and we experiment a lot with different methods for supporting +features.</p> + +<p>As with the <l n='afm'/> code, we may decide to store more information in the +<l n='otf'/> table.</p> + +<p>Incrementing the version number will force a re-cache. We jump the number by one +when there's a fix in the <l n='fontforge'/> library or <l n='lua'/> code that +results in different tables.</p> +--ldx]]-- + +-- action handler chainproc chainmore comment +-- +-- gsub_single ok ok ok +-- gsub_multiple ok ok not implemented yet +-- gsub_alternate ok ok not implemented yet +-- gsub_ligature ok ok ok +-- gsub_context ok -- +-- gsub_contextchain ok -- +-- gsub_reversecontextchain ok -- +-- chainsub -- ok +-- reversesub -- ok +-- gpos_mark2base ok ok +-- gpos_mark2ligature ok ok +-- gpos_mark2mark ok ok +-- gpos_cursive ok untested +-- gpos_single ok ok +-- gpos_pair ok ok +-- gpos_context ok -- +-- gpos_contextchain ok -- +-- +-- todo: contextpos and contextsub and class stuff +-- +-- actions: +-- +-- handler : actions triggered by lookup +-- chainproc : actions triggered by contextual lookup +-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij) +-- +-- remark: the 'not implemented yet' variants will be done when we have fonts that use them +-- remark: we need to check what to do with discretionaries + +-- We used to have independent hashes for lookups but as the tags are unique +-- we now use only one hash. If needed we can have multiple again but in that +-- case I will probably prefix (i.e. rename) the lookups in the cached font file. + +-- Todo: make plugin feature that operates on char/glyphnode arrays + +local concat, insert, remove = table.concat, table.insert, table.remove +local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip +local type, next, tonumber, tostring = type, next, tonumber, tostring +local lpegmatch = lpeg.match +local random = math.random +local formatters = string.formatters + +local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes + +local registertracker = trackers.register + +local fonts = fonts +local otf = fonts.handlers.otf + +local trace_lookups = false registertracker("otf.lookups", function(v) trace_lookups = v end) +local trace_singles = false registertracker("otf.singles", function(v) trace_singles = v end) +local trace_multiples = false registertracker("otf.multiples", function(v) trace_multiples = v end) +local trace_alternatives = false registertracker("otf.alternatives", function(v) trace_alternatives = v end) +local trace_ligatures = false registertracker("otf.ligatures", function(v) trace_ligatures = v end) +local trace_contexts = false registertracker("otf.contexts", function(v) trace_contexts = v end) +local trace_marks = false registertracker("otf.marks", function(v) trace_marks = v end) +local trace_kerns = false registertracker("otf.kerns", function(v) trace_kerns = v end) +local trace_cursive = false registertracker("otf.cursive", function(v) trace_cursive = v end) +local trace_preparing = false registertracker("otf.preparing", function(v) trace_preparing = v end) +local trace_bugs = false registertracker("otf.bugs", function(v) trace_bugs = v end) +local trace_details = false registertracker("otf.details", function(v) trace_details = v end) +local trace_applied = false registertracker("otf.applied", function(v) trace_applied = v end) +local trace_steps = false registertracker("otf.steps", function(v) trace_steps = v end) +local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) +local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) + +local report_direct = logs.reporter("fonts","otf direct") +local report_subchain = logs.reporter("fonts","otf subchain") +local report_chain = logs.reporter("fonts","otf chain") +local report_process = logs.reporter("fonts","otf process") +local report_prepare = logs.reporter("fonts","otf prepare") +local report_warning = logs.reporter("fonts","otf warning") + +registertracker("otf.verbose_chain", function(v) otf.setcontextchain(v and "verbose") end) +registertracker("otf.normal_chain", function(v) otf.setcontextchain(v and "normal") end) + +registertracker("otf.replacements", "otf.singles,otf.multiples,otf.alternatives,otf.ligatures") +registertracker("otf.positions","otf.marks,otf.kerns,otf.cursive") +registertracker("otf.actions","otf.replacements,otf.positions") +registertracker("otf.injections","nodes.injections") + +registertracker("*otf.sample","otf.steps,otf.actions,otf.analyzing") + +local insert_node_after = node.insert_after +local delete_node = nodes.delete +local copy_node = node.copy +local find_node_tail = node.tail or node.slide +local flush_node_list = node.flush_list +local end_of_math = node.end_of_math + +local setmetatableindex = table.setmetatableindex + +local zwnj = 0x200C +local zwj = 0x200D +local wildcard = "*" +local default = "dflt" + +local nodecodes = nodes.nodecodes +local whatcodes = nodes.whatcodes +local glyphcodes = nodes.glyphcodes +local disccodes = nodes.disccodes + +local glyph_code = nodecodes.glyph +local glue_code = nodecodes.glue +local disc_code = nodecodes.disc +local whatsit_code = nodecodes.whatsit +local math_code = nodecodes.math + +local dir_code = whatcodes.dir +local localpar_code = whatcodes.localpar + +local discretionary_code = disccodes.discretionary + +local ligature_code = glyphcodes.ligature + +local privateattribute = attributes.private + +-- Something is messed up: we have two mark / ligature indices, one at the injection +-- end and one here ... this is bases in KE's patches but there is something fishy +-- there as I'm pretty sure that for husayni we need some connection (as it's much +-- more complex than an average font) but I need proper examples of all cases, not +-- of only some. + +local a_state = privateattribute('state') +local a_markbase = privateattribute('markbase') +local a_markmark = privateattribute('markmark') +local a_markdone = privateattribute('markdone') -- assigned at the injection end +local a_cursbase = privateattribute('cursbase') +local a_curscurs = privateattribute('curscurs') +local a_cursdone = privateattribute('cursdone') +local a_kernpair = privateattribute('kernpair') +local a_ligacomp = privateattribute('ligacomp') -- assigned here (ideally it should be combined) + +local injections = nodes.injections +local setmark = injections.setmark +local setcursive = injections.setcursive +local setkern = injections.setkern +local setpair = injections.setpair + +local markonce = true +local cursonce = true +local kernonce = true + +local fonthashes = fonts.hashes +local fontdata = fonthashes.identifiers + +local otffeatures = fonts.constructors.newfeatures("otf") +local registerotffeature = otffeatures.register + +local onetimemessage = fonts.loggers.onetimemessage or function() end + +otf.defaultnodealternate = "none" -- first last + +-- we share some vars here, after all, we have no nested lookups and less code + +local tfmdata = false +local characters = false +local descriptions = false +local resources = false +local marks = false +local currentfont = false +local lookuptable = false +local anchorlookups = false +local lookuptypes = false +local handlers = { } +local rlmode = 0 +local featurevalue = false + +-- head is always a whatsit so we can safely assume that head is not changed + +-- we use this for special testing and documentation + +local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end +local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end +local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end + +local function logprocess(...) + if trace_steps then + registermessage(...) + end + report_direct(...) +end + +local function logwarning(...) + report_direct(...) +end + +local f_unicode = formatters["%U"] +local f_uniname = formatters["%U (%s)"] +local f_unilist = formatters["% t (% t)"] + +local function gref(n) -- currently the same as in font-otb + if type(n) == "number" then + local description = descriptions[n] + local name = description and description.name + if name then + return f_uniname(n,name) + else + return f_unicode(n) + end + elseif n then + local num, nam = { }, { } + for i=1,#n do + local ni = n[i] + if tonumber(ni) then -- later we will start at 2 + local di = descriptions[ni] + num[i] = f_unicode(ni) + nam[i] = di and di.name or "-" + end + end + return f_unilist(num,nam) + else + return "<error in node mode tracing>" + end +end + +local function cref(kind,chainname,chainlookupname,lookupname,index) -- not in the mood to alias f_ + if index then + return formatters["feature %a, chain %a, sub %a, lookup %a, index %a"](kind,chainname,chainlookupname,lookupname,index) + elseif lookupname then + return formatters["feature %a, chain %a, sub %a, lookup %a"](kind,chainname,chainlookupname,lookupname) + elseif chainlookupname then + return formatters["feature %a, chain %a, sub %a"](kind,chainname,chainlookupname) + elseif chainname then + return formatters["feature %a, chain %a"](kind,chainname) + else + return formatters["feature %a"](kind) + end +end + +local function pref(kind,lookupname) + return formatters["feature %a, lookup %a"](kind,lookupname) +end + +-- We can assume that languages that use marks are not hyphenated. We can also assume +-- that at most one discretionary is present. + +-- We do need components in funny kerning mode but maybe I can better reconstruct then +-- as we do have the font components info available; removing components makes the +-- previous code much simpler. Also, later on copying and freeing becomes easier. +-- However, for arabic we need to keep them around for the sake of mark placement +-- and indices. + +local function copy_glyph(g) -- next and prev are untouched ! + local components = g.components + if components then + g.components = nil + local n = copy_node(g) + g.components = components + return n + else + return copy_node(g) + end +end + +-- start is a mark and we need to keep that one + +local function markstoligature(kind,lookupname,head,start,stop,char) + if start == stop and start.char == char then + return head, start + else + local prev = start.prev + local next = stop.next + start.prev = nil + stop.next = nil + local base = copy_glyph(start) + if head == start then + head = base + end + base.char = char + base.subtype = ligature_code + base.components = start + if prev then + prev.next = base + end + if next then + next.prev = base + end + base.next = next + base.prev = prev + return head, base + end +end + +-- The next code is somewhat complicated by the fact that some fonts can have ligatures made +-- from ligatures that themselves have marks. This was identified by Kai in for instance +-- arabtype: KAF LAM SHADDA ALEF FATHA (0x0643 0x0644 0x0651 0x0627 0x064E). This becomes +-- KAF LAM-ALEF with a SHADDA on the first and a FATHA op de second component. In a next +-- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the +-- third component. + +local function getcomponentindex(start) + if start.id ~= glyph_code then + return 0 + elseif start.subtype == ligature_code then + local i = 0 + local components = start.components + while components do + i = i + getcomponentindex(components) + components = components.next + end + return i + elseif not marks[start.char] then + return 1 + else + return 0 + end +end + +-- eventually we will do positioning in an other way (needs addional w/h/d fields) + +local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head + if start == stop and start.char == char then + start.char = char + return head, start + end + local prev = start.prev + local next = stop.next + start.prev = nil + stop.next = nil + local base = copy_glyph(start) + if start == head then + head = base + end + base.char = char + base.subtype = ligature_code + base.components = start -- start can have components + if prev then + prev.next = base + end + if next then + next.prev = base + end + base.next = next + base.prev = prev + if not discfound then + local deletemarks = markflag ~= "mark" + local components = start + local baseindex = 0 + local componentindex = 0 + local head = base + local current = base + -- first we loop over the glyphs in start .. stop + while start do + local char = start.char + if not marks[char] then + baseindex = baseindex + componentindex + componentindex = getcomponentindex(start) + elseif not deletemarks then -- quite fishy + start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex) + if trace_marks then + logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp]) + end + head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components + elseif trace_marks then + logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char)) + end + start = start.next + end + -- we can have one accent as part of a lookup and another following + -- local start = components -- was wrong (component scanning was introduced when more complex ligs in devanagari was added) + local start = current.next + while start and start.id == glyph_code do + local char = start.char + if marks[char] then + start[a_ligacomp] = baseindex + (start[a_ligacomp] or componentindex) + if trace_marks then + logwarning("%s: set mark %s, gets index %s",pref(kind,lookupname),gref(char),start[a_ligacomp]) + end + else + break + end + start = start.next + end + end + return head, base +end + +function handlers.gsub_single(head,start,kind,lookupname,replacement) + if trace_singles then + logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement)) + end + start.char = replacement + return head, start, true +end + +local function get_alternative_glyph(start,alternatives,value,trace_alternatives) + local n = #alternatives + if value == "random" then + local r = random(1,n) + return alternatives[r], trace_alternatives and formatters["value %a, taking %a"](value,r) + elseif value == "first" then + return alternatives[1], trace_alternatives and formatters["value %a, taking %a"](value,1) + elseif value == "last" then + return alternatives[n], trace_alternatives and formatters["value %a, taking %a"](value,n) + else + value = tonumber(value) + if type(value) ~= "number" then + return alternatives[1], trace_alternatives and formatters["invalid value %s, taking %a"](value,1) + elseif value > n then + local defaultalt = otf.defaultnodealternate + if defaultalt == "first" then + return alternatives[n], trace_alternatives and formatters["invalid value %s, taking %a"](value,1) + elseif defaultalt == "last" then + return alternatives[1], trace_alternatives and formatters["invalid value %s, taking %a"](value,n) + else + return false, trace_alternatives and formatters["invalid value %a, %s"](value,"out of range") + end + elseif value == 0 then + return start.char, trace_alternatives and formatters["invalid value %a, %s"](value,"no change") + elseif value < 1 then + return alternatives[1], trace_alternatives and formatters["invalid value %a, taking %a"](value,1) + else + return alternatives[value], trace_alternatives and formatters["value %a, taking %a"](value,value) + end + end +end + +local function multiple_glyphs(head,start,multiple,ignoremarks) + local nofmultiples = #multiple + if nofmultiples > 0 then + start.char = multiple[1] + if nofmultiples > 1 then + local sn = start.next + for k=2,nofmultiples do -- todo: use insert_node +-- untested: +-- +-- while ignoremarks and marks[sn.char] then +-- local sn = sn.next +-- end + local n = copy_node(start) -- ignore components + n.char = multiple[k] + n.next = sn + n.prev = start + if sn then + sn.prev = n + end + start.next = n + start = n + end + end + return head, start, true + else + if trace_multiples then + logprocess("no multiple for %s",gref(start.char)) + end + return head, start, false + end +end + +function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence) + local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue + local choice, comment = get_alternative_glyph(start,alternative,value,trace_alternatives) + if choice then + if trace_alternatives then + logprocess("%s: replacing %s by alternative %a to %s, %s",pref(kind,lookupname),gref(start.char),choice,gref(choice),comment) + end + start.char = choice + else + if trace_alternatives then + logwarning("%s: no variant %a for %s, %s",pref(kind,lookupname),value,gref(start.char),comment) + end + end + return head, start, true +end + +function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence) + if trace_multiples then + logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple)) + end + return multiple_glyphs(head,start,multiple,sequence.flags[1]) +end + +function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) + local s, stop, discfound = start.next, nil, false + local startchar = start.char + if marks[startchar] then + while s do + local id = s.id + if id == glyph_code and s.font == currentfont and s.subtype<256 then + local lg = ligature[s.char] + if lg then + stop = s + ligature = lg + s = s.next + else + break + end + else + break + end + end + if stop then + local lig = ligature.ligature + if lig then + if trace_ligatures then + local stopchar = stop.char + head, start = markstoligature(kind,lookupname,head,start,stop,lig) + logprocess("%s: replacing %s upto %s by ligature %s case 1",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char)) + else + head, start = markstoligature(kind,lookupname,head,start,stop,lig) + end + return head, start, true + else + -- ok, goto next lookup + end + end + else + local skipmark = sequence.flags[1] + while s do + local id = s.id + if id == glyph_code and s.subtype<256 then + if s.font == currentfont then + local char = s.char + if skipmark and marks[char] then + s = s.next + else + local lg = ligature[char] + if lg then + stop = s + ligature = lg + s = s.next + else + break + end + end + else + break + end + elseif id == disc_code then + discfound = true + s = s.next + else + break + end + end + local lig = ligature.ligature + if lig then + if stop then + if trace_ligatures then + local stopchar = stop.char + head, start = toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound) + logprocess("%s: replacing %s upto %s by ligature %s case 2",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char)) + else + head, start = toligature(kind,lookupname,head,start,stop,lig,skipmark,discfound) + end + return head, start, true + else + -- weird but happens (in some arabic font) + start.char = lig + if trace_ligatures then + logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) + end + return head, start, true + end + else + -- weird but happens + end + end + return head, start, false +end + +--[[ldx-- +<p>We get hits on a mark, but we're not sure if the it has to be applied so +we need to explicitly test for basechar, baselig and basemark entries.</p> +--ldx]]-- + +function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence) + local markchar = start.char + if marks[markchar] then + local base = start.prev -- [glyph] [start=mark] + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + local basechar = base.char + if marks[basechar] then + while true do + base = base.prev + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + basechar = base.char + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar)) + end + return head, start, false + end + end + end + local baseanchors = descriptions[basechar] + if baseanchors then + baseanchors = baseanchors.anchors + end + if baseanchors then + local baseanchors = baseanchors['basechar'] + if baseanchors then + local al = anchorlookups[lookupname] + for anchor,ba in next, baseanchors do + if al[anchor] then + local ma = markanchors[anchor] + if ma then + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", + pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true + end + end + end + if trace_bugs then + logwarning("%s, no matching anchors for mark %s and base %s",pref(kind,lookupname),gref(markchar),gref(basechar)) + end + end + elseif trace_bugs then + -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) + onetimemessage(currentfont,basechar,"no base anchors",report_fonts) + end + elseif trace_bugs then + logwarning("%s: prev node is no char",pref(kind,lookupname)) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) + end + return head, start, false +end + +function handlers.gpos_mark2ligature(head,start,kind,lookupname,markanchors,sequence) + -- check chainpos variant + local markchar = start.char + if marks[markchar] then + local base = start.prev -- [glyph] [optional marks] [start=mark] + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + local basechar = base.char + if marks[basechar] then + while true do + base = base.prev + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + basechar = base.char + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar)) + end + return head, start, false + end + end + end + local index = start[a_ligacomp] + local baseanchors = descriptions[basechar] + if baseanchors then + baseanchors = baseanchors.anchors + if baseanchors then + local baseanchors = baseanchors['baselig'] + if baseanchors then + local al = anchorlookups[lookupname] + for anchor, ba in next, baseanchors do + if al[anchor] then + local ma = markanchors[anchor] + if ma then + ba = ba[index] + if ba then + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index + if trace_marks then + logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", + pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy) + end + return head, start, true + else + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and baselig %s with index %a",pref(kind,lookupname),gref(markchar),gref(basechar),index) + end + end + end + end + end + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and baselig %s",pref(kind,lookupname),gref(markchar),gref(basechar)) + end + end + end + elseif trace_bugs then + -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) + onetimemessage(currentfont,basechar,"no base anchors",report_fonts) + end + elseif trace_bugs then + logwarning("%s: prev node is no char",pref(kind,lookupname)) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) + end + return head, start, false +end + +function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence) + local markchar = start.char + if marks[markchar] then + local base = start.prev -- [glyph] [basemark] [start=mark] + local slc = start[a_ligacomp] + if slc then -- a rather messy loop ... needs checking with husayni + while base do + local blc = base[a_ligacomp] + if blc and blc ~= slc then + base = base.prev + else + break + end + end + end + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go + local basechar = base.char + local baseanchors = descriptions[basechar] + if baseanchors then + baseanchors = baseanchors.anchors + if baseanchors then + baseanchors = baseanchors['basemark'] + if baseanchors then + local al = anchorlookups[lookupname] + for anchor,ba in next, baseanchors do + if al[anchor] then + local ma = markanchors[anchor] + if ma then + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", + pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true + end + end + end + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar)) + end + end + end + elseif trace_bugs then + -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(basechar)) + onetimemessage(currentfont,basechar,"no base anchors",report_fonts) + end + elseif trace_bugs then + logwarning("%s: prev node is no mark",pref(kind,lookupname)) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) + end + return head, start, false +end + +function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) -- to be checked + local alreadydone = cursonce and start[a_cursbase] + if not alreadydone then + local done = false + local startchar = start.char + if marks[startchar] then + if trace_cursive then + logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar)) + end + else + local nxt = start.next + while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do + local nextchar = nxt.char + if marks[nextchar] then + -- should not happen (maybe warning) + nxt = nxt.next + else + local entryanchors = descriptions[nextchar] + if entryanchors then + entryanchors = entryanchors.anchors + if entryanchors then + entryanchors = entryanchors['centry'] + if entryanchors then + local al = anchorlookups[lookupname] + for anchor, entry in next, entryanchors do + if al[anchor] then + local exit = exitanchors[anchor] + if exit then + local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) + if trace_cursive then + logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) + end + done = true + break + end + end + end + end + end + elseif trace_bugs then + -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar)) + onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) + end + break + end + end + end + return head, start, done + else + if trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone) + end + return head, start, false + end +end + +function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence) + local startchar = start.char + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) + end + return head, start, false +end + +function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) + -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too + -- todo: kerns in components of ligatures + local snext = start.next + if not snext then + return head, start, false + else + local prev, done = start, false + local factor = tfmdata.parameters.factor + local lookuptype = lookuptypes[lookupname] + while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do + local nextchar = snext.char + local krn = kerns[nextchar] + if not krn and marks[nextchar] then + prev = snext + snext = snext.next + else + if not krn then + -- skip + elseif type(krn) == "table" then + if lookuptype == "pair" then -- probably not needed + local a, b = krn[2], krn[3] + if a and #a > 0 then + local startchar = start.char + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) + if trace_kerns then + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b and #b > 0 then + local startchar = start.char + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) + if trace_kerns then + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + else -- wrong ... position has different entries + report_process("%s: check this out (old kern stuff)",pref(kind,lookupname)) + -- local a, b = krn[2], krn[6] + -- if a and a ~= 0 then + -- local k = setkern(snext,factor,rlmode,a) + -- if trace_kerns then + -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar)) + -- end + -- end + -- if b and b ~= 0 then + -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor) + -- end + end + done = true + elseif krn ~= 0 then + local k = setkern(snext,factor,rlmode,krn) + if trace_kerns then + logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar)) + end + done = true + end + break + end + end + return head, start, done + end +end + +--[[ldx-- +<p>I will implement multiple chain replacements once I run into a font that uses +it. It's not that complex to handle.</p> +--ldx]]-- + +local chainmores = { } +local chainprocs = { } + +local function logprocess(...) + if trace_steps then + registermessage(...) + end + report_subchain(...) +end + +local logwarning = report_subchain + +local function logprocess(...) + if trace_steps then + registermessage(...) + end + report_chain(...) +end + +local logwarning = report_chain + +-- We could share functions but that would lead to extra function calls with many +-- arguments, redundant tests and confusing messages. + +function chainprocs.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname) + logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname)) + return head, start, false +end + +function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n) + logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname)) + return head, start, false +end + +-- The reversesub is a special case, which is why we need to store the replacements +-- in a bit weird way. There is no lookup and the replacement comes from the lookup +-- itself. It is meant mostly for dealing with Urdu. + +function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements) + local char = start.char + local replacement = replacements[char] + if replacement then + if trace_singles then + logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement)) + end + start.char = replacement + return head, start, true + else + return head, start, false + end +end + +--[[ldx-- +<p>This chain stuff is somewhat tricky since we can have a sequence of actions to be +applied: single, alternate, multiple or ligature where ligature can be an invalid +one in the sense that it will replace multiple by one but not neccessary one that +looks like the combination (i.e. it is the counterpart of multiple then). For +example, the following is valid:</p> + +<typing> +<line>xxxabcdexxx [single a->A][multiple b->BCD][ligature cde->E] xxxABCDExxx</line> +</typing> + +<p>Therefore we we don't really do the replacement here already unless we have the +single lookup case. The efficiency of the replacements can be improved by deleting +as less as needed but that would also make the code even more messy.</p> +--ldx]]-- + +-- local function delete_till_stop(head,start,stop,ignoremarks) -- keeps start +-- local n = 1 +-- if start == stop then +-- -- done +-- elseif ignoremarks then +-- repeat -- start x x m x x stop => start m +-- local next = start.next +-- if not marks[next.char] then +-- local components = next.components +-- if components then -- probably not needed +-- flush_node_list(components) +-- end +-- head = delete_node(head,next) +-- end +-- n = n + 1 +-- until next == stop +-- else -- start x x x stop => start +-- repeat +-- local next = start.next +-- local components = next.components +-- if components then -- probably not needed +-- flush_node_list(components) +-- end +-- head = delete_node(head,next) +-- n = n + 1 +-- until next == stop +-- end +-- return head, n +-- end + +--[[ldx-- +<p>Here we replace start by a single variant, First we delete the rest of the +match.</p> +--ldx]]-- + +function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex) + -- todo: marks ? + local current = start + local subtables = currentlookup.subtables + if #subtables > 1 then + logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," ")) + end + while current do + if current.id == glyph_code then + local currentchar = current.char + local lookupname = subtables[1] -- only 1 + local replacement = lookuphash[lookupname] + if not replacement then + if trace_bugs then + logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex)) + end + else + replacement = replacement[currentchar] + if not replacement or replacement == "" then + if trace_bugs then + logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar)) + end + else + if trace_singles then + logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement)) + end + current.char = replacement + end + end + return head, start, true + elseif current == stop then + break + else + current = current.next + end + end + return head, start, false +end + +chainmores.gsub_single = chainprocs.gsub_single + +--[[ldx-- +<p>Here we replace start by a sequence of new glyphs. First we delete the rest of +the match.</p> +--ldx]]-- + +function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) + -- local head, n = delete_till_stop(head,start,stop) + local startchar = start.char + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local replacements = lookuphash[lookupname] + if not replacements then + if trace_bugs then + logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname)) + end + else + replacements = replacements[startchar] + if not replacements or replacement == "" then + if trace_bugs then + logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar)) + end + else + if trace_multiples then + logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements)) + end + return multiple_glyphs(head,start,replacements,currentlookup.flags[1]) + end + end + return head, start, false +end + +chainmores.gsub_multiple = chainprocs.gsub_multiple + +--[[ldx-- +<p>Here we replace start by new glyph. First we delete the rest of the match.</p> +--ldx]]-- + +-- char_1 mark_1 -> char_x mark_1 (ignore marks) +-- char_1 mark_1 -> char_x + +-- to be checked: do we always have just one glyph? +-- we can also have alternates for marks +-- marks come last anyway +-- are there cases where we need to delete the mark + +function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) + local current = start + local subtables = currentlookup.subtables + local value = featurevalue == true and tfmdata.shared.features[kind] or featurevalue + while current do + if current.id == glyph_code then -- is this check needed? + local currentchar = current.char + local lookupname = subtables[1] + local alternatives = lookuphash[lookupname] + if not alternatives then + if trace_bugs then + logwarning("%s: no alternative hit",cref(kind,chainname,chainlookupname,lookupname)) + end + else + alternatives = alternatives[currentchar] + if alternatives then + local choice, comment = get_alternative_glyph(current,alternatives,value,trace_alternatives) + if choice then + if trace_alternatives then + logprocess("%s: replacing %s by alternative %a to %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(char),choice,gref(choice),comment) + end + start.char = choice + else + if trace_alternatives then + logwarning("%s: no variant %a for %s, %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(char),comment) + end + end + elseif trace_bugs then + logwarning("%s: no alternative for %s, %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar),comment) + end + end + return head, start, true + elseif current == stop then + break + else + current = current.next + end + end + return head, start, false +end + +chainmores.gsub_alternate = chainprocs.gsub_alternate + +--[[ldx-- +<p>When we replace ligatures we use a helper that handles the marks. I might change +this function (move code inline and handle the marks by a separate function). We +assume rather stupid ligatures (no complex disc nodes).</p> +--ldx]]-- + +function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex) + local startchar = start.char + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local ligatures = lookuphash[lookupname] + if not ligatures then + if trace_bugs then + logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex)) + end + else + ligatures = ligatures[startchar] + if not ligatures then + if trace_bugs then + logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) + end + else + local s = start.next + local discfound = false + local last = stop + local nofreplacements = 0 + local skipmark = currentlookup.flags[1] + while s do + local id = s.id + if id == disc_code then + s = s.next + discfound = true + else + local schar = s.char + if skipmark and marks[schar] then -- marks + s = s.next + else + local lg = ligatures[schar] + if lg then + ligatures, last, nofreplacements = lg, s, nofreplacements + 1 + if s == stop then + break + else + s = s.next + end + else + break + end + end + end + end + local l2 = ligatures.ligature + if l2 then + if chainindex then + stop = last + end + if trace_ligatures then + if start == stop then + logprocess("%s: replacing character %s by ligature %s case 3",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2)) + else + logprocess("%s: replacing character %s upto %s by ligature %s case 4",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2)) + end + end + head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound) + return head, start, true, nofreplacements + elseif trace_bugs then + if start == stop then + logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) + else + logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char)) + end + end + end + end + return head, start, false, 0 +end + +chainmores.gsub_ligature = chainprocs.gsub_ligature + +function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) + local markchar = start.char + if marks[markchar] then + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local markanchors = lookuphash[lookupname] + if markanchors then + markanchors = markanchors[markchar] + end + if markanchors then + local base = start.prev -- [glyph] [start=mark] + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + local basechar = base.char + if marks[basechar] then + while true do + base = base.prev + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + basechar = base.char + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar)) + end + return head, start, false + end + end + end + local baseanchors = descriptions[basechar].anchors + if baseanchors then + local baseanchors = baseanchors['basechar'] + if baseanchors then + local al = anchorlookups[lookupname] + for anchor,ba in next, baseanchors do + if al[anchor] then + local ma = markanchors[anchor] + if ma then + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%p,%p)", + cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true + end + end + end + if trace_bugs then + logwarning("%s, no matching anchors for mark %s and base %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar)) + end + end + end + elseif trace_bugs then + logwarning("%s: prev node is no char",cref(kind,chainname,chainlookupname,lookupname)) + end + elseif trace_bugs then + logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar)) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar)) + end + return head, start, false +end + +function chainprocs.gpos_mark2ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) + local markchar = start.char + if marks[markchar] then + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local markanchors = lookuphash[lookupname] + if markanchors then + markanchors = markanchors[markchar] + end + if markanchors then + local base = start.prev -- [glyph] [optional marks] [start=mark] + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + local basechar = base.char + if marks[basechar] then + while true do + base = base.prev + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then + basechar = base.char + if not marks[basechar] then + break + end + else + if trace_bugs then + logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar) + end + return head, start, false + end + end + end + -- todo: like marks a ligatures hash + local index = start[a_ligacomp] + local baseanchors = descriptions[basechar].anchors + if baseanchors then + local baseanchors = baseanchors['baselig'] + if baseanchors then + local al = anchorlookups[lookupname] + for anchor,ba in next, baseanchors do + if al[anchor] then + local ma = markanchors[anchor] + if ma then + ba = ba[index] + if ba then + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma) -- index + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%p,%p)", + cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) + end + return head, start, true + end + end + end + end + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and baselig %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar)) + end + end + end + elseif trace_bugs then + logwarning("feature %s, lookup %s: prev node is no char",kind,lookupname) + end + elseif trace_bugs then + logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar)) + end + elseif trace_bugs then + logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar)) + end + return head, start, false +end + +function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) + local markchar = start.char + if marks[markchar] then + -- local alreadydone = markonce and start[a_markmark] + -- if not alreadydone then + -- local markanchors = descriptions[markchar].anchors markanchors = markanchors and markanchors.mark + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local markanchors = lookuphash[lookupname] + if markanchors then + markanchors = markanchors[markchar] + end + if markanchors then + local base = start.prev -- [glyph] [basemark] [start=mark] + local slc = start[a_ligacomp] + if slc then -- a rather messy loop ... needs checking with husayni + while base do + local blc = base[a_ligacomp] + if blc and blc ~= slc then + base = base.prev + else + break + end + end + end + if base and base.id == glyph_code and base.font == currentfont and base.subtype<256 then -- subtype test can go + local basechar = base.char + local baseanchors = descriptions[basechar].anchors + if baseanchors then + baseanchors = baseanchors['basemark'] + if baseanchors then + local al = anchorlookups[lookupname] + for anchor,ba in next, baseanchors do + if al[anchor] then + local ma = markanchors[anchor] + if ma then + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,true) + if trace_marks then + logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", + cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) + end + return head, start, true + end + end + end + if trace_bugs then + logwarning("%s: no matching anchors for mark %s and basemark %s",gref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar)) + end + end + end + elseif trace_bugs then + logwarning("%s: prev node is no mark",cref(kind,chainname,chainlookupname,lookupname)) + end + 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_bugs then + logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar)) + end + return head, start, false +end + +function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) + local alreadydone = cursonce and start[a_cursbase] + if not alreadydone then + local startchar = start.char + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local exitanchors = lookuphash[lookupname] + if exitanchors then + exitanchors = exitanchors[startchar] + end + if exitanchors then + local done = false + if marks[startchar] then + if trace_cursive then + logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar)) + end + else + local nxt = start.next + while not done and nxt and nxt.id == glyph_code and nxt.font == currentfont and nxt.subtype<256 do + local nextchar = nxt.char + if marks[nextchar] then + -- should not happen (maybe warning) + nxt = nxt.next + else + local entryanchors = descriptions[nextchar] + if entryanchors then + entryanchors = entryanchors.anchors + if entryanchors then + entryanchors = entryanchors['centry'] + if entryanchors then + local al = anchorlookups[lookupname] + for anchor, entry in next, entryanchors do + if al[anchor] then + local exit = exitanchors[anchor] + if exit then + local dx, dy, bound = setcursive(start,nxt,tfmdata.parameters.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) + if trace_cursive then + logprocess("%s: moving %s to %s cursive (%p,%p) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) + end + done = true + break + end + end + end + end + end + elseif trace_bugs then + -- logwarning("%s: char %s is missing in font",pref(kind,lookupname),gref(startchar)) + onetimemessage(currentfont,startchar,"no entry anchors",report_fonts) + end + break + end + end + end + return head, start, done + else + if trace_cursive and trace_details then + logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone) + end + return head, start, false + end + end + return head, start, false +end + +function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) + -- untested .. needs checking for the new model + local startchar = start.char + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local kerns = lookuphash[lookupname] + if kerns then + kerns = kerns[startchar] -- needed ? + if kerns then + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) + end + end + end + return head, start, false +end + +chainmores.gpos_single = chainprocs.gpos_single -- okay? + +-- when machines become faster i will make a shared function + +function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) + local snext = start.next + if snext then + local startchar = start.char + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local kerns = lookuphash[lookupname] + if kerns then + kerns = kerns[startchar] + if kerns then + local lookuptype = lookuptypes[lookupname] + local prev, done = start, false + local factor = tfmdata.parameters.factor + while snext and snext.id == glyph_code and snext.font == currentfont and snext.subtype<256 do + local nextchar = snext.char + local krn = kerns[nextchar] + if not krn and marks[nextchar] then + prev = snext + snext = snext.next + else + if not krn then + -- skip + elseif type(krn) == "table" then + if lookuptype == "pair" then + local a, b = krn[2], krn[3] + if a and #a > 0 then + local startchar = start.char + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) + if trace_kerns then + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b and #b > 0 then + local startchar = start.char + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) + if trace_kerns then + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + else + report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname)) + local a, b = krn[2], krn[6] + if a and a ~= 0 then + local k = setkern(snext,factor,rlmode,a) + if trace_kerns then + logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar)) + end + end + if b and b ~= 0 then + logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor) + end + end + done = true + elseif krn ~= 0 then + local k = setkern(snext,factor,rlmode,krn) + if trace_kerns then + logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar)) + end + done = true + end + break + end + end + return head, start, done + end + end + end + return head, start, false +end + +chainmores.gpos_pair = chainprocs.gpos_pair -- okay? + +-- what pointer to return, spec says stop +-- to be discussed ... is bidi changer a space? +-- elseif char == zwnj and sequence[n][32] then -- brrr + +-- somehow l or f is global +-- we don't need to pass the currentcontext, saves a bit +-- make a slow variant then can be activated but with more tracing + +local function show_skip(kind,chainname,char,ck,class) + if ck[9] then + logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10]) + else + logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2]) + end +end + +local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash) + -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6] + local flags = sequence.flags + local done = false + local skipmark = flags[1] + local skipligature = flags[2] + local skipbase = flags[3] + local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !) + local markclass = sequence.markclass -- todo, first we need a proper test + local skipped = false + for k=1,#contexts do + local match = true + local current = start + local last = start + local ck = contexts[k] + local seq = ck[3] + local s = #seq + -- f..l = mid string + if s == 1 then + -- never happens + match = current.id == glyph_code and current.font == currentfont and current.subtype<256 and seq[1][current.char] + else + -- maybe we need a better space check (maybe check for glue or category or combination) + -- we cannot optimize for n=2 because there can be disc nodes + local f, l = ck[4], ck[5] + -- current match + if f == 1 and f == l then -- current only + -- already a hit + -- match = true + else -- before/current/after | before/current | current/after + -- no need to test first hit (to be optimized) + if f == l then -- new, else last out of sync (f is > 1) + -- match = true + else + local n = f + 1 + last = last.next + while n <= l do + if last then + local id = last.id + if id == glyph_code then + if last.font == currentfont and last.subtype<256 then + local char = last.char + local ccd = descriptions[char] + if ccd then + local class = ccd.class + if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then + skipped = true + if trace_skips then + show_skip(kind,chainname,char,ck,class) + end + last = last.next + elseif seq[n][char] then + if n < l then + last = last.next + end + n = n + 1 + else + match = false + break + end + else + match = false + break + end + else + match = false + break + end + elseif id == disc_code then + last = last.next + else + match = false + break + end + else + match = false + break + end + end + end + end + -- before + if match and f > 1 then + local prev = start.prev + if prev then + local n = f-1 + while n >= 1 do + if prev then + local id = prev.id + if id == glyph_code then + if prev.font == currentfont and prev.subtype<256 then -- normal char + local char = prev.char + local ccd = descriptions[char] + if ccd then + local class = ccd.class + if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then + skipped = true + if trace_skips then + show_skip(kind,chainname,char,ck,class) + end + elseif seq[n][char] then + n = n -1 + else + match = false + break + end + else + match = false + break + end + else + match = false + break + end + elseif id == disc_code then + -- skip 'm + elseif seq[n][32] then + n = n -1 + else + match = false + break + end + prev = prev.prev + elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces + n = n -1 + else + match = false + break + end + end + elseif f == 2 then + match = seq[1][32] + else + for n=f-1,1 do + if not seq[n][32] then + match = false + break + end + end + end + end + -- after + if match and s > l then + local current = last and last.next + if current then + -- removed optimization for s-l == 1, we have to deal with marks anyway + local n = l + 1 + while n <= s do + if current then + local id = current.id + if id == glyph_code then + if current.font == currentfont and current.subtype<256 then -- normal char + local char = current.char + local ccd = descriptions[char] + if ccd then + local class = ccd.class + if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then + skipped = true + if trace_skips then + show_skip(kind,chainname,char,ck,class) + end + elseif seq[n][char] then + n = n + 1 + else + match = false + break + end + else + match = false + break + end + else + match = false + break + end + elseif id == disc_code then + -- skip 'm + elseif seq[n][32] then -- brrr + n = n + 1 + else + match = false + break + end + current = current.next + elseif seq[n][32] then + n = n + 1 + else + match = false + break + end + end + elseif s-l == 1 then + match = seq[s][32] + else + for n=l+1,s do + if not seq[n][32] then + match = false + break + end + end + end + end + end + if match then + -- ck == currentcontext + if trace_contexts then + local rule, lookuptype, f, l = ck[1], ck[2], ck[4], ck[5] + local char = start.char + if ck[9] then + logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a, %a => %a", + cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10]) + else + logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %a", + cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype) + end + end + local chainlookups = ck[6] + if chainlookups then + local nofchainlookups = #chainlookups + -- we can speed this up if needed + if nofchainlookups == 1 then + local chainlookupname = chainlookups[1] + local chainlookup = lookuptable[chainlookupname] + if chainlookup then + local cp = chainprocs[chainlookup.type] + if cp then + local ok + head, start, ok = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + if ok then + done = true + end + else + logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) + end + else -- shouldn't happen + logprocess("%s is not yet supported",cref(kind,chainname,chainlookupname)) + end + else + local i = 1 + repeat + if skipped then + while true do + local char = start.char + local ccd = descriptions[char] + if ccd then + local class = ccd.class + if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then + start = start.next + else + break + end + else + break + end + end + end + local chainlookupname = chainlookups[i] + local chainlookup = lookuptable[chainlookupname] + if not chainlookup then + -- okay, n matches, < n replacements + i = i + 1 + else + local cp = chainmores[chainlookup.type] + if not cp then + -- actually an error + logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) + i = i + 1 + else + local ok, n + head, start, ok, n = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) + -- messy since last can be changed ! + if ok then + done = true + -- skip next one(s) if ligature + i = i + (n or 1) + else + i = i + 1 + end + end + end + if start then + start = start.next + else + -- weird + end + until i > nofchainlookups + end + else + local replacements = ck[7] + if replacements then + head, start, done = chainprocs.reversesub(head,start,last,kind,chainname,ck,lookuphash,replacements) -- sequence + else + done = true -- can be meant to be skipped + if trace_contexts then + logprocess("%s: skipping match",cref(kind,chainname)) + end + end + end + end + end + return head, start, done +end + +-- Because we want to keep this elsewhere (an because speed is less an issue) we +-- pass the font id so that the verbose variant can access the relevant helper tables. + +local verbose_handle_contextchain = function(font,...) + logwarning("no verbose handler installed, reverting to 'normal'") + otf.setcontextchain() + return normal_handle_contextchain(...) +end + +otf.chainhandlers = { + normal = normal_handle_contextchain, + verbose = verbose_handle_contextchain, +} + +function otf.setcontextchain(method) + if not method or method == "normal" or not otf.chainhandlers[method] then + if handlers.contextchain then -- no need for a message while making the format + logwarning("installing normal contextchain handler") + end + handlers.contextchain = normal_handle_contextchain + else + logwarning("installing contextchain handler %a",method) + local handler = otf.chainhandlers[method] + handlers.contextchain = function(...) + return handler(currentfont,...) -- hm, get rid of ... + end + end + handlers.gsub_context = handlers.contextchain + handlers.gsub_contextchain = handlers.contextchain + handlers.gsub_reversecontextchain = handlers.contextchain + handlers.gpos_contextchain = handlers.contextchain + handlers.gpos_context = handlers.contextchain +end + +otf.setcontextchain() + +local missing = { } -- we only report once + +local function logprocess(...) + if trace_steps then + registermessage(...) + end + report_process(...) +end + +local logwarning = report_process + +local function report_missing_cache(typ,lookup) + local f = missing[currentfont] if not f then f = { } missing[currentfont] = f end + local t = f[typ] if not t then t = { } f[typ] = t end + if not t[lookup] then + t[lookup] = true + logwarning("missing cache for lookup %a, type %a, font %a, name %a",lookup,typ,currentfont,tfmdata.properties.fullname) + end +end + +local resolved = { } -- we only resolve a font,script,language pair once + +-- todo: pass all these 'locals' in a table + +local lookuphashes = { } + +setmetatableindex(lookuphashes, function(t,font) + local lookuphash = fontdata[font].resources.lookuphash + if not lookuphash or not next(lookuphash) then + lookuphash = false + end + t[font] = lookuphash + return lookuphash +end) + +-- fonts.hashes.lookups = lookuphashes + +local autofeatures = fonts.analyzers.features -- was: constants + +local function initialize(sequence,script,language,enabled) + local features = sequence.features + if features then + for kind, scripts in next, features do + local valid = enabled[kind] + if valid then + local languages = scripts[script] or scripts[wildcard] + if languages and (languages[language] or languages[wildcard]) then + return { valid, autofeatures[kind] or false, sequence.chain or 0, kind, sequence } + end + end + end + end + return false +end + +function otf.dataset(tfmdata,font) -- generic variant, overloaded in context + local shared = tfmdata.shared + local properties = tfmdata.properties + local language = properties.language or "dflt" + local script = properties.script or "dflt" + local enabled = shared.features + local res = resolved[font] + if not res then + res = { } + resolved[font] = res + end + local rs = res[script] + if not rs then + rs = { } + res[script] = rs + end + local rl = rs[language] + if not rl then + rl = { + -- indexed but we can also add specific data by key + } + rs[language] = rl + local sequences = tfmdata.resources.sequences +-- setmetatableindex(rl, function(t,k) +-- if type(k) == "number" then +-- local v = enabled and initialize(sequences[k],script,language,enabled) +-- t[k] = v +-- return v +-- end +-- end) +for s=1,#sequences do + local v = enabled and initialize(sequences[s],script,language,enabled) + if v then + rl[#rl+1] = v + end +end + end + return rl +end + +-- elseif id == glue_code then +-- if p[5] then -- chain +-- local pc = pp[32] +-- if pc then +-- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4]) +-- if ok then +-- done = true +-- end +-- if start then start = start.next end +-- else +-- start = start.next +-- end +-- else +-- start = start.next +-- end + +-- there will be a new direction parser (pre-parsed etc) + +-- less bytecode: 290 -> 254 +-- +-- attr = attr or false +-- +-- local a = getattr(start,0) +-- if (a == attr and (not attribute or getattr(start,a_state) == attribute)) or (not attribute or getattr(start,a_state) == attribute) then +-- -- the action +-- end + +local function featuresprocessor(head,font,attr) + + local lookuphash = lookuphashes[font] -- we can also check sequences here + + if not lookuphash then + return head, false + end + + if trace_steps then + checkstep(head) + end + + tfmdata = fontdata[font] + descriptions = tfmdata.descriptions + characters = tfmdata.characters + resources = tfmdata.resources + + marks = resources.marks + anchorlookups = resources.lookup_to_anchor + lookuptable = resources.lookups + lookuptypes = resources.lookuptypes + + currentfont = font + rlmode = 0 + + local sequences = resources.sequences + local done = false + local datasets = otf.dataset(tfmdata,font,attr) + + local dirstack = { } -- could move outside function + + -- We could work on sub start-stop ranges instead but I wonder if there is that + -- much speed gain (experiments showed that it made not much sense) and we need + -- to keep track of directions anyway. Also at some point I want to play with + -- font interactions and then we do need the full sweeps. + + -- Keeping track of the headnode is needed for devanagari (I generalized it a bit + -- so that multiple cases are also covered.) + + for s=1,#datasets do + local dataset = datasets[s] + featurevalue = dataset[1] -- todo: pass to function instead of using a global + + local sequence = dataset[5] -- sequences[s] -- also dataset[5] + local rlparmode = 0 + local topstack = 0 + local success = false + local attribute = dataset[2] + local chain = dataset[3] -- sequence.chain or 0 + local typ = sequence.type + local subtables = sequence.subtables + if chain < 0 then + -- this is a limited case, no special treatments like 'init' etc + local handler = handlers[typ] + -- we need to get rid of this slide! probably no longer needed in latest luatex + local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo + while start do + local id = start.id + if id == glyph_code then + if start.font == font and start.subtype<256 then + local a = start[0] + if a then + a = a == attr + else + a = true + end + if a then + for i=1,#subtables do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[start.char] + if lookupmatch then + head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + if success then + break + end + end + else + report_missing_cache(typ,lookupname) + end + end + if start then start = start.prev end + else + start = start.prev + end + else + start = start.prev + end + else + start = start.prev + end + end + else + local handler = handlers[typ] + local ns = #subtables + local start = head -- local ? + rlmode = 0 -- to be checked ? + if ns == 1 then -- happens often + local lookupname = subtables[1] + local lookupcache = lookuphash[lookupname] + if not lookupcache then -- also check for empty cache + report_missing_cache(typ,lookupname) + else + + local function subrun(start) + -- mostly for gsub, gpos would demand a more clever approach + local head = start + local done = false + while start do + local id = start.id + if id == glyph_code and start.font == font and start.subtype <256 then + local a = start[0] + if a then + a = (a == attr) and (not attribute or start[a_state] == attribute) + else + a = not attribute or start[a_state] == attribute + end + if a then + local lookupmatch = lookupcache[start.char] + if lookupmatch then + -- sequence kan weg + local ok + head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + if ok then + done = true + end + end + if start then start = start.next end + else + start = start.next + end + else + start = start.next + end + end + if done then + success = true + return head + end + end + + local function kerndisc(disc) -- we can assume that prev and next are glyphs + local prev = disc.prev + local next = disc.next + if prev and next then + prev.next = next + -- next.prev = prev + local a = prev[0] + if a then + a = (a == attr) and (not attribute or prev[a_state] == attribute) + else + a = not attribute or prev[a_state] == attribute + end + if a then + local lookupmatch = lookupcache[prev.char] + if lookupmatch then + -- sequence kan weg + local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + if ok then + done = true + success = true + end + end + end + prev.next = disc + -- next.prev = disc + end + return next + end + + while start do + local id = start.id + if id == glyph_code then + if start.font == font and start.subtype<256 then + local a = start[0] + if a then + a = (a == attr) and (not attribute or start[a_state] == attribute) + else + a = not attribute or start[a_state] == attribute + end + if a then + local lookupmatch = lookupcache[start.char] + if lookupmatch then + -- sequence kan weg + local ok + head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + if ok then + success = true + end + end + if start then start = start.next end + else + start = start.next + end + else + start = start.next + end + elseif id == disc_code then + -- mostly for gsub + if start.subtype == discretionary_code then + local pre = start.pre + if pre then + local new = subrun(pre) + if new then start.pre = new end + end + local post = start.post + if post then + local new = subrun(post) + if new then start.post = new end + end + local replace = start.replace + if replace then + local new = subrun(replace) + if new then start.replace = new end + end +elseif typ == "gpos_single" or typ == "gpos_pair" then + kerndisc(start) + end + start = start.next + elseif id == whatsit_code then -- will be function + local subtype = start.subtype + if subtype == dir_code then + local dir = start.dir + if dir == "+TRT" or dir == "+TLT" then + topstack = topstack + 1 + dirstack[topstack] = dir + elseif dir == "-TRT" or dir == "-TLT" then + topstack = topstack - 1 + end + local newdir = dirstack[topstack] + if newdir == "+TRT" then + rlmode = -1 + elseif newdir == "+TLT" then + rlmode = 1 + else + rlmode = rlparmode + end + if trace_directions then + report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) + end + elseif subtype == localpar_code then + local dir = start.dir + if dir == "TRT" then + rlparmode = -1 + elseif dir == "TLT" then + rlparmode = 1 + else + rlparmode = 0 + end + -- one might wonder if the par dir should be looked at, so we might as well drop the next line + rlmode = rlparmode + if trace_directions then + report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) + end + end + start = start.next + elseif id == math_code then + start = end_of_math(start).next + else + start = start.next + end + end + end + else + + local function subrun(start) + -- mostly for gsub, gpos would demand a more clever approach + local head = start + local done = false + while start do + local id = start.id + if id == glyph_code and start.id == font and start.subtype <256 then + local a = start[0] + if a then + a = (a == attr) and (not attribute or start[a_state] == attribute) + else + a = not attribute or start[a_state] == attribute + end + if a then + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[start.char] + if lookupmatch then + -- we could move all code inline but that makes things even more unreadable + local ok + head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + if ok then + done = true + break + elseif not start then + -- don't ask why ... shouldn't happen + break + end + end + else + report_missing_cache(typ,lookupname) + end + end + if start then start = start.next end + else + start = start.next + end + else + start = start.next + end + end + if done then + success = true + return head + end + end + + local function kerndisc(disc) -- we can assume that prev and next are glyphs + local prev = disc.prev + local next = disc.next + if prev and next then + prev.next = next + -- next.prev = prev + local a = prev[0] + if a then + a = (a == attr) and (not attribute or prev[a_state] == attribute) + else + a = not attribute or prev[a_state] == attribute + end + if a then + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[prev.char] + if lookupmatch then + -- we could move all code inline but that makes things even more unreadable + local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + if ok then + done = true + break + end + end + else + report_missing_cache(typ,lookupname) + end + end + end + prev.next = disc + -- next.prev = disc + end + return next + end + + while start do + local id = start.id + if id == glyph_code then + if start.font == font and start.subtype<256 then + local a = start[0] + if a then + a = (a == attr) and (not attribute or start[a_state] == attribute) + else + a = not attribute or start[a_state] == attribute + end + if a then + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[start.char] + if lookupmatch then + -- we could move all code inline but that makes things even more unreadable + local ok + head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + if ok then + success = true + break + elseif not start then + -- don't ask why ... shouldn't happen + break + end + end + else + report_missing_cache(typ,lookupname) + end + end + if start then start = start.next end + else + start = start.next + end + else + start = start.next + end + elseif id == disc_code then + -- mostly for gsub + if start.subtype == discretionary_code then + local pre = start.pre + if pre then + local new = subrun(pre) + if new then start.pre = new end + end + local post = start.post + if post then + local new = subrun(post) + if new then start.post = new end + end + local replace = start.replace + if replace then + local new = subrun(replace) + if new then start.replace = new end + end +elseif typ == "gpos_single" or typ == "gpos_pair" then + kerndisc(start) + end + start = start.next + elseif id == whatsit_code then + local subtype = start.subtype + if subtype == dir_code then + local dir = start.dir + if dir == "+TRT" or dir == "+TLT" then + topstack = topstack + 1 + dirstack[topstack] = dir + elseif dir == "-TRT" or dir == "-TLT" then + topstack = topstack - 1 + end + local newdir = dirstack[topstack] + if newdir == "+TRT" then + rlmode = -1 + elseif newdir == "+TLT" then + rlmode = 1 + else + rlmode = rlparmode + end + if trace_directions then + report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) + end + elseif subtype == localpar_code then + local dir = start.dir + if dir == "TRT" then + rlparmode = -1 + elseif dir == "TLT" then + rlparmode = 1 + else + rlparmode = 0 + end + rlmode = rlparmode + if trace_directions then + report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) + end + end + start = start.next + elseif id == math_code then + start = end_of_math(start).next + else + start = start.next + end + end + end + end + if success then + done = true + end + if trace_steps then -- ? + registerstep(head) + end + end + return head, done +end + +local function generic(lookupdata,lookupname,unicode,lookuphash) + local target = lookuphash[lookupname] + if target then + target[unicode] = lookupdata + else + lookuphash[lookupname] = { [unicode] = lookupdata } + end +end + +local action = { + + substitution = generic, + multiple = generic, + alternate = generic, + position = generic, + + ligature = function(lookupdata,lookupname,unicode,lookuphash) + local target = lookuphash[lookupname] + if not target then + target = { } + lookuphash[lookupname] = target + end + for i=1,#lookupdata do + local li = lookupdata[i] + local tu = target[li] + if not tu then + tu = { } + target[li] = tu + end + target = tu + end + target.ligature = unicode + end, + + pair = function(lookupdata,lookupname,unicode,lookuphash) + local target = lookuphash[lookupname] + if not target then + target = { } + lookuphash[lookupname] = target + end + local others = target[unicode] + local paired = lookupdata[1] + if others then + others[paired] = lookupdata + else + others = { [paired] = lookupdata } + target[unicode] = others + end + end, + +} + +local function prepare_lookups(tfmdata) + + local rawdata = tfmdata.shared.rawdata + local resources = rawdata.resources + local lookuphash = resources.lookuphash + local anchor_to_lookup = resources.anchor_to_lookup + local lookup_to_anchor = resources.lookup_to_anchor + local lookuptypes = resources.lookuptypes + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + + -- we cannot free the entries in the descriptions as sometimes we access + -- then directly (for instance anchors) ... selectively freeing does save + -- much memory as it's only a reference to a table and the slot in the + -- description hash is not freed anyway + + for unicode, character in next, characters do -- we cannot loop over descriptions ! + + local description = descriptions[unicode] + + if description then + + local lookups = description.slookups + if lookups then + for lookupname, lookupdata in next, lookups do + action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash) + end + end + + local lookups = description.mlookups + if lookups then + for lookupname, lookuplist in next, lookups do + local lookuptype = lookuptypes[lookupname] + for l=1,#lookuplist do + local lookupdata = lookuplist[l] + action[lookuptype](lookupdata,lookupname,unicode,lookuphash) + end + end + end + + local list = description.kerns + if list then + for lookup, krn in next, list do -- ref to glyph, saves lookup + local target = lookuphash[lookup] + if target then + target[unicode] = krn + else + lookuphash[lookup] = { [unicode] = krn } + end + end + end + + local list = description.anchors + if list then + for typ, anchors in next, list do -- types + if typ == "mark" or typ == "cexit" then -- or entry? + for name, anchor in next, anchors do + local lookups = anchor_to_lookup[name] + if lookups then + for lookup, _ in next, lookups do + local target = lookuphash[lookup] + if target then + target[unicode] = anchors + else + lookuphash[lookup] = { [unicode] = anchors } + end + end + end + end + end + end + end + + end + + end + +end + +local function split(replacement,original) + local result = { } + for i=1,#replacement do + result[original[i]] = replacement[i] + end + return result +end + +local valid = { + coverage = { chainsub = true, chainpos = true, contextsub = true }, + reversecoverage = { reversesub = true }, + glyphs = { chainsub = true, chainpos = true }, +} + +local function prepare_contextchains(tfmdata) + local rawdata = tfmdata.shared.rawdata + local resources = rawdata.resources + local lookuphash = resources.lookuphash + local lookups = rawdata.lookups + if lookups then + for lookupname, lookupdata in next, rawdata.lookups do + local lookuptype = lookupdata.type + if lookuptype then + local rules = lookupdata.rules + if rules then + local format = lookupdata.format + local validformat = valid[format] + if not validformat then + report_prepare("unsupported format %a",format) + elseif not validformat[lookuptype] then + -- todo: dejavu-serif has one (but i need to see what use it has) + report_prepare("unsupported format %a, lookuptype %a, lookupname %a",format,lookuptype,lookupname) + else + local contexts = lookuphash[lookupname] + if not contexts then + contexts = { } + lookuphash[lookupname] = contexts + end + local t, nt = { }, 0 + for nofrules=1,#rules do + local rule = rules[nofrules] + local current = rule.current + local before = rule.before + local after = rule.after + local replacements = rule.replacements + local sequence = { } + local nofsequences = 0 + -- Eventually we can store start, stop and sequence in the cached file + -- but then less sharing takes place so best not do that without a lot + -- of profiling so let's forget about it. + if before then + for n=1,#before do + nofsequences = nofsequences + 1 + sequence[nofsequences] = before[n] + end + end + local start = nofsequences + 1 + for n=1,#current do + nofsequences = nofsequences + 1 + sequence[nofsequences] = current[n] + end + local stop = nofsequences + if after then + for n=1,#after do + nofsequences = nofsequences + 1 + sequence[nofsequences] = after[n] + end + end + if sequence[1] then + -- Replacements only happen with reverse lookups as they are single only. We + -- could pack them into current (replacement value instead of true) and then + -- use sequence[start] instead but it's somewhat ugly. + nt = nt + 1 + t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements } + for unic, _ in next, sequence[start] do + local cu = contexts[unic] + if not cu then + contexts[unic] = t + end + end + end + end + end + else + -- no rules + end + else + report_prepare("missing lookuptype for lookupname %a",lookupname) + end + end + end +end + +-- we can consider lookuphash == false (initialized but empty) vs lookuphash == table + +local function featuresinitializer(tfmdata,value) + if true then -- value then + -- beware we need to use the topmost properties table + local rawdata = tfmdata.shared.rawdata + local properties = rawdata.properties + if not properties.initialized then + local starttime = trace_preparing and os.clock() + local resources = rawdata.resources + resources.lookuphash = resources.lookuphash or { } + prepare_contextchains(tfmdata) + prepare_lookups(tfmdata) + properties.initialized = true + if trace_preparing then + report_prepare("preparation time is %0.3f seconds for %a",os.clock()-starttime,tfmdata.properties.fullname) + end + end + end +end + +registerotffeature { + name = "features", + description = "features", + default = true, + initializers = { + position = 1, + node = featuresinitializer, + }, + processors = { + node = featuresprocessor, + } +} + +-- This can be used for extra handlers, but should be used with care! + +otf.handlers = handlers diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-attributes.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-attributes.lua deleted file mode 100644 index c6130b4f781..00000000000 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-attributes.lua +++ /dev/null @@ -1,27 +0,0 @@ ------------------------------------------------------------------------ --- FILE: otfl-luat-att.lua --- USAGE: with old luaotfload --- DESCRIPTION: setting attributes abide luatexbase rules --- REQUIREMENTS: some old luatex --- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> --- CREATED: 2013-05-10 20:37:19+0200 ------------------------------------------------------------------------ --- - -if not modules then modules = { } end modules ['otfl-luat-att'] = { - version = math.pi/42, - comment = "companion to luaotfload.lua", - author = "Philipp Gesang", - copyright = "Luaotfload Development Team", - license = "GNU GPL v2" -} - -function attributes.private(name) - local attr = "otfl@" .. name - local number = luatexbase.attributes[attr] - if not number then - number = luatexbase.new_attribute(attr) - end - return number -end - diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-database.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-database.lua deleted file mode 100644 index b31fe885264..00000000000 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-database.lua +++ /dev/null @@ -1,724 +0,0 @@ -if not modules then modules = { } end modules ['font-nms'] = { - version = "old", - comment = "companion to luaotfload.lua", - author = "Khaled Hosny and Elie Roux", - copyright = "Luaotfload Development Team", - license = "GNU GPL v2" -} - -fonts = fonts or { } -fonts.names = fonts.names or { } - -local names = fonts.names -local names_dir = "luatex-cache/generic/names" -names.version = "old" -- not the same as in context -names.data = nil -names.path = { - basename = "otfl-names.lua", --- different from current - localdir = file.join(kpse.expand_var("$TEXMFVAR"), names_dir), - systemdir = file.join(kpse.expand_var("$TEXMFSYSVAR"), names_dir), -} - - -local splitpath, expandpath = file.split_path, kpse.expand_path -local glob, basename = dir.glob, file.basename -local upper, lower, format = string.upper, string.lower, string.format -local gsub, match, rpadd = string.gsub, string.match, string.rpadd -local gmatch, sub, find = string.gmatch, string.sub, string.find -local utfgsub = unicode.utf8.gsub - -local trace_short = false --tracing adapted to rebuilding of the database inside a document -local trace_search = false --trackers.register("names.search", function(v) trace_search = v end) -local trace_loading = false --trackers.register("names.loading", function(v) trace_loading = v end) - -local function sanitize(str) - if str then - return utfgsub(lower(str), "[^%a%d]", "") - else - return str -- nil - end -end - -local function fontnames_init() - return { - mappings = { }, - status = { }, - version = names.version, - } -end - -local function load_names() - local localpath = file.join(names.path.localdir, names.path.basename) - local systempath = file.join(names.path.systemdir, names.path.basename) - local kpsefound = kpse.find_file(names.path.basename) - local foundname - local data - if kpsefound and file.isreadable(kpsefound) then - data = dofile(kpsefound) - foundname = kpsefound - elseif file.isreadable(localpath) then - data = dofile(localpath) - foundname = localpath - elseif file.isreadable(systempath) then - data = dofile(systempath) - foundname = systempath - end - if data then - logs.info("Font names database loaded: " .. foundname) - else - logs.info([[Font names database not found, generating new one. - This can take several minutes; please be patient.]]) - data = names.update(fontnames_init()) - names.save(data) - end - return data -end - -local synonyms = { - regular = { "normal", "roman", "plain", "book", "medium" }, - -- boldregular was for old versions of Linux Libertine, is it still useful? - -- semibold is in new versions of Linux Libertine, but there is also a bold, - -- not sure it's useful here... - bold = { "demi", "demibold", "semibold", "boldregular" }, - italic = { "regularitalic", "normalitalic", "oblique", "slanted" }, - bolditalic = { "boldoblique", "boldslanted", "demiitalic", "demioblique", "demislanted", "demibolditalic", "semibolditalic" }, -} - -local loaded = false -local reloaded = false - -function names.resolve(specification) - local name = sanitize(specification.name) - local style = sanitize(specification.style) or "regular" - - local size - if specification.optsize then - size = tonumber(specification.optsize) - elseif specification.size then - size = specification.size / 65536 - end - - - if not loaded then - names.data = names.load() - loaded = true - end - - local data = names.data - if type(data) == "table" and data.version == names.version then - if data.mappings then - local found = { } - for _,face in next, data.mappings do - local family, subfamily, fullname, psname - local optsize, dsnsize, maxsize, minsize - - if face.names then - family = sanitize(face.names.family) - subfamily = sanitize(face.names.subfamily) - fullname = sanitize(face.names.fullname) - psname = sanitize(face.names.psname) - end - local fontname = sanitize(face.fontname) - local pfullname = sanitize(face.fullname) - if #face.size > 0 then - optsize = face.size - dsnsize = optsize[1] and optsize[1] / 10 - -- can be nil - maxsize = optsize[2] and optsize[2] / 10 or dsnsize - minsize = optsize[3] and optsize[3] / 10 or dsnsize - end - if name == family then - if subfamily == style then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else - found[1] = face - break - end - elseif synonyms[style] and - table.contains(synonyms[style], subfamily) then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else - found[1] = face - break - end - elseif subfamily == "regular" or - table.contains(synonyms.regular, subfamily) then - found.fallback = face - elseif name == fullname - or name == pfullname - or name == fontname - or name == psname then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else - found[1] = face - break - end - end - else - if name == fullname - or name == pfullname - or name == fontname - or name == psname then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else - found[1] = face - break - end - end - end - end - if #found == 1 then - if kpse.lookup(found[1].filename[1]) then - logs.report("load font", - "font family='%s', subfamily='%s' found: %s", - name, style, found[1].filename[1]) - return found[1].filename[1], found[1].filename[2] - elseif lfs.isfile(found[1].found_at) then - logs.report("load font", - "font family='%s', subfamily='%s' found: %s", - name, style, found[1].found_at) - return found[1].found_at, found[1].filename[2] - end - elseif #found > 1 then - -- we found matching font(s) but not in the requested optical - -- sizes, so we loop through the matches to find the one with - -- least difference from the requested size. - local closest - local least = math.huge -- initial value is infinity - for i,face in next, found do - local dsnsize = face.size[1]/10 - local difference = math.abs(dsnsize-size) - if difference < least then - closest = face - least = difference - end - end - if kpse.lookup(closest.filename[1]) then - logs.report("load font", - "font family='%s', subfamily='%s' found: %s", - name, style, closest.filename[1]) - return closest.filename[1], closest.filename[2] - elseif lfs.isfile(closest.found_at) then - logs.report("load font", - "font family='%s', subfamily='%s' found: %s", - name, style, closest.found_at) - return closest.found_at, closest.filename[2] - end - elseif found.fallback then - return found.fallback.filename[1], found.fallback.filename[2] - end - -- no font found so far - if not reloaded then - -- try reloading the database - names.data = names.update(names.data) - names.save(names.data) - reloaded = true - return names.resolve(specification) - else - -- else, fallback to filename - return specification.name, false - end - end - else - if not reloaded then - names.data = names.update() - names.save(names.data) - reloaded = true - return names.resolve(specification) - else - return specification.name, false - end - end -end - -names.resolvespec = names.resolve - -function names.set_log_level(level) - if level == 2 then - trace_loading = true - elseif level >= 3 then - trace_loading = true - trace_search = true - end -end - -local lastislog = 0 - -local function log(fmt, ...) - lastislog = 1 - texio.write_nl(format("luaotfload | %s", format(fmt,...))) - io.flush() -end - -logs = logs or { } -logs.report = logs.report or log -logs.info = logs.info or log - -local function font_fullinfo(filename, subfont, texmf) - local found_at = filename - local t = { } - local f = fontloader.open(filename, subfont) - if not f then - if trace_loading then - logs.report("error: failed to open %s", filename) - end - return - end - local m = fontloader.to_table(f) - fontloader.close(f) - collectgarbage('collect') - -- see http://www.microsoft.com/typography/OTSPEC/features_pt.htm#size - if m.fontstyle_name then - for _,v in next, m.fontstyle_name do - if v.lang == 1033 then - t.fontstyle_name = v.name - end - end - end - if m.names then - for _,v in next, m.names do - if v.lang == "English (US)" then - t.names = { - -- see - -- http://developer.apple.com/textfonts/ - -- TTRefMan/RM06/Chap6name.html - fullname = v.names.compatfull or v.names.fullname, - family = v.names.preffamilyname or v.names.family, - subfamily= t.fontstyle_name or v.names.prefmodifiers or v.names.subfamily, - psname = v.names.postscriptname - } - end - end - else - -- no names table, propably a broken font - if trace_loading then - logs.report("broken font rejected: %s", basefile) - end - return - end - t.fontname = m.fontname - t.fullname = m.fullname - t.familyname = m.familyname - t.filename = { texmf and basename(filename) or filename, subfont } - t.weight = m.pfminfo.weight - t.width = m.pfminfo.width - t.slant = m.italicangle - -- don't waste the space with zero values - t.size = { - m.design_size ~= 0 and m.design_size or nil, - m.design_range_top ~= 0 and m.design_range_top or nil, - m.design_range_bottom ~= 0 and m.design_range_bottom or nil, - } - -- rather, waste space on paths - t.found_at = found_at - return t -end - -local function load_font(filename, fontnames, newfontnames, texmf) - local newmappings = newfontnames.mappings - local newstatus = newfontnames.status - local mappings = fontnames.mappings - local status = fontnames.status - local basefile = texmf and basename(filename) or filename - if filename then - if table.contains(names.blacklist, filename) or - table.contains(names.blacklist, basename(filename)) then - if trace_search then - logs.report("ignoring font '%s'", filename) - end - return - end - local timestamp, db_timestamp - db_timestamp = status[basefile] and status[basefile].timestamp - timestamp = lfs.attributes(filename, "modification") - - local index_status = newstatus[basefile] or (not texmf and newstatus[basename(filename)]) - if index_status and index_status.timestamp == timestamp then - -- already indexed this run - return - end - - newstatus[basefile] = newstatus[basefile] or { } - newstatus[basefile].timestamp = timestamp - newstatus[basefile].index = newstatus[basefile].index or { } - - if db_timestamp == timestamp and not newstatus[basefile].index[1] then - for _,v in next, status[basefile].index do - local index = #newstatus[basefile].index - newmappings[#newmappings+1] = mappings[v] - newstatus[basefile].index[index+1] = #newmappings - end - if trace_loading then - logs.report("font already indexed: %s", basefile) - end - return - end - local info = fontloader.info(filename) - if info then - if type(info) == "table" and #info > 1 then - for i in next, info do - local fullinfo = font_fullinfo(filename, i-1, texmf) - if not fullinfo then - return - end - local index = newstatus[basefile].index[i] - if not index then - index = #newmappings+1 - end - newmappings[index] = fullinfo - newstatus[basefile].index[i] = index - end - else - local fullinfo = font_fullinfo(filename, false, texmf) - if not fullinfo then - return - end - local index = newstatus[basefile].index[1] - if not index then - index = #newmappings+1 - end - newmappings[index] = fullinfo - newstatus[basefile].index[1] = index - end - else - if trace_loading then - logs.report("failed to load %s", basefile) - end - end - end -end - -local function path_normalize(path) - --[[ - path normalization: - - a\b\c -> a/b/c - - a/../b -> b - - /cygdrive/a/b -> a:/b - - reading symlinks under non-Win32 - - using kpse.readable_file on Win32 - ]] - if os.type == "windows" or os.type == "msdos" then - path = path:gsub('\\', '/') - path = path:lower() - path = path:gsub('^/cygdrive/(%a)/', '%1:/') - end - if os.type ~= "windows" and os.type ~= "msdos" then - local dest = lfs.readlink(path) - if dest then - if kpse.readable_file(dest) then - path = dest - elseif kpse.readable_file(file.join(file.dirname(path), dest)) then - path = file.join(file.dirname(path), dest) - else - -- broken symlink? - end - end - end - path = file.collapse_path(path) - return path -end - -fonts.path_normalize = path_normalize - -names.blacklist = { } - -local function read_blacklist() - local files = { - kpse.lookup("otfl-blacklist.cnf", {all=true, format="tex"}) - } - local blacklist = names.blacklist - - if files and type(files) == "table" then - for _,v in next, files do - for line in io.lines(v) do - line = line:strip() -- to get rid of lines like " % foo" - if line:find("^%%") or line:is_empty() then - -- comment or empty line - else - line = line:split("%")[1] - line = line:strip() - if trace_search then - logs.report("blacklisted file: %s", line) - end - blacklist[#blacklist+1] = line - end - end - end - end -end - -local font_extensions = { "otf", "ttf", "ttc", "dfont" } - -local function scan_dir(dirname, fontnames, newfontnames, texmf) - --[[ - This function scans a directory and populates the list of fonts - with all the fonts it finds. - - dirname is the name of the directory to scan - - names is the font database to fill - - texmf is a boolean saying if we are scanning a texmf directory - ]] - local list, found = { }, { } - local nbfound = 0 - if trace_search then - logs.report("scanning '%s'", dirname) - end - for _,i in next, font_extensions do - for _,ext in next, { i, upper(i) } do - found = glob(format("%s/**.%s$", dirname, ext)) - -- note that glob fails silently on broken symlinks, which happens - -- sometimes in TeX Live. - if trace_search then - logs.report("%s '%s' fonts found", #found, ext) - end - nbfound = nbfound + #found - table.append(list, found) - end - end - if trace_search then - logs.report("%d fonts found in '%s'", nbfound, dirname) - end - - for _,file in next, list do - file = path_normalize(file) - if trace_loading then - logs.report("loading font: %s", file) - end - load_font(file, fontnames, newfontnames, texmf) - end -end - -local function scan_texmf_fonts(fontnames, newfontnames) - --[[ - This function scans all fonts in the texmf tree, through kpathsea - variables OPENTYPEFONTS and TTFONTS of texmf.cnf - ]] - if expandpath("$OSFONTDIR"):is_empty() then - logs.info("Scanning TEXMF fonts...") - else - logs.info("Scanning TEXMF and OS fonts...") - end - local fontdirs = expandpath("$OPENTYPEFONTS"):gsub("^%.", "") - fontdirs = fontdirs .. expandpath("$TTFONTS"):gsub("^%.", "") - if not fontdirs:is_empty() then - for _,d in next, splitpath(fontdirs) do - scan_dir(d, fontnames, newfontnames, true) - end - end -end - ---[[ - For the OS fonts, there are several options: - - if OSFONTDIR is set (which is the case under windows by default but - not on the other OSs), it scans it at the same time as the texmf tree, - in the scan_texmf_fonts. - - in addition: - - under Windows and Mac OSX, we take a look at some hardcoded directories - - under Unix, we read /etc/fonts/fonts.conf and read the directories in it - - This means that if you have fonts in fancy directories, you need to set them - in OSFONTDIR if they cannot be found by fontconfig. -]] - -local function read_fonts_conf(path, results, passed_paths) - --[[ - This function parses /etc/fonts/fonts.conf and returns all the dir it finds. - The code is minimal, please report any error it may generate. - ]] - local f = io.open(path) - table.insert(passed_paths, path) - if not f then - logs.info("Warning: unable to read "..path.. ", skipping...") - return results - end - local incomments = false - for line in f:lines() do - while line and line ~= "" do - -- spaghetti code... hmmm... - if incomments then - local tmp = find(line, '-->') - if tmp then - incomments = false - line = sub(line, tmp+3) - else - line = nil - end - else - local tmp = find(line, '<!--') - local newline = line - if tmp then - -- for the analysis, we take everything that is before the - -- comment sign - newline = sub(line, 1, tmp-1) - -- and we loop again with the comment - incomments = true - line = sub(line, tmp+4) - else - -- if there is no comment start, the block after that will - -- end the analysis, we exit the while loop - line = nil - end - for dir in gmatch(newline, '<dir>([^<]+)</dir>') do - -- now we need to replace ~ by kpse.expand_path('~') - if sub(dir, 1, 1) == '~' then - dir = file.join(kpse.expand_path('~'), sub(dir, 2)) - end - -- we exclude paths with texmf in them, as they should be - -- found anyway - if not find(dir, 'texmf') then - results[#results+1] = dir - end - end - for include in gmatch(newline, '<include[^<]*>([^<]+)</include>') do - -- include here can be four things: a directory or a file, - -- in absolute or relative path. - if sub(include, 1, 1) == '~' then - include = file.join(kpse.expand_path('~'),sub(include, 2)) - -- First if the path is relative, we make it absolute: - elseif not lfs.isfile(include) and not lfs.isdir(include) then - include = file.join(file.dirname(path), include) - end - if lfs.isfile(include) and kpse.readable_file(include) and not table.contains(passed_paths, include) then - -- we exclude path with texmf in them, as they should - -- be found otherwise - read_fonts_conf(include, results, passed_paths) - elseif lfs.isdir(include) then - for _,f in next, glob(file.join(include, "*.conf")) do - if not table.contains(passed_paths, f) then - read_fonts_conf(f, results, passed_paths) - end - end - end - end - end - end - end - f:close() - return results -end - --- for testing purpose -names.read_fonts_conf = read_fonts_conf - -local function get_os_dirs() - if os.name == 'macosx' then - return { - file.join(kpse.expand_path('~'), "Library/Fonts"), - "/Library/Fonts", - "/System/Library/Fonts", - "/Network/Library/Fonts", - } - elseif os.type == "windows" or os.type == "msdos" then - local windir = os.getenv("WINDIR") - return { file.join(windir, 'Fonts') } - else - return read_fonts_conf("/etc/fonts/fonts.conf", {}, {}) - end -end - -local function scan_os_fonts(fontnames, newfontnames) - --[[ - This function scans the OS fonts through - - fontcache for Unix (reads the fonts.conf file and scans the directories) - - a static set of directories for Windows and MacOSX - ]] - logs.info("Scanning OS fonts...") - if trace_search then - logs.info("Searching in static system directories...") - end - for _,d in next, get_os_dirs() do - scan_dir(d, fontnames, newfontnames, false) - end -end - -local function update_names(fontnames, force) - --[[ - The main function, scans everything - - fontnames is the final table to return - - force is whether we rebuild it from scratch or not - ]] - logs.info("Updating the font names database:") - - if force then - fontnames = fontnames_init() - else - if not fontnames then - fontnames = names.load() - end - if fontnames.version ~= names.version then - fontnames = fontnames_init() - if trace_search then - logs.report("No font names database or old one found; " - .."generating new one") - end - end - end - local newfontnames = fontnames_init() - read_blacklist() - scan_texmf_fonts(fontnames, newfontnames) - scan_os_fonts(fontnames, newfontnames) - return newfontnames -end - -local function save_names(fontnames) - local savepath = names.path.localdir - if not lfs.isdir(savepath) then - dir.mkdirs(savepath) - end - savepath = file.join(savepath, names.path.basename) - if file.iswritable(savepath) then - table.tofile(savepath, fontnames, true) - logs.info("Font names database saved: %s \n", savepath) - return savepath - else - logs.info("Failed to save names database\n") - return nil - end -end - -local function scan_external_dir(dir) - local old_names, new_names - if loaded then - old_names = names.data - else - old_names = names.load() - loaded = true - end - new_names = table.copy(old_names) - scan_dir(dir, old_names, new_names) - names.data = new_names -end - -names.scan = scan_external_dir -names.load = load_names -names.update = update_names -names.save = save_names - --- vim:ft=lua:sw=4:ts=4:expandtab diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-merged.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-merged.lua deleted file mode 100644 index 9bec2986dea..00000000000 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-merged.lua +++ /dev/null @@ -1,8157 +0,0 @@ --- merged file : luaotfload-legacy-merged.lua --- parent file : luaotfload-legacy.lua --- merge date : Fri May 10 20:57:35 2013 - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['luat-dum']={ - version=1.100, - comment="companion to luatex-*.tex", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local dummyfunction=function() end -statistics={ - register=dummyfunction, - starttiming=dummyfunction, - stoptiming=dummyfunction, -} -directives={ - register=dummyfunction, - enable=dummyfunction, - disable=dummyfunction, -} -trackers={ - register=dummyfunction, - enable=dummyfunction, - disable=dummyfunction, -} -experiments={ - register=dummyfunction, - enable=dummyfunction, - disable=dummyfunction, -} -storage={ - register=dummyfunction, - shared={}, -} -logs={ - report=dummyfunction, - simple=dummyfunction, -} -tasks={ - new=dummyfunction, - actions=dummyfunction, - appendaction=dummyfunction, - prependaction=dummyfunction, -} -callbacks={ - register=function(n,f) return callback.register(n,f) end, -} -texconfig.kpse_init=true -resolvers=resolvers or {} -local remapper={ - otf="opentype fonts", - ttf="truetype fonts", - ttc="truetype fonts", - dfont="truetype fonts", - cid="cid maps", - fea="font feature files", -} -function resolvers.find_file(name,kind) - name=string.gsub(name,"\\","/") - kind=string.lower(kind) - return kpse.find_file(name,(kind and kind~="" and (remapper[kind] or kind)) or file.extname(name,"tex")) -end -function resolvers.findbinfile(name,kind) - if not kind or kind=="" then - kind=file.extname(name) - end - return resolvers.find_file(name,(kind and remapper[kind]) or kind) -end -caches={} -local writable,readables=nil,{} -if not caches.namespace or caches.namespace=="" or caches.namespace=="context" then - caches.namespace='generic' -end -do - local cachepaths - if kpse.expand_var('$TEXMFCACHE')~='$TEXMFCACHE' then - cachepaths=kpse.expand_var('$TEXMFCACHE') - elseif kpse.expand_var('$TEXMFVAR')~='$TEXMFVAR' then - cachepaths=kpse.expand_var('$TEXMFVAR') - end - if not cachepaths then - cachepaths="." - end - cachepaths=string.split(cachepaths,os.type=="windows" and ";" or ":") - for i=1,#cachepaths do - local done - writable=file.join(cachepaths[i],"luatex-cache") - writable=file.join(writable,caches.namespace) - writable,done=dir.mkdirs(writable) - if done then - break - end - end - for i=1,#cachepaths do - if file.isreadable(cachepaths[i]) then - readables[#readables+1]=file.join(cachepaths[i],"luatex-cache",caches.namespace) - end - end - if not writable then - texio.write_nl("quiting: fix your writable cache path\n") - os.exit() - elseif #readables==0 then - texio.write_nl("quiting: fix your readable cache path\n") - os.exit() - elseif #readables==1 and readables[1]==writable then - texio.write(string.format("(using cache: %s)",writable)) - else - texio.write(string.format("(using write cache: %s)",writable)) - texio.write(string.format("(using read cache: %s)",table.concat(readables," "))) - end -end -function caches.getwritablepath(category,subcategory) - local path=file.join(writable,category) - lfs.mkdir(path) - path=file.join(path,subcategory) - lfs.mkdir(path) - return path -end -function caches.getreadablepaths(category,subcategory) - local t={} - for i=1,#readables do - t[i]=file.join(readables[i],category,subcategory) - end - return t -end -local function makefullname(path,name) - if path and path~="" then - name="temp-"..name - return file.addsuffix(file.join(path,name),"lua") - end -end -function caches.iswritable(path,name) - local fullname=makefullname(path,name) - return fullname and file.iswritable(fullname) -end -function caches.loaddata(paths,name) - for i=1,#paths do - local fullname=makefullname(paths[i],name) - if fullname then - texio.write(string.format("(load: %s)",fullname)) - local data=loadfile(fullname) - return data and data() - end - end -end -function caches.savedata(path,name,data) - local fullname=makefullname(path,name) - if fullname then - texio.write(string.format("(save: %s)",fullname)) - table.tofile(fullname,data,'return',false,true,false) - end -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['luat-ovr']={ - version=1.001, - comment="companion to luatex-*.tex", - author="Khaled Hosny and Elie Roux", - copyright="Luaotfload Development Team", - license="GNU GPL v2" -} -local write_nl,format,name=texio.write_nl,string.format,"luaotfload" -local dummyfunction=function() end -callbacks={ - register=dummyfunction, -} -function logs.report(category,fmt,...) - if fmt then - write_nl('log',format("%s | %s: %s",name,category,format(fmt,...))) - elseif category then - write_nl('log',format("%s | %s",name,category)) - else - write_nl('log',format("%s |",name)) - end -end -function logs.info(category,fmt,...) - if fmt then - write_nl(format("%s | %s: %s",name,category,format(fmt,...))) - elseif category then - write_nl(format("%s | %s",name,category)) - else - write_nl(format("%s |",name)) - end - io.flush() -end -function logs.simple(fmt,...) - if fmt then - write_nl('log',format("%s | %s",name,format(fmt,...))) - else - write_nl('log',format("%s |",name)) - end -end -tex.attribute[0]=0 -tex.ctxcatcodes=luatexbase.catcodetables.latex - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['data-con']={ - version=1.100, - comment="companion to luat-lib.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local format,lower,gsub=string.format,string.lower,string.gsub -local trace_cache=false trackers.register("resolvers.cache",function(v) trace_cache=v end) -local trace_containers=false trackers.register("resolvers.containers",function(v) trace_containers=v end) -local trace_storage=false trackers.register("resolvers.storage",function(v) trace_storage=v end) -containers=containers or {} -containers.usecache=true -local function report(container,tag,name) - if trace_cache or trace_containers then - logs.report(format("%s cache",container.subcategory),"%s: %s",tag,name or 'invalid') - end -end -local allocated={} -local mt={ - __index=function(t,k) - if k=="writable" then - local writable=caches.getwritablepath(t.category,t.subcategory) or { "." } - t.writable=writable - return writable - elseif k=="readables" then - local readables=caches.getreadablepaths(t.category,t.subcategory) or { "." } - t.readables=readables - return readables - end - end -} -function containers.define(category,subcategory,version,enabled) - if category and subcategory then - local c=allocated[category] - if not c then - c={} - allocated[category]=c - end - local s=c[subcategory] - if not s then - s={ - category=category, - subcategory=subcategory, - storage={}, - enabled=enabled, - version=version or math.pi, - trace=false, - } - setmetatable(s,mt) - c[subcategory]=s - end - return s - end -end -function containers.is_usable(container,name) - return container.enabled and caches and caches.iswritable(container.writable,name) -end -function containers.is_valid(container,name) - if name and name~="" then - local storage=container.storage[name] - return storage and storage.cache_version==container.version - else - return false - end -end -function containers.read(container,name) - local storage=container.storage - local stored=storage[name] - if not stored and container.enabled and caches and containers.usecache then - stored=caches.loaddata(container.readables,name) - if stored and stored.cache_version==container.version then - report(container,"loaded",name) - else - stored=nil - end - storage[name]=stored - elseif stored then - report(container,"reusing",name) - end - return stored -end -function containers.write(container,name,data) - if data then - data.cache_version=container.version - if container.enabled and caches then - local unique,shared=data.unique,data.shared - data.unique,data.shared=nil,nil - caches.savedata(container.writable,name,data) - report(container,"saved",name) - data.unique,data.shared=unique,shared - end - report(container,"stored",name) - container.storage[name]=data - end - return data -end -function containers.content(container,name) - return container.storage[name] -end -function containers.cleanname(name) - return (gsub(lower(name),"[^%w%d]+","-")) -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-ini']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local utf=unicode.utf8 -local format,serialize=string.format,table.serialize -local write_nl=texio.write_nl -local lower=string.lower -if not fontloader then fontloader=fontforge end -fontloader.totable=fontloader.to_table -fonts=fonts or {} -fonts.ids=fonts.ids or {} fonts.identifiers=fonts.ids -fonts.chr=fonts.chr or {} fonts.characters=fonts.chr -fonts.qua=fonts.qua or {} fonts.quads=fonts.qua -fonts.tfm=fonts.tfm or {} -fonts.mode='base' -fonts.private=0xF0000 -fonts.verbose=false -fonts.ids[0]={ - characters={}, - descriptions={}, - name="nullfont", -} -fonts.chr[0]={} -fonts.methods=fonts.methods or { - base={ tfm={},afm={},otf={},vtf={},fix={} }, - node={ tfm={},afm={},otf={},vtf={},fix={} }, -} -fonts.initializers=fonts.initializers or { - base={ tfm={},afm={},otf={},vtf={},fix={} }, - node={ tfm={},afm={},otf={},vtf={},fix={} } -} -fonts.triggers=fonts.triggers or { - 'mode', - 'language', - 'script', - 'strategy', -} -fonts.processors=fonts.processors or {} -fonts.manipulators=fonts.manipulators or {} -fonts.define=fonts.define or {} -fonts.define.specify=fonts.define.specify or {} -fonts.define.specify.synonyms=fonts.define.specify.synonyms or {} -if not fonts.color then - fonts.color={ - set=function() end, - reset=function() end, - } -end -fonts.formats={} -function fonts.fontformat(filename,default) - local extname=lower(file.extname(filename)) - local format=fonts.formats[extname] - if format then - return format - else - logs.report("fonts define","unable to determine font format for '%s'",filename) - return default - end -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['node-dum']={ - version=1.001, - comment="companion to luatex-*.tex", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -nodes=nodes or {} -fonts=fonts or {} -attributes=attributes or {} -local traverse_id=node.traverse_id -local free_node=node.free -local remove_node=node.remove -local new_node=node.new -local glyph=node.id('glyph') -local fontdata=fonts.ids or {} -function nodes.simple_font_handler(head) - head=nodes.process_characters(head) - nodes.inject_kerns(head) - nodes.protect_glyphs(head) - head=node.ligaturing(head) - head=node.kerning(head) - return head -end -if tex.attribute[0]~=0 then - texio.write_nl("log","!") - texio.write_nl("log","! Attribute 0 is reserved for ConTeXt's font feature management and has to be") - texio.write_nl("log","! set to zero. Also, some attributes in the range 1-255 are used for special") - texio.write_nl("log","! purposed so setting them at the TeX end might break the font handler.") - texio.write_nl("log","!") - tex.attribute[0]=0 -end -nodes.protect_glyphs=node.protect_glyphs -nodes.unprotect_glyphs=node.unprotect_glyphs -function nodes.process_characters(head) - local usedfonts,done,prevfont={},false,nil - for n in traverse_id(glyph,head) do - local font=n.font - if font~=prevfont then - prevfont=font - local used=usedfonts[font] - if not used then - local tfmdata=fontdata[font] - if tfmdata then - local shared=tfmdata.shared - if shared then - local processors=shared.processes - if processors and #processors>0 then - usedfonts[font]=processors - done=true - end - end - end - end - end - end - if done then - for font,processors in next,usedfonts do - for i=1,#processors do - local h,d=processors[i](head,font,0) - head,done=h or head,done or d - end - end - end - return head,true -end -function nodes.kern(k) - local n=new_node("kern",1) - n.kern=k - return n -end -function nodes.remove(head,current,free_too) - local t=current - head,current=remove_node(head,current) - if t then - if free_too then - free_node(t) - t=nil - else - t.next,t.prev=nil,nil - end - end - return head,current,t -end -function nodes.delete(head,current) - return nodes.remove(head,current,true) -end -nodes.before=node.insert_before -nodes.after=node.insert_after -attributes.unsetvalue=-0x7FFFFFFF -local numbers,last={},127 -function attributes.private(name) - local number=numbers[name] - if not number then - if last<255 then - last=last+1 - end - number=last - numbers[name]=number - end - return number -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['node-inj']={ - version=1.001, - comment="companion to node-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local next=next -local trace_injections=false trackers.register("nodes.injections",function(v) trace_injections=v end) -fonts=fonts or {} -fonts.tfm=fonts.tfm or {} -fonts.ids=fonts.ids or {} -local fontdata=fonts.ids -local glyph=node.id('glyph') -local kern=node.id('kern') -local traverse_id=node.traverse_id -local unset_attribute=node.unset_attribute -local has_attribute=node.has_attribute -local set_attribute=node.set_attribute -local insert_node_before=node.insert_before -local insert_node_after=node.insert_after -local newkern=nodes.kern -local markbase=attributes.private('markbase') -local markmark=attributes.private('markmark') -local markdone=attributes.private('markdone') -local cursbase=attributes.private('cursbase') -local curscurs=attributes.private('curscurs') -local cursdone=attributes.private('cursdone') -local kernpair=attributes.private('kernpair') -local cursives={} -local marks={} -local kerns={} -function nodes.set_cursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) - local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2]) - local ws,wn=tfmstart.width,tfmnext.width - local bound=#cursives+1 - set_attribute(start,cursbase,bound) - set_attribute(nxt,curscurs,bound) - cursives[bound]={ rlmode,dx,dy,ws,wn } - return dx,dy,bound -end -function nodes.set_pair(current,factor,rlmode,r2lflag,spec,tfmchr) - local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4] - if x~=0 or w~=0 or y~=0 or h~=0 then - local bound=has_attribute(current,kernpair) - if bound then - local kb=kerns[bound] - kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h - else - bound=#kerns+1 - set_attribute(current,kernpair,bound) - kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width } - end - return x,y,w,h,bound - end - return x,y,w,h -end -function nodes.set_kern(current,factor,rlmode,x,tfmchr) - local dx=factor*x - if dx~=0 then - local bound=#kerns+1 - set_attribute(current,kernpair,bound) - kerns[bound]={ rlmode,dx } - return dx,bound - else - return 0,0 - end -end -function nodes.set_mark(start,base,factor,rlmode,ba,ma,index) - local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2]) - local bound=has_attribute(base,markbase) - if bound then - local mb=marks[bound] - if mb then - if not index then index=#mb+1 end - mb[index]={ dx,dy } - set_attribute(start,markmark,bound) - set_attribute(start,markdone,index) - return dx,dy,bound - else - logs.report("nodes mark","possible problem, U+%04X is base without data (id: %s)",base.char,bound) - end - end - index=index or 1 - bound=#marks+1 - set_attribute(base,markbase,bound) - set_attribute(start,markmark,bound) - set_attribute(start,markdone,index) - marks[bound]={ [index]={ dx,dy,rlmode } } - return dx,dy,bound -end -function nodes.trace_injection(head) - local function dir(n) - return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or ("unset") - end - local function report(...) - logs.report("nodes finisher",...) - end - report("begin run") - for n in traverse_id(glyph,head) do - if n.subtype<256 then - local kp=has_attribute(n,kernpair) - local mb=has_attribute(n,markbase) - local mm=has_attribute(n,markmark) - local md=has_attribute(n,markdone) - local cb=has_attribute(n,cursbase) - local cc=has_attribute(n,curscurs) - report("char U+%05X, font=%s",n.char,n.font) - if kp then - local k=kerns[kp] - if k[3] then - report(" pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2] or "?",k[3] or "?",k[4] or "?",k[5] or "?") - else - report(" kern: dir=%s, dx=%s",dir(k[1]),k[2] or "?") - end - end - if mb then - report(" markbase: bound=%s",mb) - end - if mm then - local m=marks[mm] - if mb then - local m=m[mb] - if m then - report(" markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,md or "?",m[1] or "?",m[2] or "?") - else - report(" markmark: bound=%s, missing index",mm) - end - else - m=m[1] - report(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1] or "?",m[2] or "?") - end - end - if cb then - report(" cursbase: bound=%s",cb) - end - if cc then - local c=cursives[cc] - report(" curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2] or "?",c[3] or "?") - end - end - end - report("end run") -end -function nodes.inject_kerns(head,where,keep) - local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns) - if has_marks or has_cursives then - if trace_injections then - nodes.trace_injection(head) - end - local done,ky,rl,valid,cx,wx,mk=false,{},{},{},{},{},{} - if has_kerns then - local nf,tm=nil,nil - for n in traverse_id(glyph,head) do - if n.subtype<256 then - valid[#valid+1]=n - if n.font~=nf then - nf=n.font - tm=fontdata[nf].marks - end - mk[n]=tm[n.char] - local k=has_attribute(n,kernpair) - if k then - local kk=kerns[k] - if kk then - local x,y,w,h=kk[2] or 0,kk[3] or 0,kk[4] or 0,kk[5] or 0 - local dy=y-h - if dy~=0 then - ky[n]=dy - end - if w~=0 or x~=0 then - wx[n]=kk - end - rl[n]=kk[1] - end - end - end - end - else - local nf,tm=nil,nil - for n in traverse_id(glyph,head) do - if n.subtype<256 then - valid[#valid+1]=n - if n.font~=nf then - nf=n.font - tm=fontdata[nf].marks - end - mk[n]=tm[n.char] - end - end - end - if #valid>0 then - local cx={} - if has_kerns and next(ky) then - for n,k in next,ky do - n.yoffset=k - end - end - if has_cursives then - local p_cursbase,p=nil,nil - local t,d,maxt={},{},0 - for i=1,#valid do - local n=valid[i] - if not mk[n] then - local n_cursbase=has_attribute(n,cursbase) - if p_cursbase then - local n_curscurs=has_attribute(n,curscurs) - if p_cursbase==n_curscurs then - local c=cursives[n_curscurs] - if c then - local rlmode,dx,dy,ws,wn=c[1],c[2],c[3],c[4],c[5] - if rlmode>=0 then - dx=dx-ws - else - dx=dx+wn - end - if dx~=0 then - cx[n]=dx - rl[n]=rlmode - end - dy=-dy - maxt=maxt+1 - t[maxt]=p - d[maxt]=dy - else - maxt=0 - end - end - elseif maxt>0 then - local ny=n.yoffset - for i=maxt,1,-1 do - ny=ny+d[i] - local ti=t[i] - ti.yoffset=ti.yoffset+ny - end - maxt=0 - end - if not n_cursbase and maxt>0 then - local ny=n.yoffset - for i=maxt,1,-1 do - ny=ny+d[i] - local ti=t[i] - ti.yoffset=ny - end - maxt=0 - end - p_cursbase,p=n_cursbase,n - end - end - if maxt>0 then - local ny=n.yoffset - for i=maxt,1,-1 do - ny=ny+d[i] - local ti=t[i] - ti.yoffset=ny - end - maxt=0 - end - if not keep then - cursives={} - end - end - if has_marks then - for i=1,#valid do - local p=valid[i] - local p_markbase=has_attribute(p,markbase) - if p_markbase then - local mrks=marks[p_markbase] - for n in traverse_id(glyph,p.next) do - local n_markmark=has_attribute(n,markmark) - if p_markbase==n_markmark then - local index=has_attribute(n,markdone) or 1 - local d=mrks[index] - if d then - local rlmode=d[3] - if rlmode and rlmode>0 then - local k=wx[p] - if k then - n.xoffset=p.xoffset-(p.width-d[1])-k[2] - else - n.xoffset=p.xoffset-(p.width-d[1]) - end - else - local k=wx[p] - if k then - n.xoffset=p.xoffset-d[1]-k[2] - else - n.xoffset=p.xoffset-d[1] - end - end - if mk[p] then - n.yoffset=p.yoffset+d[2] - else - n.yoffset=n.yoffset+p.yoffset+d[2] - end - end - else - break - end - end - end - end - if not keep then - marks={} - end - end - if next(wx) then - for n,k in next,wx do - local rl,x,w,r2l=k[1],k[2] or 0,k[4] or 0,k[6] - local wx=w-x - if r2l then - if wx~=0 then - insert_node_before(head,n,newkern(wx)) - end - if x~=0 then - insert_node_after (head,n,newkern(x)) - end - else - if x~=0 then - insert_node_before(head,n,newkern(x)) - end - if wx~=0 then - insert_node_after(head,n,newkern(wx)) - end - end - end - end - if next(cx) then - for n,k in next,cx do - if k~=0 then - local rln=rl[n] - if rln and rln<0 then - insert_node_before(head,n,newkern(-k)) - else - insert_node_before(head,n,newkern(k)) - end - end - end - end - if not keep then - kerns={} - end - return head,true - elseif not keep then - kerns,cursives,marks={},{},{} - end - elseif has_kerns then - if trace_injections then - nodes.trace_injection(head) - end - for n in traverse_id(glyph,head) do - if n.subtype<256 then - local k=has_attribute(n,kernpair) - if k then - local kk=kerns[k] - if kk then - local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4] - if y and y~=0 then - n.yoffset=y - end - if w then - local r2l=kk[6] - local wx=w-x - if r2l then - if wx~=0 then - insert_node_before(head,n,newkern(wx)) - end - if x~=0 then - insert_node_after (head,n,newkern(x)) - end - else - if x~=0 then - insert_node_before(head,n,newkern(x)) - end - if wx~=0 then - insert_node_after(head,n,newkern(wx)) - end - end - else - if x~=0 then - insert_node_before(head,n,newkern(x)) - end - end - end - end - end - end - if not keep then - kerns={} - end - return head,true - else - end - return head,false -end - -end -- closure - -do -- begin closure to overcome local limits and interference - - -if not modules then modules={} end modules ['otfl-luat-att']={ - version=math.pi/42, - comment="companion to luaotfload.lua", - author="Philipp Gesang", - copyright="Luaotfload Development Team", - license="GNU GPL v2" -} -function attributes.private(name) - local attr="otfl@"..name - local number=luatexbase.attributes[attr] - if not number then - number=luatexbase.new_attribute(attr) - end - return number -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-tfm']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local utf=unicode.utf8 -local next,format,match,lower,gsub=next,string.format,string.match,string.lower,string.gsub -local concat,sortedkeys,utfbyte,serialize=table.concat,table.sortedkeys,utf.byte,table.serialize -local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) -local trace_scaling=false trackers.register("fonts.scaling",function(v) trace_scaling=v end) -fonts=fonts or {} -fonts.tfm=fonts.tfm or {} -fonts.ids=fonts.ids or {} -local tfm=fonts.tfm -fonts.loaded=fonts.loaded or {} -fonts.dontembed=fonts.dontembed or {} -fonts.triggers=fonts.triggers or {} -fonts.initializers=fonts.initializers or {} -fonts.initializers.common=fonts.initializers.common or {} -local fontdata=fonts.ids -local disc=node.id('disc') -local glyph=node.id('glyph') -local set_attribute=node.set_attribute -tfm.resolve_vf=true -tfm.share_base_kerns=false -tfm.mathactions={} -tfm.fontname_mode="fullpath" -tfm.enhance=tfm.enhance or function() end -fonts.formats.tfm="type1" -function tfm.read_from_tfm(specification) - local fname,tfmdata=specification.filename or "",nil - if fname~="" then - if trace_defining then - logs.report("define font","loading tfm file %s at size %s",fname,specification.size) - end - tfmdata=font.read_tfm(fname,specification.size) - if tfmdata then - tfmdata.descriptions=tfmdata.descriptions or {} - if tfm.resolve_vf then - fonts.logger.save(tfmdata,file.extname(fname),specification) - fname=resolvers.findbinfile(specification.name,'ovf') - if fname and fname~="" then - local vfdata=font.read_vf(fname,specification.size) - if vfdata then - local chars=tfmdata.characters - for k,v in next,vfdata.characters do - chars[k].commands=v.commands - end - tfmdata.type='virtual' - tfmdata.fonts=vfdata.fonts - end - end - end - tfm.enhance(tfmdata,specification) - end - elseif trace_defining then - logs.report("define font","loading tfm with name %s fails",specification.name) - end - return tfmdata -end -local factors={ - pt=65536.0, - bp=65781.8, -} -function tfm.setfactor(f) - tfm.factor=factors[f or 'pt'] or factors.pt -end -tfm.setfactor() -function tfm.scaled(scaledpoints,designsize) - if scaledpoints<0 then - if designsize then - if designsize>tfm.factor then - return (- scaledpoints/1000)*designsize - else - return (- scaledpoints/1000)*designsize*tfm.factor - end - else - return (- scaledpoints/1000)*10*tfm.factor - end - else - return scaledpoints - end -end -function tfm.get_virtual_id(tfmdata) - if not tfmdata.fonts then - tfmdata.type="virtual" - tfmdata.fonts={ { id=0 } } - return 1 - else - tfmdata.fonts[#tfmdata.fonts+1]={ id=0 } - return #tfmdata.fonts - end -end -function tfm.check_virtual_id(tfmdata,id) - if tfmdata and tfmdata.type=="virtual" then - if not tfmdata.fonts or #tfmdata.fonts==0 then - tfmdata.type,tfmdata.fonts="real",nil - else - local vfonts=tfmdata.fonts - for f=1,#vfonts do - local fnt=vfonts[f] - if fnt.id and fnt.id==0 then - fnt.id=id - end - end - end - end -end -fonts.trace_scaling=false -local charactercache={} -function tfm.calculate_scale(tfmtable,scaledpoints,relativeid) - if scaledpoints<0 then - scaledpoints=(- scaledpoints/1000)*tfmtable.designsize - end - local units=tfmtable.units or 1000 - local delta=scaledpoints/units - return scaledpoints,delta,units -end -function tfm.do_scale(tfmtable,scaledpoints,relativeid) - local t={} - local scaledpoints,delta,units=tfm.calculate_scale(tfmtable,scaledpoints,relativeid) - t.units_per_em=units or 1000 - local hdelta,vdelta=delta,delta - for k,v in next,tfmtable do - if type(v)=="table" then - else - t[k]=v - end - end - local extend_factor=tfmtable.extend_factor or 0 - if extend_factor~=0 and extend_factor~=1 then - hdelta=hdelta*extend_factor - t.extend=extend_factor*1000 - else - t.extend=1000 - end - local slant_factor=tfmtable.slant_factor or 0 - if slant_factor~=0 then - t.slant=slant_factor*1000 - else - t.slant=0 - end - local isvirtual=tfmtable.type=="virtual" or tfmtable.virtualized - local hasmath=(tfmtable.math_parameters~=nil and next(tfmtable.math_parameters)~=nil) or (tfmtable.MathConstants~=nil and next(tfmtable.MathConstants)~=nil) - local nodemode=tfmtable.mode=="node" - local hasquality=tfmtable.auto_expand or tfmtable.auto_protrude - local hasitalic=tfmtable.has_italic - t.parameters={} - t.characters={} - t.MathConstants={} - local descriptions=tfmtable.descriptions or {} - t.unicodes=tfmtable.unicodes - t.indices=tfmtable.indices - t.marks=tfmtable.marks -t.goodies=tfmtable.goodies -t.colorscheme=tfmtable.colorscheme - t.descriptions=descriptions - if tfmtable.fonts then - t.fonts=table.fastcopy(tfmtable.fonts) - end - local tp=t.parameters - local mp=t.math_parameters - local tfmp=tfmtable.parameters - tp.slant=(tfmp.slant or tfmp[1] or 0) - tp.space=(tfmp.space or tfmp[2] or 0)*hdelta - tp.space_stretch=(tfmp.space_stretch or tfmp[3] or 0)*hdelta - tp.space_shrink=(tfmp.space_shrink or tfmp[4] or 0)*hdelta - tp.x_height=(tfmp.x_height or tfmp[5] or 0)*vdelta - tp.quad=(tfmp.quad or tfmp[6] or 0)*hdelta - tp.extra_space=(tfmp.extra_space or tfmp[7] or 0)*hdelta - local protrusionfactor=(tp.quad~=0 and 1000/tp.quad) or 0 - local tc=t.characters - local characters=tfmtable.characters - local nameneeded=not tfmtable.shared.otfdata - local changed=tfmtable.changed or {} - local ischanged=changed and next(changed) - local indices=tfmtable.indices - local luatex=tfmtable.luatex - local tounicode=luatex and luatex.tounicode - local defaultwidth=luatex and luatex.defaultwidth or 0 - local defaultheight=luatex and luatex.defaultheight or 0 - local defaultdepth=luatex and luatex.defaultdepth or 0 - local scaledwidth=defaultwidth*hdelta - local scaledheight=defaultheight*vdelta - local scaleddepth=defaultdepth*vdelta - local stackmath=tfmtable.ignore_stack_math~=true - local private=fonts.private - local sharedkerns={} - for k,v in next,characters do - local chr,description,index - if ischanged then - local c=changed[k] - if c then - description=descriptions[c] or v - v=characters[c] or v - index=(indices and indices[c]) or c - else - description=descriptions[k] or v - index=(indices and indices[k]) or k - end - else - description=descriptions[k] or v - index=(indices and indices[k]) or k - end - local width=description.width - local height=description.height - local depth=description.depth - if width then width=hdelta*width else width=scaledwidth end - if height then height=vdelta*height else height=scaledheight end - if depth and depth~=0 then - depth=delta*depth - if nameneeded then - chr={ - name=description.name, - index=index, - height=height, - depth=depth, - width=width, - } - else - chr={ - index=index, - height=height, - depth=depth, - width=width, - } - end - else - if nameneeded then - chr={ - name=description.name, - index=index, - height=height, - width=width, - } - else - chr={ - index=index, - height=height, - width=width, - } - end - end - if tounicode then - local tu=tounicode[index] - if tu then - chr.tounicode=tu - end - end - if hasquality then - local ve=v.expansion_factor - if ve then - chr.expansion_factor=ve*1000 - end - local vl=v.left_protruding - if vl then - chr.left_protruding=protrusionfactor*width*vl - end - local vr=v.right_protruding - if vr then - chr.right_protruding=protrusionfactor*width*vr - end - end - if hasitalic then - local vi=description.italic or v.italic - if vi and vi~=0 then - chr.italic=vi*hdelta - end - end - if hasmath then - local vn=v.next - if vn then - chr.next=vn - else - local vv=v.vert_variants - if vv then - local t={} - for i=1,#vv do - local vvi=vv[i] - t[i]={ - ["start"]=(vvi["start"] or 0)*vdelta, - ["end"]=(vvi["end"] or 0)*vdelta, - ["advance"]=(vvi["advance"] or 0)*vdelta, - ["extender"]=vvi["extender"], - ["glyph"]=vvi["glyph"], - } - end - chr.vert_variants=t - else - local hv=v.horiz_variants - if hv then - local t={} - for i=1,#hv do - local hvi=hv[i] - t[i]={ - ["start"]=(hvi["start"] or 0)*hdelta, - ["end"]=(hvi["end"] or 0)*hdelta, - ["advance"]=(hvi["advance"] or 0)*hdelta, - ["extender"]=hvi["extender"], - ["glyph"]=hvi["glyph"], - } - end - chr.horiz_variants=t - end - end - end - local vt=description.top_accent - if vt then - chr.top_accent=vdelta*vt - end - if stackmath then - local mk=v.mathkerns - if mk then - local kerns={} - local v=mk.top_right if v then local k={} for i=1,#v do local vi=v[i] - k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern } - end kerns.top_right=k end - local v=mk.top_left if v then local k={} for i=1,#v do local vi=v[i] - k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern } - end kerns.top_left=k end - local v=mk.bottom_left if v then local k={} for i=1,#v do local vi=v[i] - k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern } - end kerns.bottom_left=k end - local v=mk.bottom_right if v then local k={} for i=1,#v do local vi=v[i] - k[i]={ height=vdelta*vi.height,kern=vdelta*vi.kern } - end kerns.bottom_right=k end - chr.mathkern=kerns - end - end - end - if not nodemode then - local vk=v.kerns - if vk then - local s=sharedkerns[vk] - if not s then - s={} - for k,v in next,vk do s[k]=v*hdelta end - sharedkerns[vk]=s - end - chr.kerns=s - end - local vl=v.ligatures - if vl then - if true then - chr.ligatures=vl - else - local tt={} - for i,l in next,vl do - tt[i]=l - end - chr.ligatures=tt - end - end - end - if isvirtual then - local vc=v.commands - if vc then - local ok=false - for i=1,#vc do - local key=vc[i][1] - if key=="right" or key=="down" then - ok=true - break - end - end - if ok then - local tt={} - for i=1,#vc do - local ivc=vc[i] - local key=ivc[1] - if key=="right" then - tt[#tt+1]={ key,ivc[2]*hdelta } - elseif key=="down" then - tt[#tt+1]={ key,ivc[2]*vdelta } - elseif key=="rule" then - tt[#tt+1]={ key,ivc[2]*vdelta,ivc[3]*hdelta } - else - tt[#tt+1]=ivc - end - end - chr.commands=tt - else - chr.commands=vc - end - end - end - tc[k]=chr - end - t.size=scaledpoints - t.factor=delta - t.hfactor=hdelta - t.vfactor=vdelta - if t.fonts then - t.fonts=table.fastcopy(t.fonts) - end - if hasmath then - local ma=tfm.mathactions - for i=1,#ma do - ma[i](t,tfmtable,delta,hdelta,vdelta) - end - end - local tpx=tp.x_height - if hasmath then - if not tp[13] then tp[13]=.86*tpx end - if not tp[14] then tp[14]=.86*tpx end - if not tp[15] then tp[15]=.86*tpx end - if not tp[16] then tp[16]=.48*tpx end - if not tp[17] then tp[17]=.48*tpx end - if not tp[22] then tp[22]=0 end - if t.MathConstants then t.MathConstants.AccentBaseHeight=nil end - end - t.tounicode=1 - t.cidinfo=tfmtable.cidinfo - if hasmath then - if trace_defining then - logs.report("define font","math enabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") - end - else - if trace_defining then - logs.report("define font","math disabled for: name '%s', fullname: '%s', filename: '%s'",t.name or "noname",t.fullname or "nofullname",t.filename or "nofilename") - end - t.nomath,t.MathConstants=true,nil - end - if not t.psname then - t.psname=t.fontname or (t.fullname and fonts.names.cleanname(t.fullname)) - end - if trace_defining then - logs.report("define font","used for accesing subfont: '%s'",t.psname or "nopsname") - logs.report("define font","used for subsetting: '%s'",t.fontname or "nofontname") - end - return t,delta -end -tfm.auto_cleanup=true -local lastfont=nil -function tfm.cleanup_table(tfmdata) - if tfm.auto_cleanup then - if tfmdata.type=='virtual' or tfmdata.virtualized then - for k,v in next,tfmdata.characters do - if v.commands then v.commands=nil end - end - else - end - end -end -function tfm.cleanup(tfmdata) -end -function tfm.scale(tfmtable,scaledpoints,relativeid) - local t,factor=tfm.do_scale(tfmtable,scaledpoints,relativeid) - t.factor=factor - t.ascender=factor*(tfmtable.ascender or 0) - t.descender=factor*(tfmtable.descender or 0) - t.shared=tfmtable.shared or {} - t.unique=table.fastcopy(tfmtable.unique or {}) - tfm.cleanup(t) - return t -end -fonts.analyzers=fonts.analyzers or {} -fonts.analyzers.aux=fonts.analyzers.aux or {} -fonts.analyzers.methods=fonts.analyzers.methods or {} -fonts.analyzers.initializers=fonts.analyzers.initializers or {} -local state=attributes.private('state') -function fonts.analyzers.aux.setstate(head,font) - local tfmdata=fontdata[font] - local characters=tfmdata.characters - local descriptions=tfmdata.descriptions - local first,last,current,n,done=nil,nil,head,0,false - while current do - local id=current.id - if id==glyph and current.font==font then - local d=descriptions[current.char] - if d then - if d.class=="mark" then - done=true - set_attribute(current,state,5) - elseif n==0 then - first,last,n=current,current,1 - set_attribute(current,state,1) - else - last,n=current,n+1 - set_attribute(current,state,2) - end - else - if first and first==last then - set_attribute(last,state,4) - elseif last then - set_attribute(last,state,3) - end - first,last,n=nil,nil,0 - end - elseif id==disc then - set_attribute(current,state,2) - last=current - else - if first and first==last then - set_attribute(last,state,4) - elseif last then - set_attribute(last,state,3) - end - first,last,n=nil,nil,0 - end - current=current.next - end - if first and first==last then - set_attribute(last,state,4) - elseif last then - set_attribute(last,state,3) - end - return head,done -end -function tfm.replacements(tfm,value) - tfm.characters[0x0027]=tfm.characters[0x2019] -end -function tfm.checked_filename(metadata,whatever) - local foundfilename=metadata.foundfilename - if not foundfilename then - local askedfilename=metadata.filename or "" - if askedfilename~="" then - foundfilename=resolvers.findbinfile(askedfilename,"") or "" - if foundfilename=="" then - logs.report("fonts","source file '%s' is not found",askedfilename) - foundfilename=resolvers.findbinfile(file.basename(askedfilename),"") or "" - if foundfilename~="" then - logs.report("fonts","using source file '%s' (cache mismatch)",foundfilename) - end - end - elseif whatever then - logs.report("fonts","no source file for '%s'",whatever) - foundfilename="" - end - metadata.foundfilename=foundfilename - end - return foundfilename -end -statistics.register("fonts load time",function() - return statistics.elapsedseconds(fonts) -end) - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-cid']={ - version=1.001, - comment="companion to font-otf.lua (cidmaps)", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local format,match,lower=string.format,string.match,string.lower -local tonumber=tonumber -local lpegmatch=lpeg.match -local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) -fonts=fonts or {} -fonts.cid=fonts.cid or {} -fonts.cid.map=fonts.cid.map or {} -fonts.cid.max=fonts.cid.max or 10 -local number=lpeg.C(lpeg.R("09","af","AF")^1) -local space=lpeg.S(" \n\r\t") -local spaces=space^0 -local period=lpeg.P(".") -local periods=period*period -local name=lpeg.P("/")*lpeg.C((1-space)^1) -local unicodes,names={},{} -local function do_one(a,b) - unicodes[tonumber(a)]=tonumber(b,16) -end -local function do_range(a,b,c) - c=tonumber(c,16) - for i=tonumber(a),tonumber(b) do - unicodes[i]=c - c=c+1 - end -end -local function do_name(a,b) - names[tonumber(a)]=b -end -local grammar=lpeg.P { "start", - start=number*spaces*number*lpeg.V("series"), - series=(spaces*(lpeg.V("one")+lpeg.V("range")+lpeg.V("named")) )^1, - one=(number*spaces*number)/do_one, - range=(number*periods*number*spaces*number)/do_range, - named=(number*spaces*name)/do_name -} -function fonts.cid.load(filename) - local data=io.loaddata(filename) - if data then - unicodes,names={},{} - lpegmatch(grammar,data) - local supplement,registry,ordering=match(filename,"^(.-)%-(.-)%-()%.(.-)$") - return { - supplement=supplement, - registry=registry, - ordering=ordering, - filename=filename, - unicodes=unicodes, - names=names - } - else - return nil - end -end -local template="%s-%s-%s.cidmap" -local function locate(registry,ordering,supplement) - local filename=format(template,registry,ordering,supplement) - local hashname=lower(filename) - local cidmap=fonts.cid.map[hashname] - if not cidmap then - if trace_loading then - logs.report("load otf","checking cidmap, registry: %s, ordering: %s, supplement: %s, filename: %s",registry,ordering,supplement,filename) - end - local fullname=resolvers.find_file(filename,'cid') or "" - if fullname~="" then - cidmap=fonts.cid.load(fullname) - if cidmap then - if trace_loading then - logs.report("load otf","using cidmap file %s",filename) - end - fonts.cid.map[hashname]=cidmap - cidmap.usedname=file.basename(filename) - return cidmap - end - end - end - return cidmap -end -function fonts.cid.getmap(registry,ordering,supplement) - local supplement=tonumber(supplement) - if trace_loading then - logs.report("load otf","needed cidmap, registry: %s, ordering: %s, supplement: %s",registry,ordering,supplement) - end - local cidmap=locate(registry,ordering,supplement) - if not cidmap then - local cidnum=nil - if supplement<fonts.cid.max then - for supplement=supplement+1,fonts.cid.max do - local c=locate(registry,ordering,supplement) - if c then - cidmap,cidnum=c,supplement - break - end - end - end - if not cidmap and supplement>0 then - for supplement=supplement-1,0,-1 do - local c=locate(registry,ordering,supplement) - if c then - cidmap,cidnum=c,supplement - break - end - end - end - if cidmap and cidnum>0 then - for s=0,cidnum-1 do - filename=format(template,registry,ordering,s) - if not fonts.cid.map[filename] then - fonts.cid.map[filename]=cidmap - end - end - end - end - return cidmap -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -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', - ['expt']='Expert Forms', - ['falt']='Final glyph Alternates', - ['fin2']='Terminal Forms #2', - ['fin3']='Terminal Forms #3', - ['fina']='Terminal Forms', - ['flac']='Flattened Accents Over Capitals', - ['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', - ['rtlm']='Right To Left Math', - ['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', - ['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' -} -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 -for k,v in next,to_features do - local stripped=gsub(k,"%-"," ") - to_features[stripped]=v - local stripped=gsub(k,"[^a-zA-Z0-9]","") - to_features[stripped]=v -end -for k,v in next,to_features do - to_features[lower(k)]=v -end -otf.meanings.checkers={ - rand=function(v) - return v and "random" - end -} -local checkers=otf.meanings.checkers -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%-]","") - 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 - k=to_features[k] or k - local c=checkers[k] - h[k]=c and c(v) or v - end - end - return h -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-map']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local utf=unicode.utf8 -local match,format,find,concat,gsub,lower=string.match,string.format,string.find,table.concat,string.gsub,string.lower -local lpegmatch=lpeg.match -local utfbyte=utf.byte -local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) -local trace_unimapping=false trackers.register("otf.unimapping",function(v) trace_unimapping=v end) -local ctxcatcodes=tex and tex.ctxcatcodes -fonts=fonts or {} -fonts.map=fonts.map or {} -local function load_lum_table(filename) - local lumname=file.replacesuffix(file.basename(filename),"lum") - local lumfile=resolvers.find_file(lumname,"map") or "" - if lumfile~="" and lfs.isfile(lumfile) then - if trace_loading or trace_unimapping then - logs.report("load otf","enhance: loading %s ",lumfile) - end - lumunic=dofile(lumfile) - return lumunic,lumfile - end -end -local hex=lpeg.R("AF","09") -local hexfour=(hex*hex*hex*hex)/function(s) return tonumber(s,16) end -local hexsix=(hex^1)/function(s) return tonumber(s,16) end -local dec=(lpeg.R("09")^1)/tonumber -local period=lpeg.P(".") -local unicode=lpeg.P("uni")*(hexfour*(period+lpeg.P(-1))*lpeg.Cc(false)+lpeg.Ct(hexfour^1)*lpeg.Cc(true)) -local ucode=lpeg.P("u")*(hexsix*(period+lpeg.P(-1))*lpeg.Cc(false)+lpeg.Ct(hexsix^1)*lpeg.Cc(true)) -local index=lpeg.P("index")*dec*lpeg.Cc(false) -local parser=unicode+ucode+index -local parsers={} -local function make_name_parser(str) - if not str or str=="" then - return parser - else - local p=parsers[str] - if not p then - p=lpeg.P(str)*period*dec*lpeg.Cc(false) - parsers[str]=p - end - return p - end -end -local function tounicode16(unicode) - if unicode<0x10000 then - return format("%04X",unicode) - else - return format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) - end -end -local function tounicode16sequence(unicodes) - local t={} - for l=1,#unicodes do - local unicode=unicodes[l] - if unicode<0x10000 then - t[l]=format("%04X",unicode) - else - t[l]=format("%04X%04X",unicode/1024+0xD800,unicode%1024+0xDC00) - end - end - return concat(t) -end -fonts.map.load_lum_table=load_lum_table -fonts.map.make_name_parser=make_name_parser -fonts.map.tounicode16=tounicode16 -fonts.map.tounicode16sequence=tounicode16sequence -local separator=lpeg.S("_.") -local other=lpeg.C((1-separator)^1) -local ligsplitter=lpeg.Ct(other*(separator*other)^0) -fonts.map.add_to_unicode=function(data,filename) - local unicodes=data.luatex and data.luatex.unicodes - if not unicodes then - return - end - unicodes['space']=unicodes['space'] or 32 - unicodes['hyphen']=unicodes['hyphen'] or 45 - unicodes['zwj']=unicodes['zwj'] or 0x200D - unicodes['zwnj']=unicodes['zwnj'] or 0x200C - local tounicode,originals,ns,nl,private,unknown={},{},0,0,fonts.private,format("%04X",utfbyte("?")) - data.luatex.tounicode,data.luatex.originals=tounicode,originals - local lumunic,uparser,oparser - if false then - lumunic=load_lum_table(filename) - lumunic=lumunic and lumunic.tounicode - end - local cidinfo,cidnames,cidcodes=data.cidinfo - local usedmap=cidinfo and cidinfo.usedname - usedmap=usedmap and lower(usedmap) - usedmap=usedmap and fonts.cid.map[usedmap] - if usedmap then - oparser=usedmap and make_name_parser(cidinfo.ordering) - cidnames=usedmap.names - cidcodes=usedmap.unicodes - end - uparser=make_name_parser() - local aglmap=fonts.map and fonts.map.agl_to_unicode - for index,glyph in next,data.glyphs do - local name,unic=glyph.name,glyph.unicode or -1 - if unic==-1 or unic>=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then - local unicode=(lumunic and lumunic[name]) or (aglmap and aglmap[name]) - if unicode then - originals[index],tounicode[index],ns=unicode,tounicode16(unicode),ns+1 - end - if (not unicode) and usedmap then - local foundindex=lpegmatch(oparser,name) - if foundindex then - unicode=cidcodes[foundindex] - if unicode then - originals[index],tounicode[index],ns=unicode,tounicode16(unicode),ns+1 - else - local reference=cidnames[foundindex] - if reference then - local foundindex=lpegmatch(oparser,reference) - if foundindex then - unicode=cidcodes[foundindex] - if unicode then - originals[index],tounicode[index],ns=unicode,tounicode16(unicode),ns+1 - end - end - if not unicode then - local foundcodes,multiple=lpegmatch(uparser,reference) - if foundcodes then - if multiple then - originals[index],tounicode[index],nl,unicode=foundcodes,tounicode16sequence(foundcodes),nl+1,true - else - originals[index],tounicode[index],ns,unicode=foundcodes,tounicode16(foundcodes),ns+1,foundcodes - end - end - end - end - end - end - end - if not unicode then - local split=lpegmatch(ligsplitter,name) - local nplit=(split and #split) or 0 - if nplit==0 then - elseif nplit==1 then - local base=split[1] - unicode=unicodes[base] or (aglmap and aglmap[base]) - if unicode then - if type(unicode)=="table" then - unicode=unicode[1] - end - originals[index],tounicode[index],ns=unicode,tounicode16(unicode),ns+1 - end - else - local t={} - for l=1,nplit do - local base=split[l] - local u=unicodes[base] or (aglmap and aglmap[base]) - if not u then - break - elseif type(u)=="table" then - t[#t+1]=u[1] - else - t[#t+1]=u - end - end - if #t>0 then - originals[index],tounicode[index],nl,unicode=t,tounicode16sequence(t),nl+1,true - end - end - end - if not unicode then - local foundcodes,multiple=lpegmatch(uparser,name) - if foundcodes then - if multiple then - originals[index],tounicode[index],nl,unicode=foundcodes,tounicode16sequence(foundcodes),nl+1,true - else - originals[index],tounicode[index],ns,unicode=foundcodes,tounicode16(foundcodes),ns+1,foundcodes - end - end - end - if not unicode then - originals[index],tounicode[index]=0xFFFD,"FFFD" - end - end - end - if trace_unimapping then - for index,glyph in table.sortedhash(data.glyphs) do - local toun,name,unic=tounicode[index],glyph.name,glyph.unicode or -1 - if toun then - logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun) - else - logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic) - end - end - end - if trace_loading and (ns>0 or nl>0) then - logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns,ns) - end -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-otf']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local utf=unicode.utf8 -local concat,utfbyte=table.concat,utf.byte -local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip -local type,next,tonumber,tostring=type,next,tonumber,tostring -local abs=math.abs -local getn=table.getn -local lpegmatch=lpeg.match -local trace_private=false trackers.register("otf.private",function(v) trace_private=v end) -local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) -local trace_features=false trackers.register("otf.features",function(v) trace_features=v end) -local trace_dynamics=false trackers.register("otf.dynamics",function(v) trace_dynamics=v end) -local trace_sequences=false trackers.register("otf.sequences",function(v) trace_sequences=v end) -local trace_math=false trackers.register("otf.math",function(v) trace_math=v end) -local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) -fonts=fonts or {} -fonts.otf=fonts.otf or {} -fonts.tfm=fonts.tfm or {} -local otf=fonts.otf -local tfm=fonts.tfm -local fontdata=fonts.ids -otf.tables=otf.tables or {} -otf.meanings=otf.meanings or {} -otf.tables.features=otf.tables.features or {} -otf.tables.languages=otf.tables.languages or {} -otf.tables.scripts=otf.tables.scripts or {} -otf.features=otf.features or {} -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.653 -otf.pack=true -otf.syncspace=true -otf.notdef=false -otf.cache=containers.define("fonts","otf",otf.version,true) -otf.cleanup_aat=false -local wildcard="*" -local default="dflt" -otf.tables.global_fields=table.tohash { - "lookups", - "glyphs", - "subfonts", - "luatex", - "pfminfo", - "cidinfo", - "tables", - "names", - "unicodes", - "names", - "anchor_classes", - "kern_classes", - "gpos", - "gsub" -} -otf.tables.valid_fields={ - "anchor_classes", - "ascent", - "cache_version", - "cidinfo", - "copyright", - "creationtime", - "descent", - "design_range_bottom", - "design_range_top", - "design_size", - "encodingchanged", - "extrema_bound", - "familyname", - "fontname", - "fontstyle_id", - "fontstyle_name", - "fullname", - "glyphs", - "hasvmetrics", - "head_optimized_for_cleartype", - "horiz_base", - "issans", - "isserif", - "italicangle", - "kerns", - "lookups", - "macstyle", - "modificationtime", - "onlybitmaps", - "origname", - "os2_version", - "pfminfo", - "private", - "serifcheck", - "sfd_version", - "strokedfont", - "strokewidth", - "subfonts", - "table_version", - "ttf_tables", - "uni_interp", - "uniqueid", - "units_per_em", - "upos", - "use_typo_metrics", - "uwidth", - "validation_state", - "verbose", - "version", - "vert_base", - "weight", - "weight_width_slope_only", - "xuid", -} -local function load_featurefile(ff,featurefile) - if featurefile then - featurefile=resolvers.find_file(file.addsuffix(featurefile,'fea'),'fea') - if featurefile and featurefile~="" then - if trace_loading then - logs.report("load otf","featurefile: %s",featurefile) - end - fontloader.apply_featurefile(ff,featurefile) - end - end -end -function otf.enhance(name,data,filename,verbose) - local enhancer=otf.enhancers[name] - if enhancer then - if (verbose~=nil and verbose) or trace_loading then - logs.report("load otf","enhance: %s (%s)",name,filename) - end - enhancer(data,filename) - end -end -local enhancers={ - "patch bugs", - "merge cid fonts","prepare unicode","cleanup ttf tables","compact glyphs","reverse coverage", - "cleanup aat","enrich with features","add some missing characters", - "reorganize mark classes", - "reorganize kerns", - "flatten glyph lookups","flatten anchor tables","flatten feature tables", - "simplify glyph lookups", - "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", - "check math parameters", -} -function otf.load(filename,format,sub,featurefile) - local name=file.basename(file.removesuffix(filename)) - local attr=lfs.attributes(filename) - local size,time=attr.size or 0,attr.modification or 0 - if featurefile then - local fattr=lfs.attributes(featurefile) - local fsize,ftime=fattr and fattr.size or 0,fattr and fattr.modification or 0 - name=name.."@"..file.removesuffix(file.basename(featurefile))..ftime..fsize - end - if sub=="" then sub=false end - local hash=name - if sub then - hash=hash.."-"..sub - end - hash=containers.cleanname(hash) - local data=containers.read(otf.cache,hash) - if not data or data.verbose~=fonts.verbose or data.size~=size or data.time~=time then - logs.report("load otf","loading: %s (hash: %s)",filename,hash) - local ff,messages - if sub then - ff,messages=fontloader.open(filename,sub) - else - ff,messages=fontloader.open(filename) - end - if trace_loading and messages and #messages>0 then - if type(messages)=="string" then - logs.report("load otf","warning: %s",messages) - else - for m=1,#messages do - logs.report("load otf","warning: %s",tostring(messages[m])) - end - end - else - logs.report("load otf","font loaded okay") - end - if ff then - load_featurefile(ff,featurefile) - data=fontloader.to_table(ff) - fontloader.close(ff) - if data then - logs.report("load otf","file size: %s",size) - logs.report("load otf","enhancing ...") - for e=1,#enhancers do - otf.enhance(enhancers[e],data,filename) - io.flush() - end - if otf.pack and not fonts.verbose then - otf.enhance("pack",data,filename) - end - data.size=size - data.time=time - data.verbose=fonts.verbose - logs.report("load otf","saving in cache: %s",filename) - data=containers.write(otf.cache,hash,data) - collectgarbage("collect") - data=containers.read(otf.cache,hash) - collectgarbage("collect") - else - logs.report("load otf","loading failed (table conversion error)") - end - else - logs.report("load otf","loading failed (file read error)") - end - end - if data then - if trace_defining then - logs.report("define font","loading from cache: %s",hash) - end - otf.enhance("unpack",data,filename,false) - otf.add_dimensions(data) - if trace_sequences then - otf.show_feature_order(data,filename) - end - end - return data -end -function otf.add_dimensions(data) - if data then - local force=otf.notdef - local luatex=data.luatex - local defaultwidth=luatex.defaultwidth or 0 - local defaultheight=luatex.defaultheight or 0 - local defaultdepth=luatex.defaultdepth or 0 - for _,d in next,data.glyphs do - local bb,wd=d.boundingbox,d.width - if not wd then - d.width=defaultwidth - elseif wd~=0 and d.class=="mark" then - d.width=-wd - end - if force and not d.name then - d.name=".notdef" - end - if bb then - local ht,dp=bb[4],-bb[2] - if ht==0 or ht<0 then - else - d.height=ht - end - if dp==0 or dp<0 then - else - d.depth=dp - end - end - end - end -end -function otf.show_feature_order(otfdata,filename) - local sequences=otfdata.luatex.sequences - if sequences and #sequences>0 then - if trace_loading then - logs.report("otf check","font %s has %s sequences",filename,#sequences) - logs.report("otf check"," ") - end - for nos=1,#sequences do - local sequence=sequences[nos] - local typ=sequence.type or "no-type" - local name=sequence.name or "no-name" - local subtables=sequence.subtables or { "no-subtables" } - local features=sequence.features - if trace_loading then - logs.report("otf check","%3i %-15s %-20s [%s]",nos,name,typ,concat(subtables,",")) - end - if features then - for feature,scripts in next,features do - local tt={} - for script,languages in next,scripts do - local ttt={} - for language,_ in next,languages do - ttt[#ttt+1]=language - end - tt[#tt+1]=format("[%s: %s]",script,concat(ttt," ")) - end - if trace_loading then - logs.report("otf check"," %s: %s",feature,concat(tt," ")) - end - end - end - end - if trace_loading then - logs.report("otf check","\n") - end - elseif trace_loading then - logs.report("otf check","font %s has no sequences",filename) - end -end -otf.enhancers["reorganize mark classes"]=function(data,filename) - if data.mark_classes then - local unicodes=data.luatex.unicodes - local reverse={} - for name,class in next,data.mark_classes do - local t={} - for s in gmatch(class,"[^ ]+") do - local us=unicodes[s] - if type(us)=="table" then - for u=1,#us do - t[us[u]]=true - end - else - t[us]=true - end - end - reverse[name]=t - end - data.luatex.markclasses=reverse - data.mark_classes=nil - end -end -otf.enhancers["prepare luatex tables"]=function(data,filename) - data.luatex=data.luatex or {} - local luatex=data.luatex - luatex.filename=filename - luatex.version=otf.version - 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={},{} - for k=1,#g do - local f=features or g[k].features - if f then - for k=1,#f do - local tag=f[k].tag - if not done[tag] then - t[#t+1]=tag - done[tag]=true - end - end - end - end - if #t>0 then - return t - end - end - return nil -end -otf.enhancers["analyse features"]=function(data,filename) -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) - local classes=data.anchor_classes - local luatex=data.luatex - local anchor_to_lookup,lookup_to_anchor={},{} - luatex.anchor_to_lookup,luatex.lookup_to_anchor=anchor_to_lookup,lookup_to_anchor - if classes then - for c=1,#classes do - local class=classes[c] - local anchor=class.name - local lookups=class.lookup - if type(lookups)~="table" then - lookups={ lookups } - end - local a=anchor_to_lookup[anchor] - if not a then a={} anchor_to_lookup[anchor]=a end - for l=1,#lookups do - local lookup=lookups[l] - local l=lookup_to_anchor[lookup] - if not l then l={} lookup_to_anchor[lookup]=l end - l[anchor]=true - a[lookup]=true - end - end - end -end -otf.enhancers["analyse marks"]=function(data,filename) - local glyphs=data.glyphs - local marks={} - data.luatex.marks=marks - for unicode,index in next,data.luatex.indices do - local glyph=glyphs[index] - if glyph.class=="mark" then - marks[unicode]=true - end - end -end -otf.enhancers["analyse unicodes"]=fonts.map.add_to_unicode -otf.enhancers["analyse subtables"]=function(data,filename) - data.luatex=data.luatex or {} - local luatex=data.luatex - local sequences={} - local lookups={} - luatex.sequences=sequences - luatex.lookups=lookups - for _,g in next,{ data.gsub,data.gpos } do - for k=1,#g do - local gk=g[k] - local typ=gk.type - if typ=="gsub_contextchain" or typ=="gpos_contextchain" then - gk.chain=1 - elseif typ=="gsub_reversecontextchain" or typ=="gpos_reversecontextchain" then - gk.chain=-1 - else - gk.chain=0 - end - local features=gk.features - if features then - sequences[#sequences+1]=gk - local t={} - for f=1,#features do - local feature=features[f] - local hash={} - for s,languages in next,feature.scripts do - s=lower(s) - local h=hash[s] - if not h then h={} hash[s]=h end - for l=1,#languages do - h[strip(lower(languages[l]))]=true - end - end - t[feature.tag]=hash - end - gk.features=t - else - lookups[gk.name]=gk - gk.name=nil - end - local subtables=gk.subtables - if subtables then - local t={} - for s=1,#subtables do - local subtable=subtables[s] - local name=subtable.name - t[#t+1]=name - end - gk.subtables=t - end - local flags=gk.flags - if flags then - gk.flags={ - (flags.ignorecombiningmarks and "mark") or false, - (flags.ignoreligatures and "ligature") or false, - (flags.ignorebaseglyphs and "base") or false, - flags.r2l or false, - } - if flags.mark_class then - gk.markclass=luatex.markclasses[flags.mark_class] - end - end - end - end -end -otf.enhancers["merge cid fonts"]=function(data,filename) - if data.subfonts then - if data.glyphs and next(data.glyphs) then - logs.report("load otf","replacing existing glyph table due to subfonts") - end - local cidinfo=data.cidinfo - local verbose=fonts.verbose - if cidinfo.registry then - local cidmap,cidname=fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement) - if cidmap then - cidinfo.usedname=cidmap.usedname - local glyphs,uni_to_int,int_to_uni,nofnames,nofunicodes={},{},{},0,0 - local unicodes,names=cidmap.unicodes,cidmap.names - for n,subfont in next,data.subfonts do - for index,g in next,subfont.glyphs do - if not next(g) then - else - local unicode,name=unicodes[index],names[index] - g.cidindex=n - g.boundingbox=g.boundingbox - g.name=g.name or name or "unknown" - if unicode then - uni_to_int[unicode]=index - int_to_uni[index]=unicode - nofunicodes=nofunicodes+1 - g.unicode=unicode - elseif name then - nofnames=nofnames+1 - g.unicode=-1 - end - glyphs[index]=g - end - end - subfont.glyphs=nil - end - if trace_loading then - logs.report("load otf","cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes,nofnames,nofunicodes+nofnames) - end - data.glyphs=glyphs - data.map=data.map or {} - data.map.map=uni_to_int - data.map.backmap=int_to_uni - elseif trace_loading then - logs.report("load otf","unable to remap cid font, missing cid file for %s",filename) - end - elseif trace_loading then - logs.report("load otf","font %s has no glyphs",filename) - end - end -end -otf.enhancers["prepare unicode"]=function(data,filename) - local luatex=data.luatex - if not luatex then luatex={} data.luatex=luatex end - local indices,unicodes,multiples,internals={},{},{},{} - local glyphs=data.glyphs - 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 - if index>0 then - local name=glyph.name - if name then - local unicode=glyph.unicode - if unicode==-1 or unicode>=criterium then - glyph.unicode=private - indices[private]=index - unicodes[name]=private - internals[index]=true - if trace_private then - logs.report("load otf","enhance: glyph %s at index U+%04X is moved to private unicode slot U+%04X",name,index,private) - end - private=private+1 - else - indices[unicode]=index - unicodes[name]=unicode - end - end - end - end - for unicode,index in next,mapmap do - if not internals[index] then - local name=glyphs[index].name - if name then - local un=unicodes[name] - if not un then - unicodes[name]=unicode - elseif type(un)=="number" then - if un~=unicode then - multiples[#multiples+1]=name - unicodes[name]={ un,unicode } - indices[unicode]=index - end - else - local ok=false - for u=1,#un do - if un[u]==unicode then - ok=true - break - end - end - if not ok then - multiples[#multiples+1]=name - un[#un+1]=unicode - indices[unicode]=index - end - end - end - end - end - if trace_loading then - if #multiples>0 then - logs.report("load otf","%s glyph are reused: %s",#multiples,concat(multiples," ")) - else - logs.report("load otf","no glyph are reused") - end - end - luatex.indices=indices - luatex.unicodes=unicodes - luatex.private=private -end -otf.enhancers["cleanup ttf tables"]=function(data,filename) - local ttf_tables=data.ttf_tables - if ttf_tables then - for k=1,#ttf_tables do - if ttf_tables[k].data then ttf_tables[k].data="deleted" end - end - end - data.ttf_tab_saved=nil -end -otf.enhancers["compact glyphs"]=function(data,filename) - table.compact(data.glyphs) - if data.subfonts then - for _,subfont in next,data.subfonts do - table.compact(subfont.glyphs) - end - end -end -otf.enhancers["reverse coverage"]=function(data,filename) - if data.lookups then - for _,v in next,data.lookups do - if v.rules then - for _,vv in next,v.rules do - local c=vv.coverage - if c and c.before then - c.before=table.reverse(c.before) - end - end - end - end - end -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 - if ic~=0 then - glyph.italic=ic - end - glyph.italic_correction=nil - ok=true - end - end - otf.tables.valid_fields[#otf.tables.valid_fields+1]="has_italic" - data.has_italic=true -end -otf.enhancers["check math"]=function(data,filename) - if data.math then - local glyphs=data.glyphs - local unicodes=data.luatex.unicodes - for index,glyph in next,glyphs do - local mk=glyph.mathkern - local hv=glyph.horiz_variants - local vv=glyph.vert_variants - if mk or hv or vv then - local math={} - glyph.math=math - if mk then - for k,v in next,mk do - if not next(v) then - mk[k]=nil - end - end - math.kerns=mk - glyph.mathkern=nil - end - if hv then - math.horiz_variants=hv.variants - local p=hv.parts - if p and #p>0 then - for i=1,#p do - local pi=p[i] - pi.glyph=unicodes[pi.component] or 0 - end - math.horiz_parts=p - end - local ic=hv.italic_correction - if ic and ic~=0 then - math.horiz_italic_correction=ic - end - glyph.horiz_variants=nil - end - if vv then - local uc=unicodes[index] - math.vert_variants=vv.variants - local p=vv.parts - if p and #p>0 then - for i=1,#p do - local pi=p[i] - pi.glyph=unicodes[pi.component] or 0 - end - math.vert_parts=p - end - local ic=vv.italic_correction - if ic and ic~=0 then - math.vert_italic_correction=ic - end - glyph.vert_variants=nil - end - local ic=glyph.italic_correction - if ic then - if ic~=0 then - math.italic_correction=ic - end - glyph.italic_correction=nil - end - end - end - end -end -otf.enhancers["share widths"]=function(data,filename) - local glyphs=data.glyphs - local widths={} - for index,glyph in next,glyphs do - local width=glyph.width - widths[width]=(widths[width] or 0)+1 - end - local wd,most=0,1 - for k,v in next,widths do - if v>most then - wd,most=k,v - end - end - if most>1000 then - if trace_loading then - logs.report("load otf","most common width: %s (%s times), sharing (cjk font)",wd,most) - end - for k,v in next,glyphs do - if v.width==wd then - v.width=nil - end - end - data.luatex.defaultwidth=wd - end -end -otf.enhancers["reorganize kerns"]=function(data,filename) - local glyphs,mapmap,unicodes=data.glyphs,data.luatex.indices,data.luatex.unicodes - local mkdone=false - local function do_it(lookup,first_unicode,kerns) - local glyph=glyphs[mapmap[first_unicode]] - if glyph then - local mykerns=glyph.mykerns - if not mykerns then - mykerns={} - glyph.mykerns=mykerns - end - local lookupkerns=mykerns[lookup] - if not lookupkerns then - lookupkerns={} - mykerns[lookup]=lookupkerns - end - for second_unicode,kern in next,kerns do - lookupkerns[second_unicode]=kern - end - elseif trace_loading then - logs.report("load otf","no glyph data for U+%04X",first_unicode) - end - end - for index,glyph in next,glyphs do - if glyph.kerns then - local mykerns={} - for k,v in next,glyph.kerns do - local vc,vo,vl=v.char,v.off,v.lookup - if vc and vo and vl then - local uvc=unicodes[vc] - if not uvc then - if trace_loading then - logs.report("load otf","problems with unicode %s of kern %s at glyph %s",vc,k,index) - end - else - if type(vl)~="table" then - vl={ vl } - end - for l=1,#vl do - local vll=vl[l] - local mkl=mykerns[vll] - if not mkl then - mkl={} - mykerns[vll]=mkl - end - if type(uvc)=="table" then - for u=1,#uvc do - mkl[uvc[u]]=vo - end - else - mkl[uvc]=vo - end - end - end - end - end - glyph.mykerns=mykerns - glyph.kerns=nil - mkdone=true - end - end - if trace_loading and mkdone then - logs.report("load otf","replacing 'kerns' tables by 'mykerns' tables") - end - if data.kerns then - if trace_loading then - logs.report("load otf","removing global 'kern' table") - end - data.kerns=nil - end - local dgpos=data.gpos - if dgpos then - local separator=lpeg.P(" ") - local other=((1-separator)^0)/unicodes - local splitter=lpeg.Ct(other*(separator*other)^0) - for gp=1,#dgpos do - local gpos=dgpos[gp] - local subtables=gpos.subtables - if subtables then - for s=1,#subtables do - local subtable=subtables[s] - local kernclass=subtable.kernclass - if kernclass then - local split={} - for k=1,#kernclass do - local kcl=kernclass[k] - local firsts,seconds,offsets,lookups=kcl.firsts,kcl.seconds,kcl.offsets,kcl.lookup - if type(lookups)~="table" then - lookups={ lookups } - end - local maxfirsts,maxseconds=#firsts,#seconds - for _,s in next,firsts do - split[s]=split[s] or lpegmatch(splitter,s) - end - for _,s in next,seconds do - split[s]=split[s] or lpegmatch(splitter,s) - end - for l=1,#lookups do - local lookup=lookups[l] - for fk=1,#firsts do - local fv=firsts[fk] - local splt=split[fv] - if splt then - local kerns,baseoffset={},(fk-1)*maxseconds - for sk=2,maxseconds do - local sv=seconds[sk] - local splt=split[sv] - if splt then - local offset=offsets[baseoffset+sk] - if offset then - for i=1,#splt do - local second_unicode=splt[i] - if tonumber(second_unicode) then - kerns[second_unicode]=offset - else for s=1,#second_unicode do - kerns[second_unicode[s]]=offset - end end - end - end - end - end - for i=1,#splt do - local first_unicode=splt[i] - if tonumber(first_unicode) then - do_it(lookup,first_unicode,kerns) - else for f=1,#first_unicode do - do_it(lookup,first_unicode[f],kerns) - end end - end - end - end - end - end - subtable.comment="The kernclass table is merged into mykerns in the indexed glyph tables." - subtable.kernclass={} - end - end - end - end - end -end -otf.enhancers["strip not needed data"]=function(data,filename) - local verbose=fonts.verbose - local int_to_uni=data.luatex.unicodes - for k,v in next,data.glyphs do - local d=v.dependents - if d then v.dependents=nil end - local a=v.altuni - if a then v.altuni=nil end - if verbose then - local code=int_to_uni[k] - if code then - local vu=v.unicode - if not vu then - v.unicode=code - elseif type(vu)=="table" then - if vu[#vu]==code then - else - vu[#vu+1]=code - end - elseif vu~=code then - v.unicode={ vu,code } - end - end - else - v.unicode=nil - v.index=nil - end - end - data.luatex.comment="Glyph tables have their original index. When present, mykern tables are indexed by unicode." - data.map=nil - data.names=nil - data.glyphcnt=nil - data.glyphmax=nil - if true then - data.gpos=nil - 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 - if not global_fields[k] then - metadata[k]=v - data[k]=nil - end - end - data.metadata=metadata - local pfminfo=data.pfminfo - metadata.isfixedpitch=metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose["proportion"]=="Monospaced") - metadata.charwidth=pfminfo and pfminfo.avgwidth -end -local private_math_parameters={ - "FractionDelimiterSize", - "FractionDelimiterDisplayStyleSize", -} -otf.enhancers["check math parameters"]=function(data,filename) - local mathdata=data.metadata.math - if mathdata then - for m=1,#private_math_parameters do - local pmp=private_math_parameters[m] - if not mathdata[pmp] then - if trace_loading then - logs.report("load otf","setting math parameter '%s' to 0",pmp) - end - mathdata[pmp]=0 - end - end - end -end -otf.enhancers["flatten glyph lookups"]=function(data,filename) - for k,v in next,data.glyphs do - local lookups=v.lookups - if lookups then - for kk,vv in next,lookups do - for kkk=1,#vv do - local vvv=vv[kkk] - local s=vvv.specification - if s then - local t=vvv.type - if t=="ligature" then - vv[kkk]={ "ligature",s.components,s.char } - elseif t=="alternate" then - vv[kkk]={ "alternate",s.components } - elseif t=="substitution" then - vv[kkk]={ "substitution",s.variant } - elseif t=="multiple" then - vv[kkk]={ "multiple",s.components } - elseif t=="position" then - vv[kkk]={ "position",{ s.x or 0,s.y or 0,s.h or 0,s.v or 0 } } - elseif t=="pair" then - local one,two,paired=s.offsets[1],s.offsets[2],s.paired or "" - if one then - if two then - vv[kkk]={ "pair",paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 },{ two.x or 0,two.y or 0,two.h or 0,two.v or 0 } } - else - vv[kkk]={ "pair",paired,{ one.x or 0,one.y or 0,one.h or 0,one.v or 0 } } - end - else - if two then - vv[kkk]={ "pair",paired,{},{ two.x or 0,two.y or 0,two.h or 0,two.v or 0} } - else - vv[kkk]={ "pair",paired } - end - end - else - if trace_loading then - logs.report("load otf","flattening needed, report to context list") - end - for a,b in next,s do - if trace_loading and vvv[a] then - logs.report("load otf","flattening conflict, report to context list") - end - vvv[a]=b - end - vvv.specification=nil - end - end - end - end - end - end -end -otf.enhancers["simplify glyph lookups"]=function(data,filename) - for k,v in next,data.glyphs do - local lookups=v.lookups - if lookups then - local slookups,mlookups - for kk,vv in next,lookups do - if #vv==1 then - if not slookups then - slookups={} - v.slookups=slookups - end - slookups[kk]=vv[1] - else - if not mlookups then - mlookups={} - v.mlookups=mlookups - end - mlookups[kk]=vv - end - end - v.lookups=nil - end - end -end -otf.enhancers["flatten anchor tables"]=function(data,filename) - for k,v in next,data.glyphs do - if v.anchors then - for kk,vv in next,v.anchors do - for kkk,vvv in next,vv do - if vvv.x or vvv.y then - vv[kkk]={ vvv.x or 0,vvv.y or 0 } - else - for kkkk=1,#vvv do - local vvvv=vvv[kkkk] - vvv[kkkk]={ vvvv.x or 0,vvvv.y or 0 } - end - end - end - end - end - end -end -otf.enhancers["flatten feature tables"]=function(data,filename) - for _,tag in next,otf.glists do - if data[tag] then - if trace_loading then - logs.report("load otf","flattening %s table",tag) - end - for k,v in next,data[tag] do - local features=v.features - if features then - for kk=1,#features do - local vv=features[kk] - local t={} - local scripts=vv.scripts - for kkk=1,#scripts do - local vvv=scripts[kkk] - t[vvv.script]=vvv.langs - end - vv.scripts=t - end - end - end - end - end -end -otf.enhancers.patches=otf.enhancers.patches or {} -otf.enhancers["patch bugs"]=function(data,filename) - local basename=file.basename(lower(filename)) - for pattern,action in next,otf.enhancers.patches do - if find(basename,pattern) then - action(data,filename) - end - end -end -fonts.otf.enhancers["enrich with features"]=function(data,filename) -end -function otf.features.register(name,default) - otf.features.list[#otf.features.list+1]=name - otf.features.default[name]=default -end -function otf.set_features(tfmdata,features) - local processes={} - if features and next(features) then - local lists={ - fonts.triggers, - fonts.processors, - fonts.manipulators, - } - local mode=tfmdata.mode or fonts.mode - local initializers=fonts.initializers - local fi=initializers[mode] - if fi then - local fiotf=fi.otf - if fiotf then - local done={} - for l=1,4 do - local list=lists[l] - if list then - for i=1,#list do - local f=list[i] - local value=features[f] - if value and fiotf[f] then - if not done[f] then - if trace_features then - logs.report("define otf","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.fullname or 'unknown') - end - fiotf[f](tfmdata,value) - mode=tfmdata.mode or fonts.mode - local im=initializers[mode] - if im then - fiotf=initializers[mode].otf - end - done[f]=true - end - end - end - end - end - end - end - local fm=fonts.methods[mode] - if fm then - local fmotf=fm.otf - if fmotf then - for l=1,4 do - local list=lists[l] - if list then - for i=1,#list do - local f=list[i] - if fmotf[f] then - if trace_features then - logs.report("define otf","installing feature handler %s for mode %s for font %s",f,mode or 'unknown',tfmdata.fullname or 'unknown') - end - processes[#processes+1]=fmotf[f] - end - end - end - end - end - else - end - end - return processes,features -end -function otf.otf_to_tfm(specification) - local name=specification.name - local sub=specification.sub - local filename=specification.filename - local format=specification.format - local features=specification.features.normal - local cache_id=specification.hash - local tfmdata=containers.read(tfm.cache,cache_id) - if not tfmdata then - local otfdata=otf.load(filename,format,sub,features and features.featurefile) - if otfdata and next(otfdata) then - otfdata.shared=otfdata.shared or { - featuredata={}, - anchorhash={}, - initialized=false, - } - tfmdata=otf.copy_to_tfm(otfdata,cache_id) - if tfmdata and next(tfmdata) then - tfmdata.unique=tfmdata.unique or {} - tfmdata.shared=tfmdata.shared or {} - local shared=tfmdata.shared - shared.otfdata=otfdata - shared.features=features - shared.dynamics={} - shared.processes={} - shared.set_dynamics=otf.set_dynamics - tfmdata.luatex=otfdata.luatex - tfmdata.indices=otfdata.luatex.indices - tfmdata.unicodes=otfdata.luatex.unicodes - 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)) - end - end - containers.write(tfm.cache,cache_id,tfmdata) - end - return tfmdata -end -fonts.formats.dfont="truetype" -fonts.formats.ttc="truetype" -fonts.formats.ttf="truetype" -fonts.formats.otf="opentype" -function otf.copy_to_tfm(data,cache_id) - if data then - local glyphs,pfminfo,metadata=data.glyphs or {},data.pfminfo or {},data.metadata or {} - local luatex=data.luatex - local unicodes=luatex.unicodes - local indices=luatex.indices - local characters,parameters,math_parameters,descriptions={},{},{},{} - local designsize=metadata.designsize or metadata.design_size or 100 - if designsize==0 then - designsize=100 - end - local spaceunits,spacer=500,"space" - for u,i in next,indices do - characters[u]={} - descriptions[u]=glyphs[i] - end - if metadata.math then - for name,value in next,metadata.math do - math_parameters[name]=value - end - for u,char in next,characters do - local d=descriptions[u] - local m=d.math - if m then - local variants,parts,c,uc=m.horiz_variants,m.horiz_parts,char,u - if variants then - for n in gmatch(variants,"[^ ]+") do - local un=unicodes[n] - if un and uc~=un then - c.next=un - c=characters[un] - uc=un - end - end - c.horiz_variants=parts - elseif parts then - c.horiz_variants=parts - end - local variants,parts,c,uc=m.vert_variants,m.vert_parts,char,u - if variants then - for n in gmatch(variants,"[^ ]+") do - local un=unicodes[n] - if un and uc~=un then - c.next=un - c=characters[un] - uc=un - end - end - c.vert_variants=parts - elseif parts then - c.vert_variants=parts - end - local italic_correction=m.vert_italic_correction - if italic_correction then - c.vert_italic_correction=italic_correction - end - local kerns=m.kerns - if kerns then - char.mathkerns=kerns - end - end - end - end - local endash,emdash,space=0x20,0x2014,"space" - if metadata.isfixedpitch then - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and descriptions[emdash] then - spaceunits,spacer=descriptions[emdash].width,"emdash" - end - if not spaceunits and metadata.charwidth then - spaceunits,spacer=metadata.charwidth,"charwidth" - end - else - if descriptions[endash] then - spaceunits,spacer=descriptions[endash].width,"space" - end - if not spaceunits and descriptions[emdash] then - spaceunits,spacer=descriptions[emdash].width/2,"emdash/2" - end - if not spaceunits and metadata.charwidth then - spaceunits,spacer=metadata.charwidth,"charwidth" - end - end - spaceunits=tonumber(spaceunits) or tfm.units/2 - local filename=fonts.tfm.checked_filename(luatex) - local fontname=metadata.fontname - local fullname=metadata.fullname or fontname - local cidinfo=data.cidinfo - local units=metadata.units_per_em or 1000 - cidinfo.registry=cidinfo and cidinfo.registry or "" - parameters.slant=0 - parameters.space=spaceunits - parameters.space_stretch=units/2 - parameters.space_shrink=1*units/3 - parameters.x_height=2*units/5 - parameters.quad=units - if spaceunits<2*units/5 then - end - local italicangle=metadata.italicangle - if italicangle then - parameters.slant=parameters.slant-math.round(math.tan(italicangle*math.pi/180)) - end - if metadata.isfixedpitch then - parameters.space_stretch=0 - parameters.space_shrink=0 - elseif otf.syncspace then - parameters.space_stretch=spaceunits/2 - parameters.space_shrink=spaceunits/3 - end - parameters.extra_space=parameters.space_shrink - if pfminfo.os2_xheight and pfminfo.os2_xheight>0 then - parameters.x_height=pfminfo.os2_xheight - else - local x=0x78 - if x then - local x=descriptions[x] - if x then - parameters.x_height=x.height - end - end - end - return { - characters=characters, - parameters=parameters, - math_parameters=math_parameters, - descriptions=descriptions, - indices=indices, - unicodes=unicodes, - type="real", - direction=0, - boundarychar_label=0, - boundarychar=65536, - designsize=(designsize/10)*65536, - spacer="500 units", - encodingbytes=2, - filename=filename, - fontname=fontname, - fullname=fullname, - psname=fontname or fullname, - name=filename or fullname, - units=units, - format=fonts.fontformat(filename,"opentype"), - cidinfo=cidinfo, - ascender=abs(metadata.ascent or 0), - descender=abs(metadata.descent or 0), - spacer=spacer, - italicangle=italicangle, - } - else - return nil - end -end -otf.features.register('mathsize') -function tfm.read_from_open_type(specification) - local tfmtable=otf.otf_to_tfm(specification) - if tfmtable then - local otfdata=tfmtable.shared.otfdata - tfmtable.name=specification.name - tfmtable.sub=specification.sub - local s=specification.size - local m=otfdata.metadata.math - if m then - local f=specification.features - if f then - local f=f.normal - if f and f.mathsize then - local mathsize=specification.mathsize or 0 - if mathsize==2 then - local p=m.ScriptPercentScaleDown - if p then - local ps=p*specification.textsize/100 - if trace_math then - logs.report("define font","asked script size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100) - end - s=ps - end - elseif mathsize==3 then - local p=m.ScriptScriptPercentScaleDown - if p then - local ps=p*specification.textsize/100 - if trace_math then - logs.report("define font","asked scriptscript size: %s, used: %s (%2.2f %%)",s,ps,(ps/s)*100) - end - s=ps - end - end - end - end - end - tfmtable=tfm.scale(tfmtable,s,specification.relativeid) - if tfm.fontname_mode=="specification" then - local specname=specification.specification - if specname then - tfmtable.name=specname - if trace_defining then - logs.report("define font","overloaded fontname: '%s'",specname) - end - end - end - fonts.logger.save(tfmtable,file.extname(specification.filename),specification) - end - return tfmtable -end -function otf.collect_lookups(otfdata,kind,script,language) - local sequences=otfdata.luatex.sequences - if sequences then - local featuremap,featurelist={},{} - for s=1,#sequences do - local sequence=sequences[s] - local features=sequence.features - features=features and features[kind] - 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 - for s=1,#subtables do - local ss=subtables[s] - if not featuremap[s] then - featuremap[ss]=true - featurelist[#featurelist+1]=ss - end - end - end - end - end - if #featurelist>0 then - return featuremap,featurelist - end - end - return nil,nil -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-otd']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local 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) - local features=context_setups[context_numbers[attribute]] - 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 - return dsla - else - local tfmdata=fontdata[font] - a_to_script [attribute]=script - a_to_language[attribute]=language - 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={} - local set=fonts.define.check(features,otf.features.default) - dsla=otf.set_features(tfmdata,set) - if trace_dynamics then - logs.report("otf define","setting dynamics %s: attribute %s, script %s, language %s, set: %s",context_numbers[attribute],attribute,script,language,table.sequenced(set)) - end - tfmdata.script=saved.script - tfmdata.language=saved.language - tfmdata.mode=saved.mode - tfmdata.shared.features=saved.features - dynamics[script][language][attribute]=dsla - return dsla - end - end - return nil -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-oti']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local 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) -table.insert(fonts.processors,"features") - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-otb']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local concat=table.concat -local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip -local type,next,tonumber,tostring=type,next,tonumber,tostring -local lpegmatch=lpeg.match -local otf=fonts.otf -local tfm=fonts.tfm -local trace_baseinit=false trackers.register("otf.baseinit",function(v) trace_baseinit=v end) -local trace_singles=false trackers.register("otf.singles",function(v) trace_singles=v end) -local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end) -local trace_alternatives=false trackers.register("otf.alternatives",function(v) trace_alternatives=v end) -local trace_ligatures=false trackers.register("otf.ligatures",function(v) trace_ligatures=v end) -local trace_kerns=false trackers.register("otf.kerns",function(v) trace_kerns=v end) -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(" ")) -local pcache,fcache={},{} -local function gref(descriptions,n) - if type(n)=="number" then - local name=descriptions[n].name - if name then - return format("U+%04X (%s)",n,name) - else - return format("U+%04X") - end - elseif n then - local num,nam={},{} - for i=1,#n do - local ni=n[i] - num[i]=format("U+%04X",ni) - nam[i]=descriptions[ni].name or "?" - end - return format("%s (%s)",concat(num," "),concat(nam," ")) - else - return "?" - end -end -local function cref(kind,lookupname) - if lookupname then - return format("feature %s, lookup %s",kind,lookupname) - else - return format("feature %s",kind) - end -end -local function resolve_ligatures(tfmdata,ligatures,kind) - kind=kind or "unknown" - local unicodes=tfmdata.unicodes - local characters=tfmdata.characters - local descriptions=tfmdata.descriptions - local changed=tfmdata.changed - local done={} - while true do - local ok=false - for k,v in next,ligatures do - local lig=v[1] - if not done[lig] then - local ligs=lpegmatch(split_at_space,lig) - if #ligs==2 then - local uc=v[2] - local c,f,s=characters[uc],ligs[1],ligs[2] - local uft,ust=unicodes[f] or 0,unicodes[s] or 0 - if not uft or not ust then - logs.report("define otf","%s: unicode problem with base ligature %s = %s + %s",cref(kind),gref(descriptions,uc),gref(descriptions,uft),gref(descriptions,ust)) - else - if type(uft)=="number" then uft={ uft } end - if type(ust)=="number" then ust={ ust } end - for ufi=1,#uft do - local uf=uft[ufi] - for usi=1,#ust do - local us=ust[usi] - if changed[uf] or changed[us] then - if trace_baseinit and trace_ligatures then - logs.report("define otf","%s: base ligature %s + %s ignored",cref(kind),gref(descriptions,uf),gref(descriptions,us)) - end - else - local first,second=characters[uf],us - if first and second then - local t=first.ligatures - if not t then - t={} - first.ligatures=t - end - if type(uc)=="number" then - t[second]={ type=0,char=uc } - else - t[second]={ type=0,char=uc[1] } - end - if trace_baseinit and trace_ligatures then - logs.report("define otf","%s: base ligature %s + %s => %s",cref(kind),gref(descriptions,uf),gref(descriptions,us),gref(descriptions,uc)) - end - end - end - end - end - end - ok,done[lig]=true,descriptions[uc].name - end - end - end - if ok then - for d,n in next,done do - local pattern=pcache[d] if not pattern then pattern="^("..d..") " pcache[d]=pattern end - local fnc=fcache[n] if not fnc then fnc=function() return n.." " end fcache[n]=fnc end - for k,v in next,ligatures do - v[1]=gsub(v[1],pattern,fnc) - end - end - else - break - end - end -end -local splitter=lpeg.splitat(" ") -local function prepare_base_substitutions(tfmdata,kind,value) - if value then - local otfdata=tfmdata.shared.otfdata - local validlookups,lookuplist=otf.collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language) - if validlookups then - local ligatures={} - local unicodes=tfmdata.unicodes - local indices=tfmdata.indices - local characters=tfmdata.characters - local descriptions=tfmdata.descriptions - local changed=tfmdata.changed - local actions={ - substitution=function(p,lookup,k,glyph,unicode) - local pv=p[2] - if pv then - local upv=unicodes[pv] - if upv then - if type(upv)=="table" then - upv=upv[1] - end - if characters[upv] then - if trace_baseinit and trace_singles then - logs.report("define otf","%s: base substitution %s => %s",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upv)) - end - changed[k]=upv - end - end - end - end, - alternate=function(p,lookup,k,glyph,unicode) - local pc=p[2] - if pc then - if value==1 then - pc=lpegmatch(splitter,pc) - elseif value==2 then - local a,b=lpegmatch(splitter,pc) - pc=b or a - else - pc={ lpegmatch(splitter,pc) } - pc=pc[value] or pc[#pc] - end - if pc then - local upc=unicodes[pc] - if upc then - if type(upc)=="table" then - upc=upc[1] - end - if characters[upc] then - if trace_baseinit and trace_alternatives then - logs.report("define otf","%s: base alternate %s %s => %s",cref(kind,lookup),tostring(value),gref(descriptions,k),gref(descriptions,upc)) - end - changed[k]=upc - end - end - end - end - end, - ligature=function(p,lookup,k,glyph,unicode) - local pc=p[2] - if pc then - if trace_baseinit and trace_ligatures then - local upc={ lpegmatch(splitter,pc) } - for i=1,#upc do upc[i]=unicodes[upc[i]] end - logs.report("define otf","%s: base ligature %s => %s",cref(kind,lookup),gref(descriptions,upc),gref(descriptions,k)) - end - ligatures[#ligatures+1]={ pc,k } - end - end, - } - for k,c in next,characters do - local glyph=descriptions[k] - local lookups=glyph.slookups - if lookups then - for l=1,#lookuplist do - local lookup=lookuplist[l] - local p=lookups[lookup] - if p then - local a=actions[p[1]] - if a then - a(p,lookup,k,glyph,unicode) - end - end - end - end - local lookups=glyph.mlookups - if lookups then - for l=1,#lookuplist do - local lookup=lookuplist[l] - local ps=lookups[lookup] - if ps then - for i=1,#ps do - local p=ps[i] - local a=actions[p[1]] - if a then - a(p,lookup,k,glyph,unicode) - end - end - end - end - end - end - resolve_ligatures(tfmdata,ligatures,kind) - end - else - tfmdata.ligatures=tfmdata.ligatures or {} - end -end -local function prepare_base_kerns(tfmdata,kind,value) - if value then - local otfdata=tfmdata.shared.otfdata - local validlookups,lookuplist=otf.collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language) - if validlookups then - local unicodes=tfmdata.unicodes - local indices=tfmdata.indices - local characters=tfmdata.characters - local descriptions=tfmdata.descriptions - local sharedkerns={} - for u,chr in next,characters do - local d=descriptions[u] - if d then - local dk=d.mykerns - if dk then - local s=sharedkerns[dk] - if s==false then - elseif s then - chr.kerns=s - else - local t,done=chr.kerns or {},false - for l=1,#lookuplist do - local lookup=lookuplist[l] - local kerns=dk[lookup] - if kerns then - for k,v in next,kerns do - if v~=0 and not t[k] then - t[k],done=v,true - if trace_baseinit and trace_kerns then - logs.report("define otf","%s: base kern %s + %s => %s",cref(kind,lookup),gref(descriptions,u),gref(descriptions,k),v) - end - end - end - end - end - if done then - sharedkerns[dk]=t - chr.kerns=t - else - sharedkerns[dk]=false - end - end - end - end - end - end - end -end -local supported_gsub={ - 'liga','dlig','rlig','hlig', - 'pnum','onum','tnum','lnum', - 'zero', - 'smcp','cpsp','c2sc','ornm','aalt', - 'hwid','fwid', - 'ssty','rtlm', -} -local supported_gpos={ - 'kern' -} -function otf.features.register_base_substitution(tag) - supported_gsub[#supported_gsub+1]=tag -end -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 - 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] - 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 - tfmdata.fullname=tfmdata.fullname.."-"..base - end - if trace_preparing then - logs.report("otf define","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?") - end - end -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-otn']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local concat,insert,remove=table.concat,table.insert,table.remove -local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip -local type,next,tonumber,tostring=type,next,tonumber,tostring -local lpegmatch=lpeg.match -local otf=fonts.otf -local tfm=fonts.tfm -local trace_lookups=false trackers.register("otf.lookups",function(v) trace_lookups=v end) -local trace_singles=false trackers.register("otf.singles",function(v) trace_singles=v end) -local trace_multiples=false trackers.register("otf.multiples",function(v) trace_multiples=v end) -local trace_alternatives=false trackers.register("otf.alternatives",function(v) trace_alternatives=v end) -local trace_ligatures=false trackers.register("otf.ligatures",function(v) trace_ligatures=v end) -local trace_contexts=false trackers.register("otf.contexts",function(v) trace_contexts=v end) -local trace_marks=false trackers.register("otf.marks",function(v) trace_marks=v end) -local trace_kerns=false trackers.register("otf.kerns",function(v) trace_kerns=v end) -local trace_cursive=false trackers.register("otf.cursive",function(v) trace_cursive=v end) -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) -local trace_skips=false trackers.register("otf.skips",function(v) trace_skips=v end) -local trace_directions=false trackers.register("otf.directions",function(v) trace_directions=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) -trackers.register("otf.replacements","otf.singles,otf.multiples,otf.alternatives,otf.ligatures") -trackers.register("otf.positions","otf.marks,otf.kerns,otf.cursive") -trackers.register("otf.actions","otf.replacements,otf.positions") -trackers.register("otf.injections","nodes.injections") -trackers.register("*otf.sample","otf.steps,otf.actions,otf.analyzing") -local insert_node_after=node.insert_after -local delete_node=nodes.delete -local copy_node=node.copy -local find_node_tail=node.tail or node.slide -local set_attribute=node.set_attribute -local has_attribute=node.has_attribute -local zwnj=0x200C -local zwj=0x200D -local wildcard="*" -local default="dflt" -local split_at_space=lpeg.splitters[" "] or lpeg.Ct(lpeg.splitat(" ")) -local glyph=node.id('glyph') -local glue=node.id('glue') -local kern=node.id('kern') -local disc=node.id('disc') -local whatsit=node.id('whatsit') -local state=attributes.private('state') -local markbase=attributes.private('markbase') -local markmark=attributes.private('markmark') -local markdone=attributes.private('markdone') -local cursbase=attributes.private('cursbase') -local curscurs=attributes.private('curscurs') -local cursdone=attributes.private('cursdone') -local kernpair=attributes.private('kernpair') -local set_mark=nodes.set_mark -local set_cursive=nodes.set_cursive -local set_kern=nodes.set_kern -local set_pair=nodes.set_pair -local markonce=true -local cursonce=true -local kernonce=true -local fontdata=fonts.ids -otf.features.process={} -local tfmdata=false -local otfdata=false -local characters=false -local descriptions=false -local marks=false -local indices=false -local unicodes=false -local currentfont=false -local lookuptable=false -local anchorlookups=false -local handlers={} -local rlmode=0 -local featurevalue=false -local context_setups=fonts.define.specify.context_setups -local context_numbers=fonts.define.specify.context_numbers -local context_merged=fonts.define.specify.context_merged -local special_attributes={ - init=1, - medi=2, - fina=3, - isol=4 -} -local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end -local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end -local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end -local function logprocess(...) - if trace_steps then - registermessage(...) - end - logs.report("otf direct",...) -end -local function logwarning(...) - logs.report("otf direct",...) -end -local function gref(n) - if type(n)=="number" then - local description=descriptions[n] - local name=description and description.name - if name then - return format("U+%04X (%s)",n,name) - else - return format("U+%04X",n) - end - elseif not n then - return "<error in tracing>" - else - local num,nam={},{} - for i=1,#n do - local ni=n[i] - num[#num+1]=format("U+%04X",ni) - local dni=descriptions[ni] - nam[#num]=(dni and dni.name) or "?" - end - return format("%s (%s)",concat(num," "),concat(nam," ")) - end -end -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 or "?",chainlookupname or "?",lookupname) - elseif chainlookupname then - return format("feature %s, chain %s, sub %s",kind,chainname or "?",chainlookupname) - elseif chainname then - return format("feature %s, chain %s",kind,chainname) - else - return format("feature %s",kind) - end -end -local function pref(kind,lookupname) - return format("feature %s, lookup %s",kind,lookupname) -end -local function markstoligature(kind,lookupname,start,stop,char) - local n=copy_node(start) - local keep=start - local current - current,start=insert_node_after(start,start,n) - local snext=stop.next - current.next=snext - if snext then - snext.prev=current - end - start.prev,stop.next=nil,nil - current.char,current.subtype,current.components=char,2,start - return keep -end -local function toligature(kind,lookupname,start,stop,char,markflag,discfound) - if start~=stop then - if discfound then - local lignode=copy_node(start) - lignode.font,lignode.char,lignode.subtype=start.font,char,2 - local next,prev=stop.next,start.prev - stop.next=nil - lignode=node.do_ligature_n(start,stop,lignode) - prev.next=lignode - if next then - next.prev=lignode - end - lignode.next,lignode.prev=next,prev - start=lignode - else - local deletemarks=markflag~="mark" - local n=copy_node(start) - local current - current,start=insert_node_after(start,start,n) - local snext=stop.next - current.next=snext - if snext then - snext.prev=current - end - start.prev,stop.next=nil,nil - current.char,current.subtype,current.components=char,2,start - local head=current - if deletemarks then - if trace_marks then - while start do - if marks[start.char] then - logwarning("%s: remove mark %s",pref(kind,lookupname),gref(start.char)) - end - start=start.next - end - end - else - local i=0 - while start do - if marks[start.char] then - set_attribute(start,markdone,i) - if trace_marks then - logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i) - end - head,current=insert_node_after(head,current,copy_node(start)) - else - i=i+1 - end - start=start.next - end - start=current.next - while start and start.id==glyph do - if marks[start.char] then - set_attribute(start,markdone,i) - if trace_marks then - logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(start.char),i) - end - else - break - end - start=start.next - end - end - return head - end - else - start.char=char - end - return start -end -function handlers.gsub_single(start,kind,lookupname,replacement) - if trace_singles then - logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(start.char),gref(replacement)) - end - start.char=replacement - return start,true -end -local function alternative_glyph(start,alternatives,kind,chainname,chainlookupname,lookupname) - local value,choice,n=featurevalue or tfmdata.shared.features[kind],nil,#alternatives - if value=="random" then - local r=math.random(1,n) - value,choice=format("random, choice %s",r),alternatives[r] - elseif value=="first" then - value,choice=format("first, choice %s",1),alternatives[1] - elseif value=="last" then - value,choice=format("last, choice %s",n),alternatives[n] - else - value=tonumber(value) - if type(value)~="number" then - 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 - value,choice=format("choice %s",value),alternatives[value] - end - end - if not choice then - logwarning("%s: no variant %s for %s",cref(kind,chainname,chainlookupname,lookupname),value,gref(start.char)) - choice,value=start.char,format("no replacement instead of %s",value) - end - return choice,value -end -function handlers.gsub_alternate(start,kind,lookupname,alternative,sequence) - local choice,index=alternative_glyph(start,alternative,kind,lookupname) - if trace_alternatives then - logprocess("%s: replacing %s by alternative %s (%s)",pref(kind,lookupname),gref(start.char),gref(choice),index) - end - start.char=choice - return start,true -end -function handlers.gsub_multiple(start,kind,lookupname,multiple) - if trace_multiples then - logprocess("%s: replacing %s by multiple %s",pref(kind,lookupname),gref(start.char),gref(multiple)) - end - start.char=multiple[1] - if #multiple>1 then - for k=2,#multiple do - local n=copy_node(start) - n.char=multiple[k] - local sn=start.next - n.next=sn - n.prev=start - if sn then - sn.prev=n - end - start.next=n - start=n - end - end - return start,true -end -function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) - local s,stop,discfound=start.next,nil,false - local startchar=start.char - if marks[startchar] then - while s do - local id=s.id - if id==glyph and s.subtype<256 then - if s.font==currentfont then - local char=s.char - local lg=ligature[1][char] - if not lg then - break - else - stop=s - ligature=lg - s=s.next - end - else - break - end - else - break - end - end - if stop and ligature[2] then - if trace_ligatures then - local stopchar=stop.char - start=markstoligature(kind,lookupname,start,stop,ligature[2]) - logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char)) - else - start=markstoligature(kind,lookupname,start,stop,ligature[2]) - end - return start,true - end - else - local skipmark=sequence.flags[1] - while s do - local id=s.id - if id==glyph and s.subtype<256 then - if s.font==currentfont then - local char=s.char - if skipmark and marks[char] then - s=s.next - else - local lg=ligature[1][char] - if not lg then - break - else - stop=s - ligature=lg - s=s.next - end - end - else - break - end - elseif id==disc then - discfound=true - s=s.next - else - break - end - end - if stop and ligature[2] then - if trace_ligatures then - local stopchar=stop.char - start=toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound) - logprocess("%s: replacing %s upto %s by ligature %s",pref(kind,lookupname),gref(startchar),gref(stopchar),gref(start.char)) - else - start=toligature(kind,lookupname,start,stop,ligature[2],skipmark,discfound) - end - return start,true - end - end - return start,false -end -function handlers.gpos_mark2base(start,kind,lookupname,markanchors,sequence) - local markchar=start.char - if marks[markchar] then - local base=start.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - local basechar=base.char - if marks[basechar] then - while true do - base=base.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - basechar=base.char - if not marks[basechar] then - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar)) - end - return start,false - end - end - end - local baseanchors=descriptions[basechar] - if baseanchors then - baseanchors=baseanchors.anchors - end - if baseanchors then - local baseanchors=baseanchors['basechar'] - if baseanchors then - local al=anchorlookups[lookupname] - for anchor,ba in next,baseanchors do - if al[anchor] then - local ma=markanchors[anchor] - if ma then - local dx,dy,bound=set_mark(start,base,tfmdata.factor,rlmode,ba,ma) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)", - pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) - end - return start,true - end - end - end - if trace_bugs then - logwarning("%s, no matching anchors for mark %s and base %s",pref(kind,lookupname),gref(markchar),gref(basechar)) - end - end - else - fonts.register_message(currentfont,basechar,"no base anchors") - end - elseif trace_bugs then - logwarning("%s: prev node is no char",pref(kind,lookupname)) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) - end - return start,false -end -function handlers.gpos_mark2ligature(start,kind,lookupname,markanchors,sequence) - local markchar=start.char - if marks[markchar] then - local base=start.prev - local index=1 - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - local basechar=base.char - if marks[basechar] then - index=index+1 - while true do - base=base.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - basechar=base.char - if marks[basechar] then - index=index+1 - else - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar)) - end - return start,false - end - end - end - local i=has_attribute(start,markdone) - if i then index=i end - local baseanchors=descriptions[basechar] - if baseanchors then - baseanchors=baseanchors.anchors - if baseanchors then - local baseanchors=baseanchors['baselig'] - if baseanchors then - local al=anchorlookups[lookupname] - for anchor,ba in next,baseanchors do - if al[anchor] then - local ma=markanchors[anchor] - if ma then - ba=ba[index] - if ba then - local dx,dy,bound=set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index) - if trace_marks then - logprocess("%s, anchor %s, index %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)", - pref(kind,lookupname),anchor,index,bound,gref(markchar),gref(basechar),index,dx,dy) - end - return start,true - end - end - end - end - if trace_bugs then - logwarning("%s: no matching anchors for mark %s and baselig %s",pref(kind,lookupname),gref(markchar),gref(basechar)) - end - end - end - else - fonts.register_message(currentfont,basechar,"no base anchors") - end - elseif trace_bugs then - logwarning("%s: prev node is no char",pref(kind,lookupname)) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) - end - return start,false -end -function handlers.gpos_mark2mark(start,kind,lookupname,markanchors,sequence) - local markchar=start.char - if marks[markchar] then - local base=start.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - local basechar=base.char - local baseanchors=descriptions[basechar] - if baseanchors then - baseanchors=baseanchors.anchors - if baseanchors then - baseanchors=baseanchors['basemark'] - if baseanchors then - local al=anchorlookups[lookupname] - for anchor,ba in next,baseanchors do - if al[anchor] then - local ma=markanchors[anchor] - if ma then - local dx,dy,bound=set_mark(start,base,tfmdata.factor,rlmode,ba,ma) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)", - pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) - end - return start,true - end - end - end - if trace_bugs then - logwarning("%s: no matching anchors for mark %s and basemark %s",pref(kind,lookupname),gref(markchar),gref(basechar)) - end - end - end - else - 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_bugs then - logwarning("%s: mark %s is no mark",pref(kind,lookupname),gref(markchar)) - end - return start,false -end -function handlers.gpos_cursive(start,kind,lookupname,exitanchors,sequence) - local alreadydone=cursonce and has_attribute(start,cursbase) - if not alreadydone then - local done=false - local startchar=start.char - if marks[startchar] then - if trace_cursive then - logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar)) - end - else - local nxt=start.next - while not done and nxt and nxt.id==glyph and nxt.subtype<256 and nxt.font==currentfont do - local nextchar=nxt.char - if marks[nextchar] then - nxt=nxt.next - else - local entryanchors=descriptions[nextchar] - if entryanchors then - entryanchors=entryanchors.anchors - if entryanchors then - entryanchors=entryanchors['centry'] - if entryanchors then - local al=anchorlookups[lookupname] - for anchor,entry in next,entryanchors do - if al[anchor] then - local exit=exitanchors[anchor] - if exit then - local dx,dy,bound=set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) - if trace_cursive then - logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) - end - done=true - break - end - end - end - end - end - else - fonts.register_message(currentfont,startchar,"no entry anchors") - end - break - end - end - end - return start,done - else - if trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone) - end - return start,false - end -end -function handlers.gpos_single(start,kind,lookupname,kerns,sequence) - local startchar=start.char - local dx,dy,w,h=set_pair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) - end - return start,false -end -function handlers.gpos_pair(start,kind,lookupname,kerns,sequence) - local snext=start.next - if not snext then - return start,false - else - local prev,done=start,false - local factor=tfmdata.factor - while snext and snext.id==glyph and snext.subtype<256 and snext.font==currentfont do - local nextchar=snext.char -local krn=kerns[nextchar] - if not krn and marks[nextchar] then - prev=snext - snext=snext.next - else - local krn=kerns[nextchar] - if not krn then - elseif type(krn)=="table" then - if krn[1]=="pair" then - local a,b=krn[3],krn[4] - if a and #a>0 then - local startchar=start.char - local x,y,w,h=set_pair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - if b and #b>0 then - local startchar=start.char - local x,y,w,h=set_pair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) - if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - else - logs.report("%s: check this out (old kern stuff)",pref(kind,lookupname)) - local a,b=krn[3],krn[7] - if a and a~=0 then - local k=set_kern(snext,factor,rlmode,a) - if trace_kerns then - logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar)) - end - end - if b and b~=0 then - logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor) - end - end - done=true - elseif krn~=0 then - local k=set_kern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(prev.char),gref(nextchar)) - end - done=true - end - break - end - end - return start,done - end -end -local chainmores={} -local chainprocs={} -local function logprocess(...) - if trace_steps then - registermessage(...) - end - logs.report("otf subchain",...) -end -local function logwarning(...) - logs.report("otf subchain",...) -end -function chainmores.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname,n) - logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname)) - return start,false -end -function chainmores.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n) - logprocess("%s: gsub_multiple not yet supported",cref(kind,chainname,chainlookupname)) - return start,false -end -function chainmores.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,n) - logprocess("%s: gsub_alternate not yet supported",cref(kind,chainname,chainlookupname)) - return start,false -end -local function logprocess(...) - if trace_steps then - registermessage(...) - end - logs.report("otf chain",...) -end -local function logwarning(...) - logs.report("otf chain",...) -end -function chainprocs.chainsub(start,stop,kind,chainname,currentcontext,cache,lookuplist,chainlookupname) - logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname)) - return start,false -end -function chainprocs.reversesub(start,stop,kind,chainname,currentcontext,cache,replacements) - local char=start.char - local replacement=replacements[char] - if replacement then - if trace_singles then - logprocess("%s: single reverse replacement of %s by %s",cref(kind,chainname),gref(char),gref(replacement)) - end - start.char=replacement - return start,true - else - return start,false - end -end -local function delete_till_stop(start,stop,ignoremarks) - if start~=stop then - local done=false - while not done do - done=start==stop - delete_node(start,start.next) - end - end -end -function chainprocs.gsub_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex) - if not chainindex then - delete_till_stop(start,stop) - end - local current=start - local subtables=currentlookup.subtables - while current do - if current.id==glyph then - local currentchar=current.char - local lookupname=subtables[1] - local replacement=cache.gsub_single[lookupname] - if not replacement then - if trace_bugs then - logwarning("%s: no single hits",cref(kind,chainname,chainlookupname,lookupname,chainindex)) - end - else - replacement=replacement[currentchar] - if not replacement then - if trace_bugs then - logwarning("%s: no single for %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar)) - end - else - if trace_singles then - logprocess("%s: replacing single %s by %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(currentchar),gref(replacement)) - end - current.char=replacement - end - end - return start,true - elseif current==stop then - break - else - current=current.next - end - end - return start,false -end -chainmores.gsub_single=chainprocs.gsub_single -function chainprocs.gsub_multiple(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname) - delete_till_stop(start,stop) - local startchar=start.char - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local replacements=cache.gsub_multiple[lookupname] - if not replacements then - if trace_bugs then - logwarning("%s: no multiple hits",cref(kind,chainname,chainlookupname,lookupname)) - end - else - replacements=replacements[startchar] - if not replacements then - if trace_bugs then - logwarning("%s: no multiple for %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar)) - end - else - if trace_multiples then - logprocess("%s: replacing %s by multiple characters %s",cref(kind,chainname,chainlookupname,lookupname),gref(startchar),gref(replacements)) - end - local sn=start.next - for k=1,#replacements do - if k==1 then - start.char=replacements[k] - else - local n=copy_node(start) - n.char=replacements[k] - n.next,n.prev=sn,start - if sn then - sn.prev=n - end - start.next,start=n,n - end - end - return start,true - end - end - return start,false -end -function chainprocs.gsub_alternate(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname) - delete_till_stop(start,stop) - local current=start - local subtables=currentlookup.subtables - while current do - if current.id==glyph then - local currentchar=current.char - local lookupname=subtables[1] - local alternatives=cache.gsub_alternate[lookupname] - if not alternatives then - if trace_bugs then - logwarning("%s: no alternative hits",cref(kind,chainname,chainlookupname,lookupname)) - end - else - alternatives=alternatives[currentchar] - if not alternatives then - if trace_bugs then - logwarning("%s: no alternative for %s",cref(kind,chainname,chainlookupname,lookupname),gref(currentchar)) - end - else - local choice,index=alternative_glyph(current,alternatives,kind,chainname,chainlookupname,lookupname) - current.char=choice - if trace_alternatives then - logprocess("%s: replacing single %s by alternative %s (%s)",cref(kind,chainname,chainlookupname,lookupname),index,gref(currentchar),gref(choice),index) - end - end - end - return start,true - elseif current==stop then - break - else - current=current.next - end - end - return start,false -end -function chainprocs.gsub_ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex) - local startchar=start.char - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local ligatures=cache.gsub_ligature[lookupname] - if not ligatures then - if trace_bugs then - logwarning("%s: no ligature hits",cref(kind,chainname,chainlookupname,lookupname,chainindex)) - end - else - ligatures=ligatures[startchar] - if not ligatures then - if trace_bugs then - logwarning("%s: no ligatures starting with %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) - end - else - local s,discfound,last,nofreplacements=start.next,false,stop,0 - while s do - local id=s.id - if id==disc then - s=s.next - discfound=true - else - local schar=s.char - if marks[schar] then - s=s.next - else - local lg=ligatures[1][schar] - if not lg then - break - else - ligatures,last,nofreplacements=lg,s,nofreplacements+1 - if s==stop then - break - else - s=s.next - end - end - end - end - end - local l2=ligatures[2] - if l2 then - if chainindex then - stop=last - end - if trace_ligatures then - if start==stop then - logprocess("%s: replacing character %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(l2)) - else - logprocess("%s: replacing character %s upto %s by ligature %s",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char),gref(l2)) - end - end - start=toligature(kind,lookupname,start,stop,l2,currentlookup.flags[1],discfound) - return start,true,nofreplacements - elseif trace_bugs then - if start==stop then - logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) - else - logwarning("%s: replacing character %s upto %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar),gref(stop.char)) - end - end - end - end - return start,false,0 -end -chainmores.gsub_ligature=chainprocs.gsub_ligature -function chainprocs.gpos_mark2base(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname) - local markchar=start.char - if marks[markchar] then - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local markanchors=cache.gpos_mark2base[lookupname] - if markanchors then - markanchors=markanchors[markchar] - end - if markanchors then - local base=start.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - local basechar=base.char - if marks[basechar] then - while true do - base=base.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - basechar=base.char - if not marks[basechar] then - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",pref(kind,lookupname),gref(markchar)) - end - return start,false - end - end - end - local baseanchors=descriptions[basechar].anchors - if baseanchors then - local baseanchors=baseanchors['basechar'] - if baseanchors then - local al=anchorlookups[lookupname] - for anchor,ba in next,baseanchors do - if al[anchor] then - local ma=markanchors[anchor] - if ma then - local dx,dy,bound=set_mark(start,base,tfmdata.factor,rlmode,ba,ma) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basechar %s => (%s,%s)", - cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) - end - return start,true - end - end - end - if trace_bugs then - logwarning("%s, no matching anchors for mark %s and base %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar)) - end - end - end - elseif trace_bugs then - logwarning("%s: prev node is no char",cref(kind,chainname,chainlookupname,lookupname)) - end - elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar)) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar)) - end - return start,false -end -function chainprocs.gpos_mark2ligature(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname) - local markchar=start.char - if marks[markchar] then - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local markanchors=cache.gpos_mark2ligature[lookupname] - if markanchors then - markanchors=markanchors[markchar] - end - if markanchors then - local base=start.prev - local index=1 - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - local basechar=base.char - if marks[basechar] then - index=index+1 - while true do - base=base.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - basechar=base.char - if marks[basechar] then - index=index+1 - else - break - end - else - if trace_bugs then - logwarning("%s: no base for mark %s",cref(kind,chainname,chainlookupname,lookupname),markchar) - end - return start,false - end - end - end - local i=has_attribute(start,markdone) - if i then index=i end - local baseanchors=descriptions[basechar].anchors - if baseanchors then - local baseanchors=baseanchors['baselig'] - if baseanchors then - local al=anchorlookups[lookupname] - for anchor,ba in next,baseanchors do - if al[anchor] then - local ma=markanchors[anchor] - if ma then - ba=ba[index] - if ba then - local dx,dy,bound=set_mark(start,base,tfmdata.factor,rlmode,ba,ma,index) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to baselig %s at index %s => (%s,%s)", - cref(kind,chainname,chainlookupname,lookupname),anchor,a or bound,gref(markchar),gref(basechar),index,dx,dy) - end - return start,true - end - end - end - end - if trace_bugs then - logwarning("%s: no matching anchors for mark %s and baselig %s",cref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar)) - end - end - end - elseif trace_bugs then - logwarning("feature %s, lookup %s: prev node is no char",kind,lookupname) - end - elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar)) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar)) - end - return start,false -end -function chainprocs.gpos_mark2mark(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname) - local markchar=start.char - if marks[markchar] then - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local markanchors=cache.gpos_mark2mark[lookupname] - if markanchors then - markanchors=markanchors[markchar] - end - if markanchors then - local base=start.prev - if base and base.id==glyph and base.subtype<256 and base.font==currentfont then - local basechar=base.char - local baseanchors=descriptions[basechar].anchors - if baseanchors then - baseanchors=baseanchors['basemark'] - if baseanchors then - local al=anchorlookups[lookupname] - for anchor,ba in next,baseanchors do - if al[anchor] then - local ma=markanchors[anchor] - if ma then - local dx,dy,bound=set_mark(start,base,tfmdata.factor,rlmode,ba,ma) - if trace_marks then - logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%s,%s)", - cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) - end - return start,true - end - end - end - if trace_bugs then - logwarning("%s: no matching anchors for mark %s and basemark %s",gref(kind,chainname,chainlookupname,lookupname),gref(markchar),gref(basechar)) - end - end - end - elseif trace_bugs then - logwarning("%s: prev node is no mark",cref(kind,chainname,chainlookupname,lookupname)) - end - elseif trace_bugs then - logwarning("%s: mark %s has no anchors",cref(kind,chainname,chainlookupname,lookupname),gref(markchar)) - end - elseif trace_bugs then - logwarning("%s: mark %s is no mark",cref(kind,chainname,chainlookupname),gref(markchar)) - end - return start,false -end -function chainprocs.gpos_cursive(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname) - local alreadydone=cursonce and has_attribute(start,cursbase) - if not alreadydone then - local startchar=start.char - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local exitanchors=cache.gpos_cursive[lookupname] - if exitanchors then - exitanchors=exitanchors[startchar] - end - if exitanchors then - local done=false - if marks[startchar] then - if trace_cursive then - logprocess("%s: ignoring cursive for mark %s",pref(kind,lookupname),gref(startchar)) - end - else - local nxt=start.next - while not done and nxt and nxt.id==glyph and nxt.subtype<256 and nxt.font==currentfont do - local nextchar=nxt.char - if marks[nextchar] then - nxt=nxt.next - else - local entryanchors=descriptions[nextchar] - if entryanchors then - entryanchors=entryanchors.anchors - if entryanchors then - entryanchors=entryanchors['centry'] - if entryanchors then - local al=anchorlookups[lookupname] - for anchor,entry in next,entryanchors do - if al[anchor] then - local exit=exitanchors[anchor] - if exit then - local dx,dy,bound=set_cursive(start,nxt,tfmdata.factor,rlmode,exit,entry,characters[startchar],characters[nextchar]) - if trace_cursive then - logprocess("%s: moving %s to %s cursive (%s,%s) using anchor %s and bound %s in rlmode %s",pref(kind,lookupname),gref(startchar),gref(nextchar),dx,dy,anchor,bound,rlmode) - end - done=true - break - end - end - end - end - end - else - fonts.register_message(currentfont,startchar,"no entry anchors") - end - break - end - end - end - return start,done - else - if trace_cursive and trace_details then - logprocess("%s, cursive %s is already done",pref(kind,lookupname),gref(start.char),alreadydone) - end - return start,false - end - end - return start,false -end -function chainprocs.gpos_single(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence) - local startchar=start.char - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local kerns=cache.gpos_single[lookupname] - if kerns then - kerns=kerns[startchar] - if kerns then - local dx,dy,w,h=set_pair(start,tfmdata.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting single %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) - end - end - end - return start,false -end -function chainprocs.gpos_pair(start,stop,kind,chainname,currentcontext,cache,currentlookup,chainlookupname,chainindex,sequence) - local snext=start.next - if snext then - local startchar=start.char - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local kerns=cache.gpos_pair[lookupname] - if kerns then - kerns=kerns[startchar] - if kerns then - local prev,done=start,false - local factor=tfmdata.factor - while snext and snext.id==glyph and snext.subtype<256 and snext.font==currentfont do - local nextchar=snext.char - local krn=kerns[nextchar] - if not krn and marks[nextchar] then - prev=snext - snext=snext.next - else - if not krn then - elseif type(krn)=="table" then - if krn[1]=="pair" then - local a,b=krn[3],krn[4] - if a and #a>0 then - local startchar=start.char - local x,y,w,h=set_pair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - if b and #b>0 then - local startchar=start.char - local x,y,w,h=set_pair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) - if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%s,%s) and correction (%s,%s)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - else - logs.report("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname)) - local a,b=krn[3],krn[7] - if a and a~=0 then - local k=set_kern(snext,factor,rlmode,a) - if trace_kerns then - logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar)) - end - end - if b and b~=0 then - logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor) - end - end - done=true - elseif krn~=0 then - local k=set_kern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(prev.char),gref(nextchar)) - end - done=true - end - break - end - end - return start,done - end - end - end - return start,false -end -local function show_skip(kind,chainname,char,ck,class) - if ck[9] then - logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s (%s=>%s)",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10]) - else - logwarning("%s: skipping char %s (%s) in rule %s, lookuptype %s",cref(kind,chainname),gref(char),class,ck[1],ck[2]) - end -end -local function normal_handle_contextchain(start,kind,chainname,contexts,sequence,cache) - local flags,done=sequence.flags,false - local skipmark,skipligature,skipbase=flags[1],flags[2],flags[3] - local someskip=skipmark or skipligature or skipbase - local markclass=sequence.markclass - local skipped=false - for k=1,#contexts do - local match,current,last=true,start,start - local ck=contexts[k] - local seq=ck[3] - local s=#seq - if s==1 then - match=current.id==glyph and current.subtype<256 and current.font==currentfont and seq[1][current.char] - else - local f,l=ck[4],ck[5] - if f==l then - match=true - else - local n=f+1 - last=last.next - while n<=l do - if last then - local id=last.id - if id==glyph then - if last.subtype<256 and last.font==currentfont then - local char=last.char - local ccd=descriptions[char] - if ccd then - local class=ccd.class - if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then - skipped=true - if trace_skips then - show_skip(kind,chainname,char,ck,class) - end - last=last.next - elseif seq[n][char] then - if n<l then - last=last.next - end - n=n+1 - else - match=false break - end - else - match=false break - end - else - match=false break - end - elseif id==disc then - last=last.next - else - match=false break - end - else - match=false break - end - end - end - if match and f>1 then - local prev=start.prev - if prev then - local n=f-1 - while n>=1 do - if prev then - local id=prev.id - if id==glyph then - if prev.subtype<256 and prev.font==currentfont then - local char=prev.char - local ccd=descriptions[char] - if ccd then - local class=ccd.class - if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then - skipped=true - if trace_skips then - show_skip(kind,chainname,char,ck,class) - end - elseif seq[n][char] then - n=n -1 - else - match=false break - end - else - match=false break - end - else - match=false break - end - elseif id==disc then - elseif seq[n][32] then - n=n -1 - else - match=false break - end - prev=prev.prev - elseif seq[n][32] then - n=n -1 - else - match=false break - end - end - elseif f==2 then - match=seq[1][32] - else - for n=f-1,1 do - if not seq[n][32] then - match=false break - end - end - end - end - if match and s>l then - local current=last.next - if current then - local n=l+1 - while n<=s do - if current then - local id=current.id - if id==glyph then - if current.subtype<256 and current.font==currentfont then - local char=current.char - local ccd=descriptions[char] - if ccd then - local class=ccd.class - if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then - skipped=true - if trace_skips then - show_skip(kind,chainname,char,ck,class) - end - elseif seq[n][char] then - n=n+1 - else - match=false break - end - else - match=false break - end - else - match=false break - end - elseif id==disc then - elseif seq[n][32] then - n=n+1 - else - match=false break - end - current=current.next - elseif seq[n][32] then - n=n+1 - else - match=false break - end - end - elseif s-l==1 then - match=seq[s][32] - else - for n=l+1,s do - if not seq[n][32] then - match=false break - end - end - end - end - end - if match then - if trace_contexts then - local rule,lookuptype,f,l=ck[1],ck[2],ck[4],ck[5] - local char=start.char - if ck[9] then - logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s (%s=>%s)",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype,ck[9],ck[10]) - else - logwarning("%s: rule %s matches at char %s for (%s,%s,%s) chars, lookuptype %s",cref(kind,chainname),rule,gref(char),f-1,l-f+1,s-l,lookuptype) - end - end - local chainlookups=ck[6] - if chainlookups then - local nofchainlookups=#chainlookups - if nofchainlookups==1 then - local chainlookupname=chainlookups[1] - local chainlookup=lookuptable[chainlookupname] - local cp=chainprocs[chainlookup.type] - if cp then - start,done=cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,nil,sequence) - else - logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) - end - else - local i=1 - repeat -if skipped then - while true do - local char=start.char - local ccd=descriptions[char] - if ccd then - local class=ccd.class - if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then - start=start.next - else - break - end - else - break - end - end -end - local chainlookupname=chainlookups[i] - local chainlookup=lookuptable[chainlookupname] - local cp=chainmores[chainlookup.type] - if cp then - local ok,n - start,ok,n=cp(start,last,kind,chainname,ck,cache,chainlookup,chainlookupname,i,sequence) - if ok then - done=true - i=i+(n or 1) - else - i=i+1 - end - else - logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) - i=i+1 - end - start=start.next - until i>nofchainlookups - end - else - local replacements=ck[7] - if replacements then - start,done=chainprocs.reversesub(start,last,kind,chainname,ck,cache,replacements) - else - done=true - if trace_contexts then - logprocess("%s: skipping match",cref(kind,chainname)) - end - end - end - end - end - return start,done -end -local verbose_handle_contextchain=function(font,...) - logwarning("no verbose handler installed, reverting to 'normal'") - otf.setcontextchain() - return normal_handle_contextchain(...) -end -otf.chainhandlers={ - normal=normal_handle_contextchain, - verbose=verbose_handle_contextchain, -} -function otf.setcontextchain(method) - if not method or method=="normal" or not otf.chainhandlers[method] then - if handlers.contextchain then - logwarning("installing normal contextchain handler") - end - handlers.contextchain=normal_handle_contextchain - else - logwarning("installing contextchain handler '%s'",method) - local handler=otf.chainhandlers[method] - handlers.contextchain=function(...) - return handler(currentfont,...) - end - end - handlers.gsub_context=handlers.contextchain - handlers.gsub_contextchain=handlers.contextchain - handlers.gsub_reversecontextchain=handlers.contextchain - handlers.gpos_contextchain=handlers.contextchain - handlers.gpos_context=handlers.contextchain -end -otf.setcontextchain() -local missing={} -local function logprocess(...) - if trace_steps then - registermessage(...) - end - logs.report("otf process",...) -end -local function logwarning(...) - logs.report("otf process",...) -end -local function report_missing_cache(typ,lookup) - local f=missing[currentfont] if not f then f={} missing[currentfont]=f end - local t=f[typ] if not t then t={} f[typ]=t end - if not t[lookup] then - t[lookup]=true - logwarning("missing cache for lookup %s of type %s in font %s (%s)",lookup,typ,currentfont,tfmdata.fullname) - end -end -local resolved={} -function fonts.methods.node.otf.features(head,font,attr) - if trace_steps then - checkstep(head) - end - tfmdata=fontdata[font] - local shared=tfmdata.shared - otfdata=shared.otfdata - local luatex=otfdata.luatex - descriptions=tfmdata.descriptions - characters=tfmdata.characters - indices=tfmdata.indices - unicodes=tfmdata.unicodes - marks=tfmdata.marks - anchorlookups=luatex.lookup_to_anchor - currentfont=font - rlmode=0 - local featuredata=otfdata.shared.featuredata - local sequences=luatex.sequences - lookuptable=luatex.lookups - local done=false - 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]] - dyn=context_merged[attr] or 0 - language,script=features.language or "dflt",features.script or "dflt" - a_enabled=features - if dyn==2 or dyn==-2 then - s_enabled=shared.features - end - else - language,script=tfmdata.language or "dflt",tfmdata.script or "dflt" - s_enabled=shared.features - dyn=0 - end - local res=resolved[font] if not res then res={} resolved[font]=res end - local rs=res [script] if not rs then rs={} res [script]=rs end - local rl=rs [language] if not rl then rl={} rs [language]=rl end - local ra=rl [attr] if ra==nil then ra={} rl [attr]=ra end - for s=1,#sequences do - local pardir,txtdir,success=0,{},false - local sequence=sequences[s] - local r=ra[s] - if r==nil then - local chain=sequence.chain or 0 - local features=sequence.features - if not features then - r=false - else - local valid,attribute,kind,what=false,false - for k,v in next,features do - 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 then - if l[language] then - valid,what=s_e or a_e,language - elseif l[wildcard] then - 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 valid then - r={ valid,attribute,chain,kind } - else - r=false - end - end - ra[s]=r - end - featurevalue=r and r[1] - if featurevalue then - local attribute,chain,typ,subtables=r[2],r[3],sequence.type,sequence.subtables - if chain<0 then - local handler=handlers[typ] - local thecache=featuredata[typ] or {} - local start=find_node_tail(head) - while start do - local id=start.id - if id==glyph then - if start.subtype<256 and start.font==font then - local a=has_attribute(start,0) - if a then - a=a==attr - else - a=true - end - if a then - for i=1,#subtables do - local lookupname=subtables[i] - local lookupcache=thecache[lookupname] - if lookupcache then - local lookupmatch=lookupcache[start.char] - if lookupmatch then - start,success=handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i) - if success then - break - end - end - else - report_missing_cache(typ,lookupname) - end - end - if start then start=start.prev end - else - start=start.prev - end - else - start=start.prev - end - else - start=start.prev - end - end - else - local handler=handlers[typ] - local ns=#subtables - local thecache=featuredata[typ] or {} - local start=head - rlmode=0 - if ns==1 then - local lookupname=subtables[1] - local lookupcache=thecache[lookupname] - if not lookupcache then - report_missing_cache(typ,lookupname) - else - while start do - local id=start.id - if id==glyph then - if start.subtype<256 and start.font==font then - local a=has_attribute(start,0) - if a then - a=(a==attr) and (not attribute or has_attribute(start,state,attribute)) - else - a=not attribute or has_attribute(start,state,attribute) - end - if a then - local lookupmatch=lookupcache[start.char] - if lookupmatch then - local ok - start,ok=handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1) - if ok then - success=true - end - end - if start then start=start.next end - else - start=start.next - end - else - start=start.next - end - elseif id==whatsit then - local subtype=start.subtype - if subtype==7 then - local dir=start.dir - if dir=="+TRT" or dir=="+TLT" then - insert(txtdir,dir) - elseif dir=="-TRT" or dir=="-TLT" then - remove(txtdir) - end - local d=txtdir[#txtdir] - if d=="+TRT" then - rlmode=-1 - elseif d=="+TLT" then - rlmode=1 - else - rlmode=pardir - end - if trace_directions then - logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) - end - elseif subtype==6 then - local dir=start.dir - if dir=="TRT" then - pardir=-1 - elseif dir=="TLT" then - pardir=1 - else - pardir=0 - end - rlmode=pardir - if trace_directions then - logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) - end - end - start=start.next - else - start=start.next - end - end - end - else - while start do - local id=start.id - if id==glyph then - if start.subtype<256 and start.font==font then - local a=has_attribute(start,0) - if a then - a=(a==attr) and (not attribute or has_attribute(start,state,attribute)) - else - a=not attribute or has_attribute(start,state,attribute) - end - if a then - for i=1,ns do - local lookupname=subtables[i] - local lookupcache=thecache[lookupname] - if lookupcache then - local lookupmatch=lookupcache[start.char] - if lookupmatch then - local ok - start,ok=handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,i) - if ok then - success=true - break - end - end - else - report_missing_cache(typ,lookupname) - end - end - if start then start=start.next end - else - start=start.next - end - else - start=start.next - end - elseif id==whatsit then - local subtype=start.subtype - if subtype==7 then - local dir=start.dir - if dir=="+TRT" or dir=="+TLT" then - insert(txtdir,dir) - elseif dir=="-TRT" or dir=="-TLT" then - remove(txtdir) - end - local d=txtdir[#txtdir] - if d=="+TRT" then - rlmode=-1 - elseif d=="+TLT" then - rlmode=1 - else - rlmode=pardir - end - if trace_directions then - logs.report("fonts","directions after textdir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) - end - elseif subtype==6 then - local dir=start.dir - if dir=="TRT" then - pardir=-1 - elseif dir=="TLT" then - pardir=1 - else - pardir=0 - end - rlmode=pardir - if trace_directions then - logs.report("fonts","directions after pardir %s: pardir=%s, txtdir=%s:%s, rlmode=%s",dir,pardir,#txtdir,txtdir[#txtdir] or "unset",rlmode) - end - end - start=start.next - else - start=start.next - end - end - end - end - if success then - done=true - end - if trace_steps then - registerstep(head) - end - end - end - return head,done -end -otf.features.prepare={} -local function split(replacement,original,cache,unicodes) - local o,t,n={},{},0 - for s in gmatch(original,"[^ ]+") do - local us=unicodes[s] - if type(us)=="number" then - o[#o+1]=us - else - o[#o+1]=us[1] - end - end - for s in gmatch(replacement,"[^ ]+") do - n=n+1 - local us=unicodes[s] - if type(us)=="number" then - t[o[n]]=us - else - t[o[n]]=us[1] - end - end - return t -end -local function uncover(covers,result,cache,unicodes) - for n=1,#covers do - local c=covers[n] - local cc=cache[c] - if not cc then - local t={} - for s in gmatch(c,"[^ ]+") do - local us=unicodes[s] - if type(us)=="number" then - t[us]=true - else - for i=1,#us do - t[us[i]]=true - end - end - end - cache[c]=t - result[#result+1]=t - else - result[#result+1]=cc - end - end -end -local function prepare_lookups(tfmdata) - local otfdata=tfmdata.shared.otfdata - local featuredata=otfdata.shared.featuredata - local anchor_to_lookup=otfdata.luatex.anchor_to_lookup - local lookup_to_anchor=otfdata.luatex.lookup_to_anchor - local multiple=featuredata.gsub_multiple - local alternate=featuredata.gsub_alternate - local single=featuredata.gsub_single - local ligature=featuredata.gsub_ligature - local pair=featuredata.gpos_pair - local position=featuredata.gpos_single - local kerns=featuredata.gpos_pair - local mark=featuredata.gpos_mark2mark - local cursive=featuredata.gpos_cursive - local unicodes=tfmdata.unicodes - local indices=tfmdata.indices - local descriptions=tfmdata.descriptions - local action={ - substitution=function(p,lookup,glyph,unicode) - local old,new=unicode,unicodes[p[2]] - if type(new)=="table" then - new=new[1] - end - local s=single[lookup] - if not s then s={} single[lookup]=s end - s[old]=new - end, - multiple=function (p,lookup,glyph,unicode) - local old,new=unicode,{} - local m=multiple[lookup] - if not m then m={} multiple[lookup]=m end - m[old]=new - for pc in gmatch(p[2],"[^ ]+") do - local upc=unicodes[pc] - if type(upc)=="number" then - new[#new+1]=upc - else - new[#new+1]=upc[1] - end - end - end, - alternate=function(p,lookup,glyph,unicode) - local old,new=unicode,{} - local a=alternate[lookup] - if not a then a={} alternate[lookup]=a end - a[old]=new - for pc in gmatch(p[2],"[^ ]+") do - local upc=unicodes[pc] - if type(upc)=="number" then - new[#new+1]=upc - else - new[#new+1]=upc[1] - end - end - end, - ligature=function (p,lookup,glyph,unicode) - local first=true - local t=ligature[lookup] - if not t then t={} ligature[lookup]=t end - for s in gmatch(p[2],"[^ ]+") do - if first then - local u=unicodes[s] - if not u then - logs.report("define otf","lookup %s: ligature %s => %s ignored due to invalid unicode",lookup,p[2],glyph.name) - break - elseif type(u)=="number" then - if not t[u] then - t[u]={ {} } - end - t=t[u] - else - local tt=t - local tu - for i=1,#u do - local u=u[i] - if i==1 then - if not t[u] then - t[u]={ {} } - end - tu=t[u] - t=tu - else - if not t[u] then - tt[u]=tu - end - end - end - end - first=false - else - s=unicodes[s] - local t1=t[1] - if not t1[s] then - t1[s]={ {} } - end - t=t1[s] - end - end - t[2]=unicode - end, - position=function(p,lookup,glyph,unicode) - local s=position[lookup] - if not s then s={} position[lookup]=s end - s[unicode]=p[2] - end, - pair=function(p,lookup,glyph,unicode) - local s=pair[lookup] - if not s then s={} pair[lookup]=s end - local others=s[unicode] - if not others then others={} s[unicode]=others end - local two=p[2] - local upc=unicodes[two] - if not upc then - for pc in gmatch(two,"[^ ]+") do - local upc=unicodes[pc] - if type(upc)=="number" then - others[upc]=p - else - for i=1,#upc do - others[upc[i]]=p - end - end - end - elseif type(upc)=="number" then - others[upc]=p - else - for i=1,#upc do - others[upc[i]]=p - end - end - end, - } - for unicode,glyph in next,descriptions do - local lookups=glyph.slookups - if lookups then - for lookup,p in next,lookups do - action[p[1]](p,lookup,glyph,unicode) - end - end - local lookups=glyph.mlookups - if lookups then - for lookup,whatever in next,lookups do - for i=1,#whatever do - local p=whatever[i] - action[p[1]](p,lookup,glyph,unicode) - end - end - end - local list=glyph.mykerns - if list then - for lookup,krn in next,list do - local k=kerns[lookup] - if not k then k={} kerns[lookup]=k end - k[unicode]=krn - end - end - local oanchor=glyph.anchors - if oanchor then - for typ,anchors in next,oanchor do - if typ=="mark" then - for name,anchor in next,anchors do - local lookups=anchor_to_lookup[name] - if lookups then - for lookup,_ in next,lookups do - local f=mark[lookup] - if not f then f={} mark[lookup]=f end - f[unicode]=anchors - end - end - end - elseif typ=="cexit" then - for name,anchor in next,anchors do - local lookups=anchor_to_lookup[name] - if lookups then - for lookup,_ in next,lookups do - local f=cursive[lookup] - if not f then f={} cursive[lookup]=f end - f[unicode]=anchors - end - end - end - end - end - end - end -end -luatex=luatex or {} -local function prepare_contextchains(tfmdata) - local otfdata=tfmdata.shared.otfdata - local lookups=otfdata.lookups - if lookups then - local featuredata=otfdata.shared.featuredata - local contextchain=featuredata.gsub_contextchain - local reversecontextchain=featuredata.gsub_reversecontextchain - local characters=tfmdata.characters - local unicodes=tfmdata.unicodes - local indices=tfmdata.indices - local cache=luatex.covers - if not cache then - cache={} - luatex.covers=cache - end - for lookupname,lookupdata in next,otfdata.lookups do - local lookuptype=lookupdata.type - if not lookuptype then - logs.report("otf process","missing lookuptype for %s",lookupname) - else - local rules=lookupdata.rules - if rules then - local fmt=lookupdata.format - if fmt=="coverage" then - if lookuptype~="chainsub" and lookuptype~="chainpos" then - logs.report("otf process","unsupported coverage %s for %s",lookuptype,lookupname) - else - local contexts=contextchain[lookupname] - if not contexts then - contexts={} - contextchain[lookupname]=contexts - end - local t={} - for nofrules=1,#rules do - local rule=rules[nofrules] - local coverage=rule.coverage - if coverage and coverage.current then - local current,before,after,sequence=coverage.current,coverage.before,coverage.after,{} - if before then - uncover(before,sequence,cache,unicodes) - end - local start=#sequence+1 - uncover(current,sequence,cache,unicodes) - local stop=#sequence - if after then - uncover(after,sequence,cache,unicodes) - end - if sequence[1] then - t[#t+1]={ nofrules,lookuptype,sequence,start,stop,rule.lookups } - for unic,_ in next,sequence[start] do - local cu=contexts[unic] - if not cu then - contexts[unic]=t - end - end - end - end - end - end - elseif fmt=="reversecoverage" then - if lookuptype~="reversesub" then - logs.report("otf process","unsupported reverse coverage %s for %s",lookuptype,lookupname) - else - local contexts=reversecontextchain[lookupname] - if not contexts then - contexts={} - reversecontextchain[lookupname]=contexts - end - local t={} - for nofrules=1,#rules do - local rule=rules[nofrules] - local reversecoverage=rule.reversecoverage - if reversecoverage and reversecoverage.current then - local current,before,after,replacements,sequence=reversecoverage.current,reversecoverage.before,reversecoverage.after,reversecoverage.replacements,{} - if before then - uncover(before,sequence,cache,unicodes) - end - local start=#sequence+1 - uncover(current,sequence,cache,unicodes) - local stop=#sequence - if after then - uncover(after,sequence,cache,unicodes) - end - if replacements then - replacements=split(replacements,current[1],cache,unicodes) - end - if sequence[1] then - t[#t+1]={ nofrules,lookuptype,sequence,start,stop,rule.lookups,replacements } - for unic,_ in next,sequence[start] do - local cu=contexts[unic] - if not cu then - contexts[unic]=t - end - end - end - end - end - end - elseif fmt=="glyphs" then - if lookuptype~="chainsub" and lookuptype~="chainpos" then - logs.report("otf process","unsupported coverage %s for %s",lookuptype,lookupname) - else - local contexts=contextchain[lookupname] - if not contexts then - contexts={} - contextchain[lookupname]=contexts - end - local t={} - for nofrules=1,#rules do - local rule=rules[nofrules] - local glyphs=rule.glyphs - if glyphs and glyphs.names then - local fore,back,names,sequence=glyphs.fore,glyphs.back,glyphs.names,{} - if fore and fore~="" then - fore=lpegmatch(split_at_space,fore) - uncover(fore,sequence,cache,unicodes) - end - local start=#sequence+1 - names=lpegmatch(split_at_space,names) - uncover(names,sequence,cache,unicodes) - local stop=#sequence - if back and back~="" then - back=lpegmatch(split_at_space,back) - uncover(back,sequence,cache,unicodes) - end - if sequence[1] then - t[#t+1]={ nofrules,lookuptype,sequence,start,stop,rule.lookups } - for unic,_ in next,sequence[start] do - local cu=contexts[unic] - if not cu then - contexts[unic]=t - end - end - end - end - end - end - end - end - end - end - end -end -function fonts.initializers.node.otf.features(tfmdata,value) - if true then - if not tfmdata.shared.otfdata.shared.initialized then - local t=trace_preparing and os.clock() - local otfdata=tfmdata.shared.otfdata - local featuredata=otfdata.shared.featuredata - featuredata.gsub_multiple={} - featuredata.gsub_alternate={} - featuredata.gsub_single={} - featuredata.gsub_ligature={} - featuredata.gsub_contextchain={} - featuredata.gsub_reversecontextchain={} - featuredata.gpos_pair={} - featuredata.gpos_single={} - featuredata.gpos_mark2base={} - featuredata.gpos_mark2ligature=featuredata.gpos_mark2base - featuredata.gpos_mark2mark=featuredata.gpos_mark2base - featuredata.gpos_cursive={} - featuredata.gpos_contextchain=featuredata.gsub_contextchain - featuredata.gpos_reversecontextchain=featuredata.gsub_reversecontextchain - prepare_contextchains(tfmdata) - prepare_lookups(tfmdata) - otfdata.shared.initialized=true - if trace_preparing then - logs.report("otf process","preparation time is %0.3f seconds for %s",os.clock()-t,tfmdata.fullname or "?") - end - end - end -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-ota']={ - version=1.001, - comment="companion to font-otf.lua (analysing)", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local type,tostring,match,format,concat=type,tostring,string.match,string.format,table.concat -if not trackers then trackers={ register=function() end } end -local trace_analyzing=false trackers.register("otf.analyzing",function(v) trace_analyzing=v end) -local trace_cjk=false trackers.register("cjk.injections",function(v) trace_cjk=v end) -trackers.register("cjk.analyzing","otf.analyzing") -fonts=fonts or {} -fonts.analyzers=fonts.analyzers or {} -fonts.analyzers.initializers=fonts.analyzers.initializers or { node={ otf={} } } -fonts.analyzers.methods=fonts.analyzers.methods or { node={ otf={} } } -local otf=fonts.otf -local tfm=fonts.tfm -local initializers=fonts.analyzers.initializers -local methods=fonts.analyzers.methods -local glyph=node.id('glyph') -local glue=node.id('glue') -local penalty=node.id('penalty') -local set_attribute=node.set_attribute -local has_attribute=node.has_attribute -local traverse_id=node.traverse_id -local traverse_node_list=node.traverse -local fontdata=fonts.ids -local state=attributes.private('state') -local fcs=(fonts.color and fonts.color.set) or function() end -local fcr=(fonts.color and fonts.color.reset) or function() end -local a_to_script=otf.a_to_script -local a_to_language=otf.a_to_language -function fonts.initializers.node.otf.analyze(tfmdata,value,attr) - local script,language - if attr and attr>0 then - script,language=a_to_script[attr],a_to_language[attr] - else - script,language=tfmdata.script,tfmdata.language - end - local action=initializers[script] - if action then - if type(action)=="function" then - return action(tfmdata,value) - else - local action=action[language] - if action then - return action(tfmdata,value) - end - end - end - return nil -end -function fonts.methods.node.otf.analyze(head,font,attr) - local tfmdata=fontdata[font] - local script,language - if attr and attr>0 then - script,language=a_to_script[attr],a_to_language[attr] - else - script,language=tfmdata.script,tfmdata.language - end - local action=methods[script] - if action then - if type(action)=="function" then - return action(head,font,attr) - else - action=action[language] - if action then - return action(head,font,attr) - end - end - end - return head,false -end -otf.features.register("analyze",true) -table.insert(fonts.triggers,"analyze") -fonts.analyzers.methods.latn=fonts.analyzers.aux.setstate -local zwnj=0x200C -local zwj=0x200D -local isol={ - [0x0600]=true,[0x0601]=true,[0x0602]=true,[0x0603]=true, - [0x0608]=true,[0x060B]=true,[0x0621]=true,[0x0674]=true, - [0x06DD]=true,[zwnj]=true, -} -local isol_fina={ - [0x0622]=true,[0x0623]=true,[0x0624]=true,[0x0625]=true, - [0x0627]=true,[0x0629]=true,[0x062F]=true,[0x0630]=true, - [0x0631]=true,[0x0632]=true,[0x0648]=true,[0x0671]=true, - [0x0672]=true,[0x0673]=true,[0x0675]=true,[0x0676]=true, - [0x0677]=true,[0x0688]=true,[0x0689]=true,[0x068A]=true, - [0x068B]=true,[0x068C]=true,[0x068D]=true,[0x068E]=true, - [0x068F]=true,[0x0690]=true,[0x0691]=true,[0x0692]=true, - [0x0693]=true,[0x0694]=true,[0x0695]=true,[0x0696]=true, - [0x0697]=true,[0x0698]=true,[0x0699]=true,[0x06C0]=true, - [0x06C3]=true,[0x06C4]=true,[0x06C5]=true,[0x06C6]=true, - [0x06C7]=true,[0x06C8]=true,[0x06C9]=true,[0x06CA]=true, - [0x06CB]=true,[0x06CD]=true,[0x06CF]=true,[0x06D2]=true, - [0x06D3]=true,[0x06D5]=true,[0x06EE]=true,[0x06EF]=true, - [0x0759]=true,[0x075A]=true,[0x075B]=true,[0x076B]=true, - [0x076C]=true,[0x0771]=true,[0x0773]=true,[0x0774]=true, - [0x0778]=true,[0x0779]=true,[0xFEF5]=true,[0xFEF7]=true, - [0xFEF9]=true,[0xFEFB]=true, -} -local isol_fina_medi_init={ - [0x0626]=true,[0x0628]=true,[0x062A]=true,[0x062B]=true, - [0x062C]=true,[0x062D]=true,[0x062E]=true,[0x0633]=true, - [0x0634]=true,[0x0635]=true,[0x0636]=true,[0x0637]=true, - [0x0638]=true,[0x0639]=true,[0x063A]=true,[0x063B]=true, - [0x063C]=true,[0x063D]=true,[0x063E]=true,[0x063F]=true, - [0x0640]=true,[0x0641]=true,[0x0642]=true,[0x0643]=true, - [0x0644]=true,[0x0645]=true,[0x0646]=true,[0x0647]=true, - [0x0649]=true,[0x064A]=true,[0x066E]=true,[0x066F]=true, - [0x0678]=true,[0x0679]=true,[0x067A]=true,[0x067B]=true, - [0x067C]=true,[0x067D]=true,[0x067E]=true,[0x067F]=true, - [0x0680]=true,[0x0681]=true,[0x0682]=true,[0x0683]=true, - [0x0684]=true,[0x0685]=true,[0x0686]=true,[0x0687]=true, - [0x069A]=true,[0x069B]=true,[0x069C]=true,[0x069D]=true, - [0x069E]=true,[0x069F]=true,[0x06A0]=true,[0x06A1]=true, - [0x06A2]=true,[0x06A3]=true,[0x06A4]=true,[0x06A5]=true, - [0x06A6]=true,[0x06A7]=true,[0x06A8]=true,[0x06A9]=true, - [0x06AA]=true,[0x06AB]=true,[0x06AC]=true,[0x06AD]=true, - [0x06AE]=true,[0x06AF]=true,[0x06B0]=true,[0x06B1]=true, - [0x06B2]=true,[0x06B3]=true,[0x06B4]=true,[0x06B5]=true, - [0x06B6]=true,[0x06B7]=true,[0x06B8]=true,[0x06B9]=true, - [0x06BA]=true,[0x06BB]=true,[0x06BC]=true,[0x06BD]=true, - [0x06BE]=true,[0x06BF]=true,[0x06C1]=true,[0x06C2]=true, - [0x06CC]=true,[0x06CE]=true,[0x06D0]=true,[0x06D1]=true, - [0x06FA]=true,[0x06FB]=true,[0x06FC]=true,[0x06FF]=true, - [0x0750]=true,[0x0751]=true,[0x0752]=true,[0x0753]=true, - [0x0754]=true,[0x0755]=true,[0x0756]=true,[0x0757]=true, - [0x0758]=true,[0x075C]=true,[0x075D]=true,[0x075E]=true, - [0x075F]=true,[0x0760]=true,[0x0761]=true,[0x0762]=true, - [0x0763]=true,[0x0764]=true,[0x0765]=true,[0x0766]=true, - [0x0767]=true,[0x0768]=true,[0x0769]=true,[0x076A]=true, - [0x076D]=true,[0x076E]=true,[0x076F]=true,[0x0770]=true, - [0x0772]=true,[0x0775]=true,[0x0776]=true,[0x0777]=true, - [0x077A]=true,[0x077B]=true,[0x077C]=true,[0x077D]=true, - [0x077E]=true,[0x077F]=true,[zwj]=true, -} -local arab_warned={} -local function warning(current,what) - local char=current.char - if not arab_warned[char] then - log.report("analyze","arab: character %s (U+%04X) has no %s class",char,char,what) - arab_warned[char]=true - end -end -function fonts.analyzers.methods.nocolor(head,font,attr) - for n in traverse_node_list(head,glyph) do - if not font or n.font==font then - fcr(n) - end - end - return head,true -end -local function finish(first,last) - if last then - if first==last then - local fc=first.char - if isol_fina_medi_init[fc] or isol_fina[fc] then - set_attribute(first,state,4) - if trace_analyzing then fcs(first,"font:isol") end - else - warning(first,"isol") - set_attribute(first,state,0) - if trace_analyzing then fcr(first) end - end - else - local lc=last.char - if isol_fina_medi_init[lc] or isol_fina[lc] then - set_attribute(last,state,3) - if trace_analyzing then fcs(last,"font:fina") end - else - warning(last,"fina") - set_attribute(last,state,0) - if trace_analyzing then fcr(last) end - end - end - first,last=nil,nil - elseif first then - local fc=first.char - if isol_fina_medi_init[fc] or isol_fina[fc] then - set_attribute(first,state,4) - if trace_analyzing then fcs(first,"font:isol") end - else - warning(first,"isol") - set_attribute(first,state,0) - if trace_analyzing then fcr(first) end - end - first=nil - end - return first,last -end -function fonts.analyzers.methods.arab(head,font,attr) - local tfmdata=fontdata[font] - local marks=tfmdata.marks - local first,last,current,done=nil,nil,head,false - while current do - if current.id==glyph and current.subtype<256 and current.font==font and not has_attribute(current,state) then - done=true - local char=current.char - if marks[char] then - set_attribute(current,state,5) - if trace_analyzing then fcs(current,"font:mark") end - elseif isol[char] then - first,last=finish(first,last) - set_attribute(current,state,4) - if trace_analyzing then fcs(current,"font:isol") end - first,last=nil,nil - elseif not first then - if isol_fina_medi_init[char] then - set_attribute(current,state,1) - if trace_analyzing then fcs(current,"font:init") end - first,last=first or current,current - elseif isol_fina[char] then - set_attribute(current,state,4) - if trace_analyzing then fcs(current,"font:isol") end - first,last=nil,nil - else - first,last=finish(first,last) - end - elseif isol_fina_medi_init[char] then - first,last=first or current,current - set_attribute(current,state,2) - if trace_analyzing then fcs(current,"font:medi") end - elseif isol_fina[char] then - if not has_attribute(last,state,1) then - set_attribute(last,state,2) - if trace_analyzing then fcs(last,"font:medi") end - end - set_attribute(current,state,3) - if trace_analyzing then fcs(current,"font:fina") end - first,last=nil,nil - elseif char>=0x0600 and char<=0x06FF then - if trace_analyzing then fcs(current,"font:rest") end - first,last=finish(first,last) - else - first,last=finish(first,last) - end - else - first,last=finish(first,last) - end - current=current.next - end - first,last=finish(first,last) - return head,done -end - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-otc']={ - version=1.001, - comment="companion to font-otf.lua (context)", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local format,insert=string.format,table.insert -local type,next=type,next -local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) -local otf=fonts.otf -local tfm=fonts.tfm -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", - exclamdown="exclam grave", - questiondown="question grave", - guillemotleft="less less", - guillemotright="greater greater", - }, - }, - trep={ - { - [0x0022]=0x201D, - [0x0027]=0x2019, - [0x0060]=0x2018, - }, - }, - anum={ - { - [0x0030]=0x0660, - [0x0031]=0x0661, - [0x0032]=0x0662, - [0x0033]=0x0663, - [0x0034]=0x0664, - [0x0035]=0x0665, - [0x0036]=0x0666, - [0x0037]=0x0667, - [0x0038]=0x0668, - [0x0039]=0x0669, - }, - { - [0x0030]=0x06F0, - [0x0031]=0x06F1, - [0x0032]=0x06F2, - [0x0033]=0x06F3, - [0x0034]=0x06F4, - [0x0035]=0x06F5, - [0x0036]=0x06F6, - [0x0037]=0x06F7, - [0x0038]=0x06F8, - [0x0039]=0x06F9, - }, - }, -} -local extra_features={ - 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","ARA" },} },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={ "FAR" },} },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) -end -fonts.otf.enhancers["enrich with features"]=function(data,filename) - 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 {} - 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]={ - { - ["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]={ - { - ["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)) - 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 -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') -fonts.initializers.base.otf.equaldigits=fonts.initializers.common.equaldigits -fonts.initializers.node.otf.equaldigits=fonts.initializers.common.equaldigits -fonts.initializers.base.otf.lineheight=fonts.initializers.common.lineheight -fonts.initializers.node.otf.lineheight=fonts.initializers.common.lineheight -fonts.initializers.base.otf.compose=fonts.initializers.common.compose -fonts.initializers.node.otf.compose=fonts.initializers.common.compose - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-def']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local format,concat,gmatch,match,find,lower=string.format,table.concat,string.gmatch,string.match,string.find,string.lower -local tostring,next=tostring,next -local lpegmatch=lpeg.match -local trace_defining=false trackers .register("fonts.defining",function(v) trace_defining=v end) -local directive_embedall=false directives.register("fonts.embedall",function(v) directive_embedall=v end) -trackers.register("fonts.loading","fonts.defining","otf.loading","afm.loading","tfm.loading") -trackers.register("fonts.all","fonts.*","otf.*","afm.*","tfm.*") -fonts=fonts or {} -fonts.define=fonts.define or {} -fonts.tfm=fonts.tfm or {} -fonts.ids=fonts.ids or {} -fonts.vf=fonts.vf or {} -fonts.used=fonts.used or {} -local tfm=fonts.tfm -local vf=fonts.vf -local define=fonts.define -tfm.version=1.01 -tfm.cache=containers.define("fonts","tfm",tfm.version,false) -define.method="afm or tfm" -define.specify=fonts.define.specify or {} -define.methods=fonts.define.methods or {} -tfm.fonts=tfm.fonts or {} -tfm.readers=tfm.readers or {} -tfm.internalized=tfm.internalized or {} -tfm.readers.sequence={ 'otf','ttf','afm','tfm' } -tfm.auto_afm=true -local readers=tfm.readers -local sequence=readers.sequence -fonts.version=1.05 -fonts.cache=containers.define("fonts","def",fonts.version,false) -local splitter,specifiers=nil,"" -local P,C,S,Cc=lpeg.P,lpeg.C,lpeg.S,lpeg.Cc -local left=P("(") -local right=P(")") -local colon=P(":") -local space=P(" ") -define.defaultlookup="file" -local prefixpattern=P(false) -function define.add_specifier(symbol) - specifiers=specifiers..symbol - local method=S(specifiers) - local lookup=C(prefixpattern)*colon - local sub=left*C(P(1-left-right-method)^1)*right - local specification=C(method)*C(P(1)^1) - local name=C((1-sub-specification)^1) - splitter=P((lookup+Cc(""))*name*(sub+Cc(""))*(specification+Cc(""))) -end -function define.add_lookup(str,default) - prefixpattern=prefixpattern+P(str) -end -define.add_lookup("file") -define.add_lookup("name") -define.add_lookup("spec") -function define.get_specification(str) - return lpegmatch(splitter,str) -end -function define.register_split(symbol,action) - define.add_specifier(symbol) - define.specify[symbol]=action -end -function define.makespecification(specification,lookup,name,sub,method,detail,size) - size=size or 655360 - if trace_defining then - logs.report("define font","%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s", - specification,(lookup~="" and lookup) or "[file]",(name~="" and name) or "-", - (sub~="" and sub) or "-",(method~="" and method) or "-",(detail~="" and detail) or "-") - end - if not lookup or lookup=="" then - lookup=define.defaultlookup - end - local t={ - lookup=lookup, - specification=specification, - size=size, - name=name, - sub=sub, - method=method, - detail=detail, - resolved="", - forced="", - features={}, - } - return t -end -function define.analyze(specification,size) - local lookup,name,sub,method,detail=define.get_specification(specification or "") - return define.makespecification(specification,lookup,name,sub,method,detail,size) -end -local sortedhashkeys=table.sortedhashkeys -function tfm.hash_features(specification) - local features=specification.features - if features then - local t={} - local normal=features.normal - if normal and next(normal) then - local f=sortedhashkeys(normal) - for i=1,#f do - local v=f[i] - if v~="number" and v~="features" then - t[#t+1]=v..'='..tostring(normal[v]) - end - end - end - local vtf=features.vtf - if vtf and next(vtf) then - local f=sortedhashkeys(vtf) - for i=1,#f do - local v=f[i] - t[#t+1]=v..'='..tostring(vtf[v]) - end - end - if #t>0 then - return concat(t,"+") - end - end - return "unknown" -end -fonts.designsizes={} -function tfm.hash_instance(specification,force) - local hash,size,fallbacks=specification.hash,specification.size,specification.fallbacks - if force or not hash then - hash=tfm.hash_features(specification) - specification.hash=hash - end - if size<1000 and fonts.designsizes[hash] then - size=math.round(tfm.scaled(size,fonts.designsizes[hash])) - specification.size=size - end - if fallbacks then - return hash..' @ '..tostring(size)..' @ '..fallbacks - else - return hash..' @ '..tostring(size) - end -end -define.resolvers=resolvers -function define.resolvers.file(specification) - local suffix=file.suffix(specification.name) - if fonts.formats[suffix] then - specification.forced=suffix - specification.name=file.removesuffix(specification.name) - end -end -function define.resolvers.name(specification) - local resolve=fonts.names.resolve - if resolve then - local resolved,sub=fonts.names.resolve(specification) - specification.resolved,specification.sub=resolved,sub - if resolved then - local suffix=file.suffix(resolved) - if fonts.formats[suffix] then - specification.forced=suffix - specification.name=file.removesuffix(resolved) - else - specification.name=resolved - end - end - else - define.resolvers.file(specification) - end -end -function define.resolvers.spec(specification) - local resolvespec=fonts.names.resolvespec - if resolvespec then - specification.resolved,specification.sub=fonts.names.resolvespec(specification) - if specification.resolved then - specification.forced=file.extname(specification.resolved) - specification.name=file.removesuffix(specification.resolved) - end - else - define.resolvers.name(specification) - end -end -function define.resolve(specification) - if not specification.resolved or specification.resolved=="" then - local r=define.resolvers[specification.lookup] - if r then - r(specification) - end - end - if specification.forced=="" then - specification.forced=nil - else - specification.forced=specification.forced - end - specification.hash=lower(specification.name..' @ '..tfm.hash_features(specification)) - if specification.sub and specification.sub~="" then - specification.hash=specification.sub..' @ '..specification.hash - end - return specification -end -function tfm.read(specification) - local hash=tfm.hash_instance(specification) - local tfmtable=tfm.fonts[hash] - if not tfmtable then - local forced=specification.forced or "" - if forced~="" then - tfmtable=readers[lower(forced)](specification) - if not tfmtable then - logs.report("define font","forced type %s of %s not found",forced,specification.name) - end - else - for s=1,#sequence do - local reader=sequence[s] - if readers[reader] then - if trace_defining then - logs.report("define font","trying (reader sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown") - end - tfmtable=readers[reader](specification) - if tfmtable then - break - else - specification.filename=nil - end - end - end - end - if tfmtable then - if directive_embedall then - tfmtable.embedding="full" - elseif tfmtable.filename and fonts.dontembed[tfmtable.filename] then - tfmtable.embedding="no" - else - tfmtable.embedding="subset" - end - tfm.fonts[hash]=tfmtable - fonts.designsizes[specification.hash]=tfmtable.designsize - end - end - if not tfmtable then - logs.report("define font","font with name %s is not found",specification.name) - end - return tfmtable -end -function tfm.read_and_define(name,size) - local specification=define.analyze(name,size) - local method=specification.method - if method and define.specify[method] then - specification=define.specify[method](specification) - end - specification=define.resolve(specification) - local hash=tfm.hash_instance(specification) - local id=define.registered(hash) - if not id then - local fontdata=tfm.read(specification) - if fontdata then - fontdata.hash=hash - id=font.define(fontdata) - define.register(fontdata,id) - tfm.cleanup_table(fontdata) - else - id=0 - end - end - return fonts.ids[id],id -end -local function check_tfm(specification,fullname) - local foundname=resolvers.findbinfile(fullname,'tfm') or "" - if foundname=="" then - foundname=resolvers.findbinfile(fullname,'ofm') or "" - end - if foundname~="" then - specification.filename,specification.format=foundname,"ofm" - return tfm.read_from_tfm(specification) - end -end -local function check_afm(specification,fullname) - local foundname=resolvers.findbinfile(fullname,'afm') or "" - if foundname=="" and tfm.auto_afm then - local encoding,shortname=match(fullname,"^(.-)%-(.*)$") - if encoding and shortname and fonts.enc.known[encoding] then - shortname=resolvers.findbinfile(shortname,'afm') or "" - if shortname~="" then - foundname=shortname - if trace_loading then - logs.report("load afm","stripping encoding prefix from filename %s",afmname) - end - end - end - end - if foundname~="" then - specification.filename,specification.format=foundname,"afm" - return tfm.read_from_afm(specification) - end -end -function readers.tfm(specification) - local fullname,tfmtable=specification.filename or "",nil - if fullname=="" then - local forced=specification.forced or "" - if forced~="" then - tfmtable=check_tfm(specification,specification.name.."."..forced) - end - if not tfmtable then - tfmtable=check_tfm(specification,specification.name) - end - else - tfmtable=check_tfm(specification,fullname) - end - return tfmtable -end -function readers.afm(specification,method) - local fullname,tfmtable=specification.filename or "",nil - if fullname=="" then - local forced=specification.forced or "" - if forced~="" then - tfmtable=check_afm(specification,specification.name.."."..forced) - end - if not tfmtable then - method=method or define.method or "afm or tfm" - if method=="tfm" then - tfmtable=check_tfm(specification,specification.name) - elseif method=="afm" then - tfmtable=check_afm(specification,specification.name) - elseif method=="tfm or afm" then - tfmtable=check_tfm(specification,specification.name) or check_afm(specification,specification.name) - else - tfmtable=check_afm(specification,specification.name) or check_tfm(specification,specification.name) - end - end - else - tfmtable=check_afm(specification,fullname) - end - return tfmtable -end -local function check_otf(forced,specification,suffix,what) - local name=specification.name - if forced then - name=file.addsuffix(name,suffix,true) - end - local fullname,tfmtable=resolvers.findbinfile(name,suffix) or "",nil - if fullname=="" then - local fb=fonts.names.old_to_new[name] - if fb then - fullname=resolvers.findbinfile(fb,suffix) or "" - end - end - if fullname=="" then - local fb=fonts.names.new_to_old[name] - if fb then - fullname=resolvers.findbinfile(fb,suffix) or "" - end - end - if fullname~="" then - specification.filename,specification.format=fullname,what - tfmtable=tfm.read_from_open_type(specification) - end - return tfmtable -end -function readers.opentype(specification,suffix,what) - local forced=specification.forced or "" - if forced=="otf" then - return check_otf(true,specification,forced,"opentype") - elseif forced=="ttf" or forced=="ttc" or forced=="dfont" then - return check_otf(true,specification,forced,"truetype") - else - return check_otf(false,specification,suffix,what) - end -end -function readers.otf (specification) return readers.opentype(specification,"otf","opentype") end -function readers.ttf (specification) return readers.opentype(specification,"ttf","truetype") end -function readers.ttc (specification) return readers.opentype(specification,"ttf","truetype") end -function readers.dfont(specification) return readers.opentype(specification,"ttf","truetype") end -function define.check(features,defaults) - local done=false - if features and next(features) then - for k,v in next,defaults do - if features[k]==nil then - features[k],done=v,true - end - end - else - features,done=table.fastcopy(defaults),true - end - return features,done -end -define.last=nil -function define.register(fontdata,id) - if fontdata and id then - local hash=fontdata.hash - if not tfm.internalized[hash] then - if trace_defining then - logs.report("define font","loading at 2 id %s, hash: %s",id or "?",hash or "?") - end - fonts.identifiers[id]=fontdata - fonts.characters [id]=fontdata.characters - fonts.quads [id]=fontdata.parameters.quad - tfm.internalized[hash]=id - end - end -end -function define.registered(hash) - local id=tfm.internalized[hash] - return id,id and fonts.ids[id] -end -local cache_them=false -function tfm.make(specification) - local fvm=define.methods[specification.features.vtf.preset] - if fvm then - return fvm(specification) - else - return nil - end -end -function define.read(specification,size,id) - statistics.starttiming(fonts) - if type(specification)=="string" then - specification=define.analyze(specification,size) - end - local method=specification.method - if method and define.specify[method] then - specification=define.specify[method](specification) - end - specification=define.resolve(specification) - local hash=tfm.hash_instance(specification) - if cache_them then - local fontdata=containers.read(fonts.cache,hash) - end - local fontdata=define.registered(hash) - if not fontdata then - if specification.features.vtf and specification.features.vtf.preset then - fontdata=tfm.make(specification) - else - fontdata=tfm.read(specification) - if fontdata then - tfm.check_virtual_id(fontdata) - end - end - if cache_them then - fontdata=containers.write(fonts.cache,hash,fontdata) - end - if fontdata then - fontdata.hash=hash - fontdata.cache="no" - if id then - define.register(fontdata,id) - end - end - end - define.last=fontdata or id - if not fontdata then - logs.report("define font","unknown font %s, loading aborted",specification.name) - elseif trace_defining and type(fontdata)=="table" then - logs.report("define font","using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s", - fontdata.type or "unknown", - id or "?", - fontdata.name or "?", - fontdata.size or "default", - fontdata.encodingbytes or "?", - fontdata.encodingname or "unicode", - fontdata.fullname or "?", - file.basename(fontdata.filename or "?")) - end - statistics.stoptiming(fonts) - return fontdata -end -function vf.find(name) - name=file.removesuffix(file.basename(name)) - if tfm.resolve_vf then - local format=fonts.logger.format(name) - if format=='tfm' or format=='ofm' then - if trace_defining then - logs.report("define font","locating vf for %s",name) - end - return resolvers.findbinfile(name,"ovf") - else - if trace_defining then - logs.report("define font","vf for %s is already taken care of",name) - end - return nil - end - else - if trace_defining then - logs.report("define font","locating vf for %s",name) - end - return resolvers.findbinfile(name,"ovf") - end -end -callbacks.register('define_font',define.read,"definition of fonts (tfmtable preparation)") -callbacks.register('find_vf_file',vf.find,"locating virtual fonts, insofar needed") - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-xtx']={ - version=1.001, - comment="companion to font-ini.mkiv", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -local texsprint,count=tex.sprint,tex.count -local format,concat,gmatch,match,find,lower=string.format,table.concat,string.gmatch,string.match,string.find,string.lower -local tostring,next=tostring,next -local lpegmatch=lpeg.match -local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end) -local list={} -fonts.define.specify.colonized_default_lookup="file" -local function isstyle(s) - local style=string.lower(s):split("/") - for _,v in ipairs(style) do - if v=="b" then - list.style="bold" - elseif v=="i" then - list.style="italic" - elseif v=="bi" or v=="ib" then - list.style="bolditalic" - elseif v:find("^s=") then - list.optsize=v:split("=")[2] - elseif v=="aat" or v=="icu" or v=="gr" then - logs.report("load font","unsupported font option: %s",v) - elseif not v:is_empty() then - list.style=v:gsub("[^%a%d]","") - end - end -end -fonts=fonts or {} -fonts.otf=fonts.otf or {} -local otf=fonts.otf -otf.tables=otf.tables or {} -otf.tables.defaults={ - dflt={ - "ccmp","locl","rlig","liga","clig", - "kern","mark","mkmk","itlc", - }, - arab={ - "ccmp","locl","isol","fina","fin2", - "fin3","medi","med2","init","rlig", - "calt","liga","cswh","mset","curs", - "kern","mark","mkmk", - }, - deva={ - "ccmp","locl","init","nukt","akhn", - "rphf","blwf","half","pstf","vatu", - "pres","blws","abvs","psts","haln", - "calt","blwm","abvm","dist","kern", - "mark","mkmk", - }, - khmr={ - "ccmp","locl","pref","blwf","abvf", - "pstf","pres","blws","abvs","psts", - "clig","calt","blwm","abvm","dist", - "kern","mark","mkmk", - }, - thai={ - "ccmp","locl","liga","kern","mark", - "mkmk", - }, - hang={ - "ccmp","ljmo","vjmo","tjmo", - }, -} -otf.tables.defaults.beng=otf.tables.defaults.deva -otf.tables.defaults.guru=otf.tables.defaults.deva -otf.tables.defaults.gujr=otf.tables.defaults.deva -otf.tables.defaults.orya=otf.tables.defaults.deva -otf.tables.defaults.taml=otf.tables.defaults.deva -otf.tables.defaults.telu=otf.tables.defaults.deva -otf.tables.defaults.knda=otf.tables.defaults.deva -otf.tables.defaults.mlym=otf.tables.defaults.deva -otf.tables.defaults.sinh=otf.tables.defaults.deva -otf.tables.defaults.syrc=otf.tables.defaults.arab -otf.tables.defaults.mong=otf.tables.defaults.arab -otf.tables.defaults.nko=otf.tables.defaults.arab -otf.tables.defaults.tibt=otf.tables.defaults.khmr -otf.tables.defaults.lao=otf.tables.defaults.thai -local function parse_script(script) - if otf.tables.scripts[script] then - local dflt - if otf.tables.defaults[script] then - logs.report("load font","auto-selecting default features for script: %s",script) - dflt=otf.tables.defaults[script] - else - logs.report("load font","auto-selecting default features for script: dflt (was %s)",script) - dflt=otf.tables.defaults["dflt"] - end - for _,v in next,dflt do - list[v]="yes" - end - else - logs.report("load font","unknown script: %s",script) - end -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 iskey (k,v) - if k=="script" then - parse_script(v) - end - list[k]=v -end -local function istrue (s) list[s]=true end -local function isfalse(s) list[s]=false end -local spaces=lpeg.P(" ")^0 -local namespec=(1-lpeg.S("/:("))^0 -local filespec=(lpeg.R("az","AZ")*lpeg.P(":"))^-1*(1-lpeg.S(":("))^1 -local crapspec=spaces*lpeg.P("/")*(((1-lpeg.P(":"))^0)/isstyle)*spaces -local filename=(lpeg.P("file:")/isfile*(filespec/thename))+(lpeg.P("[")*lpeg.P(true)/isfile*(((1-lpeg.P("]"))^0)/thename)*lpeg.P("]")) -local fontname=(lpeg.P("name:")/isname*(namespec/thename))+lpeg.P(true)/issome*(namespec/thename) -local sometext=(lpeg.R("az","AZ","09")+lpeg.S("+-."))^1 -local truevalue=lpeg.P("+")*spaces*(sometext/istrue) -local falsevalue=lpeg.P("-")*spaces*(sometext/isfalse) -local keyvalue=lpeg.P("+")+(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(")") -local option=spaces*(keyvalue+falsevalue+truevalue+somevalue)*spaces -local options=lpeg.P(":")*spaces*(lpeg.P(";")^0*option)^0 -local pattern=(filename+fontname)*subvalue^0*crapspec^0*options^0 -local normalize_meanings=fonts.otf.meanings.normalize -function fonts.define.specify.colonized(specification) - list={} - lpegmatch(pattern,specification.specification) - if list.style then - specification.style=list.style - list.style=nil - end - if list.optsize then - specification.optsize=list.optsize - list.optsize=nil - end - if list.name then - if resolvers.find_file(list.name,"tfm") then - list.lookup="file" - list.name=file.addsuffix(list.name,"tfm") - elseif resolvers.find_file(list.name,"ofm") then - list.lookup="file" - list.name=file.addsuffix(list.name,"ofm") - end - specification.name=list.name - list.name=nil - end - if list.lookup then - specification.lookup=list.lookup - list.lookup=nil - end - if list.sub then - specification.sub=list.sub - list.sub=nil - end - specification.features.normal=normalize_meanings(list) - return specification -end -fonts.define.register_split(":",fonts.define.specify.colonized) - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-dum']={ - version=1.001, - comment="companion to luatex-*.tex", - author="Hans Hagen, PRAGMA-ADE, Hasselt NL", - copyright="PRAGMA ADE / ConTeXt Development Team", - license="see context related readme files" -} -fonts=fonts or {} -fonts.otf.pack=false -fonts.tfm.resolve_vf=false -fonts.tfm.fontname_mode="specification" -fonts.tfm.readers=fonts.tfm.readers or {} -fonts.tfm.readers.sequence={ 'otf','ttf','tfm' } -fonts.tfm.readers.afm=nil -fonts.define=fonts.define or {} -fonts.define.specify.colonized_default_lookup="name" -function fonts.define.get_specification(str) - return "",str,"",":",str -end -fonts.logger=fonts.logger or {} -function fonts.logger.save() -end -fonts.names=fonts.names or {} -fonts.names.version=1.001 -fonts.names.basename="luatex-fonts-names.lua" -fonts.names.new_to_old={} -fonts.names.old_to_new={} -local data,loaded=nil,false -local fileformats={ "lua","tex","other text files" } -function fonts.names.resolve(name,sub) - if not loaded then - local basename=fonts.names.basename - if basename and basename~="" then - for i=1,#fileformats do - local format=fileformats[i] - local foundname=resolvers.find_file(basename,format) or "" - if foundname~="" then - data=dofile(foundname) - break - end - end - end - loaded=true - end - if type(data)=="table" and data.version==fonts.names.version then - local condensed=string.gsub(string.lower(name),"[^%a%d]","") - local found=data.mappings and data.mappings[condensed] - if found then - local fontname,filename,subfont=found[1],found[2],found[3] - if subfont then - return filename,fontname - else - return filename,false - end - else - return name,false - end - end -end -fonts.names.resolvespec=fonts.names.resolve -table.insert(fonts.triggers,"itlc") -local function itlc(tfmdata,value) - if value then - 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 -function fonts.initializers.common.slant(tfmdata,value) - value=tonumber(value) - if not value then - value=0 - elseif value>1 then - value=1 - elseif value<-1 then - value=-1 - end - tfmdata.slant_factor=value -end -function fonts.initializers.common.extend(tfmdata,value) - value=tonumber(value) - if not value then - value=0 - elseif value>10 then - value=10 - elseif value<-10 then - value=-10 - end - tfmdata.extend_factor=value -end -table.insert(fonts.triggers,"slant") -table.insert(fonts.triggers,"extend") -fonts.initializers.base.otf.slant=fonts.initializers.common.slant -fonts.initializers.node.otf.slant=fonts.initializers.common.slant -fonts.initializers.base.otf.extend=fonts.initializers.common.extend -fonts.initializers.node.otf.extend=fonts.initializers.common.extend -fonts.protrusions=fonts.protrusions or {} -fonts.protrusions.setups=fonts.protrusions.setups or {} -local setups=fonts.protrusions.setups -local function map_opbd_onto_protrusion(tfmdata,value,opbd) - local characters,descriptions=tfmdata.characters,tfmdata.descriptions - local otfdata=tfmdata.shared.otfdata - local singles=otfdata.shared.featuredata.gpos_single - local script,language=tfmdata.script,tfmdata.language - local done,factor,left,right=false,1,1,1 - local setup=setups[value] - if setup then - factor=setup.factor or 1 - left=setup.left or 1 - right=setup.right or 1 - else - factor=tonumber(value) or 1 - end - if opbd~="right" then - local validlookups,lookuplist=fonts.otf.collect_lookups(otfdata,"lfbd",script,language) - if validlookups then - for i=1,#lookuplist do - local lookup=lookuplist[i] - local data=singles[lookup] - if data then - if trace_protrusion then - logs.report("fonts","set left protrusion using lfbd lookup '%s'",lookup) - end - for k,v in next,data do - local p=- (v[1]/1000)*factor*left - characters[k].left_protruding=p - if trace_protrusion then - logs.report("opbd","lfbd -> %s -> 0x%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," ")) - end - end - done=true - end - end - end - end - if opbd~="left" then - local validlookups,lookuplist=fonts.otf.collect_lookups(otfdata,"rtbd",script,language) - if validlookups then - for i=1,#lookuplist do - local lookup=lookuplist[i] - local data=singles[lookup] - if data then - if trace_protrusion then - logs.report("fonts","set right protrusion using rtbd lookup '%s'",lookup) - end - for k,v in next,data do - local p=(v[1]/1000)*factor*right - characters[k].right_protruding=p - if trace_protrusion then - logs.report("opbd","rtbd -> %s -> 0x%05X (%s) -> %0.03f (%s)",lookup,k,utfchar(k),p,concat(v," ")) - end - end - end - done=true - end - end - end - tfmdata.auto_protrude=done -end -function fonts.initializers.common.protrusion(tfmdata,value) - if value then - local opbd=tfmdata.shared.features.opbd - if opbd then - map_opbd_onto_protrusion(tfmdata,value,opbd) - elseif value then - local setup=setups[value] - if setup then - local factor,left,right=setup.factor or 1,setup.left or 1,setup.right or 1 - local emwidth=tfmdata.parameters.quad - tfmdata.auto_protrude=true - for i,chr in next,tfmdata.characters do - local v,pl,pr=setup[i],nil,nil - if v then - pl,pr=v[1],v[2] - end - if pl and pl~=0 then chr.left_protruding=left*pl*factor end - if pr and pr~=0 then chr.right_protruding=right*pr*factor end - end - end - end - end -end -fonts.expansions=fonts.expansions or {} -fonts.expansions.setups=fonts.expansions.setups or {} -local setups=fonts.expansions.setups -function fonts.initializers.common.expansion(tfmdata,value) - if value then - local setup=setups[value] - if setup then - local stretch,shrink,step,factor=setup.stretch or 0,setup.shrink or 0,setup.step or 0,setup.factor or 1 - tfmdata.stretch,tfmdata.shrink,tfmdata.step,tfmdata.auto_expand=stretch*10,shrink*10,step*10,true - for i,chr in next,tfmdata.characters do - local v=setup[i] - if v and v~=0 then - chr.expansion_factor=v*factor - else - chr.expansion_factor=factor - end - end - end - end -end -table.insert(fonts.manipulators,"protrusion") -table.insert(fonts.manipulators,"expansion") -fonts.initializers.base.otf.protrusion=fonts.initializers.common.protrusion -fonts.initializers.node.otf.protrusion=fonts.initializers.common.protrusion -fonts.initializers.base.otf.expansion=fonts.initializers.common.expansion -fonts.initializers.node.otf.expansion=fonts.initializers.common.expansion -function fonts.register_message() -end -local byte=string.byte -fonts.expansions.setups['default']={ - stretch=2,shrink=2,step=.5,factor=1, - [byte('A')]=0.5,[byte('B')]=0.7,[byte('C')]=0.7,[byte('D')]=0.5,[byte('E')]=0.7, - [byte('F')]=0.7,[byte('G')]=0.5,[byte('H')]=0.7,[byte('K')]=0.7,[byte('M')]=0.7, - [byte('N')]=0.7,[byte('O')]=0.5,[byte('P')]=0.7,[byte('Q')]=0.5,[byte('R')]=0.7, - [byte('S')]=0.7,[byte('U')]=0.7,[byte('W')]=0.7,[byte('Z')]=0.7, - [byte('a')]=0.7,[byte('b')]=0.7,[byte('c')]=0.7,[byte('d')]=0.7,[byte('e')]=0.7, - [byte('g')]=0.7,[byte('h')]=0.7,[byte('k')]=0.7,[byte('m')]=0.7,[byte('n')]=0.7, - [byte('o')]=0.7,[byte('p')]=0.7,[byte('q')]=0.7,[byte('s')]=0.7,[byte('u')]=0.7, - [byte('w')]=0.7,[byte('z')]=0.7, - [byte('2')]=0.7,[byte('3')]=0.7,[byte('6')]=0.7,[byte('8')]=0.7,[byte('9')]=0.7, -} -fonts.protrusions.setups['default']={ - factor=1,left=1,right=1, - [0x002C]={ 0,1 }, - [0x002E]={ 0,1 }, - [0x003A]={ 0,1 }, - [0x003B]={ 0,1 }, - [0x002D]={ 0,1 }, - [0x2013]={ 0,0.50 }, - [0x2014]={ 0,0.33 }, - [0x3001]={ 0,1 }, - [0x3002]={ 0,1 }, - [0x060C]={ 0,1 }, - [0x061B]={ 0,1 }, - [0x06D4]={ 0,1 }, -} -fonts.otf.meanings=fonts.otf.meanings or {} -fonts.otf.meanings.normalize=fonts.otf.meanings.normalize or function(t) - if t.rand then - t.rand="random" - end -end -function fonts.otf.name_to_slot(name) - local tfmdata=fonts.ids[font.current()] - if tfmdata and tfmdata.shared then - local otfdata=tfmdata.shared.otfdata - local unicode=otfdata.luatex.unicodes[name] - return unicode and (type(unicode)=="number" and unicode or unicode[1]) - end -end -function fonts.otf.char(n) - if type(n)=="string" then - n=fonts.otf.name_to_slot(n) - end - if type(n)=="number" then - tex.sprint("\\char"..n) - end -end -fonts.strippables=table.tohash { - 0x000AD,0x017B4,0x017B5,0x0200B,0x0200C,0x0200D,0x0200E,0x0200F,0x0202A,0x0202B, - 0x0202C,0x0202D,0x0202E,0x02060,0x02061,0x02062,0x02063,0x0206A,0x0206B,0x0206C, - 0x0206D,0x0206E,0x0206F,0x0FEFF,0x1D173,0x1D174,0x1D175,0x1D176,0x1D177,0x1D178, - 0x1D179,0x1D17A,0xE0001,0xE0020,0xE0021,0xE0022,0xE0023,0xE0024,0xE0025,0xE0026, - 0xE0027,0xE0028,0xE0029,0xE002A,0xE002B,0xE002C,0xE002D,0xE002E,0xE002F,0xE0030, - 0xE0031,0xE0032,0xE0033,0xE0034,0xE0035,0xE0036,0xE0037,0xE0038,0xE0039,0xE003A, - 0xE003B,0xE003C,0xE003D,0xE003E,0xE003F,0xE0040,0xE0041,0xE0042,0xE0043,0xE0044, - 0xE0045,0xE0046,0xE0047,0xE0048,0xE0049,0xE004A,0xE004B,0xE004C,0xE004D,0xE004E, - 0xE004F,0xE0050,0xE0051,0xE0052,0xE0053,0xE0054,0xE0055,0xE0056,0xE0057,0xE0058, - 0xE0059,0xE005A,0xE005B,0xE005C,0xE005D,0xE005E,0xE005F,0xE0060,0xE0061,0xE0062, - 0xE0063,0xE0064,0xE0065,0xE0066,0xE0067,0xE0068,0xE0069,0xE006A,0xE006B,0xE006C, - 0xE006D,0xE006E,0xE006F,0xE0070,0xE0071,0xE0072,0xE0073,0xE0074,0xE0075,0xE0076, - 0xE0077,0xE0078,0xE0079,0xE007A,0xE007B,0xE007C,0xE007D,0xE007E,0xE007F, -} - -end -- closure - -do -- begin closure to overcome local limits and interference - -if not modules then modules={} end modules ['font-clr']={ - version=1.001, - comment="companion to font-otf.lua (font color)", - author="Khaled Hosny and Elie Roux", - copyright="Luaotfload Development Team", - license="GPL" -} -fonts.triggers=fonts.triggers or {} -fonts.initializers=fonts.initializers or {} -fonts.initializers.common=fonts.initializers.common or {} -local initializers,format=fonts.initializers,string.format -table.insert(fonts.triggers,"color") -function initializers.common.color(tfmdata,value) - local sanitized - if value then - value=tostring(value) - if #value==6 or #value==8 then - sanitized=value - elseif #value==7 then - _,_,sanitized=value:find("(......)") - elseif #value>8 then - _,_,sanitized=value:find("(........)") - else - end - end - if sanitized then - tfmdata.color=sanitized - add_color_callback() - end -end -initializers.base.otf.color=initializers.common.color -initializers.node.otf.color=initializers.common.color -local function hex2dec(hex,one) - if one then - return format("%.1g",tonumber(hex,16)/255) - else - return format("%.3g",tonumber(hex,16)/255) - end -end -local res -local function pageresources(a) - local res2 - if not res then - res="/TransGs1<</ca 1/CA 1>>" - end - res2=format("/TransGs%s<</ca %s/CA %s>>",a,a,a) - res=format("%s%s",res,res:find(res2) and "" or res2) -end -local function hex_to_rgba(hex) - local r,g,b,a,push,pop,res3 - if hex then - if #hex==6 then - _,_,r,g,b=hex:find('(..)(..)(..)') - elseif #hex==8 then - _,_,r,g,b,a=hex:find('(..)(..)(..)(..)') - a=hex2dec(a,true) - pageresources(a) - end - else - return nil - end - r=hex2dec(r) - g=hex2dec(g) - b=hex2dec(b) - if a then - push=format('/TransGs%g gs %s %s %s rg',a,r,g,b) - pop='0 g /TransGs1 gs' - else - push=format('%s %s %s rg',r,g,b) - pop='0 g' - end - return push,pop -end -local glyph=node.id('glyph') -local hlist=node.id('hlist') -local vlist=node.id('vlist') -local whatsit=node.id('whatsit') -local pgi=node.id('page_insert') -local sbox=node.id('sub_box') -local function lookup_next_color(head) - for n in node.traverse(head) do - if n.id==glyph then - if fonts.ids[n.font] and fonts.ids[n.font].color then - return fonts.ids[n.font].color - else - return -1 - end - elseif n.id==vlist or n.id==hlist or n.id==sbox then - local r=lookup_next_color(n.list) - if r==-1 then - return -1 - elseif r then - return r - end - elseif n.id==whatsit or n.id==pgi then - return -1 - end - end - return nil -end -local function node_colorize(head,current_color,next_color) - for n in node.traverse(head) do - if n.id==hlist or n.id==vlist or n.id==sbox then - local next_color_in=lookup_next_color(n.next) or next_color - n.list,current_color=node_colorize(n.list,current_color,next_color_in) - elseif n.id==glyph then - local tfmdata=fonts.ids[n.font] - if tfmdata and tfmdata.color then - if tfmdata.color~=current_color then - local pushcolor=hex_to_rgba(tfmdata.color) - local push=node.new(whatsit,8) - push.mode=1 - push.data=pushcolor - head=node.insert_before(head,n,push) - current_color=tfmdata.color - end - local next_color_in=lookup_next_color (n.next) or next_color - if next_color_in~=tfmdata.color then - local _,popcolor=hex_to_rgba(tfmdata.color) - local pop=node.new(whatsit,8) - pop.mode=1 - pop.data=popcolor - head=node.insert_after(head,n,pop) - current_color=nil - end - end - end - end - return head,current_color -end -local function font_colorize(head) - if res then - local r="/ExtGState<<"..res..">>" - tex.pdfpageresources=tex.pdfpageresources:gsub(r,"") - end - local h=node_colorize(head,nil,nil) - if res and res:find("%S") then - local r="/ExtGState<<"..res..">>" - tex.pdfpageresources=tex.pdfpageresources..r - end - return h -end -local color_callback_activated=0 -function add_color_callback() - if color_callback_activated==0 then - luatexbase.add_to_callback("pre_output_filter",font_colorize,"loaotfload.colorize") - color_callback_activated=1 - end -end - -end -- closure diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy.lua deleted file mode 100644 index 8bb1790c667..00000000000 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy.lua +++ /dev/null @@ -1,402 +0,0 @@ -module("luaotfload", package.seeall) - -luaotfload.module = { - name = "luaotfload-legacy", - version = 1.31, - date = "2013/04/25", - description = "Unsupported Luaotfload", - author = "Elie Roux & Hans Hagen", - copyright = "Elie Roux", - license = "GPL v2" -} - -local error, warning, info, log = luatexbase.provides_module(luaotfload.module) - ---[[doc-- - - This used to be a necessary initalization in order not to rebuild an - existing font. Maybe 600 should be replaced by |\pdfpkresolution| - or |texconfig.pk_dpi| (and it should be replaced dynamically), but - we don't have access (yet) to the |texconfig| table, so we let it be - 600. Anyway, it does still work fine even if |\pdfpkresolution| is - changed. - ---doc]]-- - -kpse.init_prog("", 600, "/") - ---[[doc-- - - The minimal required \luatex version. - We are tolerant folks. - ---doc]]-- - -local luatex_version = 60 -if tex.luatexversion < luatex_version then - warning("LuaTeX v%.2f is old, v%.2f is required, v0.76 recommended.", - tex.luatexversion/100, - luatex_version /100) -end - ---[[doc-- - - \subsection{Module loading} - We load the outdated \context files with this function. It - automatically adds the |otfl-| prefix to it, so that we call it with - the actual \context name. - ---doc]]-- - -function luaotfload.loadmodule(tofind) - local found = kpse.find_file(tofind,"tex") - if found then - log("loading file %s.", found) - dofile(found) - else - error("file %s not found.", tofind) - end -end -local loadmodule = luaotfload.loadmodule - ---[[doc-- - - Keep away from these lines! - ---doc]]-- -loadmodule"luaotfload-legacy-merged.lua" - -if not fonts then - loadmodule("otfl-luat-dum.lua") -- not used in context at all - loadmodule("otfl-luat-ovr.lua") -- override some luat-dum functions - loadmodule("otfl-data-con.lua") -- maybe some day we don't need this one - loadmodule("otfl-font-ini.lua") - loadmodule("otfl-node-dum.lua") - loadmodule("otfl-node-inj.lua") ---[[doc-- - By default \context takes some private attributes for internal use. To - avoide attribute clashes with other packages, we override the function - that allocates new attributes, making it a wraper around - |luatexbase.new_attribute()|. We also prefix attributes with |otfl@| to - avoid possiple name clashes. ---doc]]-- - loadmodule("luaotfload-legacy-attributes.lua") -- patch attributes ---[[doc-- - Font handling modules. ---doc]]-- - loadmodule("otfl-font-tfm.lua") - loadmodule("otfl-font-cid.lua") - loadmodule("otfl-font-ott.lua") - loadmodule("otfl-font-map.lua") - loadmodule("otfl-font-otf.lua") - loadmodule("otfl-font-otd.lua") - loadmodule("otfl-font-oti.lua") - loadmodule("otfl-font-otb.lua") - loadmodule("otfl-font-otn.lua") - loadmodule("otfl-font-ota.lua") - loadmodule("otfl-font-otc.lua") - loadmodule("otfl-font-def.lua") ---[[doc-- - \textsf{old luaotfload} specific modules. ---doc]]-- - loadmodule("otfl-font-xtx.lua") - loadmodule("otfl-font-dum.lua") - loadmodule("otfl-font-clr.lua") -end -loadmodule"luaotfload-legacy-database.lua" --- unmerged coz needed in db script - ---[[doc-- - - This is a patch for |otfl-font-def.lua|, that defines a reader for ofm - fonts, this is necessary if we set the forced field of the specification - to |ofm|. - ---doc]]-- - -if fonts and fonts.tfm and fonts.tfm.readers then - fonts.tfm.readers.ofm = fonts.tfm.readers.tfm -end - ---[[doc-- - - \subsection{Post-processing TFM table} - Here we do some final touches to the loaded TFM table before passing it - to the \tex end. - First we create a callback for patching fonts on the fly, to be used by - other packages. - ---doc]]-- - -luatexbase.create_callback("luaotfload.patch_font", "simple", function() end) - ---[[doc-- - - then define a function where font manipulation will take place. - ---doc]]-- - -local function def_font(...) - local fontdata = fonts.define.read(...) - if type(fontdata) == "table" and fontdata.shared then ---[[doc-- - - Then we populate |MathConstants| table, which is required for - OpenType math. - - Note: actually it isn’t, but you’re asking for it by using outdated - code. - ---doc]]-- - local otfdata = fontdata.shared.otfdata - if otfdata.metadata.math then - local mc = { } - for k,v in next, otfdata.metadata.math do - if k:find("Percent") then - -- keep percent values as is - mc[k] = v - else - mc[k] = v / fontdata.units * fontdata.size - end - end - -- for \overwithdelims - mc.FractionDelimiterSize = 1.01 * fontdata.size - mc.FractionDelimiterDisplayStyleSize = 2.39 * fontdata.size - - fontdata.MathConstants = mc - end ---[[doc-- - - Execute any registered font patching callbacks. - ---doc]]-- - luatexbase.call_callback("luaotfload.patch_font", fontdata) - end - return fontdata -end - ---[[doc-- -\subsection{\context override} - - We have a unified function for both file and name resolver. This - line is commented as it makes database reload too often. This means - that in some cases, a font in the database will not be found if - it's not in the texmf tree. A similar thing will reappear in next - version. - ---doc]]-- - ---fonts.define.resolvers.file = fonts.define.resolvers.name - ---[[doc-- - - Overriding some defaults set in \context code. - ---doc]]-- - -fonts.mode = "node" - ---[[doc-- - - The following features are useful in math (e.g. in XITS Math font), - but \textsf{luaotfload} does not recognize them in |base| mode. - ---doc]]-- - -local register_base_sub = fonts.otf.features.register_base_substitution -local gsubs = { - "ss01", "ss02", "ss03", "ss04", "ss05", - "ss06", "ss07", "ss08", "ss09", "ss10", - "ss11", "ss12", "ss13", "ss14", "ss15", - "ss16", "ss17", "ss18", "ss19", "ss20", -} - -for _,v in next, gsubs do - register_base_sub(v) -end - ---[[doc-- - - Finally we register the callbacks - ---doc]]-- - -luatexbase.add_to_callback("pre_linebreak_filter", - nodes.simple_font_handler, - "luaotfload.pre_linebreak_filter") -luatexbase.add_to_callback("hpack_filter", - nodes.simple_font_handler, - "luaotfload.hpack_filter") -luatexbase.reset_callback("define_font") -luatexbase.add_to_callback("define_font", - def_font, - "luaotfload.define_font", 1) -luatexbase.add_to_callback("find_vf_file", - fonts.vf.find, - "luaotfload.find_vf_file") ---[[doc-- - - XXX: see https://github.com/wspr/unicode-math/issues/185 - \luatex does not provide interface to accessing - |(Script)ScriptPercentScaleDown| math constants, so we - emulate \xetex behaviour by setting |\fontdimen10| and - |\fontdimen11|. - - Note: actually, it does now, but not unless you update. - ---doc]]-- - -local function set_sscale_diments(fontdata) - local mc = fontdata.MathConstants - if mc then - if mc["ScriptPercentScaleDown"] then - fontdata.parameters[10] = mc.ScriptPercentScaleDown - else -- resort to plain TeX default - fontdata.parameters[10] = 70 - end - if mc["ScriptScriptPercentScaleDown"] then - fontdata.parameters[11] = mc.ScriptScriptPercentScaleDown - else -- resort to plain TeX default - fontdata.parameters[11] = 50 - end - end -end - -luatexbase.add_to_callback("luaotfload.patch_font", set_sscale_diments, "unicodemath.set_sscale_diments") - ---[[doc-- - Version 2.3c of fontspec dropped a couple features that are now - provided in the luaotfload auxiliary libraries. To avoid breaking - Mik\TEX (again), which is sorta the entire point of distributing the - legacy codebase, we temporarily restore those functions here. - - Note that apart from cosmetic changes these are still the same as in - pre-TL2013 fontspec, relying on pairs() and other inefficient methods. ---doc]]-- - -luaotfload.aux = luaotfload.aux or { } -local aux = luaotfload.aux - -local stringlower = string.lower -local fontid = font.id - -local identifiers = fonts.identifiers - -local check_script = function (id, script) - local s = stringlower(script) - if id and id > 0 then - local tfmdata = identifiers[id] - local otfdata = tfmdata.shared and tfmdata.shared.otfdata - if otfdata then - local features = otfdata.luatex.features - for i, _ in pairs(features) do - for j, _ in pairs(features[i]) do - if features[i][j][s] then - fontspec.log("script '%s' exists in font '%s'", - script, tfmdata.fullname) - return true - end - end - end - end - end -end - -local check_language = function (id, script, language) - local s = stringlower(script) - local l = stringlower(language) - if id and id > 0 then - local tfmdata = identifiers[id] - local otfdata = tfmdata.shared and tfmdata.shared.otfdata - if otfdata then - local features = otfdata.luatex.features - for i, _ in pairs(features) do - for j, _ in pairs(features[i]) do - if features[i][j][s] and features[i][j][s][l] then - fontspec.log("language '%s' for script '%s' exists in font '%s'", - language, script, tfmdata.fullname) - return true - end - end - end - end - end -end - -local check_feature = function (id, script, language, feature) - local s = stringlower(script) - local l = stringlower(language) - local f = stringlower(feature:gsub("^[+-]", ""):gsub("=.*$", "")) - if id and id > 0 then - local tfmdata = identifiers[id] - local otfdata = tfmdata.shared and tfmdata.shared.otfdata - if otfdata then - local features = otfdata.luatex.features - for i, _ in pairs(features) do - if features[i][f] and features[i][f][s] then - if features[i][f][s][l] == true then - fontspec.log("feature '%s' for language '%s' and script '%s' exists in font '%s'", - feature, language, script, tfmdata.fullname) - return true - end - end - end - end - end -end - -local get_math_dimension = function(fnt, str) - if type(fnt) == "string" then - fnt = fontid(fnt) - end - local tfmdata = identifiers[fnt] - if tfmdata then - local mathdata = tfmdata.MathConstants - if mathdata then - return mathdata[str] - end - end -end - -aux.provides_script = check_script -aux.provides_language = check_language -aux.provides_feature = check_feature -aux.get_math_dimension = get_math_dimension - -local set_capheight = function (tfmdata) - local capheight - local shared = tfmdata.shared - if shared then - local metadata = shared.otfdata.metadata - local units_per_em = metadata.units_per_em or tfmdata.units - local os2_capheight = shared.otfdata.pfminfo.os2_capheight - local size = tfmdata.size - - if os2_capheight > 0 then - capheight = os2_capheight / units_per_em * size - else - local X8 = string.byte"X" - if tfmdata.characters[X8] then - capheight = tfmdata.characters[X8].height - else - capheight = metadata.ascent / units_per_em * size - end - end - else - local X8 = string.byte"X" - if tfmdata.characters[X8] then - capheight = tfmdata.characters[X8].height - end - end - if capheight then - tfmdata.parameters[8] = capheight - end -end -luatexbase.add_to_callback("luaotfload.patch_font", - set_capheight, - "luaotfload.set_capheight") - ---[[doc-- -End of auxiliary functionality that was moved from fontspec.lua. ---doc]]-- - --- vim:ts=2:sw=2:expandtab:ft=lua diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua index 7c5a9675354..20f29f53cb6 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua @@ -1,11 +1,14 @@ if not modules then modules = { } end modules ['letterspace'] = { - version = "2.4", - comment = "companion to luaotfload.lua", + version = "2.5", + comment = "companion to luaotfload-main.lua", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL; adapted by Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } +local log = luaotfload.log +local report = log.report + local getmetatable = getmetatable local require = require local setmetatable = setmetatable @@ -512,10 +515,10 @@ otffeatures.register { local initializecompatfontkerning = function (tfmdata, percentage) local factor = tonumber (percentage) if not factor then - logs.names_report ("both", 0, "letterspace", - "Invalid argument to letterspace: %s (type %q), " .. - "was expecting percentage as Lua number instead.", - percentage, type (percentage)) + report ("both", 0, "letterspace", + "Invalid argument to letterspace: %s (type %q), " .. + "was expecting percentage as Lua number instead.", + percentage, type (percentage)) return end return initializefontkerning (tfmdata, factor * 0.01) diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua index 523dc2468b2..2aa8c7c4f92 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua @@ -1,6 +1,6 @@ if not modules then modules = { } end modules ["loaders"] = { - version = "2.4", - comment = "companion to luaotfload.lua", + version = "2.5", + comment = "companion to luaotfload-main.lua", author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua new file mode 100644 index 00000000000..5698c841fd8 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua @@ -0,0 +1,404 @@ +if not modules then modules = { } end modules ["luaotfload-log"] = { + version = "2.5", + comment = "companion to Luaotfload", + author = "Khaled Hosny, Elie Roux, Philipp Gesang", + copyright = "Luaotfload Development Team", + license = "GNU GPL v2.0" +} + +--[[doc-- +The logging system is slow in general, as we always have the function +call overhead even if we aren’t going to output anything. On the other +hand, the more efficient approach followed by Context isn’t an option +because we lack a user interface to toggle per-subsystem tracing. +--doc]]-- + +local module_name = "luaotfload" --- prefix for messages + +luaotfload = luaotfload or { } +luaotfload.log = luaotfload.log or { } +local log = luaotfload.log + +local ioopen = io.open +local iowrite = io.write +local lfsisdir = lfs.isdir +local lfsisfile = lfs.isfile +local osdate = os.date +local ostime = os.time +local osuuid = os.uuid +local select = select +local stringformat = string.format +local stringsub = string.sub +local tableconcat = table.concat +local texiowrite_nl = texio.write_nl +local texiowrite = texio.write +local type = type + +local dummyfunction = function () end + +local texjob = false +if tex and (tex.jobname or tex.formatname) then + --- TeX + texjob = true +end + +local loglevel = 0 --- default +local logout = "log" + +--- int -> bool +local set_loglevel = function (n) + if type(n) == "number" then + loglevel = n + end + return true +end +log.set_loglevel = set_loglevel + +--- unit -> int +local get_loglevel = function ( ) + return loglevel +end +log.get_loglevel = get_loglevel + +local writeln --- pointer to terminal/log writer +local statusln --- terminal writer that reuses the current line +local first_status = true --- indicate the begin of a status region + +local log_msg = [[ +logging output redirected to %s +to monitor the progress run "tail -f %s" in another terminal +]] + +local tmppath = os.getenv "TMPDIR" or "/tmp" + +local choose_logfile = function ( ) + if lfsisdir (tmppath) then + local fname + repeat --- ensure that file of that name doesn’t exist + fname = tmppath .. "/luaotfload-log-" .. osuuid() + until not lfsisfile (fname) + iowrite (stringformat (log_msg, fname, fname)) + return ioopen (fname, "w") + end + --- missing /tmp + return false +end + +local set_logout = function (s, finalizers) + if s == "stdout" then + logout = "redirect" + elseif s == "file" then --- inject custom logger + logout = "redirect" + local chan = choose_logfile () + chan:write (stringformat ("logging initiated at %s", + osdate ("%F %T", ostime ()))) + local writefile = function (...) + if select ("#", ...) == 2 then + chan:write (select (2, ...)) + else + chan:write (select (1, ...)) + end + end + local writefile_nl= function (...) + chan:write "\n" + if select ("#", ...) == 2 then + chan:write (select (2, ...)) + else + chan:write (select (1, ...)) + end + end + + local writeln_orig = writeln + + texiowrite = writefile + texiowrite_nl = writefile_nl + writeln = writefile_nl + statusln = dummyfunction + + finalizers[#finalizers+1] = function () + chan:write (stringformat ("\nlogging finished at %s\n", + osdate ("%F %T", ostime ()))) + chan:close () + texiowrite = texio.write + texiowrite_nl = texio.write_nl + writeln = writeln_orig + end + --else --- remains “log” + end + return finalizers +end + +log.set_logout = set_logout + +local basic_logger = function (category, fmt, ...) + local res = { module_name, "|", category, ":" } + if fmt then + res [#res + 1] = stringformat (fmt, ...) + end + texiowrite_nl (logout, tableconcat(res, " ")) +end + +--- with faux db update with maximum verbosity: +--- +--- --------- -------- +--- buffering time (s) +--- --------- -------- +--- full 4.12 +--- line 4.20 +--- none 4.39 +--- --------- -------- +--- + +io.stdout:setvbuf "no" +io.stderr:setvbuf "no" + +local kill_line = "\r\x1b[K" + +if texjob == true then + --- We imitate the texio.* functions so the output is consistent. + writeln = function (str) + iowrite "\n" + iowrite(str) + end + statusln = function (str) + if first_status == false then + iowrite (kill_line) + else + iowrite "\n" + end + iowrite (str) + end +else + writeln = function (str) + iowrite(str) + iowrite "\n" + end + statusln = function (str) + if first_status == false then + iowrite (kill_line) + end + iowrite (str) + end +end + +stdout = function (writer, category, ...) + local res = { module_name, "|", category, ":" } + local nargs = select("#", ...) + if nargs == 0 then + --writeln tableconcat(res, " ") + --return + elseif nargs == 1 then + res[#res+1] = select(1, ...) -- around 30% faster than unpack() + else + res[#res+1] = stringformat(...) + end + writer (tableconcat(res, " ")) +end + +--- at default (zero), we aim to be quiet +local level_ids = { common = 1, loading = 2, search = 3 } + +--[[doc-- + + The report() logger is used more or less all over luaotfload. + Its requirements are twofold: + + 1) Provide two logging channels, the terminal and the log file; + 2) Allow for control over verbosity levels. + + The first part is addressed by specifying the log *mode* as the + first argument that can be either “log”, meaning the log file, or + “both”: log file and stdout. Anything else is taken as referring to + stdout only. + + Verbosity levels, though not as fine-grained as e.g. Context’s + system of tracers, allow keeping the logging spam caused by + different subsystems manageable. By default, luaotfload will not + emit anything if things are running smoothly on level zero. Only + warning messages are relayed, while the other messages are skipped + over. (This is a little sub-optimal performance-wise since the + function calls to the logger are executed regardless.) The log + level during a Luatex run can be adjusted by setting the “loglevel” + field in config.luaotfload, or by calling log.set_loglevel() as + defined above. + +--doc]]-- + +local report = function (mode, lvl, ...) + if type(lvl) == "string" then + lvl = level_ids[lvl] + end + if not lvl then lvl = 0 end + + if loglevel >= lvl then + if mode == "log" then + basic_logger (...) + elseif mode == "both" and logout ~= "redirect" then + basic_logger (...) + stdout (writeln, ...) + else + stdout (writeln, ...) + end + end +end + +log.report = report + +--[[doc-- + + status_logger -- Overwrites the most recently printed line of the + terminal. Its purpose is to provide feedback without spamming + stdout with irrelevant messages, i.e. when building the database. + + Status logging must be initialized by calling status_start() and + properly reset via status_stop(). + + The arguments low and high indicate the loglevel threshold at which + linewise and full logging is triggered, respectively. E.g. + + names_status (1, 4, "term", "Hello, world!") + + will print nothing if the loglevel is less than one, reuse the + current line if the loglevel ranges from one to three inclusively, + and output the message on a separate line otherwise. + +--doc]]-- + +local status_logger = function (mode, ...) + if mode == "log" then + basic_logger (...) + else + if mode == "both" and logout ~= "redirect" then + basic_logger (...) + stdout (statusln, ...) + else + stdout (statusln, ...) + end + first_status = false + end +end + +--[[doc-- + + status_start -- Initialize status logging. This installs the status + logger if the loglevel is in the specified range, and the normal + logger otherwise. It also resets the first line state which + causing the next line printed using the status logger to not kill + the current line. + +--doc]]-- + +local status_writer +local status_low = 99 +local status_high = 99 + +local status_start = function (low, high) + first_status = true + status_low = low + status_high = high + + if os.type == "windows" --- Assume broken terminal. + or os.getenv "TERM" == "dumb" + then + status_writer = function (mode, ...) + report (mode, high, ...) + end + return + end + + if low <= loglevel and loglevel < high then + status_writer = status_logger + else + status_writer = function (mode, ...) + report (mode, high, ...) + end + end +end + +--[[doc-- + + status_stop -- Finalize a status region by outputting a newline and + printing a message. + +--doc]]-- + +local status_stop = function (...) + if first_status == false then + status_writer(...) + if texjob == false then + writeln "" + end + end +end + +log.names_status = function (...) status_writer (...) end +log.names_status_start = status_start +log.names_status_stop = status_stop + +--[[doc-- + + The fontloader comes with the Context logging mechanisms + inaccessible. Instead, it provides dumb fallbacks based + on the functions in texio.write*() that can be overridden + by providing a function texio.reporter(). + + The fontloader output can be quite verbose, so we disable + it entirely by default. + +--doc]]-- + +local texioreporter = function (message) + report ("log", 2, message) +end + +texio.reporter = texioreporter + +--[[doc-- + + Adobe Glyph List. + ------------------------------------------------------------------- + + Context provides a somewhat different font-age.lua from an unclear + origin. Unfortunately, the file name it reads from is hard-coded + in font-enc.lua, so we have to replace the entire table. + + This shouldn’t cause any complications. Due to its implementation + the glyph list will be loaded upon loading a OTF or TTF for the + first time during a TeX run. (If one sticks to TFM/OFM then it is + never read at all.) For this reason we can install a metatable that + looks up the file of our choosing and only falls back to the + Context one in case it cannot be found. + +--doc]]-- + +if fonts then --- need to be running TeX + if next(fonts.encodings.agl) then + --- unnecessary because the file shouldn’t be loaded at this time + --- but we’re just making sure + fonts.encodings.agl = nil + collectgarbage"collect" + end + + + fonts.encodings.agl = { } + + setmetatable(fonts.encodings.agl, { __index = function (t, k) + if k == "unicodes" then + local glyphlist = resolvers.findfile"luaotfload-glyphlist.lua" + if glyphlist then + report ("log", 1, "load", "loading the Adobe glyph list") + else + glyphlist = resolvers.findfile"font-age.lua" + report ("both", 0, "load", + "loading the extended glyph list from ConTeXt") + end + local unicodes = dofile(glyphlist) + fonts.encodings.agl = { unicodes = unicodes } + return unicodes + else + return nil + end + end }) +end + +-- vim:tw=71:sw=4:ts=4:expandtab diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua new file mode 100644 index 00000000000..d1cba4c4300 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua @@ -0,0 +1,708 @@ +----------------------------------------------------------------------- +-- FILE: luaotfload-main.lua +-- DESCRIPTION: Luatex fontloader initialization +-- REQUIREMENTS: luatex v.0.79 or later; packages lualibs, luatexbase +-- AUTHOR: Élie Roux, Khaled Hosny, Philipp Gesang +-- VERSION: same as Luaotfload +-- MODIFIED: 2014-07-13 15:35:13+0200 +----------------------------------------------------------------------- +-- +--- Note: +--- This file was part of the original luaotfload.dtx and has been +--- converted to a pure Lua file during the transition from Luaotfload +--- version 2.4 to 2.5. Thus, the comments are still in TeX (Latex) +--- markup. + +if not modules then modules = { } end modules ["luaotfload-main"] = { + version = "2.5", + comment = "fontloader initialization", + author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang", + copyright = "PRAGMA ADE / ConTeXt Development Team", + license = "GNU General Public License v. 2.0" +} + + +--[[doc-- + + This file initializes the system and loads the font loader. To + minimize potential conflicts between other packages and the code + imported from \CONTEXT, several precautions are in order. Some of + the functionality that the font loader expects to be present, like + raw access to callbacks, are assumed to have been disabled by + \identifier{luatexbase} when this file is processed. In some cases + it is possible to trick it by putting dummies into place and + restoring the behavior from \identifier{luatexbase} after + initilization. Other cases such as attribute allocation require + that we hook the functionality from \identifier{luatexbase} into + locations where they normally wouldn’t be. + + Anyways we can import the code base without modifications, which is + due mostly to the extra effort by Hans Hagen to make \LUATEX-Fonts + self-contained and encapsulate it, and especially due to his + willingness to incorporate our suggestions. + +--doc]]-- + +local initial_log_level = 0 + +luaotfload = luaotfload or { } +local luaotfload = luaotfload +luaotfload.log = luaotfload.log or { } + +luaotfload.module = { + name = "luaotfload-main", + version = 2.50000, + date = "2014/07/13", + description = "OpenType layout system.", + author = "Elie Roux & Hans Hagen", + copyright = "Elie Roux", + license = "GPL v2.0" +} + +local luatexbase = luatexbase + +local setmetatable = setmetatable +local type, next = type, next +local stringlower = string.lower +local stringformat = string.format + +local kpsefind_file = kpse.find_file +local lfsisfile = lfs.isfile + +local add_to_callback = luatexbase.add_to_callback +local create_callback = luatexbase.create_callback +local reset_callback = luatexbase.reset_callback +local call_callback = luatexbase.call_callback + +local dummy_function = function () end --- XXX this will be moved to the luaotfload namespace when we have the init module + +local error, warning, info, log = + luatexbase.provides_module(luaotfload.module) + +luaotfload.log.tex = { + error = error, + warning = warning, + info = info, + log = log, +} + +--[[doc-- + + We set the minimum version requirement for \LUATEX to v0.76, + because the font loader requires recent features like direct + attribute indexing and \luafunction{node.end_of_math()} that aren’t + available in earlier versions.\footnote{% + See Taco’s announcement of v0.76: + \url{http://comments.gmane.org/gmane.comp.tex.luatex.user/4042} + and this commit by Hans that introduced those features. + \url{http://repo.or.cz/w/context.git/commitdiff/a51f6cf6ee087046a2ae5927ed4edff0a1acec1b}. + } + +--doc]]-- + +local min_luatex_version = 76 + +if tex.luatexversion < min_luatex_version then + warning ("LuaTeX v%.2f is old, v%.2f or later is recommended.", + tex.luatexversion / 100, + min_luatex_version / 100) + --- we install a fallback for older versions as a safety + if not node.end_of_math then + local math_t = node.id "math" + local traverse_nodes = node.traverse_id + node.end_of_math = function (n) + for n in traverse_nodes (math_t, n.next) do + return n + end + end + end +end + +--[[doc-- + + \subsection{Module loading} + We load the files imported from \CONTEXT with this function. It + automatically prepends the prefix \fileent{luaotfload-} to its + argument, so we can refer to the files with their actual \CONTEXT + name. + +--doc]]-- + +local fl_prefix = "luaotfload" -- “luatex” for luatex-plain +local loadmodule = function (name) + require (fl_prefix .."-"..name) +end + +loadmodule "log.lua" --- log messages +--loadmodule "parsers.lua" --- new in 2.5; fonts.conf and syntax +--loadmodule "configuration.lua" --- configuration options + +local log = luaotfload.log +local logreport = log.report + +log.set_loglevel (default_log_level) + +--[[doc-- + + Before \TeX Live 2013 version, \LUATEX had a bug that made ofm fonts + fail when called with their extension. There was a side-effect making + ofm totally unloadable when luaotfload was present. The following + lines are a patch for this bug. The utility of these lines is + questionable as they are not necessary since \TeX Live 2013. They + should be removed in the next version. + +--doc]]-- + +local Cs, P, lpegmatch = lpeg.Cs, lpeg.P, lpeg.match + +local p_dot, p_slash = P".", P"/" +local p_suffix = (p_dot * (1 - p_dot - p_slash)^1 * P(-1)) / "" +local p_removesuffix = Cs((p_suffix + 1)^1) + +local find_vf_file = function (name) + local fullname = kpsefind_file(name, "ovf") + if not fullname then + --fullname = kpsefind_file(file.removesuffix(name), "ovf") + fullname = kpsefind_file(lpegmatch(p_removesuffix, name), "ovf") + end + if fullname then + logreport ("log", 0, "main", + "loading virtual font file %s.", fullname) + end + return fullname +end + +--[[doc-- + + \subsection{Preparing the Font Loader} + We treat the fontloader as a black box so behavior is consistent + between formats. + We load the fontloader code directly in the same fashion as the + Plain format \identifier{luatex-fonts} that is part of Context. + How this is executed depends on the presence on the + \emphasis{merged font loader code}. + In \identifier{luaotfload} this is contained in the file + \fileent{luaotfload-merged.lua}. + If this file cannot be found, the original libraries from \CONTEXT + of which the merged code was composed are loaded instead. + Since these files are not shipped with Luaotfload, an installation + of Context is required. + (Since we pull the fontloader directly from the Context minimals, + the necessary Context version is likely to be more recent than that + of other TeX distributions like Texlive.) + The imported font loader will call \luafunction{callback.register} + once while reading \fileent{font-def.lua}. + This is unavoidable unless we modify the imported files, but + harmless if we make it call a dummy instead. + However, this problem might vanish if we decide to do the merging + ourselves, like the \identifier{lualibs} package does. + With this step we would obtain the freedom to load our own + overrides in the process right where they are needed, at the cost + of losing encapsulation. + The decision on how to progress is currently on indefinite hold. + +--doc]]-- + +local starttime = os.gettimeofday () +local trapped_register = callback.register +callback.register = dummy_function + +--[[doc-- + + By default, the fontloader requires a number of \emphasis{private + attributes} for internal use. + These must be kept consistent with the attribute handling methods + as provided by \identifier{luatexbase}. + Our strategy is to override the function that allocates new + attributes before we initialize the font loader, making it a + wrapper around \luafunction{luatexbase.new_attribute}.\footnote{% + Many thanks, again, to Hans Hagen for making this part + configurable! + } + The attribute identifiers are prefixed “\fileent{luaotfload@}” to + avoid name clashes. + +--doc]]-- + +do + local new_attribute = luatexbase.new_attribute + local the_attributes = luatexbase.attributes + + attributes = attributes or { } + + attributes.private = function (name) + local attr = "luaotfload@" .. name --- used to be: “otfl@” + local number = the_attributes[attr] + if not number then + number = new_attribute(attr) + end + return number + end +end + +--[[doc-- + + These next lines replicate the behavior of + \fileent{luatex-fonts.lua}. + +--doc]]-- + +local context_environment = { } + +local push_namespaces = function () + logreport ("log", 1, "main", "push namespace for font loader") + local normalglobal = { } + for k, v in next, _G do + normalglobal[k] = v + end + return normalglobal +end + +local pop_namespaces = function (normalglobal, isolate) + if normalglobal then + local _G = _G + local mode = "non-destructive" + if isolate then mode = "destructive" end + logreport ("log", 1, "main", "pop namespace from font loader -- " .. mode) + for k, v in next, _G do + if not normalglobal[k] then + context_environment[k] = v + if isolate then + _G[k] = nil + end + end + end + for k, v in next, normalglobal do + _G[k] = v + end + -- just to be sure: + setmetatable(context_environment,_G) + else + logreport ("both", 0, "main", + "irrecoverable error during pop_namespace: no globals to restore") + os.exit() + end +end + +luaotfload.context_environment = context_environment +luaotfload.push_namespaces = push_namespaces +luaotfload.pop_namespaces = pop_namespaces + +local our_environment = push_namespaces() + +--[[doc-- + + The font loader requires that the attribute with index zero be + zero. We happily oblige. + (Cf. \fileent{luatex-fonts-nod.lua}.) + +--doc]]-- + +tex.attribute[0] = 0 + +--[[doc-- + + Now that things are sorted out we can finally load the fontloader. + +--doc]]-- + +loadmodule "fontloader.lua" +---loadmodule"font-odv.lua" --- <= Devanagari support from Context + +if fonts then + + if not fonts._merge_loaded_message_done_ then + logreport ("log", 5, "main", [["I am using the merged fontloader here.]]) + logreport ("log", 5, "main", [[ If you run into problems or experience unexpected]]) + logreport ("log", 5, "main", [[ behaviour, and if you have ConTeXt installed you can try]]) + logreport ("log", 5, "main", [[ to delete the file 'luaotfload-fontloader.lua' as I might]]) + logreport ("log", 5, "main", [[ then use the possibly updated libraries. The merged]]) + logreport ("log", 5, "main", [[ version is not supported as it is a frozen instance.]]) + logreport ("log", 5, "main", [[ Problems can be reported to the ConTeXt mailing list."]]) + end + fonts._merge_loaded_message_done_ = true + +else--- the loading sequence is known to change, so this might have to + --- be updated with future updates! + --- do not modify it though unless there is a change to the merged + --- package! + loadmodule("l-lua.lua") + loadmodule("l-lpeg.lua") + loadmodule("l-function.lua") + loadmodule("l-string.lua") + loadmodule("l-table.lua") + loadmodule("l-io.lua") + loadmodule("l-file.lua") + loadmodule("l-boolean.lua") + loadmodule("l-math.lua") + loadmodule("util-str.lua") + loadmodule('luatex-basics-gen.lua') + loadmodule('data-con.lua') + loadmodule('luatex-basics-nod.lua') + loadmodule('font-ini.lua') + loadmodule('font-con.lua') + loadmodule('luatex-fonts-enc.lua') + loadmodule('font-cid.lua') + loadmodule('font-map.lua') + loadmodule('luatex-fonts-syn.lua') + loadmodule('luatex-fonts-tfm.lua') + loadmodule('font-oti.lua') + loadmodule('font-otf.lua') + loadmodule('font-otb.lua') + loadmodule('luatex-fonts-inj.lua') --> since 2014-01-07, replaces node-inj.lua + loadmodule('font-ota.lua') + loadmodule('luatex-fonts-otn.lua') --> since 2014-01-07, replaces font-otn.lua + loadmodule('font-otp.lua') --> since 2013-04-23 + loadmodule('luatex-fonts-lua.lua') + loadmodule('font-def.lua') + loadmodule('luatex-fonts-def.lua') + loadmodule('luatex-fonts-ext.lua') + loadmodule('luatex-fonts-cbk.lua') +end --- non-merge fallback scope + +--[[doc-- + + Here we adjust the globals created during font loader + initialization. If the second argument to + \luafunction{pop_namespaces()} is \verb|true| this will restore the + state of \luafunction{_G}, eliminating every global generated since + the last call to \luafunction{push_namespaces()}. At the moment we + see no reason to do this, and since the font loader is considered + an essential part of \identifier{luatex} as well as a very well + organized piece of code, we happily concede it the right to add to + \luafunction{_G} if needed. + +--doc]]-- + +pop_namespaces(our_environment, false)-- true) + +logreport ("both", 0, "main", + "fontloader loaded in %0.3f seconds", os.gettimeofday()-starttime) + +--[[doc-- + + \subsection{Callbacks} + After the fontloader is ready we can restore the callback trap from + \identifier{luatexbase}. + +--doc]]-- + +callback.register = trapped_register + +--[[doc-- + + We do our own callback handling with the means provided by + luatexbase. + Note: \luafunction{pre_linebreak_filter} and + \luafunction{hpack_filter} are coupled in \CONTEXT in the concept + of \emphasis{node processor}. + +--doc]]-- + +add_to_callback("pre_linebreak_filter", + nodes.simple_font_handler, + "luaotfload.node_processor", + 1) +add_to_callback("hpack_filter", + nodes.simple_font_handler, + "luaotfload.node_processor", + 1) +add_to_callback("find_vf_file", + find_vf_file, "luaotfload.find_vf_file") + +loadmodule "override.lua" --- load glyphlist on demand + +--[[doc-- + + Now we load the modules written for \identifier{luaotfload}. + +--doc]]-- + +loadmodule "parsers.lua" --- fonts.conf and syntax +loadmodule "configuration.lua" --- configuration options + +if not config.actions.apply_defaults () then + logreport ("log", 0, "load", "Configuration unsuccessful.") +end + +loadmodule "loaders.lua" --- Type1 font wrappers +loadmodule "database.lua" --- Font management. +loadmodule "colors.lua" --- Per-font colors. + +if not config.actions.reconfigure () then + logreport ("log", 0, "load", "Post-configuration hooks failed.") +end + +--[[doc-- + + Relying on the \verb|name:| resolver for everything has been the + source of permanent trouble with the database. + With the introduction of the new syntax parser we now have enough + granularity to distinguish between the \XETEX emulation layer and + the genuine \verb|name:| and \verb|file:| lookups of \LUATEX-Fonts. + Another benefit is that we can now easily plug in or replace new + lookup behaviors if necessary. + The name resolver remains untouched, but it calls + \luafunction{fonts.names.resolve()} internally anyways (see + \fileent{luaotfload-database.lua}). + +--doc]]-- + +local filesuffix = file.suffix +local fileremovesuffix = file.removesuffix +local request_resolvers = fonts.definers.resolvers +local formats = fonts.formats +local names = fonts.names +formats.ofm = "type1" + +fonts.encodings.known = fonts.encodings.known or { } + +--[[doc-- + + \identifier{luaotfload} promises easy access to system fonts. + Without additional precautions, this cannot be achieved by + \identifier{kpathsea} alone, because it searches only the + \fileent{texmf} directories by default. + Although it is possible for \identifier{kpathsea} to include extra + paths by adding them to the \verb|OSFONTDIR| environment variable, + this is still short of the goal »\emphasis{it just works!}«. + When building the font database \identifier{luaotfload} scans + system font directories anyways, so we already have all the + information for looking sytem fonts. + With the release version 2.2 the file names are indexed in the + database as well and we are ready to resolve \verb|file:| lookups + this way. + Thus we no longer need to call the \identifier{kpathsea} library in + most cases when looking up font files, only when generating the + database, and when verifying the existence of a file in the + \fileent{texmf} tree. + +--doc]]-- + +local resolve_file = names.font_file_lookup + +local file_resolver = function (specification) + local name = resolve_file (specification.name) + local suffix = filesuffix(name) + if formats[suffix] then + specification.forced = stringlower (suffix) + specification.forcedname = file.removesuffix(name) + else + specification.name = name + end +end + +request_resolvers.file = file_resolver + +--[[doc-- + + We classify as \verb|anon:| those requests that have neither a + prefix nor brackets. According to Khaled\footnote{% + \url{https://github.com/phi-gamma/luaotfload/issues/4#issuecomment-17090553}. + } + they are the \XETEX equivalent of a \verb|name:| request, so we + will be treating them as such. + +--doc]]-- + +--request_resolvers.anon = request_resolvers.name + +--[[doc-- + + There is one drawback, though. + This syntax is also used for requesting fonts in \identifier{Type1} + (\abbrev{tfm}, \abbrev{ofm}) format. + These are essentially \verb|file:| lookups and must be caught + before the \verb|name:| resolver kicks in, lest they cause the + database to update. + Even if we were to require the \verb|file:| prefix for all + \identifier{Type1} requests, tests have shown that certain fonts + still include further fonts (e.~g. \fileent{omlgcb.ofm} will ask + for \fileent{omsecob.tfm}) \emphasis{using the old syntax}. + For this reason, we introduce an extra check with an early return. + +--doc]]-- + +local type1_formats = { "tfm", "ofm", "TFM", "OFM", } + +request_resolvers.anon = function (specification) + local name = specification.name + for i=1, #type1_formats do + local format = type1_formats[i] + if resolvers.findfile(name, format) then + specification.forcedname = file.addsuffix(name, format) + specification.forced = format + return + end + end + --- under some weird circumstances absolute paths get + --- passed to the definer; we have to catch them + --- before the name: resolver misinterprets them. + name = specification.specification + local exists, _ = lfsisfile(name) + if exists then --- garbage; we do this because we are nice, + --- not because it is correct + logreport ("log", 1, "load", "file %q exists", name) + logreport ("log", 1, "load", + "... overriding borked anon: lookup with path: lookup") + specification.name = name + request_resolvers.path(specification) + return + end + request_resolvers.name(specification) +end + +--[[doc-- + + Prior to version 2.2, \identifier{luaotfload} did not distinguish + \verb|file:| and \verb|path:| lookups, causing complications with + the resolver. + Now we test if the requested name is an absolute path in the file + system, otherwise we fall back to the \verb|file:| lookup. + +--doc]]-- + +request_resolvers.path = function (specification) + local name = specification.name + local exists, _ = lfsisfile(name) + if not exists then -- resort to file: lookup + logreport ("log", 0, "load", + "path lookup of %q unsuccessful, falling back to file:", + name) + file_resolver (specification) + else + local suffix = filesuffix (name) + if formats[suffix] then + specification.forced = stringlower (suffix) + specification.name = file.removesuffix(name) + specification.forcedname = name + else + specification.name = name + end + end +end + +--[[doc-- + + {\bfseries EXPERIMENTAL}: + \identifier{kpse}-only resolver, for those who can do without + system fonts. + +--doc]]-- + +request_resolvers.kpse = function (specification) + local name = specification.name + local suffix = filesuffix(name) + if suffix and formats[suffix] then + name = file.removesuffix(name) + if resolvers.findfile(name, suffix) then + specification.forced = stringlower (suffix) + specification.forcedname = name + return + end + end + for t, format in next, formats do --- brute force + if kpse.find_file (name, format) then + specification.forced = t + specification.name = name + return + end + end +end + +--[[doc-- + + The \verb|name:| resolver. + +--doc]]-- + +--- fonts.names.resolvers.name -- Customized version of the +--- generic name resolver. + +request_resolvers.name = function (specification) + local resolver = names.resolve_cached + if config.luaotfload.run.resolver == "normal" then + resolver = names.resolve_name + end + local resolved, subfont = resolver (specification) + if resolved then + logreport ("log", 0, "load", "Lookup/name: %q -> \"%s%s\"", + specification.name, + resolved, + subfont and stringformat ("(%d)", subfont) or "") + specification.resolved = resolved + specification.sub = subfont + specification.forced = stringlower (filesuffix (resolved) or "") + specification.forcedname = resolved + specification.name = fileremovesuffix (resolved) + else + file_resolver (specification) + end +end + +--[[doc-- + + Also {\bfseries EXPERIMENTAL}: custom file resolvers via callback. + +--doc]]-- +create_callback("luaotfload.resolve_font", "simple", dummy_function) + +request_resolvers.my = function (specification) + call_callback("luaotfload.resolve_font", specification) +end + +--[[doc-- + + We create a callback for patching fonts on the fly, to be used by + other packages. + It initially contains the empty function that we are going to + override below. + +--doc]]-- + +create_callback("luaotfload.patch_font", "simple", dummy_function) + +--[[doc-- + + \subsection{\CONTEXT override} + \label{define-font} + We provide a simplified version of the original font definition + callback. + +--doc]]-- + +local read_font_file = fonts.definers.read + +local definers = { + generic = read_font_file, + --- spec -> size -> id -> tmfdata + patch = function (specification, size, id) + local tfmdata = read_font_file (specification, size, id) + if type (tfmdata) == "table" and tfmdata.shared then + --- We need to test for the “shared” field here + --- or else the fontspec capheight callback will + --- operate on tfm fonts. + call_callback ("luaotfload.patch_font", tfmdata, specification) + end + return tfmdata + end, +} + +reset_callback "define_font" + +--[[doc-- + + Finally we register the callbacks. + +--doc]]-- + +local definer = config.luaotfload.run.definer +add_to_callback ("define_font", definers[definer], "luaotfload.define_font", 1) + +loadmodule "features.lua" --- font request and feature handling +loadmodule "letterspace.lua" --- extra character kerning +loadmodule "auxiliary.lua" --- additional high-level functionality + +luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec + +-- vim:tw=79:sw=4:ts=4:et diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-override.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-override.lua index fe70dcb4209..b75530b5cdf 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-override.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-override.lua @@ -1,360 +1,16 @@ -if not modules then modules = { } end modules ['luat-ovr'] = { - version = "2.4", - comment = "companion to luatex-*.tex", +if not modules then modules = { } end modules ["luaotfload-override"] = { + version = "2.5", + comment = "companion to Luaotfload", author = "Khaled Hosny, Elie Roux, Philipp Gesang", copyright = "Luaotfload Development Team", - license = "GNU GPL v2" + license = "GNU GPL v2.0" } ---[[doc-- -The logging system is slow in general, as we always have the function -call overhead even if we aren’t going to output anything. On the other -hand, the more efficient approach followed by Context isn’t an option -because we lack a user interface to toggle per-subsystem tracing. ---doc]]-- - -local module_name = "luaotfload" - -local ioopen = io.open -local iowrite = io.write -local lfsisdir = lfs.isdir -local lfsisfile = lfs.isfile -local md5sumhexa = md5.sumhexa -local osdate = os.date -local ostime = os.time -local select = select -local stringformat = string.format -local stringsub = string.sub -local tableconcat = table.concat -local texio_write_nl = texio.write_nl -local texiowrite_nl = texio.write_nl -local texio_write = texio.write -local texiowrite = texio.write -local type = type - -local dummyfunction = function () end - -local texjob = false -if tex and (tex.jobname or tex.formatname) then - --- TeX - texjob = true -end - -local loglevel = 0 --- default -local logout = "log" - ---- int -> bool -local set_loglevel = function (n) - if type(n) == "number" then - loglevel = n - end - return true -end -logs.setloglevel = set_loglevel -logs.set_loglevel = set_loglevel -logs.set_log_level = set_loglevel --- accomodating lazy typists - ---- unit -> int -local get_loglevel = function ( ) - return loglevel -end -logs.getloglevel = get_loglevel -logs.get_loglevel = get_loglevel -logs.get_log_level = get_loglevel - -local writeln --- pointer to terminal/log writer -local statusln --- terminal writer that reuses the current line -local first_status = true --- indicate the begin of a status region - -local log_msg = [[ -logging output redirected to %s -to monitor the progress run "tail -f %s" in another terminal -]] - -local tmppath = os.getenv "TMPDIR" or "/tmp" - -local choose_logfile = function ( ) - if lfsisdir (tmppath) then - local fname - repeat --- ensure that file of that name doesn’t exist - fname = tmppath .. "/luaotfload-log-" - .. stringsub (md5sumhexa (ostime ()), 1, 8) - until not lfsisfile (fname) - iowrite (stringformat (log_msg, fname, fname)) - return ioopen (fname, "w") - end - --- missing /tmp - return false -end - -local set_logout = function (s, finalizers) - if s == "stdout" then - logout = "redirect" - elseif s == "file" then --- inject custom logger - logout = "redirect" - local chan = choose_logfile () - chan:write (stringformat ("logging initiated at %s", - osdate ("%F %T", ostime ()))) - local writefile = function (...) - if select ("#", ...) == 2 then - chan:write (select (2, ...)) - else - chan:write (select (1, ...)) - end - end - local writefile_nl= function (...) - chan:write "\n" - if select ("#", ...) == 2 then - chan:write (select (2, ...)) - else - chan:write (select (1, ...)) - end - end - - local writeln_orig = writeln - - texiowrite = writefile - texiowrite_nl = writefile_nl - writeln = writefile_nl - statusln = dummyfunction - - finalizers[#finalizers+1] = function () - chan:write (stringformat ("\nlogging finished at %s\n", - osdate ("%F %T", ostime ()))) - chan:close () - texiowrite = texio.write - texiowrite_nl = texio.write_nl - writeln = writeln_orig - end - --else --- remains “log” - end - return finalizers -end - -logs.set_logout = set_logout - -local log = function (category, fmt, ...) - local res = { module_name, "|", category, ":" } - if fmt then - res [#res + 1] = stringformat (fmt, ...) - end - texiowrite_nl (logout, tableconcat(res, " ")) -end - ---- with faux db update with maximum verbosity: ---- ---- --------- -------- ---- buffering time (s) ---- --------- -------- ---- full 4.12 ---- line 4.20 ---- none 4.39 ---- --------- -------- ---- - -io.stdout:setvbuf "no" -io.stderr:setvbuf "no" - -local kill_line = "\r\x1b[K" - -if texjob == true then - --- We imitate the texio.* functions so the output is consistent. - writeln = function (str) - iowrite "\n" - iowrite(str) - end - statusln = function (str) - if first_status == false then - iowrite (kill_line) - else - iowrite "\n" - end - iowrite (str) - end -else - writeln = function (str) - iowrite(str) - iowrite "\n" - end - statusln = function (str) - if first_status == false then - iowrite (kill_line) - end - iowrite (str) - end -end - -stdout = function (writer, category, ...) - local res = { module_name, "|", category, ":" } - local nargs = select("#", ...) - if nargs == 0 then - --writeln tableconcat(res, " ") - --return - elseif nargs == 1 then - res[#res+1] = select(1, ...) -- around 30% faster than unpack() - else - res[#res+1] = stringformat(...) - end - writer (tableconcat(res, " ")) -end - ---- at default (zero), we aim to be quiet -local level_ids = { common = 1, loading = 2, search = 3 } - ---[[doc-- - - The names_report logger is used more or less all over luaotfload. - Its requirements are twofold: - - 1) Provide two logging channels, the terminal and the log file; - 2) Allow for control over verbosity levels. - - The first part is addressed by specifying the log *mode* as the - first argument that can be either “log”, meaning the log file, or - “both”: log file and stdout. Anything else is taken as referring to - stdout only. - - Verbosity levels, though not as fine-grained as e.g. Context’s - system of tracers, allow keeping the logging spam caused by - different subsystems manageable. By default, luaotfload will not - emit anything if things are running smoothly on level zero. Only - warning messages are relayed, while the other messages are skipped - over. (This is a little sub-optimal performance-wise since the - function calls to the logger are executed regardless.) The log - level during a Luatex run can be adjusted by setting the “loglevel” - field in config.luaotfload, or by calling logs.set_loglevel() as - defined above. - ---doc]]-- - -local names_report = function (mode, lvl, ...) - if type(lvl) == "string" then - lvl = level_ids[lvl] - end - if not lvl then lvl = 0 end - - if loglevel >= lvl then - if mode == "log" then - log (...) - elseif mode == "both" and logout ~= "redirect" then - log (...) - stdout (writeln, ...) - else - stdout (writeln, ...) - end - end -end - -logs.names_report = names_report - ---[[doc-- - - status_logger -- Overwrites the most recently printed line of the - terminal. Its purpose is to provide feedback without spamming - stdout with irrelevant messages, i.e. when building the database. - - Status logging must be initialized by calling status_start() and - properly reset via status_stop(). - - The arguments low and high indicate the loglevel threshold at which - linewise and full logging is triggered, respectively. E.g. - - names_status (1, 4, "term", "Hello, world!") - - will print nothing if the loglevel is less than one, reuse the - current line if the loglevel ranges from one to three inclusively, - and output the message on a separate line otherwise. - ---doc]]-- - -local status_logger = function (mode, ...) - if mode == "log" then - log (...) - else - if mode == "both" and logout ~= "redirect" then - log (...) - stdout (statusln, ...) - else - stdout (statusln, ...) - end - first_status = false - end -end - ---[[doc-- - - status_start -- Initialize status logging. This installs the status - logger if the loglevel is in the specified range, and the normal - logger otherwise. It also resets the first line state which - causing the next line printed using the status logger to not kill - the current line. - ---doc]]-- - -local status_writer -local status_low = 99 -local status_high = 99 - -local status_start = function (low, high) - first_status = true - status_low = low - status_high = high - - if os.type == "windows" --- Assume broken terminal. - or os.getenv "TERM" == "dumb" - then - status_writer = function (mode, ...) - names_report (mode, high, ...) - end - return - end +local findfile = resolvers.findfile +local encodings = fonts.encodings - if low <= loglevel and loglevel < high then - status_writer = status_logger - else - status_writer = function (mode, ...) - names_report (mode, high, ...) - end - end -end - ---[[doc-- - - status_stop -- Finalize a status region by outputting a newline and - printing a message. - ---doc]]-- - -local status_stop = function (...) - if first_status == false then - status_writer(...) - if texjob == false then - writeln "" - end - end -end - -logs.names_status = function (...) status_writer (...) end -logs.names_status_start = status_start -logs.names_status_stop = status_stop - ---[[doc-- - - The fontloader comes with the Context logging mechanisms - inaccessible. Instead, it provides dumb fallbacks based - on the functions in texio.write*() that can be overridden - by providing a function texio.reporter(). - - The fontloader output can be quite verbose, so we disable - it entirely by default. - ---doc]]-- - -local texioreporter = function (message) - names_report("log", 2, message) -end - -texio.reporter = texioreporter +local log = luaotfload.log +local report = log.report --[[doc-- @@ -374,34 +30,23 @@ texio.reporter = texioreporter --doc]]-- -if fonts then --- need to be running TeX - if next(fonts.encodings.agl) then - --- unnecessary because the file shouldn’t be loaded at this time - --- but we’re just making sure - fonts.encodings.agl = nil - collectgarbage"collect" - end - - - fonts.encodings.agl = { } +encodings.agl = { } - setmetatable(fonts.encodings.agl, { __index = function (t, k) - if k == "unicodes" then - local glyphlist = resolvers.findfile"luaotfload-glyphlist.lua" - if glyphlist then - names_report("log", 1, "load", "loading the Adobe glyph list") - else - glyphlist = resolvers.findfile"font-age.lua" - names_report("both", 0, "load", - "loading the extended glyph list from ConTeXt") - end - local unicodes = dofile(glyphlist) - fonts.encodings.agl = { unicodes = unicodes } - return unicodes - else - return nil - end - end }) -end +setmetatable(fonts.encodings.agl, { __index = function (t, k) + if k ~= "unicodes" then + return nil + end + local glyphlist = findfile "luaotfload-glyphlist.lua" + if glyphlist then + report ("log", 1, "load", "loading the Adobe glyph list") + else + glyphlist = findfile "font-age.lua" + report ("both", 0, "load", + "loading the extended glyph list from ConTeXt") + end + local unicodes = dofile(glyphlist) + encodings.agl = { unicodes = unicodes } + return unicodes +end }) -- vim:tw=71:sw=4:ts=4:expandtab diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua new file mode 100644 index 00000000000..3eeb614a202 --- /dev/null +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua @@ -0,0 +1,701 @@ +#!/usr/bin/env texlua +------------------------------------------------------------------------------- +-- FILE: luaotfload-parsers.lua +-- DESCRIPTION: various lpeg-based parsers used in Luaotfload +-- REQUIREMENTS: Luaotfload > 2.4 +-- AUTHOR: Philipp Gesang (Phg), <phg42.2a@gmail.com> +-- VERSION: same as Luaotfload +-- CREATED: 2014-01-14 10:15:20+0100 +------------------------------------------------------------------------------- +-- + +if not modules then modules = { } end modules ['luaotfload-parsers'] = { + version = "2.5", + comment = "companion to luaotfload-main.lua", + author = "Philipp Gesang", + copyright = "Luaotfload Development Team", + license = "GNU GPL v2.0" +} + +luaotfload = luaotfload or { } +luaotfload.parsers = luaotfload.parsers or { } +local parsers = luaotfload.parsers + +local rawset = rawset + +local lpeg = require "lpeg" +local P, R, S = lpeg.P, lpeg.R, lpeg.S +local lpegmatch = lpeg.match +local C, Cc, Cf = lpeg.C, lpeg.Cc, lpeg.Cf +local Cg, Cmt, Cs, Ct = lpeg.Cg, lpeg.Cmt, lpeg.Cs, lpeg.Ct + +local kpse = kpse +local kpseexpand_path = kpse.expand_path +local kpsereadable_file = kpse.readable_file + +local file = file +local filejoin = file.join +local filedirname = file.dirname + +local io = io +local ioopen = io.open + +local log = luaotfload.log +local logreport = log.report + +local string = string +local stringsub = string.sub +local stringfind = string.find +local stringlower = string.lower + +local mathceil = math.ceil + +local lfs = lfs +local lfsisfile = lfs.isfile +local lfsisdir = lfs.isdir + +------------------------------------------------------------------------------- +--- COMMON PATTERNS +------------------------------------------------------------------------------- + +local dot = P"." +local colon = P":" +local semicolon = P";" +local comma = P"," +local noncomma = 1 - comma +local slash = P"/" +local backslash = P"\\" +local equals = P"=" +local dash = P"-" +local gartenzaun = P"#" +local lbrk, rbrk = P"[", P"]" +local squote = P"'" +local dquote = P"\"" + +local newline = P"\n" +local returnchar = P"\r" +local spacing = S" \t\v" +local linebreak = S"\n\r" +local whitespace = spacing + linebreak +local ws = spacing^0 +local xmlws = whitespace^1 +local eol = P"\n\r" + P"\r\n" + linebreak + +local digit = R"09" +local alpha = R("az", "AZ") +local anum = alpha + digit +local decimal = digit^1 * (dot * digit^0)^-1 + +------------------------------------------------------------------------------- +--- FONTCONFIG +------------------------------------------------------------------------------- + +--[[doc-- + + For fonts installed on the operating system, there are several + options to make Luaotfload index them: + + - If OSFONTDIR is set (which is the case under windows by default + but not on the other OSs), it scans it at the same time as the + texmf tree, in the function scan_texmf_fonts(). + + - Otherwise + - under Windows and Mac OSX, we take a look at some hardcoded + directories, + - under Unix, it reads /etc/fonts/fonts.conf and processes the + directories specified there. + + This means that if you have fonts in fancy directories, you need to + set them in OSFONTDIR. + + Beware: OSFONTDIR is a kpathsea variable, so fonts found in these + paths, though technically system fonts, are registered in the + category “texmf”, not “system”. This may have consequences for the + lookup order when a font file (or a font with the same name + information) is located in both the system and the texmf tree. + +--doc]]-- + +local tag_name = C(alpha^1) +local comment = P"<!--" * (1 - P"--")^0 * P"-->" + +---> header specifica +local xml_declaration = P"<?xml" * (1 - P"?>")^0 * P"?>" +local xml_doctype = P"<!DOCTYPE" * xmlws + * "fontconfig" * (1 - P">")^0 * P">" +local header = xml_declaration^-1 + * (xml_doctype + comment + xmlws)^0 + +---> enforce root node +local root_start = P"<" * xmlws^-1 * P"fontconfig" * xmlws^-1 * P">" +local root_stop = P"</" * xmlws^-1 * P"fontconfig" * xmlws^-1 * P">" + +local dquote, squote = P[["]], P"'" +local xml_namestartchar = S":_" + alpha --- ascii only, funk the rest +local xml_namechar = S":._" + alpha + digit +local xml_name = xmlws^-1 + * C(xml_namestartchar * xml_namechar^0) +local xml_attvalue = dquote * C((1 - S[[%&"]])^1) * dquote * xmlws^-1 + + squote * C((1 - S[[%&']])^1) * squote * xmlws^-1 +local xml_attr = Cg(xml_name * P"=" * xml_attvalue) +local xml_attr_list = Cf(Ct"" * xml_attr^1, rawset) + +--[[doc-- + scan_node creates a parser for a given xml tag. +--doc]]-- +--- string -> bool -> lpeg_t +local scan_node = function (tag) + --- Node attributes go into a table with the index “attributes” + --- (relevant for “prefix="xdg"” and the likes). + local p_tag = P(tag) + local with_attributes = P"<" * p_tag + * Cg(xml_attr_list, "attributes")^-1 + * xmlws^-1 + * P">" + local plain = P"<" * p_tag * xmlws^-1 * P">" + local node_start = plain + with_attributes + local node_stop = P"</" * p_tag * xmlws^-1 * P">" + --- there is no nesting, the earth is flat ... + local node = node_start + * Cc(tag) * C(comment + (1 - node_stop)^1) + * node_stop + return Ct(node) -- returns {string, string [, attributes = { key = val }] } +end + +--[[doc-- + At the moment, the interesting tags are “dir” for + directory declarations, and “include” for including + further configuration files. + + spec: http://freedesktop.org/software/fontconfig/fontconfig-user.html +--doc]]-- +local include_node = scan_node"include" +local dir_node = scan_node"dir" + +local element = dir_node + + include_node + + comment --> ignore + + P(1-root_stop) --> skip byte + +local root = root_start * Ct(element^0) * root_stop +local p_cheapxml = header * root + +--lpeg.print(p_cheapxml) ---> 757 rules with v0.10 + +--[[doc-- + fonts_conf_scanner() handles configuration files. + It is called on an abolute path to a config file (e.g. + /home/luser/.config/fontconfig/fonts.conf) and returns a list + of the nodes it managed to extract from the file. +--doc]]-- +--- string -> path list +local fonts_conf_scanner = function (path) + local fh = ioopen(path, "r") + if not fh then + logreport("both", 3, "db", "Cannot open fontconfig file %s.", path) + return + end + local raw = fh:read"*all" + fh:close() + + local confdata = lpegmatch(p_cheapxml, raw) + if not confdata then + logreport("both", 3, "db", "Cannot scan fontconfig file %s.", path) + return + end + return confdata +end + +local p_conf = P".conf" * P(-1) +local p_filter = (1 - p_conf)^1 * p_conf + +local conf_filter = function (path) + if lpegmatch (p_filter, path) then + return true + end + return false +end + +--[[doc-- + read_fonts_conf_indeed() is called with seven arguments; the + latter three are tables that represent the state and are + always returned. + The first four are + · the path to the file + · the expanded $HOME + · the expanded $XDG_CONFIG_HOME + · the expanded $XDG_DATA_HOME +--doc]]-- +--- string -> string -> string -> tab -> tab -> (tab * tab * tab) +local read_fonts_conf_indeed +read_fonts_conf_indeed = function (start, home, xdg_config_home, + xdg_data_home, + acc, done, dirs_done, + find_files) + + local paths = fonts_conf_scanner(start) + if not paths then --- nothing to do + return acc, done, dirs_done + end + + for i=1, #paths do + local pathobj = paths[i] + local kind, path = pathobj[1], pathobj[2] + local attributes = pathobj.attributes + + if kind == "dir" then + if attributes and attributes.prefix == "xdg" then + path = filejoin(xdg_data_home, path) + end + if stringsub(path, 1, 1) == "~" then + path = filejoin(home, stringsub(path, 2)) + end + --- We exclude paths with texmf in them, as they should be + --- found anyway; also duplicates are ignored by checking + --- if they are elements of dirs_done. + --- + --- FIXME does this mean we cannot access paths from + --- distributions (e.g. Context minimals) installed + --- separately? + if not (stringfind(path, "texmf") or dirs_done[path]) then + acc[#acc+1] = path + dirs_done[path] = true + end + + elseif kind == "include" then + if attributes and attributes.prefix == "xdg" then + path = filejoin(xdg_config_home, path) + end + --- here the path can be four things: a directory or a file, + --- in absolute or relative path. + if stringsub(path, 1, 1) == "~" then + path = filejoin(home, stringsub(path, 2)) + elseif --- if the path is relative, we make it absolute + not ( lfsisfile(path) or lfsisdir(path) ) + then + path = filejoin(filedirname(start), path) + end + if lfsisfile(path) + and kpsereadable_file(path) + and not done[path] + then + --- we exclude path with texmf in them, as they should + --- be found otherwise + acc = read_fonts_conf_indeed( + path, home, xdg_config_home, xdg_data_home, + acc, done, dirs_done) + elseif lfsisdir(path) then --- arrow code ahead + local config_files = find_files (path, conf_filter) + for _, filename in next, config_files do + if not done[filename] then + acc = read_fonts_conf_indeed( + filename, home, xdg_config_home, xdg_data_home, + acc, done, dirs_done) + end + end + end --- match “kind” + end --- iterate paths + end + + --inspect(acc) + --inspect(done) + return acc, done, dirs_done + end --- read_fonts_conf_indeed() + +--[[doc-- + read_fonts_conf() sets up an accumulator and two sets + for tracking what’s been done. + + Also, the environment variables HOME, XDG_DATA_HOME and + XDG_CONFIG_HOME -- which are constants anyways -- are expanded + so we don’t have to repeat that over and over again as with the + old parser. Now they’re just passed on to every call of + read_fonts_conf_indeed(). +--doc]]-- + +--- list -> (string -> function option -> string list) -> list + +local read_fonts_conf = function (path_list, find_files) + local home = kpseexpand_path"~" --- could be os.getenv"HOME" + local xdg_config_home = kpseexpand_path"$XDG_CONFIG_HOME" + if xdg_config_home == "" then xdg_config_home = filejoin(home, ".config") end + local xdg_data_home = kpseexpand_path"$XDG_DATA_HOME" + if xdg_data_home == "" then xdg_data_home = filejoin(home, ".local/share") end + local acc = { } ---> list: paths collected + local done = { } ---> set: files inspected + local dirs_done = { } ---> set: dirs in list + for i=1, #path_list do --- we keep the state between files + acc, done, dirs_done = read_fonts_conf_indeed( + path_list[i], home, xdg_config_home, + xdg_data_home, + acc, done, dirs_done, + find_files) + end + return acc +end + +luaotfload.parsers.read_fonts_conf = read_fonts_conf + + + +------------------------------------------------------------------------------- +--- MISC PARSERS +------------------------------------------------------------------------------- + + +local trailingslashes = slash^1 * P(-1) +local stripslashes = C((1 - trailingslashes)^0) +parsers.stripslashes = stripslashes + +local splitcomma = Ct((C(noncomma^1) + comma)^1) +parsers.splitcomma = splitcomma + + + +------------------------------------------------------------------------------- +--- FONT REQUEST +------------------------------------------------------------------------------- + + +--[[doc------------------------------------------------------------------------ + + The luaotfload font request syntax (see manual) + has a canonical form: + + \font<csname>=<prefix>:<identifier>:<features> + + where + <csname> is the control sequence that activates the font + <prefix> is either “file” or “name”, determining the lookup + <identifer> is either a file name (no path) or a font + name, depending on the lookup + <features> is a list of switches or options, separated by + semicolons or commas; a switch is of the form “+” foo + or “-” foo, options are of the form lhs “=” rhs + + however, to ensure backward compatibility we also have + support for Xetex-style requests. + + for the Xetex emulation see: + · The XeTeX Reference Guide by Will Robertson, 2011 + · The XeTeX Companion by Michel Goosens, 2010 + · About XeTeX by Jonathan Kew, 2005 + + + caueat emptor. + + the request is parsed into one of **four** different lookup + categories: the regular ones, file and name, as well as the + Xetex compatibility ones, path and anon. (maybe a better choice + of identifier would be “ambig”.) + + according to my reconstruction, the correct chaining of the + lookups for each category is as follows: + + | File -> ( db/filename lookup ) + + | Name -> ( db/name lookup, + db/filename lookup ) + + | Path -> ( db/filename lookup, + fullpath lookup ) + + | Anon -> ( kpse.find_file(), // <- for tfm, ofm + db/name lookup, + db/filename lookup, + fullpath lookup ) + + caching of successful lookups is essential. we now as of v2.2 + have a lookup cache that is stored in a separate file. it + pertains only to name: lookups, and is described in more detail + in luaotfload-database.lua. + +------------------------------------------------------------------------------- + + One further incompatibility between Xetex and Luatex-Fonts consists + in their option list syntax: apparently, Xetex requires key-value + options to be prefixed by a "+" (ascii “plus”) character. We + silently accept this as well, dropping the first byte if it is a + plus or minus character. + + Reference: https://github.com/lualatex/luaotfload/issues/79#issuecomment-18104483 + +--doc]]------------------------------------------------------------------------ + + +local handle_normal_option = function (key, val) + val = stringlower(val) + --- the former “toboolean()” handler + if val == "true" then + val = true + elseif val == "false" then + val = false + end + return key, val +end + +--[[doc-- + + Xetex style indexing begins at zero which we just increment before + passing it along to the font loader. Ymmv. + +--doc]]-- + +local handle_xetex_option = function (key, val) + val = stringlower(val) + local numeric = tonumber(val) --- decimal only; keeps colors intact + if numeric then --- ugh + if mathceil(numeric) == numeric then -- integer, possible index + val = tostring(numeric + 1) + end + elseif val == "true" then + val = true + elseif val == "false" then + val = false + end + return key, val +end + +--[[doc-- + + Instead of silently ignoring invalid options we emit a warning to + the log. + + Note that we have to return a pair to please rawset(). This creates + an entry on the resulting features hash which will later be removed + during set_default_features(). + +--doc]]-- + +local handle_invalid_option = function (opt) + logreport("log", 0, "load", "font option %q unknown.", opt) + return "", false +end + +--[[doc-- + + Dirty test if a file: request is actually a path: lookup; don’t + ask! Note this fails on Windows-style absolute paths. These will + *really* have to use the correct request. + +--doc]]-- + +local check_garbage = function (_,i, garbage) + if stringfind(garbage, "/") then + logreport("log", 0, "load", --- ffs use path! + "warning: path in file: lookups is deprecated; ") + logreport("log", 0, "load", "use bracket syntax instead!") + logreport("log", 0, "load", + "position: %d; full match: %q", + i, garbage) + return true + end + return false +end + +local featuresep = comma + semicolon + +--- modifiers --------------------------------------------------------- +--[[doc-- + The slash notation: called “modifiers” (Kew) or “font options” + (Robertson, Goosens) + we only support the shorthands for italic / bold / bold italic + shapes, as well as setting optical size, the rest is ignored. +--doc]]-- +local style_modifier = (P"BI" + P"IB" + P"bi" + P"ib" + S"biBI") + / stringlower +local size_modifier = S"Ss" * P"=" --- optical size + * Cc"optsize" * C(decimal) +local other_modifier = P"AAT" + P"aat" --- apple stuff; unsupported + + P"ICU" + P"icu" --- not applicable + + P"GR" + P"gr" --- sil stuff; unsupported +local garbage_modifier = ((1 - colon - slash)^0 * Cc(false)) +local modifier = slash * (other_modifier --> ignore + + Cs(style_modifier) --> collect + + Ct(size_modifier) --> collect + + garbage_modifier) --> warn +local modifier_list = Cg(Ct(modifier^0), "modifiers") + +--- lookups ----------------------------------------------------------- +local fontname = C((1-S":(/")^1) --- like luatex-fonts +local unsupported = Cmt((1-S":(")^1, check_garbage) +local prefixed = P"name:" * ws * Cg(fontname, "name") +--- initially we intended file: to emulate the behavior of +--- luatex-fonts, i.e. no paths allowed. after all, we do have XeTeX +--- emulation with the path lookup and it interferes with db lookups. +--- turns out fontspec and other widely used packages rely on file: +--- with paths already, so we’ll add a less strict rule here. anyways, +--- we’ll emit a warning. + + P"file:" * ws * Cg(unsupported, "path") + + P"file:" * ws * Cg(fontname, "file") +--- EXPERIMENTAL: kpse lookup + + P"kpse:" * ws * Cg(fontname, "kpse") +--- EXPERIMENTAL: custom lookup + + P"my:" * ws * Cg(fontname, "my") +local unprefixed = Cg(fontname, "anon") +local path_lookup = lbrk * Cg(C((1-rbrk)^1), "path") * rbrk + +--- features ---------------------------------------------------------- +local field_char = anum + S"+-." --- sic! +local field = field_char^1 +--- assignments are “lhs=rhs” +--- or “+lhs=rhs” (Xetex-style) +--- switches are “+key” | “-key” +local normal_option = C(field) * ws * equals * ws * C(field) * ws +local xetex_option = P"+" * ws * normal_option +local ignore_option = (1 - equals - featuresep)^1 + * equals + * (1 - featuresep)^1 +local assignment = xetex_option / handle_xetex_option + + normal_option / handle_normal_option + + ignore_option / handle_invalid_option +local switch = P"+" * ws * C(field) * Cc(true) + + P"-" * ws * C(field) * Cc(false) + + C(field) * Cc(true) --- default +local feature_expr = ws * Cg(assignment + switch) * ws +local option = feature_expr +local feature_list = Cf(Ct"" + * option + * (featuresep * option^-1)^0 + , rawset) + * featuresep^-1 + +--- other ------------------------------------------------------------- +--- This rule is present in the original parser. It sets the “sub” +--- field of the specification which allows addressing a specific +--- font inside a TTC container. Neither in Luatex-Fonts nor in +--- Luaotfload is this documented, so we might as well silently drop +--- it. However, as backward compatibility is one of our prime goals we +--- just insert it here and leave it undocumented until someone cares +--- to ask. (Note: afair subfonts are numbered, but this rule matches a +--- string; I won’t mess with it though until someone reports a +--- problem.) +--- local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim +--- Note to self: subfonts apparently start at index 0. Tested with +--- Cambria.ttc that includes “Cambria Math” at 0 and “Cambria” at 1. +--- Other values cause luatex to segfault. +local subfont = P"(" * Cg((1 - S"()")^1, "sub") * P")" +--- top-level rules --------------------------------------------------- +--- \font\foo=<specification>:<features> +local features = Cg(feature_list, "features") +local specification = (prefixed + unprefixed) + * subfont^-1 + * modifier_list^-1 +local font_request = Ct(path_lookup * (colon^-1 * features)^-1 + + specification * (colon * features)^-1) + +-- lpeg.print(font_request) +--- v2.5 parser: 1065 rules +--- v1.2 parser: 230 rules + +luaotfload.parsers.font_request = font_request + +------------------------------------------------------------------------------- +--- INI FILES +------------------------------------------------------------------------------- + +--[[doc-- + + Luaotfload uses the pervasive flavor of the INI files that allows '#' in + addition to ';' to indicate comment lines (see git-config(1) for a + description of the syntax we’re targeting). + +--doc]]-- + +local truth_ids = { + ["true"] = true, + ["1"] = true, + yes = true, + on = true, + ["false"] = false, + ["2"] = false, + no = false, + off = false, +} + +local maybe_cast = function (var) + local bool = truth_ids[var] + if bool ~= nil then + return bool + end + return tonumber (var) or var +end +local escape = function (chr, repl) + return (backslash * P(chr) / (repl or chr)) +end +local valid_escapes = escape "\"" + + escape "\\" + + escape ("n", "\n") + + escape ("t", "\t") + + escape ("b", "\b") +local comment_char = semicolon + gartenzaun +local comment_line = ws * comment_char * (1 - eol)^0 * eol +local blank_line = ws * eol +local skip_line = comment_line + blank_line +local ini_id_char = alpha + (dash / "_") +local ini_id = Cs(alpha * ini_id_char^0) / stringlower +local ini_value_char = (valid_escapes + (1 - newline - backslash - comment_char)) +local ini_value = (Cs (ini_value_char^0) / string.strip) + * (comment_char * (1 - eol)^0)^-1 +local ini_string_char = (valid_escapes + (1 - newline - dquote - backslash)) +local ini_string = dquote + * Cs (ini_string_char^0) + * dquote + +local ini_heading_title = Ct (Cg (ini_id, "title") + * (ws * Cg (ini_string / stringlower, "subtitle"))^-1) +local ini_heading = lbrk * ws + * Cg (ini_heading_title, "section") + * ws * rbrk * ws * eol + +local ini_variable_full = Cg (ws + * ini_id + * ws + * equals + * ws + * (ini_string + (ini_value / maybe_cast)) + * ws + * eol) +local ini_variable_true = Cg (ws * ini_id * ws * eol * Cc (true)) +local ini_variable = ini_variable_full + + ini_variable_true + + skip_line +local ini_variables = Cg (Cf (Ct "" * ini_variable^0, rawset), "variables") + +local ini_section = Ct (ini_heading * ini_variables) +local ini_sections = skip_line^0 * ini_section^0 +local config = Ct (ini_sections) + +--[=[doc-- + + The INI parser converts an input of the form + + [==[ + [foo] + bar = baz + xyzzy = no + buzz + + [lavernica "brutalitops"] + # It’s a locomotive that runs on us. + laan-ev = zip zop zooey ; jib-jab + Crouton = "Fibrosis \"\\ # " + + ]==] + + to a Lua table of the form + + { { section = { title = "foo" }, + variables = { bar = "baz", + xyzzy = false, + buzz = true } }, + { section = { title = "boing", + subtitle = "brutalitops" }, + variables = { ["laan-ev"] = "zip zop zooey", + crouton = "Fibrosis \"\\ # " } } } + +--doc]=]-- + +luaotfload.parsers.config = config + +-- vim:ft=lua:tw=71:et:sts=4:ts=8 diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua index c04f048d048..d613883235a 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua @@ -1,33 +1,35 @@ return { ["hashes"]={ - { "mkstatus", "51af30205d30c2b7f5bfd5169d9911a0" }, - { "mkglyphlist", "a8d64d29927ad8aebd1280a11d335895" }, - { "mkcharacters", "f25363cbe04fc5f1210930a10635247f" }, - { "luaotfload-tool.lua", "978fc97d7f3e60cc36a56e4375aabebb" }, - { "luaotfload-override.lua", "d0e40ea83d625813aa0fe2f9e76d8ef5" }, - { "luaotfload-fontloader.lua", "21b625efe6630b76250e18f7d2832cff" }, - { "luaotfload.lua", "408064879902b664459e931e6abb75f3" }, - { "luaotfload-loaders.lua", "b04c6d9aa2974d56895fe3dff3fea90d" }, - { "luaotfload-letterspace.lua", "19e6181076dda7c8c34e7096cee1f873" }, - { "luaotfload-glyphlist.lua", "ff440162d1b8a78a586375ee65630c21" }, - { "luaotfload-fonts-tfm.lua", "8fd3865240e4e87e99e0739abeda2322" }, - { "luaotfload-fonts-lua.lua", "50b8edb1db7009b6c661ab71ff24a466" }, - { "luaotfload-fonts-ext.lua", "0eee87fb26b7d135da88ac0a43a8037a" }, - { "luaotfload-fonts-enc.lua", "32775266bfc9eb6bbd9a16e3a7de398d" }, - { "luaotfload-fonts-def.lua", "8dc05f2aa96d2fd0245242c8fd3320eb" }, - { "luaotfload-fonts-cbk.lua", "c1b7a4e5508d68f45a99cdc38c2d0885" }, - { "luaotfload-features.lua", "0d97a50852fb55be4133874c8f487832" }, - { "luaotfload-diagnostics.lua", "eed12e7b7fe6545daa6786fed1405a4f" }, - { "luaotfload-database.lua", "db8d9e939910a7fce9b811546edd95c2" }, - { "luaotfload-colors.lua", "248c4c42586c17e934a4d046c3c873b9" }, - { "luaotfload-characters.lua", "2673ffb19e8505af4782aad437a76a4f" }, - { "luaotfload-basics-nod.lua", "d6b26ec86c0b1c1516936b425df04432" }, - { "luaotfload-basics-gen.lua", "3dadc2cd31ab348f7effb28e335af3ae" }, - { "luaotfload-auxiliary.lua", "7efa9d365f12006d5c4c7c38e0e2872c" }, + { "scripts/mkstatus", "fe7c02e1ecc0482033dc6bffd0974c10" }, + { "scripts/mkglyphlist", "62bc2c915a0fc936f9249deb0eddcaf3" }, + { "scripts/mkcharacters", "ec694a87f77067912eb73402ec99040d" }, + { "src/luaotfload-tool.lua", "741ba3e814cbd08ea026f56073e88162" }, + { "src/luaotfload-parsers.lua", "3dd1cb4175729c2f21dad158db4c633f" }, + { "src/luaotfload-override.lua", "e6f67a268fa9362d5ebc5cbecad1a900" }, + { "src/luaotfload-fontloader.lua", "f3055735e2d0b624000a9ce73b9dedc0" }, + { "src/luaotfload-main.lua", "cb35ddba0c110fb53908e4c0a2541839" }, + { "src/luaotfload-log.lua", "3c74574876352137b32073b763defbbf" }, + { "src/luaotfload-loaders.lua", "c364151f603514433fa3128939825d16" }, + { "src/luaotfload-letterspace.lua", "06cfb1e742d496b99c8980fdfd3f29f4" }, + { "build/luaotfload-glyphlist.lua", "ff440162d1b8a78a586375ee65630c21" }, + { "src/luaotfload-fonts-tfm.lua", "8fd3865240e4e87e99e0739abeda2322" }, + { "src/luaotfload-fonts-lua.lua", "50b8edb1db7009b6c661ab71ff24a466" }, + { "src/luaotfload-fonts-ext.lua", "0eee87fb26b7d135da88ac0a43a8037a" }, + { "src/luaotfload-fonts-enc.lua", "32775266bfc9eb6bbd9a16e3a7de398d" }, + { "src/luaotfload-fonts-def.lua", "8dc05f2aa96d2fd0245242c8fd3320eb" }, + { "src/luaotfload-fonts-cbk.lua", "c1b7a4e5508d68f45a99cdc38c2d0885" }, + { "src/luaotfload-features.lua", "6c3e33f4bd1090883851b7f63d45e7fc" }, + { "src/luaotfload-diagnostics.lua", "273afde55dff486fb222a50981b3b1d7" }, + { "src/luaotfload-database.lua", "9ea266330bbe2d974179e8dbb83997a5" }, + { "src/luaotfload-colors.lua", "99878378ef0954d0b67f13db8456dea7" }, + { "build/luaotfload-characters.lua", "9b9820f9fb6ec694df43b648026fc444" }, + { "src/luaotfload-basics-nod.lua", "7fdaff58d8c32e3115286504cbd7bcac" }, + { "src/luaotfload-basics-gen.lua", "9d5c3fc031af110ba67f3faa1a569779" }, + { "src/luaotfload-auxiliary.lua", "b3c893f68217b4147e5d3ba694648583" }, }, ["notes"]={ ["committer"]="Philipp Gesang <phg42.2a@gmail.com>", - ["revision"]="828a69efb1f899f8707270f4515db20d485ccc34", - ["timestamp"]="2014-05-18 21:35:56 +0200", + ["revision"]="5dc362a7098d9ecd4bfd446b59d7e895107f6e5e", + ["timestamp"]="2014-07-13 22:03:26 +0200", }, }
\ No newline at end of file diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua deleted file mode 100644 index 014249efd78..00000000000 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua +++ /dev/null @@ -1,442 +0,0 @@ --- --- This is file `luaotfload.lua', --- generated with the docstrip utility. --- --- The original source files were: --- --- luaotfload.dtx (with options: `lua') --- This is a generated file. --- --- Copyright (C) 2009-2014 --- by Elie Roux <elie.roux@telecom-bretagne.eu> --- and Khaled Hosny <khaledhosny@eglug.org> --- and Philipp Gesang <philipp.gesang@alumni.uni-heidelberg.de> --- --- Home: https://github.com/lualatex/luaotfload --- Support: <lualatex-dev@tug.org>. --- --- This work is under the GPL v2.0 license. --- --- This work consists of the main source file luaotfload.dtx --- and the derived files --- luaotfload.sty, luaotfload.lua --- -luaotfload = luaotfload or {} -local luaotfload = luaotfload - -config = config or { } -config.luaotfload = config.luaotfload or { } -------.luaotfload.resolver = config.luaotfload.resolver or "normal" -config.luaotfload.resolver = config.luaotfload.resolver or "cached" -config.luaotfload.definer = config.luaotfload.definer or "patch" -config.luaotfload.compatibility = config.luaotfload.compatibility or false -config.luaotfload.loglevel = config.luaotfload.loglevel or 2 -config.luaotfload.color_callback = config.luaotfload.color_callback or "pre_linebreak_filter" -config.luaotfload.prioritize = config.luaotfload.prioritize or "sys" -config.luaotfload.names_dir = config.luaotfload.names_dir or "names" -config.luaotfload.cache_dir = config.luaotfload.cache_dir or "fonts" -config.luaotfload.index_file = config.luaotfload.index_file or "luaotfload-names.lua" -config.luaotfload.formats = config.luaotfload.formats or "otf,ttf,ttc,dfont" -if not config.luaotfload.strip then - config.luaotfload.strip = true -end - -luaotfload.module = { - name = "luaotfload", - version = 2.40005, --- 2.4-4 - date = "2014/05/18", - description = "OpenType layout system.", - author = "Elie Roux & Hans Hagen", - copyright = "Elie Roux", - license = "GPL v2.0" -} - -local luatexbase = luatexbase - -local setmetatable = setmetatable -local type, next = type, next - -local kpsefind_file = kpse.find_file -local lfsisfile = lfs.isfile - -local add_to_callback, create_callback = - luatexbase.add_to_callback, luatexbase.create_callback -local reset_callback, call_callback = - luatexbase.reset_callback, luatexbase.call_callback - -local dummy_function = function () end - -local error, warning, info, log = - luatexbase.provides_module(luaotfload.module) - -luaotfload.error = error -luaotfload.warning = warning -luaotfload.info = info -luaotfload.log = log - - -local luatex_version = 76 - -if tex.luatexversion < luatex_version then - warning("LuaTeX v%.2f is old, v%.2f is recommended.", - tex.luatexversion/100, - luatex_version /100) - --- we install a fallback for older versions as a safety - if not node.end_of_math then - local math_t = node.id"math" - local traverse_nodes = node.traverse_id - node.end_of_math = function (n) - for n in traverse_nodes(math_t, n.next) do - return n - end - end - end -end - - -local fl_prefix = "luaotfload" -- “luatex” for luatex-plain -local loadmodule = function (name) - require(fl_prefix .."-"..name) -end - -local Cs, P, lpegmatch = lpeg.Cs, lpeg.P, lpeg.match - -local p_dot, p_slash = P".", P"/" -local p_suffix = (p_dot * (1 - p_dot - p_slash)^1 * P(-1)) / "" -local p_removesuffix = Cs((p_suffix + 1)^1) - -local find_vf_file = function (name) - local fullname = kpsefind_file(name, "ovf") - if not fullname then - --fullname = kpsefind_file(file.removesuffix(name), "ovf") - fullname = kpsefind_file(lpegmatch(p_removesuffix, name), "ovf") - end - if fullname then - log("loading virtual font file %s.", fullname) - end - return fullname -end - - -local starttime = os.gettimeofday() - -local trapped_register = callback.register -callback.register = dummy_function - - -do - local new_attribute = luatexbase.new_attribute - local the_attributes = luatexbase.attributes - - attributes = attributes or { } - - attributes.private = function (name) - local attr = "luaotfload@" .. name --- used to be: “otfl@” - local number = the_attributes[attr] - if not number then - number = new_attribute(attr) - end - return number - end -end - - -local context_environment = { } - -local push_namespaces = function () - log("push namespace for font loader") - local normalglobal = { } - for k, v in next, _G do - normalglobal[k] = v - end - return normalglobal -end - -local pop_namespaces = function (normalglobal, isolate) - if normalglobal then - local _G = _G - local mode = "non-destructive" - if isolate then mode = "destructive" end - log("pop namespace from font loader -- " .. mode) - for k, v in next, _G do - if not normalglobal[k] then - context_environment[k] = v - if isolate then - _G[k] = nil - end - end - end - for k, v in next, normalglobal do - _G[k] = v - end - -- just to be sure: - setmetatable(context_environment,_G) - else - log("irrecoverable error during pop_namespace: no globals to restore") - os.exit() - end -end - -luaotfload.context_environment = context_environment -luaotfload.push_namespaces = push_namespaces -luaotfload.pop_namespaces = pop_namespaces - -local our_environment = push_namespaces() - - -tex.attribute[0] = 0 - - -loadmodule"fontloader.lua" ----loadmodule"font-odv.lua" --- <= Devanagari support from Context - -if fonts then - - if not fonts._merge_loaded_message_done_ then - log [["I am using the merged version of 'luaotfload.lua' here.]] - log [[ If you run into problems or experience unexpected]] - log [[ behaviour, and if you have ConTeXt installed you can try]] - log [[ to delete the file 'luaotfload-merged.lua' as I might]] - log [[ then use the possibly updated libraries. The merged]] - log [[ version is not supported as it is a frozen instance.]] - log [[ Problems can be reported to the ConTeXt mailing list."]] - end - fonts._merge_loaded_message_done_ = true - -else--- the loading sequence is known to change, so this might have to - --- be updated with future updates! - --- do not modify it though unless there is a change to the merged - --- package! - loadmodule("l-lua.lua") - loadmodule("l-lpeg.lua") - loadmodule("l-function.lua") - loadmodule("l-string.lua") - loadmodule("l-table.lua") - loadmodule("l-io.lua") - loadmodule("l-file.lua") - loadmodule("l-boolean.lua") - loadmodule("l-math.lua") - loadmodule("util-str.lua") - loadmodule('luatex-basics-gen.lua') - loadmodule('data-con.lua') - loadmodule('luatex-basics-nod.lua') - loadmodule('font-ini.lua') - loadmodule('font-con.lua') - loadmodule('luatex-fonts-enc.lua') - loadmodule('font-cid.lua') - loadmodule('font-map.lua') - loadmodule('luatex-fonts-syn.lua') - loadmodule('luatex-fonts-tfm.lua') - loadmodule('font-oti.lua') - loadmodule('font-otf.lua') - loadmodule('font-otb.lua') - loadmodule('node-inj.lua') - loadmodule('font-ota.lua') - loadmodule('font-otn.lua') - loadmodule('font-otp.lua')--- since 2013-04-23 - loadmodule('luatex-fonts-lua.lua') - loadmodule('font-def.lua') - loadmodule('luatex-fonts-def.lua') - loadmodule('luatex-fonts-ext.lua') - loadmodule('luatex-fonts-cbk.lua') -end --- non-merge fallback scope - - -pop_namespaces(our_environment, false)-- true) - -log("fontloader loaded in %0.3f seconds", os.gettimeofday()-starttime) - - -callback.register = trapped_register - - -add_to_callback("pre_linebreak_filter", - nodes.simple_font_handler, - "luaotfload.node_processor", - 1) -add_to_callback("hpack_filter", - nodes.simple_font_handler, - "luaotfload.node_processor", - 1) -add_to_callback("find_vf_file", - find_vf_file, "luaotfload.find_vf_file") - -loadmodule"override.lua" --- “luat-ovr” - -logs.set_loglevel(config.luaotfload.loglevel) - -loadmodule"loaders.lua" --- “font-pfb” new in 2.0, added 2011 -loadmodule"database.lua" --- “font-nms” -loadmodule"colors.lua" --- “font-clr” - - -local filesuffix = file.suffix -local fileremovesuffix = file.removesuffix -local request_resolvers = fonts.definers.resolvers -local formats = fonts.formats -local names = fonts.names -formats.ofm = "type1" - -fonts.encodings.known = fonts.encodings.known or { } - - -local resolve_file = names.crude_file_lookup ---local resolve_file = names.crude_file_lookup_verbose -local resolve_name = names.resolve_name - -local file_resolver = function (specification) - local name = resolve_file (specification.name) - local suffix = filesuffix(name) - if formats[suffix] then - specification.forced = string.lower (suffix) - specification.forcedname = file.removesuffix(name) - else - specification.name = name - end -end - -request_resolvers.file = file_resolver - - ---request_resolvers.anon = request_resolvers.name - - -local type1_formats = { "tfm", "ofm", } - -request_resolvers.anon = function (specification) - local name = specification.name - for i=1, #type1_formats do - local format = type1_formats[i] - if resolvers.findfile(name, format) then - specification.forcedname = file.addsuffix(name, format) - specification.forced = format - return - end - end - --- under some weird circumstances absolute paths get - --- passed to the definer; we have to catch them - --- before the name: resolver misinterprets them. - name = specification.specification - local exists, _ = lfsisfile(name) - if exists then --- garbage; we do this because we are nice, - --- not because it is correct - logs.names_report("log", 1, "load", "file %q exists", name) - logs.names_report("log", 1, "load", - "... overriding borked anon: lookup with path: lookup") - specification.name = name - request_resolvers.path(specification) - return - end - request_resolvers.name(specification) -end - - -request_resolvers.path = function (specification) - local name = specification.name - local exists, _ = lfsisfile(name) - if not exists then -- resort to file: lookup - logs.names_report("log", 1, "load", - "path lookup of %q unsuccessful, falling back to file:", - name) - file_resolver (specification) - else - local suffix = filesuffix (name) - if formats[suffix] then - specification.forced = string.lower (suffix) - specification.name = file.removesuffix(name) - specification.forcedname = name - else - specification.name = name - end - end -end - - -request_resolvers.kpse = function (specification) - local name = specification.name - local suffix = filesuffix(name) - if suffix and formats[suffix] then - name = file.removesuffix(name) - if resolvers.findfile(name, suffix) then - specification.forced = string.lower (suffix) - specification.forcedname = name - return - end - end - for t, format in next, formats do --- brute force - if kpse.find_file (name, format) then - specification.forced = t - specification.name = name - return - end - end -end - - ---- fonts.names.resolvers.name -- Customized version of the ---- generic name resolver. - -request_resolvers.name = function (specification) - local resolved, subfont = resolve_name (specification) - if resolved then - specification.resolved = resolved - specification.sub = subfont - specification.forced = string.lower (filesuffix (resolved) or "") - specification.forcedname = resolved - specification.name = fileremovesuffix (resolved) - else - file_resolver (specification) - end -end - -create_callback("luaotfload.resolve_font", "simple", dummy_function) - -request_resolvers.my = function (specification) - call_callback("luaotfload.resolve_font", specification) -end - - -create_callback("luaotfload.patch_font", "simple", dummy_function) - - -local read_font_file = fonts.definers.read - ---- spec -> size -> id -> tmfdata -local patch_defined_font = function (specification, size, id) - local tfmdata = read_font_file(specification, size, id) - if type(tfmdata) == "table" and tfmdata.shared then - --- We need to test for the “shared” field here - --- or else the fontspec capheight callback will - --- operate on tfm fonts. - call_callback("luaotfload.patch_font", tfmdata, specification) - end - return tfmdata -end - -reset_callback "define_font" - - -local font_definer = config.luaotfload.definer - -if font_definer == "generic" then - add_to_callback("define_font", - fonts.definers.read, - "luaotfload.define_font", - 1) -elseif font_definer == "patch" then - add_to_callback("define_font", - patch_defined_font, - "luaotfload.define_font", - 1) -end - -loadmodule"features.lua" --- contains what was “font-ltx” and “font-otc” -loadmodule"letterspace.lua" --- extra character kerning -loadmodule"auxiliary.lua" --- additionaly high-level functionality (new) - -luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec - --- vim:tw=71:sw=4:ts=4:expandtab - --- --- End of File `luaotfload.lua'. diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty index 3d27502135b..9848a223d53 100644 --- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty +++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty @@ -1,26 +1,35 @@ -%% -%% This is file `luaotfload.sty', -%% generated with the docstrip utility. -%% -%% The original source files were: -%% -%% luaotfload.dtx (with options: `package') -%% This is a generated file. -%% %% Copyright (C) 2009-2014 +%% %% by Elie Roux <elie.roux@telecom-bretagne.eu> %% and Khaled Hosny <khaledhosny@eglug.org> %% and Philipp Gesang <philipp.gesang@alumni.uni-heidelberg.de> -%% +%% +%% This file is part of Luaotfload. +%% %% Home: https://github.com/lualatex/luaotfload %% Support: <lualatex-dev@tug.org>. -%% -%% This work is under the GPL v2.0 license. -%% -%% This work consists of the main source file luaotfload.dtx -%% and the derived files -%% luaotfload.sty, luaotfload.lua -%% +%% +%% Luaotfload is under the GPL v2.0 (exactly) license. +%% +%% ---------------------------------------------------------------------------- +%% +%% Luaotfload is free software; you can redistribute it and/or +%% modify it under the terms of the GNU General Public License +%% as published by the Free Software Foundation; version 2 +%% of the License. +%% +%% Luaotfload is distributed in the hope that it will be useful, +%% but WITHOUT ANY WARRANTY; without even the implied warranty of +%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +%% GNU General Public License for more details. +%% +%% You should have received a copy of the GNU General Public License +%% along with Luaotfload; if not, see <http://www.gnu.org/licenses/>. +%% +%% ---------------------------------------------------------------------------- +%% +%% Classical Plain+\LATEX package initialization. +%% \csname ifluaotfloadloaded\endcsname \let\ifluaotfloadloaded\endinput \bgroup\expandafter\expandafter\expandafter\egroup @@ -29,16 +38,8 @@ \else \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{luaotfload}% - [2014/05/18 v2.4-4 OpenType layout system] + [2014/07/13 v2.5 OpenType layout system] \RequirePackage{luatexbase} \fi -\ifnum\luatexversion<76 - %% here some deprecation warning would be in order - \RequireLuaModule{lualibs} - \RequireLuaModule{luaotfload-legacy} -\else - \RequireLuaModule{luaotfload} -\fi -\endinput -%% -%% End of file `luaotfload.sty'. +\RequireLuaModule{luaotfload-main} + |