summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2014-07-15 22:56:45 +0000
committerKarl Berry <karl@freefriends.org>2014-07-15 22:56:45 +0000
commit6caf348b43edcfc1dce127bf0895a5fb9bd77f2d (patch)
tree7b4b79f90596e69716ad87e3293743756b2a1954 /Master/texmf-dist/tex/luatex
parentd71cd04a4c07d1cdaf85a7b7c2398022cc39beab (diff)
luaotfload (15jul14)
git-svn-id: svn://tug.org/texlive/trunk@34622 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex')
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-auxiliary.lua231
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-gen.lua25
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-basics-nod.lua15
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-blacklist.cnf8
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-characters.lua11364
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-colors.lua39
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-configuration.lua704
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-database.lua1412
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-diagnostics.lua52
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-features.lua389
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fontloader.lua1522
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-inj.lua526
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-fonts-otn.lua2848
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-attributes.lua27
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-database.lua724
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy-merged.lua8157
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-legacy.lua402
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-letterspace.lua15
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-loaders.lua4
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-log.lua404
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-main.lua708
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-override.lua405
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-parsers.lua701
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload-status.lua54
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua442
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty57
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("<")/"&lt;"+P(">")/"&gt;"+P("&")/"&amp;"+P('"')/"&quot;
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}
+