summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/luatex/luaotfload
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2010-05-23 23:49:58 +0000
committerKarl Berry <karl@freefriends.org>2010-05-23 23:49:58 +0000
commit64ba2a9dbcc524178aec8cecbb6947b449724990 (patch)
tree6da81cb5f197163c244c4fb30af9221f538193d6 /Master/texmf-dist/tex/luatex/luaotfload
parentbdbf5181624ab958acf8225d0fc3c95b9894c5ea (diff)
luaotfload update
git-svn-id: svn://tug.org/texlive/trunk@18437 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/luatex/luaotfload')
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua170
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty6
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-compat-font-otf.lua1629
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-cid.lua3
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-clr.lua155
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-def.lua18
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-dum.lua245
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ini.lua8
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua377
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-nms.lua495
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ota.lua7
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otb.lua224
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otc.lua2
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otf.lua476
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otn.lua470
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ott.lua12
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-tfm.lua411
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-font-xtx.lua28
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-dum.lua68
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-ovr.lua35
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-node-fnt.lua6
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-node-ini.lua48
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-node-inj.lua3
-rw-r--r--Master/texmf-dist/tex/luatex/luaotfload/otfl-node-res.lua193
24 files changed, 2353 insertions, 2736 deletions
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua
index 2c63bd9a22c..6e76fa57f8f 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.lua
@@ -15,106 +15,59 @@
-- and the derived files
-- luaotfload.sty, luaotfload.lua
--
-luaotfload = { }
+module('luaotfload', package.seeall)
luaotfload.module = {
name = "luaotfload",
- version = 1.06,
- date = "2010/02/22",
+ version = 1.07,
+ date = "2010/05/10",
description = "ConTeXt font loading system.",
author = "Elie Roux & Hans Hagen",
copyright = "Elie Roux",
license = "CC0"
}
-luatextra.provides_module(luaotfload.module)
+luatexbase.provides_module(luaotfload.module)
-function luaotfload.loadmodule(name, compat)
- local tofind
- if compat then
- if tex.luatexversion < 45 then
- tofind = 'otfl-compat-'..name
- else
- tofind = 'otfl-'..name
- end
- else
- tofind = 'otfl-'..name
- end
- local found = kpse.find_file(tofind,"tex")
- if not found then
- luatextra.module_error('luaotfload', string.format('file %s not found.', tofind))
- return
- end
- luatextra.module_log('luaotfload', "loading file "..found)
- dofile(found)
-end
-
-
-string.strip = string.stripspaces
-
-file = fpath
-file.extname = fpath.suffix
+local format = string.format
-
-local splitters_s, splitters_m = { }, { }
-
-function lpeg.splitat(separator,single)
- local splitter = (single and splitters_s[separator]) or splitters_m[separator]
- if not splitter then
- separator = lpeg.P(separator)
- if single then
- local other, any = lpeg.C((1 - separator)^0), lpeg.P(1)
- splitter = other * (separator * lpeg.C(any^0) + "")
- splitters_s[separator] = splitter
- else
- local other = lpeg.C((1 - separator)^0)
- splitter = other * (separator * other)^0
- splitters_m[separator] = splitter
- end
- end
- return splitter
+local function log(...)
+ luatexbase.module_log ('luaotfload', format(...))
end
-function table.compact(t)
- if t then
- for k,v in next, t do
- if not next(v) then
- t[k] = nil
- end
- end
- end
+local function error(...)
+ luatexbase.module_error ('luaotfload', format(...))
end
-function table.sortedhashkeys(tab) -- fast one
- local srt = { }
- for key,_ in next, tab do
- srt[#srt+1] = key
- end
- table.sort(srt)
- return srt
+local function warning(...)
+ luatexbase.module_warning('luaotfload', format(...))
end
-function table.reverse_hash(h)
- local r = { }
- for k,v in next, h do
- r[v] = string.lower(string.gsub(k," ",""))
- end
- return r
+
+local luatex_version = 60
+
+if tex.luatexversion < luatex_version then
+ warning('LuaTeX v%.2f is old, v%.2f is recommended.',
+ tex.luatexversion/100,
+ luatex_version /100)
end
-function table.reverse(t)
- local tt = { }
- if #t > 0 then
- for i=#t,1,-1 do
- tt[#tt+1] = t[i]
- end
+
+function luaotfload.loadmodule(name)
+ local tofind = 'otfl-'..name
+ 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
- return tt
end
luaotfload.loadmodule('luat-dum.lua') -- not used in context at all
+luaotfload.loadmodule('luat-ovr.lua') -- override some luat-dum functions
luaotfload.loadmodule('data-con.lua') -- maybe some day we don't need this one
@@ -122,9 +75,11 @@ luaotfload.loadmodule('node-ini.lua')
function attributes.private(name)
- local number = tex.attributenumber['otfl@'..name]
+ local number = luatexbase.attributes['otfl@'..name]
if not number then
- luatextra.module_error('luaotfload', string.format('asking for attribute %s, but not declared. Please report to the maintainer of luaotfload.', name))
+ error('asking for attribute %s, but not declared. '
+ ..'Please report to the maintainer of luaotfload.',
+ name)
end
return number
end
@@ -140,56 +95,47 @@ luaotfload.loadmodule('node-dum.lua')
luaotfload.loadmodule('font-ini.lua')
luaotfload.loadmodule('font-tfm.lua')
luaotfload.loadmodule('font-cid.lua')
+luaotfload.loadmodule('font-map.lua')
luaotfload.loadmodule('font-ott.lua')
-luaotfload.loadmodule('font-otf.lua', 1)
+luaotfload.loadmodule('font-otf.lua')
luaotfload.loadmodule('font-otd.lua')
luaotfload.loadmodule('font-oti.lua')
luaotfload.loadmodule('font-otb.lua')
luaotfload.loadmodule('font-otn.lua')
luaotfload.loadmodule('font-ota.lua')
luaotfload.loadmodule('font-otc.lua')
-
-
-do
- local temp = callback.register
- callback.register = function (...)
- return
- end
- luaotfload.loadmodule('font-def.lua')
- callback.register = temp
-end
-
+luaotfload.loadmodule('font-def.lua')
luaotfload.loadmodule('font-xtx.lua')
-luaotfload.loadmodule('font-map.lua')
luaotfload.loadmodule('font-dum.lua')
-
-
-fonts.enc.known = {}
-
-
-function luaotfload.find_vf_file(name)
- name = file.removesuffix(file.basename(name))
- local result = kpse.find_file(name, "vf") or ""
- if result == "" then
- result = kpse.find_file(name, "ovf") or ""
- end
- return result
-end
+luaotfload.loadmodule('font-nms.lua')
+luaotfload.loadmodule('font-clr.lua')
function luaotfload.register_callbacks()
- callback.add('pre_linebreak_filter', nodes.simple_font_handler, 'luaotfload.pre_linebreak_filter')
- callback.add('hpack_filter', nodes.simple_font_handler, 'luaotfload.hpack_filter')
- callback.reset('define_font')
- callback.add('define_font', fonts.define.read, 'luaotfload.define_font', 1)
- callback.add('find_vf_file', luaotfload.find_vf_file, 'luaotfload.find_vf_file')
+ 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',
+ fonts.define.read,
+ 'luaotfload.define_font', 1)
+ luatexbase.add_to_callback('find_vf_file',
+ fonts.vf.find,
+ 'luaotfload.find_vf_file')
end
function luaotfload.unregister_callbacks()
- callback.remove('pre_linebreak_filter', 'luaotfload.pre_linebreak_filter')
- callback.remove('hpack_filter', 'luaotfload.hpack_filter')
- callback.remove('define_font', 'luaotfload.define_font')
- callback.remove('find_vf_file', 'luaotfload.find_vf_file')
+ luatexbase.remove_from_callback('pre_linebreak_filter',
+ 'luaotfload.pre_linebreak_filter')
+ luatexbase.remove_from_callback('hpack_filter',
+ 'luaotfload.hpack_filter')
+ luatexbase.remove_from_callback('define_font',
+ 'luaotfload.define_font')
+ luatexbase.remove_from_callback('find_vf_file',
+ 'luaotfload.find_vf_file')
end
--
-- 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 839b62e8bee..e2ec4bba711 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty
+++ b/Master/texmf-dist/tex/luatex/luaotfload/luaotfload.sty
@@ -23,7 +23,7 @@
\else
\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{luaotfload}%
- [2010/02/22 v1.06b ConTeXt font loading system]
+ [2010/05/10 v1.07 ConTeXt font loading system]
\RequirePackage{luatextra}
\fi
@@ -46,11 +46,11 @@
\def\otfl@off{
-\luadirect{luaotfload.unregister_callbacks()}
+\directlua{luaotfload.unregister_callbacks()}
}
\def\otfl@on{
-\luadirect{luaotfload.register_callbacks()}
+\directlua{luaotfload.register_callbacks()}
}
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-compat-font-otf.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-compat-font-otf.lua
deleted file mode 100644
index be1873898a5..00000000000
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-compat-font-otf.lua
+++ /dev/null
@@ -1,1629 +0,0 @@
-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, getn, utfbyte = table.concat, table.getn, utf.byte
-local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
-local type, next, tonumber, tostring = type, next, tonumber, tostring
-
-local trace_private = false trackers.register("otf.private", function(v) trace_private = v end)
-local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
-local trace_features = false trackers.register("otf.features", function(v) trace_features = v end)
-local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
-local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end)
-local trace_math = false trackers.register("otf.math", function(v) trace_math = v end)
-local trace_unimapping = false trackers.register("otf.unimapping", function(v) trace_unimapping = v end)
-
---~ trackers.enable("otf.loading")
-
-local zwnj = 0x200C
-local zwj = 0x200D
-
---[[ldx--
-<p>The fontforge table has organized lookups in a certain way. A first implementation
-of this code was organized featurewise: information related to features was
-collected and processing boiled down to a run over the features. The current
-implementation honors the order in the main feature table. Since we can reorder this
-table as we want, we can eventually support several models of processing. We kept
-the static as well as dynamic feature processing, because it had proved to be
-rather useful. The formerly three loop variants have beem discarded but will
-reapear at some time.</p>
-
-<itemize>
-<item>we loop over all lookups</item>
-<item>for each lookup we do a run over the list of glyphs</item>
-<item>but we only process them for features that are enabled</item>
-<item>if we're dealing with a contextual lookup, we loop over all contexts</item>
-<item>in that loop we quit at a match and then process the list of sublookups</item>
-<item>we always continue after the match</item>
-</itemize>
-
-<p>In <l n='context'/> we do this for each font that is used in a list, so in
-practice we have quite some nested loops.</p>
-
-<p>We process the whole list and then consult the glyph nodes. An alternative approach
-is to collect strings of characters using the same font including spaces (because some
-lookups involve spaces). However, we then need to reconstruct the list which is no fun.
-Also, we need to carry quite some information, like attributes, so eventually we don't
-gain much (if we gain something at all).</p>
-
-<p>Another consideration has been to operate on sublists (subhead, subtail) but again
-this would complicate matters as we then neext to keep track of a changing subhead
-and subtail. On the other hand, this might save some runtime. The number of changes
-involved is not that large. This only makes sense when we have many fonts in a list
-and don't change to frequently.</p>
---ldx]]--
-
-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 { } -- defined in font-ott.lua
-otf.meanings = otf.meanings or { } -- defined in font-ott.lua
-otf.tables.features = otf.tables.features or { } -- defined in font-ott.lua
-otf.tables.languages = otf.tables.languages or { } -- defined in font-ott.lua
-otf.tables.scripts = otf.tables.scripts or { } -- defined in font-ott.lua
-
-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.635 -- beware: also sync font-mis.lua
-otf.pack = true -- beware: also sync font-mis.lua
-otf.syncspace = true
-otf.notdef = false
-otf.cache = containers.define("fonts", "otf", otf.version, true)
-otf.cleanup_aat = false -- only context
-
---[[ldx--
-<p>We start with a lot of tables and related functions.</p>
---ldx]]--
-
-otf.tables.global_fields = table.tohash {
- "lookups",
- "glyphs",
- "subfonts",
- "luatex",
- "pfminfo",
- "cidinfo",
- "tables",
- "names",
- "unicodes",
- "names",
---~ "math",
- "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",
- -- "luatex",
- "macstyle",
- "modificationtime",
- "onlybitmaps",
- "origname",
- "os2_version",
- "pfminfo",
- "private",
- "serifcheck",
- "sfd_version",
- -- "size",
- "strokedfont",
- "strokewidth",
- "subfonts",
- "table_version",
- -- "tables",
- -- "ttf_tab_saved",
- "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",
-}
-
---[[ldx--
-<p>Here we go.</p>
---ldx]]--
-
-local function load_featurefile(ff,featurefile)
- if featurefile then
- featurefile = resolvers.find_file(file.addsuffix(featurefile,'fea')) -- "FONTFEATURES"
- 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",name)
- end
- enhancer(data,filename)
- end
-end
-
-local enhancers = {
- -- pack and unpack are handled separately; they might even be moved
- -- away from the enhancers namespace
- "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", -- moved here
- "flatten glyph lookups", "flatten anchor tables", "flatten feature tables",
- "prepare luatex tables",
- "analyse features", "rehash features",
- "analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables",
- "check italic correction","check math",
- "share widths",
- "strip not needed data",
- "migrate metadata",
-}
-
-function otf.load(filename,format,sub,featurefile)
- local name = file.basename(file.removesuffix(filename))
- if featurefile then
- name = name .. "@" .. file.removesuffix(file.basename(featurefile))
- 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)
- local size = lfs.attributes(filename,"size") or 0
- if not data or data.verbose ~= fonts.verbose or data.size ~= size then
- logs.report("load otf","loading: %s (hash: %s)",filename,hash)
- local ff, messages
- 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
- for m=1,#messages do
- logs.report("load otf","warning: %s",messages[m])
- end
- 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)
- end
- if otf.pack and not fonts.verbose then
- otf.enhance("pack",data,filename)
- end
- data.size = size
- 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) -- this frees the old table and load the sparse one
- 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
- otf.enhance("unpack",data,filename,false) -- no message here
- otf.add_dimensions(data)
- if trace_sequences then
- otf.show_feature_order(data,filename)
- end
- end
- return data
-end
-
-function otf.add_dimensions(data)
- -- todo: forget about the width if it's the defaultwidth (saves mem)
- -- we could also build the marks hash here (instead of storing it)
- 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
- -- no need to set it and no negative heights, nil == 0
- else
- d.height = ht
- end
- if dp == 0 or dp < 0 then
- -- no negative depths and no negative depths, nil == 0
- 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
-
--- todo: normalize, design_size => designsize
-
-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
- t[unicodes[s]] = true
- 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
- -- scripts and tag
- 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)
- -- local luatex = data.luatex
- -- luatex.gposfeatures = analyze_features(data.gpos)
- -- luatex.gsubfeatures = analyze_features(data.gsub)
-end
-
-otf.enhancers["rehash features"] = function(data,filename)
- local features = { }
- data.luatex.features = features
- for k, what in next, otf.glists do
- local dw = data[what]
- if dw then
- local f = { }
- features[what] = f
- for i=1,#dw do
- local d= dw[i]
- local dfeatures = d.features
- if dfeatures then
- for i=1,#dfeatures do
- local df = dfeatures[i]
- local tag = strip(lower(df.tag))
- local ft = f[tag] if not ft then ft = {} f[tag] = ft end
- local dscripts = df.scripts
- for script, languages in next, dscripts do
- script = strip(lower(script))
- local fts = ft[script] if not fts then fts = {} ft[script] = fts end
- for i=1,#languages do
- fts[strip(lower(languages[i]))] = true
- end
- end
- end
- end
- end
- end
- end
-end
-
-otf.enhancers["analyse anchors"] = function(data,filename)
- 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
-
-local separator = lpeg.S("_.")
-local other = lpeg.C((1 - separator)^1)
-local ligsplitter = lpeg.Ct(other * (separator * other)^0)
-
---~ print(table.serialize(ligsplitter:match("this")))
---~ print(table.serialize(ligsplitter:match("this.that")))
---~ print(table.serialize(ligsplitter:match("japan1.123")))
---~ print(table.serialize(ligsplitter:match("such_so_more")))
---~ print(table.serialize(ligsplitter:match("such_so_more.that")))
-
-otf.enhancers["analyse unicodes"] = function(data,filename)
- local tounicode16, tounicode16sequence = fonts.map.tounicode16, fonts.map.tounicode16sequence
- local unicodes = data.luatex.unicodes
- -- we need to move this code
- unicodes['space'] = unicodes['space'] or 32 -- handly later on
- unicodes['hyphen'] = unicodes['hyphen'] or 45 -- handly later on
- unicodes['zwj'] = unicodes['zwj'] or zwj -- handly later on
- unicodes['zwnj'] = unicodes['zwnj'] or zwnj -- handly later on
- -- the tounicode mapping is sparse and only needed for alternatives
- local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?"))
- data.luatex.tounicode, data.luatex.originals = tounicode, originals
- local lumunic, uparser, oparser
- if false then -- will become an option
- lumunic = fonts.map.load_lum_table(filename)
- lumunic = lumunic and lumunic.tounicode
- end
- local cidinfo, cidnames, cidcodes = data.cidinfo
- local usedmap = cidinfo and cidinfo.usedname
- usedmap = usedmap and fonts.cid.map[usedmap]
- if usedmap then
- oparser = usedmap and fonts.map.make_name_parser(cidinfo.ordering)
- cidnames = usedmap.names
- cidcodes = usedmap.unicodes
- end
- uparser = fonts.map.make_name_parser()
- 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 -- play safe
- 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]
- if unicode then
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
- end
- -- cidmap heuristics, beware, there is no guarantee for a match unless
- -- the chain resolves
- if (not unicode) and usedmap then
- local foundindex = oparser:match(name)
- if foundindex then
- unicode = cidcodes[foundindex] -- name to number
- if not unicode then
- local reference = cidnames[foundindex] -- number to name
- if reference then
- local foundindex = oparser:match(reference)
- if foundindex then
- unicode = cidcodes[foundindex]
- if unicode then
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
- end
- end
- if not unicode then
- local foundcodes, multiple = uparser:match(reference)
- if foundcodes then
- if multiple then
- originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
- else
- originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
- end
- end
- end
- end
- end
- end
- end
- -- a.whatever or a_b_c.whatever or a_b_c (no numbers)
- if not unicode then
- local split = ligsplitter:match(name)
- local nplit = (split and #split) or 0
- if nplit == 0 then
- -- skip
- elseif nplit == 1 then
- local base = split[1]
- unicode = unicodes[base] or (agl and agl[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 (agl and agl[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 -- done then
- originals[index], tounicode[index], nl, unicode = t, tounicode16sequence(t), nl + 1, true
- end
- end
- end
- -- last resort
- if not unicode then
- local foundcodes, multiple = uparser:match(name)
- if foundcodes then
- if multiple then
- originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
- else
- originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
- end
- end
- end
- if not unicode then
- originals[index], tounicode[index] = 0xFFFD, "FFFD"
- end
- end
- end
- if trace_unimapping then
- for index, glyph in table.sortedpairs(data.glyphs) do
- local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe
- if toun then
- logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
- else
- logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
- end
- end
- end
- if trace_loading and (ns > 0 or nl > 0) then
- logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
- end
-end
-
-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
- -- scripts, tag, ismac
- local t = { }
- for f=1,#features do
- local feature = features[f]
- local hash = { }
- -- only script and langs matter
- 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 = { -- forcing false packs nicer
- (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)
- -- we can also move the names to data.luatex.names which might
- -- save us some more memory (at the cost of harder tracing)
- if data.subfonts and table.is_empty(data.glyphs) then
- 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
- -- dummy entry
- else
- local unicode, name = unicodes[index], names[index]
- g.cidindex = n
- g.boundingbox = g.boundingbox -- or zerobox
- 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
- -- beware: the indices table is used to initialize the tfm table
- 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 -- or 0
- 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) -- needed?
- if data.subfonts then
- for _, subfont in next, data.subfonts do
- table.compact(subfont.glyphs) -- needed?
- end
- end
-end
-
-otf.enhancers["reverse coverage"] = function(data,filename)
- -- we prefer the before lookups in a normal order
- 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
- -- we can use this to avoid calculations
- otf.tables.valid_fields[#otf.tables.valid_fields+1] = "has_italic"
- data.has_italic = true
-end
-
-otf.enhancers["check math"] = function(data,filename)
- if data.math then
- -- we move the math stuff into a math subtable because we then can
- -- test faster in the tfm copy
- 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 then
- if #p>0 then
- for i=1,#p do
- local pi = p[i]
- pi.glyph = unicodes[pi.component] or 0
- end
- math.horiz_parts = p
- end
- 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 then
- if #p>0 then
- for i=1,#p do
- local pi = p[i]
- pi.glyph = unicodes[pi.component] or 0
- end
- math.vert_parts = p
- end
- 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
- -- share width for cjk fonts
- 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
-
--- kern: ttf has a table with kerns
-
-otf.enhancers["reorganize kerns"] = function(data,filename)
- local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
- local mkdone = false
- for index, glyph in next, data.glyphs do
- 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 -- brrr, wrong! we miss the non unicode ones
- 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 -- saves space and time
- 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
- 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 -- name is inconsistent with anchor_classes
- if kernclass then
- for k=1,#kernclass do
- local kcl = kernclass[k]
- local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
- if type(lookups) ~= "table" then
- lookups = { lookups }
- end
- for l=1,#lookups do
- local lookup = lookups[l]
- local maxfirsts, maxseconds = getn(firsts), getn(seconds)
- if trace_loading then
- logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
- end
- for fk, fv in next, firsts do
- for first in gmatch(fv,"[^ ]+") do
- local first_unicode = unicodes[first]
- if type(first_unicode) == "number" then
- first_unicode = { first_unicode }
- end
- for f=1,#first_unicode do
- local glyph = glyphs[mapmap[first_unicode[f]]]
- if glyph then
- local mykerns = glyph.mykerns
- if not mykerns then
- mykerns = { } -- unicode indexed !
- glyph.mykerns = mykerns
- end
- local lookupkerns = mykerns[lookup]
- if not lookupkerns then
- lookupkerns = { }
- mykerns[lookup] = lookupkerns
- end
- for sk, sv in next, seconds do
- local offset = offsets[(fk-1) * maxseconds + sk]
- --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
- for second in gmatch(sv,"[^ ]+") do
- local second_unicode = unicodes[second]
- if type(second_unicode) == "number" then
- lookupkerns[second_unicode] = offset
- else
- for s=1,#second_unicode do
- lookupkerns[second_unicode[s]] = offset
- end
- end
- end
- end
- elseif trace_loading then
- logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])
- end
- end
- 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]
- -- looks like this is done twice ... bug?
- if code then
- local vu = v.unicode
- if not vu then
- v.unicode = code
- elseif type(vu) == "table" then
- if vu[#vu] == code then
- -- weird
- 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 -- funny names for editors
- 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
- -- goodies
- local pfminfo = data.pfminfo
- metadata.isfixedpitch = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose["proportion"] == "Monospaced")
- metadata.charwidth = pfminfo and pfminfo.avgwidth
-end
-
-otf.enhancers["flatten glyph lookups"] = function(data,filename)
- for k, v in next, data.glyphs do
- if v.lookups then
- for kk, vv in next, v.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} } -- maybe nil instead of { }
- 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["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)
- -- is this needed? do we still use them at all?
- 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
-
--- tex features
-
-fonts.otf.enhancers["enrich with features"] = function(data,filename)
- -- later, ctx only
-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 not table.is_empty(features) then
- local lists = {
- fonts.triggers,
- fonts.processors,
- fonts.manipulators,
- }
- local mode = tfmdata.mode or fonts.mode -- or features.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 -- brr
- if not done[f] then -- so, we can move some to triggers
- 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) -- can set mode (no need to pass otf)
- mode = tfmdata.mode or fonts.mode -- keep this, mode can be set local !
- 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 -- brr
- 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
- -- message
- 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)
---~ print(cache_id)
- if not tfmdata then
- local otfdata = otf.load(filename,format,sub,features and features.featurefile)
- if not table.is_empty(otfdata) then
- otfdata.shared = otfdata.shared or {
- featuredata = { },
- anchorhash = { },
- initialized = false,
- }
- tfmdata = otf.copy_to_tfm(otfdata,cache_id)
- if not table.is_empty(tfmdata) then
- tfmdata.unique = tfmdata.unique or { }
- tfmdata.shared = tfmdata.shared or { } -- combine
- local shared = tfmdata.shared
- shared.otfdata = otfdata
- shared.features = features -- default
- shared.dynamics = { }
- shared.processes = { }
- shared.set_dynamics = otf.set_dynamics -- fast access and makes other modules independent
- -- this will be done later anyway, but it's convenient to have
- -- them already for fast access
- 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
-
---~ {
---~ ['boundingbox']={ 95, -458, 733, 1449 },
---~ ['class']="base",
---~ ['name']="braceleft",
---~ ['unicode']=123,
---~ ['vert_variants']={
---~ ['italic_correction']=0,
---~ ['parts']={
---~ { ['component']="uni23A9", ['endConnectorLength']=1000, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=0, }, -- bot
---~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
---~ { ['component']="uni23A8", ['endConnectorLength']=1000, ['fullAdvance']=4688, ['is_extender']=0, ['startConnectorLength']=1000, }, -- mid
---~ { ['component']="uni23AA", ['endConnectorLength']=2500, ['fullAdvance']=2501, ['is_extender']=1, ['startConnectorLength']=2500, }, -- rep
---~ { ['component']="uni23A7", ['endConnectorLength']=0, ['fullAdvance']=2546, ['is_extender']=0, ['startConnectorLength']=1000, }, -- top
---~ },
---~ ['variants']="braceleft braceleft.vsize1 braceleft.vsize2 braceleft.vsize3 braceleft.vsize4 braceleft.vsize5 braceleft.vsize6 braceleft.vsize7",
---~ },
---~ ['width']=793,
---~ },
-
--- the first version made a top/mid/not extensible table, now we just pass on the variants data
--- and deal with it in the tfm scaler (there is no longer an extensible table anyway)
-
--- we cannot share descriptions as virtual fonts might extend them (ok, we could
--- use a cache with a hash
-
-function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder the tma to unicode (nasty due to one->many)
- if data then
- local glyphs, pfminfo, metadata = data.glyphs or { }, data.pfminfo or { }, data.metadata or { }
- local luatex = data.luatex
- local unicodes = luatex.unicodes -- names to unicodes
- local indices = luatex.indices
- local characters, parameters, math_parameters, descriptions = { }, { }, { }, { }
- local tfm = {
- characters = characters,
- parameters = parameters,
- math_parameters = math_parameters,
- descriptions = descriptions,
- indices = indices,
- unicodes = unicodes,
- }
- -- indices maps from unicodes to indices
- for u, i in next, indices do
- characters[u] = { } -- we need this because for instance we add protruding info and loop over characters
- descriptions[u] = glyphs[i]
- end
- -- math
- if metadata.math then
- -- parameters
- for name, value in next, metadata.math do
- math_parameters[name] = value
- end
- -- we could use a subset
- for u, char in next, characters do
- local d = descriptions[u]
- local m = d.math
- -- we have them shared because that packs nicer
- -- we could prepare the variants and keep 'm in descriptions
- if m then
- local variants = m.horiz_variants
- if variants then
- local c = char
- for n in variants:gmatch("[^ ]+") do
- local un = unicodes[n]
- if un and u ~= un then
- c.next = un
- c = characters[un]
- end
- end
- c.horiz_variants = m.horiz_parts
- else
- local variants = m.vert_variants
- if variants then
- local c = char
- for n in variants:gmatch("[^ ]+") do
- local un = unicodes[n]
- if un and u ~= un then
- c.next = un
- c = characters[un]
- end
- end
- c.vert_variants = m.vert_parts
- end
- end
- local kerns = m.kerns
- if kerns then
- char.mathkerns = kerns
- end
- end
- end
- end
- -- end math
- local designsize = metadata.designsize or metadata.design_size or 100
- if designsize == 0 then
- designsize = 100
- end
- local spaceunits = 500
- tfm.units = metadata.units_per_em or 1000
- -- we need a runtime lookup because of running from cdrom or zip, brrr
- tfm.filename = resolvers.findbinfile(luatex.filename,"") or luatex.filename
- tfm.fullname = metadata.fontname or metadata.fullname
- tfm.psname = tfm.fullname
- tfm.encodingbytes = 2
- tfm.cidinfo = data.cidinfo
- tfm.cidinfo.registry = tfm.cidinfo.registry or ""
- tfm.type = "real"
- tfm.stretch = 0 -- stretch
- tfm.slant = 0 -- slant
- tfm.direction = 0
- tfm.boundarychar_label = 0
- tfm.boundarychar = 65536
- tfm.designsize = (designsize/10)*65536
- tfm.spacer = "500 units"
- local endash, emdash = 0x20, 0x2014 -- unicodes['space'], unicodes['emdash']
- if metadata.isfixedpitch then
- if descriptions[endash] then
- spaceunits, tfm.spacer = descriptions[endash].width, "space"
- end
- if not spaceunits and descriptions[emdash] then
- spaceunits, tfm.spacer = descriptions[emdash].width, "emdash"
- end
- if not spaceunits and metadata.charwidth then
- spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
- end
- else
- if descriptions[endash] then
- spaceunits, tfm.spacer = descriptions[endash].width, "space"
- end
- if not spaceunits and descriptions[emdash] then
- spaceunits, tfm.spacer = descriptions[emdash].width/2, "emdash/2"
- end
- if not spaceunits and metadata.charwidth then
- spaceunits, tfm.spacer = metadata.charwidth, "charwidth"
- end
- end
- spaceunits = tonumber(spaceunits) or tfm.units/2 -- 500 -- brrr
- parameters.slant = 0
- parameters.space = spaceunits -- 3.333 (cmr10)
- parameters.space_stretch = tfm.units/2 -- 500 -- 1.666 (cmr10)
- parameters.space_shrink = 1*tfm.units/3 -- 333 -- 1.111 (cmr10)
- parameters.x_height = 2*tfm.units/5 -- 400
- parameters.quad = tfm.units -- 1000
- if spaceunits < 2*tfm.units/5 then
- -- todo: warning
- end
- local italicangle = metadata.italicangle
- tfm.ascender = math.abs(metadata.ascent or 0)
- tfm.descender = math.abs(metadata.descent or 0)
- if italicangle then -- maybe also in afm _
- tfm.italicangle = italicangle
- parameters.slant = parameters.slant - math.round(math.tan(italicangle*math.pi/180))
- end
- if metadata.isfixedpitch then
- 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 -- 1.111 (cmr10)
- if pfminfo.os2_xheight and pfminfo.os2_xheight > 0 then
- parameters.x_height = pfminfo.os2_xheight
- else
- local x = 0x78 -- unicodes['x']
- if x then
- local x = descriptions[x]
- if x then
- parameters.x_height = x.height
- end
- end
- end
- -- [6]
- return tfm
- 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)
- -- here we resolve the name; file can be relocated, so this info is not in the cache
- local filename = (otfdata and otfdata.luatex and otfdata.luatex.filename) or specification.filename
- if not filename then
- -- try to locate anyway and set otfdata.luatex.filename
- end
- if filename then
- tfmtable.encodingbytes = 2
- tfmtable.filename = resolvers.findbinfile(filename,"") or filename
- tfmtable.fullname = tfmtable.fullname or otfdata.metadata.fontname or otfdata.metadata.fullname
- local order = otfdata and otfdata.metadata.order2
- if order == 0 then
- tfmtable.format = 'opentype'
- elseif order == 1 then
- tfmtable.format = 'truetype'
- else
- tfmtable.format = specification.format
- end
- tfmtable.name = tfmtable.filename or tfmtable.fullname
- end
- fonts.logger.save(tfmtable,file.extname(specification.filename),specification)
- end
---~ print(tfmtable.fullname)
- return tfmtable
-end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-cid.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-cid.lua
index 57bfcd3787d..d1c727af2d9 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-cid.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-cid.lua
@@ -8,6 +8,7 @@ if not modules then modules = { } end modules ['font-cid'] = {
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)
@@ -61,7 +62,7 @@ function fonts.cid.load(filename)
local data = io.loaddata(filename)
if data then
unicodes, names = { }, { }
- grammar:match(data)
+ lpegmatch(grammar,data)
local supplement, registry, ordering = match(filename,"^(.-)%-(.-)%-()%.(.-)$")
return {
supplement = supplement,
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-clr.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-clr.lua
new file mode 100644
index 00000000000..e1f0faa4184
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-clr.lua
@@ -0,0 +1,155 @@
+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)
+ if value then
+ tfmdata.color = value
+ 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)
+ -- check if our page resources existed in the previous run
+ -- and remove it to avoid duplicating it later
+ if res then
+ local r = "/ExtGState<<"..res..">>"
+ tex.pdfpageresources = tex.pdfpageresources:gsub(r, "")
+ end
+ local h = node_colorize(head, nil, nil)
+ -- now append our page resources
+ if res and res:find("%S") then -- test for non-empty string
+ 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
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-def.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-def.lua
index 65c74d48fd2..f64bae5636e 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-def.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-def.lua
@@ -8,6 +8,7 @@ if not modules then modules = { } end modules ['font-def'] = {
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)
@@ -108,7 +109,7 @@ define.add_lookup("name")
define.add_lookup("spec")
function define.get_specification(str)
- return splitter:match(str)
+ return lpegmatch(splitter,str)
end
function define.register_split(symbol,action)
@@ -240,7 +241,7 @@ end
function define.resolvers.name(specification)
local resolve = fonts.names.resolve
if resolve then
- specification.resolved, specification.sub = fonts.names.resolve(specification.name,specification.sub)
+ specification.resolved, specification.sub = fonts.names.resolve(specification)
if specification.resolved then
specification.forced = file.extname(specification.resolved)
specification.name = file.removesuffix(specification.resolved)
@@ -253,7 +254,7 @@ end
function define.resolvers.spec(specification)
local resolvespec = fonts.names.resolvespec
if resolvespec then
- specification.resolved, specification.sub = fonts.names.resolvespec(specification.name,specification.sub)
+ specification.resolved, specification.sub = fonts.names.resolvespec(specification)
if specification.resolved then
specification.forced = file.extname(specification.resolved)
specification.name = file.removesuffix(specification.resolved)
@@ -313,7 +314,7 @@ function tfm.read(specification)
local reader = sequence[s]
if readers[reader] then -- not really needed
if trace_defining then
- logs.report("define font","trying (sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown")
+ 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
@@ -533,7 +534,10 @@ function define.register(fontdata,id)
if trace_defining then
logs.report("define font","loading at 2 id %s, hash: %s",id or "?",hash or "?")
end
- fonts.ids[id] = fontdata
+ fonts.identifiers[id] = fontdata
+ fonts.characters [id] = fontdata.characters
+ fonts.quads [id] = fontdata.parameters.quad
+ -- todo: extra functions, e.g. setdigitwidth etc in list
tfm.internalized[hash] = id
end
end
@@ -643,5 +647,5 @@ end
<p>We overload both the <l n='tfm'/> and <l n='vf'/> readers.</p>
--ldx]]--
-callback.register('define_font' , define.read)
-callback.register('find_vf_file', vf.find ) -- not that relevant any more
+callbacks.register('define_font' , define.read, "definition of fonts (tfmtable preparation)")
+callbacks.register('find_vf_file', vf.find , "locating virtual fonts, insofar needed") -- not that relevant any more
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-dum.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-dum.lua
index e13f8a25536..5224ae187e7 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-dum.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-dum.lua
@@ -10,8 +10,9 @@ fonts = fonts or { }
-- general
-fonts.otf.pack = false
-fonts.tfm.resolve_vf = false -- no sure about this
+fonts.otf.pack = false
+fonts.tfm.resolve_vf = false -- no sure about this
+fonts.tfm.fontname_mode = "specification" -- somehow latex needs this
-- readers
@@ -113,5 +114,245 @@ end
fonts.initializers.base.otf.itlc = itlc
fonts.initializers.node.otf.itlc = itlc
+-- slant and extend
+
+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
+
+-- expansion and protrusion
+
+fonts.protrusions = fonts.protrusions or { }
+fonts.protrusions.setups = fonts.protrusions.setups or { }
+
+local setups = fonts.protrusions.setups
+
+-- As this is experimental code, users should not depend on it. The
+-- implications are still discussed on the ConTeXt Dev List and we're
+-- not sure yet what exactly the spec is (the next code is tested with
+-- a gyre font patched by / fea file made by Khaled Hosny). The double
+-- trick should not be needed it proper hanging punctuation is used in
+-- which case values < 1 can be used.
+--
+-- preferred (in context, usine vectors):
+--
+-- \definefontfeature[whatever][default][mode=node,protrusion=quality]
+--
+-- using lfbd and rtbd, with possibibility to enable only one side :
+--
+-- \definefontfeature[whocares][default][mode=node,protrusion=yes, opbd=yes,script=latn]
+-- \definefontfeature[whocares][default][mode=node,protrusion=right,opbd=yes,script=latn]
+--
+-- idem, using multiplier
+--
+-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn]
+-- \definefontfeature[whocares][default][mode=node,protrusion=double,opbd=yes,script=latn]
+--
+-- idem, using named feature file (less frozen):
+--
+-- \definefontfeature[whocares][default][mode=node,protrusion=2,opbd=yes,script=latn,featurefile=texgyrepagella-regularxx.fea]
+
+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[3] / descriptions[k].width-- or 1 ~= 0 too but the same
+ 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[3] / descriptions[k].width -- or 3
+ 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
+
+-- The opbd test is just there because it was discussed on the
+-- context development list. However, the mentioned fxlbi.otf font
+-- only has some kerns for digits. So, consider this feature not
+-- supported till we have a proper test font.
+
+function fonts.initializers.common.protrusion(tfmdata,value)
+ if value then
+ local opbd = tfmdata.shared.features.opbd
+ if opbd then
+ -- possible values: left right both yes no (experimental)
+ 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 -- can be option
+ 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
+
+-- left over
+
function fonts.register_message()
end
+
+-- example vectors
+
+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 }, -- comma
+ [0x002E] = { 0, 1 }, -- period
+ [0x003A] = { 0, 1 }, -- colon
+ [0x003B] = { 0, 1 }, -- semicolon
+ [0x002D] = { 0, 1 }, -- hyphen
+ [0x2013] = { 0, 0.50 }, -- endash
+ [0x2014] = { 0, 0.33 }, -- emdash
+ [0x3001] = { 0, 1 }, -- ideographic comma 、
+ [0x3002] = { 0, 1 }, -- ideographic full stop 。
+ [0x060C] = { 0, 1 }, -- arabic comma ،
+ [0x061B] = { 0, 1 }, -- arabic semicolon ؛
+ [0x06D4] = { 0, 1 }, -- arabic full stop ۔
+
+}
+
+-- normalizer
+
+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
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ini.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ini.lua
index 5cff22760cc..b9988687d68 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ini.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ini.lua
@@ -22,7 +22,11 @@ fontloader.totable = fontloader.to_table
-- fix comes last
fonts = fonts or { }
-fonts.ids = fonts.ids or { } -- aka fontdata
+
+fonts.ids = fonts.ids or { } fonts.identifiers = fonts.ids -- aka fontdata
+fonts.chr = fonts.chr or { } fonts.characters = fonts.chr -- aka chardata
+fonts.qua = fonts.qua or { } fonts.quads = fonts.qua -- aka quaddata
+
fonts.tfm = fonts.tfm or { }
fonts.mode = 'base'
@@ -35,6 +39,8 @@ fonts.ids[0] = { -- nullfont
name = "nullfont",
}
+fonts.chr[0] = { }
+
fonts.methods = fonts.methods or {
base = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
node = { tfm = { }, afm = { }, otf = { }, vtf = { }, fix = { } },
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua
index 0dc4eca5b86..208ad50a873 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-map.lua
@@ -6,9 +6,13 @@ if not modules then modules = { } end modules ['font-map'] = {
license = "see context related readme files"
}
-local match, format, find, concat = string.match, string.format, string.find, table.concat
+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_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
@@ -18,116 +22,10 @@ of obsolete. Some code may move to runtime or auxiliary modules.</p>
<p>The name to unciode related code will stay of course.</p>
--ldx]]--
-fonts = fonts or { }
-fonts.map = fonts.map or { }
-fonts.map.data = fonts.map.data or { }
-fonts.map.encodings = fonts.map.encodings or { }
-fonts.map.done = fonts.map.done or { }
-fonts.map.loaded = fonts.map.loaded or { }
-fonts.map.direct = fonts.map.direct or { }
-fonts.map.line = fonts.map.line or { }
-
-function fonts.map.line.pdfmapline(tag,str)
- return "\\loadmapline[" .. tag .. "][" .. str .. "]"
-end
-
-function fonts.map.line.pdftex(e) -- so far no combination of slant and stretch
- if e.name and e.fontfile then
- local fullname = e.fullname or ""
- if e.slant and e.slant ~= 0 then
- if e.encoding then
- return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile))
- else
- return fonts.map.line.pdfmapline("=",format('%s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile))
- end
- elseif e.stretch and e.stretch ~= 1 and e.stretch ~= 0 then
- if e.encoding then
- return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.stretch,e.encoding,e.fontfile))
- else
- return fonts.map.line.pdfmapline("=",format('%s %s "%g ExtendFont" <%s',e.name,fullname,e.stretch,e.fontfile))
- end
- else
- if e.encoding then
- return fonts.map.line.pdfmapline("=",format('%s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile))
- else
- return fonts.map.line.pdfmapline("=",format('%s %s <%s',e.name,fullname,e.fontfile))
- end
- end
- else
- return nil
- end
-end
-
-function fonts.map.flush(backend) -- will also erase the accumulated data
- local flushline = fonts.map.line[backend or "pdftex"] or fonts.map.line.pdftex
- for _, e in pairs(fonts.map.data) do
- tex.sprint(ctxcatcodes,flushline(e))
- end
- fonts.map.data = { }
-end
-
-fonts.map.line.dvips = fonts.map.line.pdftex
-fonts.map.line.dvipdfmx = function() end
-
-function fonts.map.convert_entries(filename)
- if not fonts.map.loaded[filename] then
- fonts.map.data, fonts.map.encodings = fonts.map.load_file(filename,fonts.map.data, fonts.map.encodings)
- fonts.map.loaded[filename] = true
- end
-end
-
-function fonts.map.load_file(filename, entries, encodings)
- entries = entries or { }
- encodings = encodings or { }
- local f = io.open(filename)
- if f then
- local data = f:read("*a")
- if data then
- for line in gmatch(data,"(.-)[\n\t]") do
- if find(line,"^[%#%%%s]") then
- -- print(line)
- else
- local stretch, slant, name, fullname, fontfile, encoding
- line = line:gsub('"(.+)"', function(s)
- stretch = find(s,'"([^"]+) ExtendFont"')
- slant = find(s,'"([^"]+) SlantFont"')
- return ""
- end)
- if not name then
- -- name fullname encoding fontfile
- name, fullname, encoding, fontfile = match(line,"^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$")
- end
- if not name then
- -- name fullname (flag) fontfile encoding
- name, fullname, fontfile, encoding = match(line,"^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$")
- end
- if not name then
- -- name fontfile
- name, fontfile = match(line,"^(%S+)%s+[%d%s<]+(%S*)%s*$")
- end
- if name then
- if encoding == "" then encoding = nil end
- entries[name] = {
- name = name, -- handy
- fullname = fullname,
- encoding = encoding,
- fontfile = fontfile,
- slant = tonumber(slant),
- stretch = tonumber(stretch)
- }
- encodings[name] = encoding
- elseif line ~= "" then
- -- print(line)
- end
- end
- end
- end
- f:close()
- end
- return entries, encodings
-end
+fonts = fonts or { }
+fonts.map = fonts.map or { }
-function fonts.map.load_lum_table(filename)
+local function load_lum_table(filename) -- will move to font goodies
local lumname = file.replacesuffix(file.basename(filename),"lum")
local lumfile = resolvers.find_file(lumname,"map") or ""
if lumfile ~= "" and lfs.isfile(lumfile) then
@@ -153,7 +51,7 @@ local parser = unicode + ucode + index
local parsers = { }
-function fonts.map.make_name_parser(str)
+local function make_name_parser(str)
if not str or str == "" then
return parser
else
@@ -169,7 +67,7 @@ end
--~ local parser = fonts.map.make_name_parser("Japan1")
--~ local parser = fonts.map.make_name_parser()
--~ local function test(str)
---~ local b, a = parser:match(str)
+--~ local b, a = lpegmatch(parser,str)
--~ print((a and table.serialize(b)) or b)
--~ end
--~ test("a.sc")
@@ -180,7 +78,7 @@ end
--~ test("index1234")
--~ test("Japan1.123")
-function fonts.map.tounicode16(unicode)
+local function tounicode16(unicode)
if unicode < 0x10000 then
return format("%04X",unicode)
else
@@ -188,7 +86,7 @@ function fonts.map.tounicode16(unicode)
end
end
-function fonts.map.tounicode16sequence(unicodes)
+local function tounicode16sequence(unicodes)
local t = { }
for l=1,#unicodes do
local unicode = unicodes[l]
@@ -221,3 +119,252 @@ end
--~ return s
--~ 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)
+
+--~ print(table.serialize(lpegmatch(ligsplitter,"this")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"this.that")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"japan1.123")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more")))
+--~ print(table.serialize(lpegmatch(ligsplitter,"such_so_more.that")))
+
+fonts.map.add_to_unicode = function(data,filename)
+ local unicodes = data.luatex and data.luatex.unicodes
+ if not unicodes then
+ return
+ end
+ -- we need to move this code
+ unicodes['space'] = unicodes['space'] or 32
+ unicodes['hyphen'] = unicodes['hyphen'] or 45
+ unicodes['zwj'] = unicodes['zwj'] or 0x200D
+ unicodes['zwnj'] = unicodes['zwnj'] or 0x200C
+ -- the tounicode mapping is sparse and only needed for alternatives
+ local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?"))
+ data.luatex.tounicode, data.luatex.originals = tounicode, originals
+ local lumunic, uparser, oparser
+ if false then -- will become an option
+ lumunic = 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 -- play safe
+ 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
+ -- cidmap heuristics, beware, there is no guarantee for a match unless
+ -- the chain resolves
+ if (not unicode) and usedmap then
+ local foundindex = lpegmatch(oparser,name)
+ if foundindex then
+ unicode = cidcodes[foundindex] -- name to number
+ if unicode then
+ originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
+ else
+ local reference = cidnames[foundindex] -- number to name
+ 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
+ -- a.whatever or a_b_c.whatever or a_b_c (no numbers)
+ if not unicode then
+ local split = lpegmatch(ligsplitter,name)
+ local nplit = (split and #split) or 0
+ if nplit == 0 then
+ -- skip
+ 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 -- done then
+ originals[index], tounicode[index], nl, unicode = t, tounicode16sequence(t), nl + 1, true
+ end
+ end
+ end
+ -- last resort
+ 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.sortedpairs(data.glyphs) do
+ local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe
+ if toun then
+ logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
+ else
+ logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
+ end
+ end
+ end
+ if trace_loading and (ns > 0 or nl > 0) then
+ logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
+ end
+end
+
+-- the following is sort of obsolete
+--
+-- fonts.map.data = fonts.map.data or { }
+-- fonts.map.encodings = fonts.map.encodings or { }
+-- fonts.map.loaded = fonts.map.loaded or { }
+-- fonts.map.line = fonts.map.line or { }
+--
+-- function fonts.map.line.pdftex(e)
+-- if e.name and e.fontfile then
+-- local fullname = e.fullname or ""
+-- if e.slant and e.slant ~= 0 then
+-- if e.encoding then
+-- pdf.mapline(format('= %s %s "%g SlantFont" <%s <%s',e.name,fullname,e.slant,e.encoding,e.fontfile)))
+-- else
+-- pdf.mapline(format('= %s %s "%g SlantFont" <%s',e.name,fullname,e.slant,e.fontfile)))
+-- end
+-- elseif e.extend and e.extend ~= 1 and e.extend ~= 0 then
+-- if e.encoding then
+-- pdf.mapline(format('= %s %s "%g ExtendFont" <%s <%s',e.name,fullname,e.extend,e.encoding,e.fontfile)))
+-- else
+-- pdf.mapline(format('= %s %s "%g ExtendFont" <%s',e.name,fullname,e.extend,e.fontfile)))
+-- end
+-- else
+-- if e.encoding then
+-- pdf.mapline(format('= %s %s <%s <%s',e.name,fullname,e.encoding,e.fontfile)))
+-- else
+-- pdf.mapline(format('= %s %s <%s',e.name,fullname,e.fontfile)))
+-- end
+-- end
+-- else
+-- return nil
+-- end
+-- end
+--
+-- function fonts.map.flush(backend) -- will also erase the accumulated data
+-- local flushline = fonts.map.line[backend or "pdftex"] or fonts.map.line.pdftex
+-- for _, e in pairs(fonts.map.data) do
+-- flushline(e)
+-- end
+-- fonts.map.data = { }
+-- end
+--
+-- fonts.map.line.dvips = fonts.map.line.pdftex
+-- fonts.map.line.dvipdfmx = function() end
+--
+-- function fonts.map.convert_entries(filename)
+-- if not fonts.map.loaded[filename] then
+-- fonts.map.data, fonts.map.encodings = fonts.map.load_file(filename,fonts.map.data, fonts.map.encodings)
+-- fonts.map.loaded[filename] = true
+-- end
+-- end
+--
+-- function fonts.map.load_file(filename, entries, encodings)
+-- entries = entries or { }
+-- encodings = encodings or { }
+-- local f = io.open(filename)
+-- if f then
+-- local data = f:read("*a")
+-- if data then
+-- for line in gmatch(data,"(.-)[\n\t]") do
+-- if find(line,"^[%#%%%s]") then
+-- -- print(line)
+-- else
+-- local extend, slant, name, fullname, fontfile, encoding
+-- line = gsub(line,'"(.+)"', function(s)
+-- extend = find(s,'"([^"]+) ExtendFont"')
+-- slant = find(s,'"([^"]+) SlantFont"')
+-- return ""
+-- end)
+-- if not name then
+-- -- name fullname encoding fontfile
+-- name, fullname, encoding, fontfile = match(line,"^(%S+)%s+(%S*)[%s<]+(%S*)[%s<]+(%S*)%s*$")
+-- end
+-- if not name then
+-- -- name fullname (flag) fontfile encoding
+-- name, fullname, fontfile, encoding = match(line,"^(%S+)%s+(%S*)[%d%s<]+(%S*)[%s<]+(%S*)%s*$")
+-- end
+-- if not name then
+-- -- name fontfile
+-- name, fontfile = match(line,"^(%S+)%s+[%d%s<]+(%S*)%s*$")
+-- end
+-- if name then
+-- if encoding == "" then encoding = nil end
+-- entries[name] = {
+-- name = name, -- handy
+-- fullname = fullname,
+-- encoding = encoding,
+-- fontfile = fontfile,
+-- slant = tonumber(slant),
+-- extend = tonumber(extend)
+-- }
+-- encodings[name] = encoding
+-- elseif line ~= "" then
+-- -- print(line)
+-- end
+-- end
+-- end
+-- end
+-- f:close()
+-- end
+-- return entries, encodings
+-- end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-nms.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-nms.lua
new file mode 100644
index 00000000000..fd31bac0832
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-nms.lua
@@ -0,0 +1,495 @@
+if not modules then modules = { } end modules ['font-nms'] = {
+ version = 1.002,
+ comment = "companion to luaotfload.lua",
+ author = "Khaled Hosny and Elie Roux",
+ copyright = "Luaotfload Development Team",
+ license = "GPL"
+}
+
+fonts = fonts or { }
+fonts.names = fonts.names or { }
+
+local names = fonts.names
+local names_dir = "/luatex/generic/luaotfload/names/"
+names.version = 2.007 -- not the same as in context
+names.data = nil
+names.path = {
+ basename = "otfl-names.lua",
+ localdir = kpse.expand_var("$TEXMFVAR") .. names_dir,
+ systemdir = kpse.expand_var("$TEXMFSYSVAR") .. names_dir,
+}
+
+
+local splitpath, expandpath, glob, basename = file.split_path, kpse.expand_path, dir.glob, file.basename
+local upper, lower, format, gsub, match = string.upper, string.lower, string.format, string.gsub, string.match
+local rpadd = string.rpadd
+local utfgsub = unicode.utf8.gsub
+
+local trace_progress = true --trackers.register("names.progress", function(v) trace_progress = v end)
+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
+
+function names.load()
+ local localpath = names.path.localdir .. names.path.basename
+ local systempath = names.path.systemdir .. names.path.basename
+ local kpsefound = kpse.find_file(names.path.basename)
+ local data
+ if kpsefound and file.isreadable(kpsefound) then
+ data = dofile(kpsefound)
+ elseif file.isreadable(localpath) then
+ data = dofile(localpath)
+ elseif file.isreadable(systempath) then
+ data = dofile(systempath)
+ end
+ if data then
+ if trace_loading then
+ logs.report("load font", "loaded font names database: %s", foundname)
+ end
+ return data
+ end
+end
+
+local loaded = false
+
+local synonyms = {
+ regular = {normal=true, roman=true, plain=true, book=true, medium=true},
+ italic = {regularitalic=true, normalitalic=true, oblique=true, slant=true},
+ bolditalic = {boldoblique=true, boldslant=true},
+}
+
+-- a small hack to get the log message "no font names database loaded" only
+-- once in the log
+local log_message_shown = false
+
+function names.resolve(specification)
+ local tfm = resolvers.find_file(specification.name, "ofm")
+ local name = sanitize(specification.name)
+ local style = sanitize(specification.style) or "regular"
+ local size = tonumber(specification.optsize) or specification.size and specification.size / 65536
+ if tfm then
+ -- is a tfm font, skip names database
+ return specification.name, false
+ 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 ipairs(data.mappings) do
+ local family = sanitize(face.names.family)
+ local subfamily = sanitize(face.names.subfamily)
+ local fullname = sanitize(face.names.fullname)
+ local psname = sanitize(face.names.psname)
+ local fontname = sanitize(face.fontname)
+ local pfullname = sanitize(face.fullname)
+ local optsize, dsnsize, maxsize, minsize
+ if #face.size > 0 then
+ optsize = face.size
+ dsnsize = optsize[1] and optsize[1] / 10
+ maxsize = optsize[2] and optsize[2] / 10 or dsnsize -- can be nil
+ minsize = optsize[3] and optsize[3] / 10 or dsnsize -- can be nil
+ 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 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
+ else
+ found[1] = face
+ 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]
+ 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 ipairs(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]
+ end
+ end
+ -- no font found so far, fallback to filename
+ return specification.name, false
+ end
+ elseif not log_message_shown then
+ logs.report("load font", "no font names database loaded")
+ log_message_shown = true
+ end
+end
+
+names.resolvespec = names.resolve -- only supported in mkiv
+
+function names.set_log_level(level)
+ if level == 2 then
+ trace_progress = false
+ trace_loading = true
+ elseif level >= 3 then
+ trace_progress = false
+ trace_loading = true
+ trace_search = true
+ end
+end
+
+local lastislog = 0
+
+function log(fmt, ...)
+ lastislog = 1
+ texio.write_nl(format("luaotfload | %s", format(fmt,...)))
+end
+
+logs = logs or { }
+logs.report = logs.report or log
+
+local log = names.log
+
+-- The progress bar
+local function progress(current, total)
+ if trace_progress then
+-- local width = os.getenv("COLUMNS") -2 --doesn't work
+ local width = 78
+ local percent = current/total
+ local gauge = format("[%s]", rpadd(" ", width, " "))
+ if percent > 0 then
+ local done = rpadd("=", (width * percent) - 1, "=") .. ">"
+ gauge = format("[%s]", rpadd(done, width, " ") )
+ end
+ if lastislog == 1 then
+ texio.write_nl("")
+ lastislog = 0
+ end
+ io.stderr:write("\r"..gauge)
+ io.stderr:flush()
+ end
+end
+
+local function font_fullinfo(filename, subfont, texmf)
+ local t = { }
+ local f = fontloader.open(filename, subfont)
+ local m = f and 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 pairs(m.fontstyle_name) do
+ if v.lang == 1033 then
+ t.fontstyle_name = v.name
+ end
+ end
+ end
+ if m.names then
+ for _,v in pairs(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, -- 18, 4
+ family = v.names.preffamilyname or v.names.family, -- 17, 1
+ subfamily = t.fontstyle_name or v.names.prefmodifiers or v.names.subfamily, -- opt. style, 16, 2
+ psname = v.names.postscriptname --or t.fontname
+ }
+ end
+ end
+ 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,
+ }
+
+ return t
+end
+
+local function load_font(filename, fontnames, status, newfontnames, newstatus, texmf)
+ local mappings = newfontnames and newfontnames.mappings or { }
+ local oldmappings = fontnames.mappings or { }
+ if filename then
+ local timestamp, db_timestamp
+ db_timestamp = status[filename] and status[filename].timestamp
+ timestamp = lfs.attributes(filename, "modification")
+ newstatus[filename] = { }
+ newstatus[filename].timestamp = timestamp
+ newstatus[filename].index = {}
+ if db_timestamp == timestamp then
+ for _,v in ipairs(status[filename].index) do
+ mappings[#mappings+1] = oldmappings[v]
+ newstatus[filename].index[#newstatus[filename].index+1] = #mappings
+ end
+ if trace_loading then
+ logs.report("font already indexed: %s", filename)
+ end
+ return
+ end
+ if trace_loading then
+ logs.report("loading font: %s", filename)
+ end
+ local info = fontloader.info(filename)
+ if info then
+ if type(info) == "table" and #info > 1 then
+ for i in ipairs(info) do
+ local fullinfo = font_fullinfo(filename, i-1, texmf)
+ mappings[#mappings+1] = fullinfo
+ newstatus[filename].index[#newstatus[filename].index+1] = #mappings
+ end
+ else
+ local fullinfo = font_fullinfo(filename, false, texmf)
+ mappings[#mappings+1] = fullinfo
+ newstatus[filename].index[#newstatus[filename].index+1] = #mappings
+ end
+ else
+ if trace_loading then
+ logs.report("failed to load %s", filename)
+ 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
+ --]]
+ if os.type == "windows" or os.type == "msdos" or os.name == "cygwin" then
+ path = path:gsub('\\', '/')
+ path = path:lower()
+ -- for cygwin cases...
+ path = path:gsub('^/cygdrive/(%a)/', '%1:/')
+ end
+ path = file.collapse_path(path)
+ return path
+end
+
+fonts.path_normalize = path_normalize
+
+local function scan_dir(dirname, fontnames, status, newfontnames, newstatus, recursive, 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
+ - recursive is whether we scan all directories recursively (always false
+ in this script)
+ - texmf is a boolean saying if we are scanning a texmf directory (always
+ true in this script)
+ --]]
+ local list, found = { }, { }
+ local nbfound = 0
+ for _,ext in ipairs { "otf", "ttf", "ttc", "dfont" } do
+ if recursive then pat = "/**." else pat = "/*." end
+ if trace_search then
+ logs.report("scanning '%s' for '%s' fonts", dirname, ext)
+ end
+ found = glob(dirname .. pat .. ext)
+ -- note that glob fails silently on broken symlinks, which happens
+ -- sometimes in TeX Live.
+ if trace_search then
+ logs.report("%s fonts found", #found)
+ end
+ nbfound = nbfound + #found
+ table.append(list, found)
+ if trace_search then
+ logs.report("scanning '%s' for '%s' fonts", dirname, upper(ext))
+ end
+ found = glob(dirname .. pat .. upper(ext))
+ table.append(list, found)
+ nbfound = nbfound + #found
+ end
+ if trace_search then
+ logs.report("%d fonts found in '%s'", nbfound, dirname)
+ end
+ for _,fnt in ipairs(list) do
+ fnt = path_normalize(fnt)
+ load_font(fnt, fontnames, status, newfontnames, newstatus, texmf)
+ end
+end
+
+local function scan_texmf_tree(fontnames, status, newfontnames, newstatus)
+ --[[
+ The function that scans all fonts in the texmf tree, through kpathsea
+ variables OPENTYPEFONTS and TTFONTS of texmf.cnf
+ --]]
+ if trace_progress then
+ if expandpath("$OSFONTDIR"):is_empty() then
+ logs.report("scanning TEXMF fonts:")
+ else
+ logs.report("scanning TEXMF and OS fonts:")
+ end
+ end
+ local fontdirs = expandpath("$OPENTYPEFONTS")
+ fontdirs = fontdirs .. gsub(expandpath("$TTFONTS"), "^\.", "")
+ if not fontdirs:is_empty() then
+ local explored_dirs = {}
+ fontdirs = splitpath(fontdirs)
+ -- hack, don't scan current dir
+ table.remove(fontdirs, 1)
+ count = 0
+ for _,d in ipairs(fontdirs) do
+ if not explored_dirs[d] then
+ count = count + 1
+ progress(count, #fontdirs)
+ scan_dir(d, fontnames, status, newfontnames, newstatus, false, true)
+ explored_dirs[d] = true
+ end
+ end
+ end
+end
+
+local function read_fcdata(data)
+ --[[
+ this function takes raw data returned by fc-list, parses it, normalizes the
+ paths and makes a list out of it.
+ --]]
+ local list = { }
+ for line in data:lines() do
+ line = line:gsub(": ", "")
+ local ext = lower(match(line,"^.+%.([^/\\]-)$"))
+ if ext == "otf" or ext == "ttf" or ext == "ttc" or ext == "dfont" then
+ list[#list+1] = path_normalize(line:gsub(": ", ""))
+ end
+ end
+ return list
+end
+
+local function scan_os_fonts(fontnames, status, newfontnames, newstatus)
+ --[[
+ This function scans the OS fonts through fontcache (fc-list), it executes
+ only if OSFONTDIR is empty (which is the case under most Unix by default).
+ If OSFONTDIR is non-empty, this means that the system fonts it contains have
+ already been scanned, and thus we don't scan them again.
+ --]]
+ if expandpath("$OSFONTDIR"):is_empty() then
+ if trace_progress then
+ logs.report("scanning OS fonts:")
+ end
+ if trace_search then
+ logs.report("executing 'fc-list : file' and parsing its result...")
+ end
+ local data = io.popen("fc-list : file", 'r')
+ local list = read_fcdata(data)
+ data:close()
+ if trace_search then
+ logs.report("%d fonts found", #list)
+ end
+ count = 0
+ for _,fnt in ipairs(list) do
+ count = count + 1
+ progress(count, #list)
+ load_font(fnt, fontnames, status, newfontnames, newstatus, false)
+ end
+ end
+end
+
+local function fontnames_init()
+ return {
+ mappings = { },
+ version = names.version,
+ }
+end
+
+local function status_init()
+ return {
+ version = names.version,
+ }
+end
+
+local function update(fontnames, status, force)
+ --[[
+ The main function, scans everything
+ - fontnames is the final table to return
+ - force is whether we rebuild it from scratch or not
+ - status is a table containing the current status of the database
+ --]]
+ if force then
+ fontnames = fontnames_init()
+ status = status_init()
+ else
+ if not fontnames or not fontnames.version or fontnames.version ~= names.version
+ or not status or not status.version or status.version ~= names.version then
+ fontnames = fontnames_init()
+ status = status_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()
+ local newstatus = status_init()
+ scan_texmf_tree(fontnames, status, newfontnames, newstatus)
+ scan_os_fonts (fontnames, status, newfontnames, newstatus)
+ return newfontnames, newstatus
+end
+
+names.scan = scan_dir
+names.update = update
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ota.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ota.lua
index e2fa3f290da..558e2fc8063 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ota.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ota.lua
@@ -41,6 +41,8 @@ local insert_node_after = node.insert_after
local insert_node_before = node.insert_before
local traverse_node_list = node.traverse
+local new_glue_node = nodes.glue
+
local fontdata = fonts.ids
local state = attributes.private('state')
@@ -302,11 +304,12 @@ function fonts.analyzers.methods.arab(head,font,attr) -- maybe make a special ve
end
first, last = finish(first,last)
if removejoiners then
+ -- is never head
for i=1,#joiners do
- head = delete_node(head,joiners[i])
+ delete_node(head,joiners[i])
end
for i=1,#nonjoiners do
- head = replace_node(head,nonjoiners[i],nodes.glue(0)) -- or maybe a kern
+ replace_node(head,nonjoiners[i],new_glue_node(0)) -- or maybe a kern
end
end
return head, done
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otb.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otb.lua
index 127d4c21896..a3d347737c8 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otb.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otb.lua
@@ -9,6 +9,7 @@ if not modules then modules = { } end modules ['font-otb'] = {
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
@@ -69,7 +70,7 @@ local function resolve_ligatures(tfmdata,ligatures,kind)
for k,v in next, ligatures do
local lig = v[1]
if not done[lig] then
- local ligs = split_at_space:match(lig)
+ 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]
@@ -133,43 +134,12 @@ local function resolve_ligatures(tfmdata,ligatures,kind)
end
end
-local function collect_lookups(otfdata,kind,script,language)
- -- maybe store this in the font
- 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
-
local splitter = lpeg.splitat(" ")
function prepare_base_substitutions(tfmdata,kind,value) -- we can share some code with the node features
if value then
local otfdata = tfmdata.shared.otfdata
- local validlookups, lookuplist = collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ local validlookups, lookuplist = otf.collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
if validlookups then
local ligatures = { }
local unicodes = tfmdata.unicodes -- names to unicodes
@@ -177,9 +147,84 @@ function prepare_base_substitutions(tfmdata,kind,value) -- we can share some cod
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] -- p.variant
+ 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] -- p.components
+ if pc then
+ -- a bit optimized ugliness
+ 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
+ -- we assume that it's no table
+ 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.lookups
+ 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]
@@ -187,62 +232,9 @@ function prepare_base_substitutions(tfmdata,kind,value) -- we can share some cod
if ps then
for i=1,#ps do
local p = ps[i]
- local t = p[1]
- if t == 'substitution' then
- local pv = p[2] -- p.variant
- 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
- elseif t == 'alternate' then
- local pc = p[2] -- p.components
- if pc then
- -- a bit optimized ugliness
- if value == 1 then
- pc = splitter:match(pc)
- elseif value == 2 then
- local a, b = splitter:match(pc)
- pc = b or a
- else
- pc = { splitter:match(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",cref(kind,lookup),gref(descriptions,k),gref(descriptions,upc))
- end
- changed[k] = upc
- end
- end
- end
- end
- elseif t == 'ligature' and not changed[k] then
- local pc = p[2]
- if pc then
- if trace_baseinit and trace_ligatures then
- local upc = { splitter:match(pc) }
- for i=1,#upc do upc[i] = unicodes[upc[i]] end
- -- we assume that it's no table
- 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
+ local a = actions[p[1]]
+ if a then
+ a(p,lookup,k,glyph,unicode)
end
end
end
@@ -259,37 +251,46 @@ end
local function prepare_base_kerns(tfmdata,kind,value) -- todo what kind of kerns, currently all
if value then
local otfdata = tfmdata.shared.otfdata
- local validlookups, lookuplist = collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
+ local validlookups, lookuplist = otf.collect_lookups(otfdata,kind,tfmdata.script,tfmdata.language)
if validlookups then
local unicodes = tfmdata.unicodes -- names to 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
+ local dk = d.mykerns -- shared
if dk then
- 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 -- maybe no 0 test here
- 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)
+ local s = sharedkerns[dk]
+ if s == false then
+ -- skip
+ 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 -- maybe no 0 test here
+ 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 -- no empty assignments
+ else
+ sharedkerns[dk] = false
+ end
end
- if done then
- chr.kerns = t -- no empty assignments
- end
- -- elseif d.kerns then
- -- logs.report("define otf","%s: invalid mykerns for %s",cref(kind),gref(descriptions,u))
end
end
end
@@ -304,12 +305,13 @@ end
-- to do complete mixed runs and not run featurewise (as we did before).
local supported_gsub = {
- 'liga','dlig','rlig','hlig',
- 'pnum','onum','tnum','lnum',
+ 'liga', 'dlig', 'rlig', 'hlig',
+ 'pnum', 'onum', 'tnum', 'lnum',
'zero',
- 'smcp','cpsp','c2sc','ornm','aalt',
- 'hwid','fwid',
+ 'smcp', 'cpsp', 'c2sc', 'ornm', 'aalt',
+ 'hwid', 'fwid',
'ssty', 'rtlm', -- math
+-- 'tlig', 'trep',
}
local supported_gpos = {
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otc.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otc.lua
index 059748dc5ef..64e09f8b117 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otc.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otc.lua
@@ -21,6 +21,8 @@ local tfm = fonts.tfm
-- instead of "script = "DFLT", langs = { 'dflt' }" we now use wildcards (we used to
-- have always); some day we can write a "force always when true" trick for other
-- features as well
+--
+-- we could have a tnum variant as well
local extra_lists = {
tlig = {
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otf.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otf.lua
index 6900b844591..29c56cd0012 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otf.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otf.lua
@@ -11,6 +11,7 @@ local utf = unicode.utf8
local concat, getn, utfbyte = table.concat, table.getn, utf.byte
local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip
local type, next, tonumber, tostring = type, next, tonumber, tostring
+local 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)
@@ -18,14 +19,10 @@ local trace_features = false trackers.register("otf.features", function(v
local trace_dynamics = false trackers.register("otf.dynamics", function(v) trace_dynamics = v end)
local trace_sequences = false trackers.register("otf.sequences", function(v) trace_sequences = v end)
local trace_math = false trackers.register("otf.math", function(v) trace_math = v end)
-local trace_unimapping = false trackers.register("otf.unimapping", function(v) trace_unimapping = v end)
local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
--~ trackers.enable("otf.loading")
-local zwnj = 0x200C
-local zwj = 0x200D
-
--[[ldx--
<p>The fontforge table has organized lookups in a certain way. A first implementation
of this code was organized featurewise: information related to features was
@@ -83,13 +80,16 @@ otf.features.default = otf.features.default or { }
otf.enhancers = otf.enhancers or { }
otf.glists = { "gsub", "gpos" }
-otf.version = 2.636 -- beware: also sync font-mis.lua
+otf.version = 2.645 -- beware: also sync font-mis.lua
otf.pack = true -- beware: also sync font-mis.lua
otf.syncspace = true
otf.notdef = false
otf.cache = containers.define("fonts", "otf", otf.version, true)
otf.cleanup_aat = false -- only context
+local wildcard = "*"
+local default = "dflt"
+
--[[ldx--
<p>We start with a lot of tables and related functions.</p>
--ldx]]--
@@ -178,7 +178,7 @@ otf.tables.valid_fields = {
local function load_featurefile(ff,featurefile)
if featurefile then
- featurefile = resolvers.find_file(file.addsuffix(featurefile,'fea')) -- "FONTFEATURES"
+ 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)
@@ -192,7 +192,7 @@ 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",name)
+ logs.report("load otf","enhance: %s (%s)",name,filename)
end
enhancer(data,filename)
end
@@ -207,6 +207,7 @@ local enhancers = {
"reorganize mark classes",
"reorganize kerns", -- moved here
"flatten glyph lookups", "flatten anchor tables", "flatten feature tables",
+ "simplify glyph lookups", -- some saving
"prepare luatex tables",
"analyse features", "rehash features",
"analyse anchors", "analyse marks", "analyse unicodes", "analyse subtables",
@@ -214,6 +215,7 @@ local enhancers = {
"share widths",
"strip not needed data",
"migrate metadata",
+ "check math parameters",
}
function otf.load(filename,format,sub,featurefile)
@@ -238,9 +240,15 @@ function otf.load(filename,format,sub,featurefile)
ff, messages = fontloader.open(filename)
end
if trace_loading and messages and #messages > 0 then
- for m=1,#messages do
- logs.report("load otf","warning: %s",messages[m])
+ 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)
@@ -251,6 +259,7 @@ function otf.load(filename,format,sub,featurefile)
logs.report("load otf","enhancing ...")
for e=1,#enhancers do
otf.enhance(enhancers[e],data,filename)
+ io.flush() -- we want instant messages
end
if otf.pack and not fonts.verbose then
otf.enhance("pack",data,filename)
@@ -494,142 +503,7 @@ otf.enhancers["analyse marks"] = function(data,filename)
end
end
-local separator = lpeg.S("_.")
-local other = lpeg.C((1 - separator)^1)
-local ligsplitter = lpeg.Ct(other * (separator * other)^0)
-
---~ print(table.serialize(ligsplitter:match("this")))
---~ print(table.serialize(ligsplitter:match("this.that")))
---~ print(table.serialize(ligsplitter:match("japan1.123")))
---~ print(table.serialize(ligsplitter:match("such_so_more")))
---~ print(table.serialize(ligsplitter:match("such_so_more.that")))
-
-otf.enhancers["analyse unicodes"] = function(data,filename)
- local tounicode16, tounicode16sequence = fonts.map.tounicode16, fonts.map.tounicode16sequence
- local unicodes = data.luatex.unicodes
- -- we need to move this code
- unicodes['space'] = unicodes['space'] or 32 -- handly later on
- unicodes['hyphen'] = unicodes['hyphen'] or 45 -- handly later on
- unicodes['zwj'] = unicodes['zwj'] or zwj -- handly later on
- unicodes['zwnj'] = unicodes['zwnj'] or zwnj -- handly later on
- -- the tounicode mapping is sparse and only needed for alternatives
- local tounicode, originals, ns, nl, private, unknown = { }, { }, 0, 0, fonts.private, format("%04X",utfbyte("?"))
- data.luatex.tounicode, data.luatex.originals = tounicode, originals
- local lumunic, uparser, oparser
- if false then -- will become an option
- lumunic = fonts.map.load_lum_table(filename)
- lumunic = lumunic and lumunic.tounicode
- end
- local cidinfo, cidnames, cidcodes = data.cidinfo
- local usedmap = cidinfo and cidinfo.usedname
- usedmap = usedmap and fonts.cid.map[usedmap]
- if usedmap then
- oparser = usedmap and fonts.map.make_name_parser(cidinfo.ordering)
- cidnames = usedmap.names
- cidcodes = usedmap.unicodes
- end
- uparser = fonts.map.make_name_parser()
- 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 -- play safe
- 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]
- if unicode then
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
- end
- -- cidmap heuristics, beware, there is no guarantee for a match unless
- -- the chain resolves
- if (not unicode) and usedmap then
- local foundindex = oparser:match(name)
- if foundindex then
- unicode = cidcodes[foundindex] -- name to number
- if not unicode then
- local reference = cidnames[foundindex] -- number to name
- if reference then
- local foundindex = oparser:match(reference)
- if foundindex then
- unicode = cidcodes[foundindex]
- if unicode then
- originals[index], tounicode[index], ns = unicode, tounicode16(unicode), ns + 1
- end
- end
- if not unicode then
- local foundcodes, multiple = uparser:match(reference)
- if foundcodes then
- if multiple then
- originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
- else
- originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
- end
- end
- end
- end
- end
- end
- end
- -- a.whatever or a_b_c.whatever or a_b_c (no numbers)
- if not unicode then
- local split = ligsplitter:match(name)
- local nplit = (split and #split) or 0
- if nplit == 0 then
- -- skip
- elseif nplit == 1 then
- local base = split[1]
- unicode = unicodes[base] or (agl and agl[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 (agl and agl[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 -- done then
- originals[index], tounicode[index], nl, unicode = t, tounicode16sequence(t), nl + 1, true
- end
- end
- end
- -- last resort
- if not unicode then
- local foundcodes, multiple = uparser:match(name)
- if foundcodes then
- if multiple then
- originals[index], tounicode[index], nl, unicode = foundcodes, tounicode16sequence(foundcodes), nl + 1, true
- else
- originals[index], tounicode[index], ns, unicode = foundcodes, tounicode16(foundcodes), ns + 1, foundcodes
- end
- end
- end
- if not unicode then
- originals[index], tounicode[index] = 0xFFFD, "FFFD"
- end
- end
- end
- if trace_unimapping then
- for index, glyph in table.sortedpairs(data.glyphs) do
- local toun, name, unic = tounicode[index], glyph.name, glyph.unicode or -1 -- play safe
- if toun then
- logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X, tounicode: %s",index,name,unic,toun)
- else
- logs.report("load otf","internal: 0x%05X, name: %s, unicode: 0x%05X",index,name,unic)
- end
- end
- end
- if trace_loading and (ns > 0 or nl > 0) then
- logs.report("load otf","enhance: %s tounicode entries added (%s ligatures)",nl+ns, ns)
- end
-end
+otf.enhancers["analyse unicodes"] = fonts.map.add_to_unicode
otf.enhancers["analyse subtables"] = function(data,filename)
data.luatex = data.luatex or { }
@@ -986,6 +860,129 @@ end
-- kern: ttf has a table with kerns
+--~ otf.enhancers["reorganize kerns"] = function(data,filename)
+--~ local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
+--~ local mkdone = false
+--~ for index, glyph in next, data.glyphs do
+--~ 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 -- brrr, wrong! we miss the non unicode ones
+--~ 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 -- saves space and time
+--~ 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
+--~ 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 -- name is inconsistent with anchor_classes
+--~ if kernclass then -- the next one is quite slow
+--~ for k=1,#kernclass do
+--~ local kcl = kernclass[k]
+--~ local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
+--~ if type(lookups) ~= "table" then
+--~ lookups = { lookups }
+--~ end
+--~ for l=1,#lookups do
+--~ local lookup = lookups[l]
+--~ -- weird, as maxfirst and maxseconds can have holes
+--~ local maxfirsts, maxseconds = getn(firsts), getn(seconds)
+--~ if trace_loading then
+--~ logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
+--~ end
+--~ for fk, fv in next, firsts do
+--~ for first in gmatch(fv,"[^ ]+") do
+--~ local first_unicode = unicodes[first]
+--~ if type(first_unicode) == "number" then
+--~ first_unicode = { first_unicode }
+--~ end
+--~ for f=1,#first_unicode do
+--~ local glyph = glyphs[mapmap[first_unicode[f]]]
+--~ if glyph then
+--~ local mykerns = glyph.mykerns
+--~ if not mykerns then
+--~ mykerns = { } -- unicode indexed !
+--~ glyph.mykerns = mykerns
+--~ end
+--~ local lookupkerns = mykerns[lookup]
+--~ if not lookupkerns then
+--~ lookupkerns = { }
+--~ mykerns[lookup] = lookupkerns
+--~ end
+--~ for sk, sv in next, seconds do
+--~ local offset = offsets[(fk-1) * maxseconds + sk]
+--~ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
+--~ for second in gmatch(sv,"[^ ]+") do
+--~ local second_unicode = unicodes[second]
+--~ if type(second_unicode) == "number" then
+--~ lookupkerns[second_unicode] = offset
+--~ else
+--~ for s=1,#second_unicode do
+--~ lookupkerns[second_unicode[s]] = offset
+--~ end
+--~ end
+--~ end
+--~ end
+--~ elseif trace_loading then
+--~ logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])
+--~ end
+--~ end
+--~ 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["reorganize kerns"] = function(data,filename)
local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
local mkdone = false
@@ -1038,6 +1035,9 @@ otf.enhancers["reorganize kerns"] = function(data,filename)
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
@@ -1045,54 +1045,75 @@ otf.enhancers["reorganize kerns"] = function(data,filename)
for s=1,#subtables do
local subtable = subtables[s]
local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
- if kernclass then
+ if kernclass then -- the next one is quite slow
for k=1,#kernclass do
local kcl = kernclass[k]
local firsts, seconds, offsets, lookups = kcl.firsts, kcl.seconds, kcl.offsets, kcl.lookup -- singular
if type(lookups) ~= "table" then
lookups = { lookups }
end
+ local split = { }
for l=1,#lookups do
local lookup = lookups[l]
+ -- weird, as maxfirst and maxseconds can have holes, first seems to be indexed, seconds starts at 2
local maxfirsts, maxseconds = getn(firsts), getn(seconds)
+ for _, s in next, firsts do
+ split[s] = split[s] or lpegmatch(splitter,s)
+ end
+ for _, s in next, seconds do
+ split[s] = split[s] or lpegmatch(splitter,s)
+ end
if trace_loading then
logs.report("load otf", "adding kernclass %s with %s times %s pairs",lookup, maxfirsts, maxseconds)
end
- for fk, fv in next, firsts do
- for first in gmatch(fv,"[^ ]+") do
- local first_unicode = unicodes[first]
- if type(first_unicode) == "number" then
- first_unicode = { first_unicode }
+ local function do_it(fk,first_unicode)
+ local glyph = glyphs[mapmap[first_unicode]]
+ if glyph then
+ local mykerns = glyph.mykerns
+ if not mykerns then
+ mykerns = { } -- unicode indexed !
+ glyph.mykerns = mykerns
end
- for f=1,#first_unicode do
- local glyph = glyphs[mapmap[first_unicode[f]]]
- if glyph then
- local mykerns = glyph.mykerns
- if not mykerns then
- mykerns = { } -- unicode indexed !
- glyph.mykerns = mykerns
- end
- local lookupkerns = mykerns[lookup]
- if not lookupkerns then
- lookupkerns = { }
- mykerns[lookup] = lookupkerns
- end
- for sk, sv in next, seconds do
- local offset = offsets[(fk-1) * maxseconds + sk]
- --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
- for second in gmatch(sv,"[^ ]+") do
- local second_unicode = unicodes[second]
- if type(second_unicode) == "number" then
- lookupkerns[second_unicode] = offset
- else
- for s=1,#second_unicode do
- lookupkerns[second_unicode[s]] = offset
- end
+ local lookupkerns = mykerns[lookup]
+ if not lookupkerns then
+ lookupkerns = { }
+ mykerns[lookup] = lookupkerns
+ end
+ local baseoffset = (fk-1) * maxseconds
+ for sk=2,maxseconds do
+ local sv = seconds[sk]
+ local offset = offsets[baseoffset + sk]
+ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
+ local splt = split[sv]
+ if splt then
+ for i=1,#splt do
+ local second_unicode = splt[i]
+ if tonumber(second_unicode) then
+ lookupkerns[second_unicode] = offset
+ else
+ for s=1,#second_unicode do
+ lookupkerns[second_unicode[s]] = offset
end
end
end
- elseif trace_loading then
- logs.report("load otf", "no glyph data for U+%04X", first_unicode[f])
+ end
+ end
+ elseif trace_loading then
+ logs.report("load otf", "no glyph data for U+%04X", first_unicode)
+ end
+ end
+ for fk=1,#firsts do
+ local fv = firsts[fk]
+ local splt = split[fv]
+ if splt then
+ for i=1,#splt do
+ local first_unicode = splt[i]
+ if tonumber(first_unicode) then
+ do_it(fk,first_unicode)
+ else
+ for f=1,#first_unicode do
+ do_it(fk,first_unicode[f])
+ end
end
end
end
@@ -1166,10 +1187,31 @@ otf.enhancers["migrate metadata"] = function(data,filename)
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
- if v.lookups then
- for kk, vv in next, v.lookups 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
@@ -1219,6 +1261,31 @@ otf.enhancers["flatten glyph lookups"] = function(data,filename)
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
@@ -1459,7 +1526,7 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
local variants = m.horiz_variants
if variants then
local c = char
- for n in variants:gmatch("[^ ]+") do
+ for n in gmatch(variants,"[^ ]+") do
local un = unicodes[n]
if un and u ~= un then
c.next = un
@@ -1471,7 +1538,7 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
local variants = m.vert_variants
if variants then
local c = char
- for n in variants:gmatch("[^ ]+") do
+ for n in gmatch(variants,"[^ ]+") do
local un = unicodes[n]
if un and u ~= un then
c.next = un
@@ -1505,8 +1572,6 @@ function otf.copy_to_tfm(data,cache_id) -- we can save a copy when we reorder th
tfm.cidinfo = data.cidinfo
tfm.cidinfo.registry = tfm.cidinfo.registry or ""
tfm.type = "real"
- tfm.stretch = 0 -- stretch
- tfm.slant = 0 -- slant
tfm.direction = 0
tfm.boundarychar_label = 0
tfm.boundarychar = 65536
@@ -1615,7 +1680,7 @@ function tfm.read_from_open_type(specification)
end
end
end
- tfmtable = tfm.scale(tfmtable,s)
+ tfmtable = tfm.scale(tfmtable,s,specification.relativeid)
-- here we resolve the name; file can be relocated, so this info is not in the cache
local filename = (otfdata and otfdata.luatex and otfdata.luatex.filename) or specification.filename
if not filename then
@@ -1635,9 +1700,52 @@ function tfm.read_from_open_type(specification)
tfmtable.format = specification.format
end
tfmtable.name = tfmtable.filename or tfmtable.fullname or tfmtable.fontname
+ if tfm.fontname_mode == "specification" then
+ -- not to be used in context !
+ 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
end
fonts.logger.save(tfmtable,file.extname(specification.filename),specification)
end
--~ print(tfmtable.fullname)
return tfmtable
end
+
+-- helpers
+
+function otf.collect_lookups(otfdata,kind,script,language)
+ -- maybe store this in the font
+ 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
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otn.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otn.lua
index fb04b367ea0..3aa1927d35f 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otn.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-otn.lua
@@ -10,6 +10,9 @@ if not modules then modules = { } end modules ['font-otn'] = {
-- much functionality could only be implemented thanks to the husayni font
-- of Idris Samawi Hamid to who we dedicate this module.
+-- I'm in the process of cleaning up the code (which happens in another
+-- file) so don't rely on things staying the same.
+
-- some day when we can jit this, we can use more functions
-- we can use more lpegs when lpeg is extended with function args and so
@@ -327,6 +330,7 @@ local function toligature(kind,lookupname,start,stop,char,markflag,discfound) --
next.prev = lignode
end
lignode.next, lignode.prev = next, prev
+ start = lignode
-- print("start->end",nodes.tosequence(start))
else -- start is the ligature
local deletemarks = markflag ~= "mark"
@@ -456,7 +460,8 @@ end
function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or maybe pass lookup ref
local s, stop, discfound = start.next, nil, false
- if marks[start.char] then
+ local startchar = start.char
+ if marks[startchar] then
while s do
local id = s.id
if id == glyph and s.subtype<256 then
@@ -479,7 +484,7 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
end
if stop and ligature[2] then
if trace_ligatures then
- local startchar, stopchar = start.char, stop.char
+ 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
@@ -518,7 +523,7 @@ function handlers.gsub_ligature(start,kind,lookupname,ligature,sequence) --or ma
end
if stop and ligature[2] then
if trace_ligatures then
- local startchar, stopchar = start.char, stop.char
+ 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
@@ -1536,6 +1541,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
local skipmark, skipligature, skipbase = flags[1], flags[2], 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, current, last = true, start, start
local ck = contexts[k]
@@ -1570,6 +1576,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
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
@@ -1614,6 +1621,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
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
@@ -1668,6 +1676,7 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
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
@@ -1733,8 +1742,47 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
end
else
-- actually this needs a more complex treatment for which we will use chainmores
+--~ local i = 1
+--~ repeat
+--~ 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)
+--~ -- messy since last can be changed !
+--~ if ok then
+--~ done = true
+--~ start = start.next
+--~ if n then
+--~ -- skip next one(s) if ligature
+--~ i = i + n - 1
+--~ end
+--~ end
+--~ else
+--~ logprocess("%s: multiple subchains for %s are not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type)
+--~ end
+--~ i = i + 1
+--~ until i > nofchainlookups
+
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]
@@ -1744,17 +1792,18 @@ local function normal_handle_contextchain(start,kind,chainname,contexts,sequence
-- messy since last can be changed !
if ok then
done = true
- start = start.next
- if n then
- -- skip next one(s) if ligature
- i = i + n - 1
- end
+ -- skip next one(s) if ligature
+ 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
- i = i + 1
+ start = start.next
until i > nofchainlookups
+
end
else
local replacements = ck[7]
@@ -1833,9 +1882,6 @@ local resolved = { } -- we only resolve a font,script,language pair once
-- todo: pass all these 'locals' in a table
--- maybe some day i'll make an alternative that works on 'sub direction runs' which might be
--- more efficient for arabic but it has quite some consequences
-
function fonts.methods.node.otf.features(head,font,attr)
if trace_steps then
checkstep(head)
@@ -1879,7 +1925,7 @@ function fonts.methods.node.otf.features(head,font,attr)
local ra = rl [attr] if ra == nil then ra = { } rl [attr] = ra end -- attr can be false
-- sequences always > 1 so no need for optimization
for s=1,#sequences do
- local pardir, txtdir = 0, { }
+ local pardir, txtdir = 0, { }
local success = false
local sequence = sequences[s]
local r = ra[s] -- cache
@@ -1905,12 +1951,10 @@ function fonts.methods.node.otf.features(head,font,attr)
-- only first attribute match check, so we assume simple fina's
-- default can become a font feature itself
if l[language] then
---~ valid, what = true, language
valid, what = s_e or a_e, language
-- elseif l[default] then
-- valid, what = true, default
elseif l[wildcard] then
---~ valid, what = true, wildcard
valid, what = s_e or a_e, wildcard
end
if valid then
@@ -1945,12 +1989,12 @@ function fonts.methods.node.otf.features(head,font,attr)
local handler = handlers[typ]
local thecache = featuredata[typ] or { }
-- we need to get rid of this slide !
- start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo
+ 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 then
---~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then
- if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then
+ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) then
+--~ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) then
for i=1,#subtables do
local lookupname = subtables[i]
local lookupcache = thecache[lookupname]
@@ -1978,7 +2022,7 @@ function fonts.methods.node.otf.features(head,font,attr)
local handler = handlers[typ]
local ns = #subtables
local thecache = featuredata[typ] or { }
- start = head -- local ?
+ local start = head -- local ?
rlmode = 0 -- to be checked ?
if ns == 1 then
local lookupname = subtables[1]
@@ -1989,14 +2033,13 @@ function fonts.methods.node.otf.features(head,font,attr)
while start do
local id = start.id
if id == glyph then
---~ if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
- if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+--~ if start.font == font and start.subtype<256 and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ if start.font == font and start.subtype<256 and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
local lookupmatch = lookupcache[start.char]
if lookupmatch then
-- sequence kan weg
local ok
start, ok = handler(start,r[4],lookupname,lookupmatch,sequence,featuredata,1)
---~ texio.write_nl(tostring(lookupname),tostring(lookupmatch),tostring(ok))
if ok then
success = true
end
@@ -2021,25 +2064,6 @@ function fonts.methods.node.otf.features(head,font,attr)
-- start = start.next
-- end
elseif id == whatsit then
---~ if subtype == 7 then
---~ local dir = start.dir
---~ if dir == "+TRT" then
---~ rlmode = -1
---~ elseif dir == "+TLT" then
---~ rlmode = 1
---~ else
---~ rlmode = 0
---~ end
---~ elseif subtype == 6 then
---~ local dir = start.dir
---~ if dir == "TRT" then
---~ rlmode = -1
---~ elseif dir == "TLT" then
---~ rlmode = 1
---~ else
---~ rlmode = 0
---~ end
---~ end
local subtype = start.subtype
if subtype == 7 then
local dir = start.dir
@@ -2084,8 +2108,8 @@ function fonts.methods.node.otf.features(head,font,attr)
while start do
local id = start.id
if id == glyph then
---~ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
- if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
+ if start.subtype<256 and start.font == font and (not attr or has_attribute(start,0,attr)) and (not attribute or has_attribute(start,state,attribute)) then
+--~ if start.subtype<256 and start.font == font and has_attribute(start,0,attr) and (not attribute or has_attribute(start,state,attribute)) then
for i=1,ns do
local lookupname = subtables[i]
local lookupcache = thecache[lookupname]
@@ -2125,59 +2149,40 @@ function fonts.methods.node.otf.features(head,font,attr)
-- end
elseif id == whatsit then
local subtype = start.subtype
---~ if subtype == 7 then
---~ local dir = start.dir
---~ if dir == "+TRT" then
---~ rlmode = -1
---~ elseif dir == "+TLT" then
---~ rlmode = 1
---~ else
---~ rlmode = 0
---~ end
---~ elseif subtype == 6 then
---~ local dir = start.dir
---~ if dir == "TRT" then
---~ rlmode = -1
---~ elseif dir == "TLT" then
---~ rlmode = 1
---~ else
---~ rlmode = 0
---~ end
---~ end
- 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
+ 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
- --~ txtdir = { }
+ end
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)
+ 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
+ --~ txtdir = { }
+ 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
@@ -2273,142 +2278,153 @@ local function prepare_lookups(tfmdata)
-- we can change the otf table after loading but then we need to adapt base mode
-- as well (no big deal)
--
- for unicode, glyph in next, descriptions do
- local lookups = glyph.lookups
- if lookups then
- for lookup, whatever in next, lookups do
- for i=1,#whatever do -- normaly one
- local p = whatever[i]
- local what = p[1]
- if what == 'substitution' then
- 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
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: substitution %s => %s",lookup,old,new)
---~ end
- break
- elseif what == 'multiple' then
- 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
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: multiple %s => %s",lookup,old,concat(new," "))
---~ end
+ local action = {
+ substitution = function(p,lookup,k,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
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: substitution %s => %s",lookup,old,new)
+ --~ end
+ end,
+ multiple = function (p,lookup,k,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
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: multiple %s => %s",lookup,old,concat(new," "))
+ --~ end
+ end,
+ alternate = function(p,lookup,k,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
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: alternate %s => %s",lookup,old,concat(new,"|"))
+ --~ end
+ end,
+ ligature = function (p,lookup,k,glyph,unicode)
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: ligature %s => %s",lookup,p[2],glyph.name)
+ --~ end
+ 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 what == 'alternate' then
- 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
+ elseif type(u) == "number" then
+ if not t[u] then
+ t[u] = { { } }
end
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: alternate %s => %s",lookup,old,concat(new,"|"))
---~ end
- break
- elseif what == "ligature" then
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: ligature %s => %s",lookup,p[2],glyph.name)
---~ end
- 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
+ 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
- first = false
+ tu = t[u]
+ t = tu
else
- s = unicodes[s]
- local t1 = t[1]
- if not t1[s] then
- t1[s] = { { } }
+ if not t[u] then
+ tt[u] = tu
end
- t = t1[s]
end
end
- t[2] = unicode
- elseif what == 'position' then
- -- not used
- local s = position[lookup]
- if not s then s = { } position[lookup] = s end
- s[unicode] = p[2] -- direct pointer to kern spec
- elseif what == 'pair' then
- 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
- -- todo: fast check for space
- 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 -- direct pointer to main table
- else
- for i=1,#upc do
- others[upc[i]] = p -- direct pointer to main table
- end
- end
- end
- elseif type(upc) == "number" then
- others[upc] = p -- direct pointer to main table
- else
- for i=1,#upc do
- others[upc[i]] = p -- direct pointer to main table
- 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,k,glyph,unicode)
+ -- not used
+ local s = position[lookup]
+ if not s then s = { } position[lookup] = s end
+ s[unicode] = p[2] -- direct pointer to kern spec
+ end,
+ pair = function(p,lookup,k,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
+ -- todo: fast check for space
+ 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 -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
end
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: pair for U+%04X",lookup,unicode)
---~ end
end
end
+ elseif type(upc) == "number" then
+ others[upc] = p -- direct pointer to main table
+ else
+ for i=1,#upc do
+ others[upc[i]] = p -- direct pointer to main table
+ end
+ end
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: pair for U+%04X",lookup,unicode)
+ --~ 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,k,glyph,unicode)
+ end
+ end
+ local lookups = glyph.mlookups
+ if lookups then
+ for lookup, whatever in next, lookups do
+ for i=1,#whatever do -- normaly one
+ local p = whatever[i]
+ action[p[1]](p,lookup,k,glyph,unicode)
+ end
end
end
local list = glyph.mykerns
@@ -2417,9 +2433,9 @@ local function prepare_lookups(tfmdata)
local k = kerns[lookup]
if not k then k = { } kerns[lookup] = k end
k[unicode] = krn -- ref to glyph, saves lookup
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: kern for U+%04X",lookup,unicode)
---~ end
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: kern for U+%04X",lookup,unicode)
+ --~ end
end
end
local oanchor = glyph.anchors
@@ -2433,9 +2449,9 @@ local function prepare_lookups(tfmdata)
local f = mark[lookup]
if not f then f = { } mark[lookup] = f end
f[unicode] = anchors -- ref to glyph, saves lookup
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: mark anchor %s for U+%04X",lookup,name,unicode)
---~ end
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: mark anchor %s for U+%04X",lookup,name,unicode)
+ --~ end
end
end
end
@@ -2447,9 +2463,9 @@ local function prepare_lookups(tfmdata)
local f = cursive[lookup]
if not f then f = { } cursive[lookup] = f end
f[unicode] = anchors -- ref to glyph, saves lookup
---~ if trace_lookups then
---~ logs.report("define otf","lookup %s: exit anchor %s for U+%04X",lookup,name,unicode)
---~ end
+ --~ if trace_lookups then
+ --~ logs.report("define otf","lookup %s: exit anchor %s for U+%04X",lookup,name,unicode)
+ --~ end
end
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ott.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ott.lua
index 55cb734d675..d26c55f4b82 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ott.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-ott.lua
@@ -682,6 +682,14 @@ for k, v in pairs(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
@@ -710,7 +718,9 @@ function otf.meanings.normalize(features)
v = b
end
end
- h[to_features[k] or k] = v
+ k = to_features[k] or k
+ local c = checkers[k]
+ h[k] = c and c(v) or v
end
end
return h
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-tfm.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-tfm.lua
index efea9def3f9..4b217a3c407 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-tfm.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-tfm.lua
@@ -36,6 +36,7 @@ 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
@@ -47,33 +48,9 @@ supplied by <l n='luatex'/>.</p>
tfm.resolve_vf = true -- false
tfm.share_base_kerns = false -- true (.5 sec slower on mk but brings down mem from 410M to 310M, beware: then script/lang share too)
tfm.mathactions = { }
+tfm.fontname_mode = "fullpath"
-function tfm.enhance(tfmdata,specification)
- local name, size = specification.name, specification.size
- local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
- if filename and encoding and fonts.enc.known[encoding] then
- local data = fonts.enc.load(encoding)
- if data then
- local characters = tfmdata.characters
- tfmdata.encoding = encoding
- local vector = data.vector
- local original = { }
- for k, v in next, characters do
- v.name = vector[k]
- v.index = k
- original[k] = v
- end
- for k,v in next, data.unicodes do
- if k ~= v then
- if trace_defining then
- logs.report("define font","mapping %s onto %s",k,v)
- end
- characters[k] = original[v]
- end
- end
- end
- end
-end
+tfm.enhance = tfm.enhance or function() end
function tfm.read_from_tfm(specification)
local fname, tfmdata = specification.filename or "", nil
@@ -186,36 +163,36 @@ fonts.trace_scaling = false
-- basekerns are scaled and will be hashed by table id
-- sharedkerns are unscaled and are be hashed by concatenated indexes
-function tfm.check_base_kerns(tfmdata)
- if tfm.share_base_kerns then
- local sharedkerns = tfmdata.sharedkerns
- if sharedkerns then
- local basekerns = { }
- tfmdata.basekerns = basekerns
- return sharedkerns, basekerns
- end
- end
- return nil, nil
-end
+--~ function tfm.check_base_kerns(tfmdata)
+--~ if tfm.share_base_kerns then
+--~ local sharedkerns = tfmdata.sharedkerns
+--~ if sharedkerns then
+--~ local basekerns = { }
+--~ tfmdata.basekerns = basekerns
+--~ return sharedkerns, basekerns
+--~ end
+--~ end
+--~ return nil, nil
+--~ end
-function tfm.prepare_base_kerns(tfmdata)
- if tfm.share_base_kerns and not tfmdata.sharedkerns then
- local sharedkerns = { }
- tfmdata.sharedkerns = sharedkerns
- for u, chr in next, tfmdata.characters do
- local kerns = chr.kerns
- if kerns then
- local hash = concat(sortedkeys(kerns), " ")
- local base = sharedkerns[hash]
- if not base then
- sharedkerns[hash] = kerns
- else
- chr.kerns = base
- end
- end
- end
- end
-end
+--~ function tfm.prepare_base_kerns(tfmdata)
+--~ if tfm.share_base_kerns and not tfmdata.sharedkerns then
+--~ local sharedkerns = { }
+--~ tfmdata.sharedkerns = sharedkerns
+--~ for u, chr in next, tfmdata.characters do
+--~ local kerns = chr.kerns
+--~ if kerns then
+--~ local hash = concat(sortedkeys(kerns), " ")
+--~ local base = sharedkerns[hash]
+--~ if not base then
+--~ sharedkerns[hash] = kerns
+--~ else
+--~ chr.kerns = base
+--~ end
+--~ end
+--~ end
+--~ end
+--~ end
-- we can have cache scaled characters when we are in node mode and don't have
-- protruding and expansion: hash == fullname @ size @ protruding @ expansion
@@ -228,13 +205,21 @@ local charactercache = { }
-- a virtual font has italic correction make sure to set the
-- has_italic flag. Some more flags will be added in the future.
-function tfm.do_scale(tfmtable, scaledpoints)
- tfm.prepare_base_kerns(tfmtable) -- optimalization
+function tfm.calculate_scale(tfmtable, scaledpoints, relativeid)
if scaledpoints < 0 then
scaledpoints = (- scaledpoints/1000) * tfmtable.designsize -- already in sp
end
- local delta = scaledpoints/(tfmtable.units or 1000) -- brr, some open type fonts have 2048
- local t = { }
+ local units = tfmtable.units or 1000
+ local delta = scaledpoints/units -- brr, some open type fonts have 2048
+ return scaledpoints, delta, units
+end
+
+function tfm.do_scale(tfmtable, scaledpoints, relativeid)
+ -- tfm.prepare_base_kerns(tfmtable) -- optimalization
+ local t = { } -- the new table
+ local scaledpoints, delta, units = tfm.calculate_scale(tfmtable, scaledpoints, relativeid)
+ t.units_per_em = units or 1000
+ local hdelta, vdelta = delta, delta
-- unicoded unique descriptions shared cidinfo characters changed parameters indices
for k,v in next, tfmtable do
if type(v) == "table" then
@@ -243,6 +228,19 @@ function tfm.do_scale(tfmtable, scaledpoints)
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
-- status
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)
@@ -270,12 +268,12 @@ t.colorscheme = tfmtable.colorscheme
local tfmp = tfmtable.parameters -- let's check for indexes
--
tp.slant = (tfmp.slant or tfmp[1] or 0)
- tp.space = (tfmp.space or tfmp[2] or 0)*delta
- tp.space_stretch = (tfmp.space_stretch or tfmp[3] or 0)*delta
- tp.space_shrink = (tfmp.space_shrink or tfmp[4] or 0)*delta
- tp.x_height = (tfmp.x_height or tfmp[5] or 0)*delta
- tp.quad = (tfmp.quad or tfmp[6] or 0)*delta
- tp.extra_space = (tfmp.extra_space or tfmp[7] or 0)*delta
+ 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
@@ -289,14 +287,15 @@ t.colorscheme = tfmtable.colorscheme
local defaultheight = luatex and luatex.defaultheight or 0
local defaultdepth = luatex and luatex.defaultdepth or 0
-- experimental, sharing kerns (unscaled and scaled) saves memory
- local sharedkerns, basekerns = tfm.check_base_kerns(tfmtable)
+ -- local sharedkerns, basekerns = tfm.check_base_kerns(tfmtable)
-- loop over descriptions (afm and otf have descriptions, tfm not)
-- there is no need (yet) to assign a value to chr.tonunicode
- local scaledwidth = defaultwidth * delta
- local scaledheight = defaultheight * delta
- local scaleddepth = defaultdepth * delta
+ local scaledwidth = defaultwidth * hdelta
+ local scaledheight = defaultheight * vdelta
+ local scaleddepth = defaultdepth * vdelta
local stackmath = tfmtable.ignore_stack_math ~= true
-local private = fonts.private
+ local private = fonts.private
+ local sharedkerns = { }
for k,v in next, characters do
local chr, description, index
if ischanged then
@@ -317,9 +316,9 @@ local private = fonts.private
local width = description.width
local height = description.height
local depth = description.depth
- if width then width = delta*width else width = scaledwidth end
- if height then height = delta*height else height = scaledheight end
- -- if depth then depth = delta*depth else depth = scaleddepth end
+ if width then width = hdelta*width else width = scaledwidth end
+ if height then height = vdelta*height else height = scaledheight end
+ -- if depth then depth = vdelta*depth else depth = scaleddepth end
if depth and depth ~= 0 then
depth = delta*depth
if nameneeded then
@@ -383,7 +382,7 @@ local private = fonts.private
if hasitalic then
local vi = description.italic or v.italic
if vi and vi ~= 0 then
- chr.italic = vi*delta
+ chr.italic = vi*hdelta
end
end
-- to be tested
@@ -399,19 +398,19 @@ local private = fonts.private
for i=1,#vv do
local vvi = vv[i]
t[i] = {
- ["start"] = (vvi["start"] or 0)*delta,
- ["end"] = (vvi["end"] or 0)*delta,
- ["advance"] = (vvi["advance"] or 0)*delta,
+ ["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
---~ local ic = v.vert_italic_correction
---~ if ic then
---~ chr.italic = ic * delta
---~ print(format("0x%05X -> %s",k,chr.italic))
---~ end
+ --~ local ic = v.vert_italic_correction
+ --~ if ic then
+ --~ chr.italic = ic * hdelta
+ --~ print(format("0x%05X -> %s",k,chr.italic))
+ --~ end
else
local hv = v.horiz_variants
if hv then
@@ -419,9 +418,9 @@ local private = fonts.private
for i=1,#hv do
local hvi = hv[i]
t[i] = {
- ["start"] = (hvi["start"] or 0)*delta,
- ["end"] = (hvi["end"] or 0)*delta,
- ["advance"] = (hvi["advance"] or 0)*delta,
+ ["start"] = (hvi["start"] or 0)*hdelta,
+ ["end"] = (hvi["end"] or 0)*hdelta,
+ ["advance"] = (hvi["advance"] or 0)*hdelta,
["extender"] = hvi["extender"],
["glyph"] = hvi["glyph"],
}
@@ -432,31 +431,23 @@ local private = fonts.private
end
local vt = description.top_accent
if vt then
- chr.top_accent = delta*vt
+ chr.top_accent = vdelta*vt
end
if stackmath then
local mk = v.mathkerns
if mk then
local kerns = { }
- -- for k, v in next, mk do
- -- local kk = { }
- -- for i=1,#v do
- -- local vi = v[i]
- -- kk[i] = { height = delta*vi.height, kern = delta*vi.kern }
- -- end
- -- kerns[k] = kk
- -- end
local v = mk.top_right if v then local k = { } for i=1,#v do local vi = v[i]
- k[i] = { height = delta*vi.height, kern = delta*vi.kern }
+ 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 = delta*vi.height, kern = delta*vi.kern }
+ 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 = delta*vi.height, kern = delta*vi.kern }
+ 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 = delta*vi.height, kern = delta*vi.kern }
+ k[i] = { height = vdelta*vi.height, kern = vdelta*vi.kern }
end kerns.bottom_right = k end
chr.mathkern = kerns -- singular
end
@@ -465,19 +456,26 @@ local private = fonts.private
if not nodemode then
local vk = v.kerns
if vk then
- if sharedkerns then
- local base = basekerns[vk] -- hashed by table id, not content
- if not base then
- base = {}
- for k,v in next, vk do base[k] = v*delta end
- basekerns[vk] = base
- end
- chr.kerns = base
- else
- local tt = {}
- for k,v in next, vk do tt[k] = v*delta end
- chr.kerns = tt
+ --~ if sharedkerns then
+ --~ local base = basekerns[vk] -- hashed by table id, not content
+ --~ if not base then
+ --~ base = {}
+ --~ for k,v in next, vk do base[k] = v*hdelta end
+ --~ basekerns[vk] = base
+ --~ end
+ --~ chr.kerns = base
+ --~ else
+ --~ local tt = {}
+ --~ for k,v in next, vk do tt[k] = v*hdelta end
+ --~ chr.kerns = tt
+ --~ end
+ 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
@@ -496,6 +494,8 @@ local private = fonts.private
local vc = v.commands
if vc then
-- we assume non scaled commands here
+ -- tricky .. we need to scale pseudo math glyphs too
+ -- which is why we deal with rules too
local ok = false
for i=1,#vc do
local key = vc[i][1]
@@ -509,8 +509,12 @@ local private = fonts.private
for i=1,#vc do
local ivc = vc[i]
local key = ivc[1]
- if key == "right" or key == "down" then
- tt[#tt+1] = { key, ivc[2]*delta }
+ 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 -- not comment
tt[#tt+1] = ivc -- shared since in cache and untouched
end
@@ -522,13 +526,12 @@ local private = fonts.private
end
end
tc[k] = chr
---~ if k == 0x222B then
---~ print(t.fontname,table.serialize(chr))
---~ end
end
-- t.encodingbytes, t.filename, t.fullname, t.name: elsewhere
t.size = scaledpoints
t.factor = delta
+ t.hfactor = hdelta
+ t.vfactor = vdelta
if t.fonts then
t.fonts = table.fastcopy(t.fonts) -- maybe we virtualize more afterwards
end
@@ -536,7 +539,7 @@ local private = fonts.private
-- mathematics.extras.copy(t) -- can be done elsewhere if needed
local ma = tfm.mathactions
for i=1,#ma do
- ma[i](t,tfmtable,delta)
+ ma[i](t,tfmtable,delta,hdelta,vdelta) -- what delta?
end
end
-- needed for \high cum suis
@@ -593,21 +596,19 @@ local lastfont = nil
--
-- flushing the kern and ligature tables from memory saves a lot (only
-- base mode) but it complicates vf building where the new characters
--- demand this data
-
---~ for id, f in pairs(fonts.ids) do -- or font.fonts
---~ local ffi = font.fonts[id]
---~ f.characters = ffi.characters
---~ f.kerns = ffi.kerns
---~ f.ligatures = ffi.ligatures
---~ end
+-- demand this data .. solution: functions that access them
function tfm.cleanup_table(tfmdata) -- we need a cleanup callback, now we miss the last one
if tfm.auto_cleanup then -- ok, we can hook this into everyshipout or so ... todo
if tfmdata.type == 'virtual' or tfmdata.virtualized then
for k, v in next, tfmdata.characters do
- if v.commands then v.commands = nil end
+ if v.commands then v.commands = nil end
+ -- if v.kerns then v.kerns = nil end
end
+ else
+ -- for k, v in next, tfmdata.characters do
+ -- if v.kerns then v.kerns = nil end
+ -- end
end
end
end
@@ -615,8 +616,8 @@ end
function tfm.cleanup(tfmdata) -- we need a cleanup callback, now we miss the last one
end
-function tfm.scale(tfmtable, scaledpoints)
- local t, factor = tfm.do_scale(tfmtable, scaledpoints)
+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)
@@ -650,7 +651,8 @@ function fonts.analyzers.aux.setstate(head,font)
local descriptions = tfmdata.descriptions
local first, last, current, n, done = nil, nil, head, 0, false -- maybe make n boolean
while current do
- if current.id == glyph and current.font == font then
+ 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
@@ -671,6 +673,10 @@ function fonts.analyzers.aux.setstate(head,font)
end
first, last, n = nil, nil, 0
end
+ elseif id == disc then
+ -- always in the middle
+ set_attribute(current,state,2) -- midi
+ last = current
else -- finish
if first and first == last then
set_attribute(last,state,4) -- isol
@@ -698,155 +704,8 @@ function tfm.replacements(tfm,value)
-- tfm.characters[0x0060] = tfm.characters[0x2018]
end
--- auto complete font with missing composed characters
-
-table.insert(fonts.manipulators,"compose")
-
-function fonts.initializers.common.compose(tfmdata,value)
- if value then
- fonts.vf.aux.compose_characters(tfmdata)
- end
-end
-
--- tfm features, experimental
-
-tfm.features = tfm.features or { }
-tfm.features.list = tfm.features.list or { }
-tfm.features.default = tfm.features.default or { }
-
-function tfm.enhance(tfmdata,specification)
- -- we don't really share tfm data because we always reload
- -- but this is more in sycn with afm and such
- local features = (specification.features and specification.features.normal ) or { }
- tfmdata.shared = tfmdata.shared or { }
- tfmdata.shared.features = features
- -- tfmdata.shared.tfmdata = tfmdata -- circular
- tfmdata.filename = specification.name
- if not features.encoding then
- local name, size = specification.name, specification.size
- local encoding, filename = match(name,"^(.-)%-(.*)$") -- context: encoding-name.*
- if filename and encoding and fonts.enc.known[encoding] then
- features.encoding = encoding
- end
- end
- tfm.set_features(tfmdata)
-end
-
-function tfm.set_features(tfmdata)
- -- todo: no local functions
- local shared = tfmdata.shared
--- local tfmdata = shared.tfmdata
- local features = shared.features
- if not table.is_empty(features) then
- local mode = tfmdata.mode or fonts.mode
- local fi = fonts.initializers[mode]
- if fi and fi.tfm then
- local function initialize(list) -- using tex lig and kerning
- if list then
- for i=1,#list do
- local f = list[i]
- local value = features[f]
- if value and fi.tfm[f] then -- brr
- if tfm.trace_features then
- logs.report("define font","initializing feature %s to %s for mode %s for font %s",f,tostring(value),mode or 'unknown',tfmdata.name or 'unknown')
- end
- fi.tfm[f](tfmdata,value)
- mode = tfmdata.mode or fonts.mode
- fi = fonts.initializers[mode]
- end
- end
- end
- end
- initialize(fonts.triggers)
- initialize(tfm.features.list)
- initialize(fonts.manipulators)
- end
- local fm = fonts.methods[mode]
- if fm and fm.tfm then
- local function register(list) -- node manipulations
- if list then
- for i=1,#list do
- local f = list[i]
- if features[f] and fm.tfm[f] then -- brr
- if not shared.processors then -- maybe also predefine
- shared.processors = { fm.tfm[f] }
- else
- shared.processors[#shared.processors+1] = fm.tfm[f]
- end
- end
- end
- end
- end
- register(tfm.features.list)
- end
- end
-end
-
-function tfm.features.register(name,default)
- tfm.features.list[#tfm.features.list+1] = name
- tfm.features.default[name] = default
-end
-
-function tfm.reencode(tfmdata,encoding)
- if encoding and fonts.enc.known[encoding] then
- local data = fonts.enc.load(encoding)
- if data then
- local characters, original, vector = tfmdata.characters, { }, data.vector
- tfmdata.encoding = encoding -- not needed
- for k, v in next, characters do
- v.name, v.index, original[k] = vector[k], k, v
- end
- for k,v in next, data.unicodes do
- if k ~= v then
- if trace_defining then
- logs.report("define font","reencoding U+%04X to U+%04X",k,v)
- end
- characters[k] = original[v]
- end
- end
- end
- end
-end
-
-tfm.features.register('reencode')
-
-fonts.initializers.base.tfm.reencode = tfm.reencode
-fonts.initializers.node.tfm.reencode = tfm.reencode
-
-fonts.enc = fonts.enc or { }
-fonts.enc.remappings = fonts.enc.remappings or { }
-
-function tfm.remap(tfmdata,remapping)
- local vector = remapping and fonts.enc.remappings[remapping]
- if vector then
- local characters, original = tfmdata.characters, { }
- for k, v in next, characters do
- original[k], characters[k] = v, nil
- end
- for k,v in next, vector do
- if k ~= v then
- if trace_defining then
- logs.report("define font","remapping U+%04X to U+%04X",k,v)
- end
- local c = original[k]
- characters[v] = c
- c.index = k
- end
- end
- tfmdata.encodingbytes = 2
- tfmdata.format = 'type1'
- end
-end
-
-tfm.features.register('remap')
-
-fonts.initializers.base.tfm.remap = tfm.remap
-fonts.initializers.node.tfm.remap = tfm.remap
-
-- status info
statistics.register("fonts load time", function()
- if statistics.elapsedindeed(fonts) then
- return format("%s seconds",statistics.elapsedtime(fonts))
- end
+ return statistics.elapsedseconds(fonts)
end)
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-xtx.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-xtx.lua
index d5397da3aa3..0fa2d696ab0 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-xtx.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-font-xtx.lua
@@ -74,7 +74,7 @@ local function isstyle(s)
elseif v:find("^s=") then
list.optsize = v:split("=")[2]
elseif v == "aat" or v == "icu" or v == "gr" then
- logs.report("define font", "unsupported font option: %s", v)
+ logs.report("load font", "unsupported font option: %s", v)
elseif not v:is_empty() then
list.style = v:gsub("[^%a%d]", "")
end
@@ -143,13 +143,17 @@ 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
@@ -158,9 +162,6 @@ 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 istrue (s) list[s] = 'yes' end
---KH local function isfalse(s) list[s] = 'no' end
-local function isfalse(s) list[s] = nil end -- see mpg/luaotfload#4
local function iskey (k,v)
if k == "script" then
parse_script(v)
@@ -168,6 +169,9 @@ local function iskey (k,v)
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
-- ER: now accepting names like C:/program files/texlive/2009/...
local namespec = (lpeg.R("az", "AZ") * lpeg.P(":"))^-1 * (1-lpeg.S("/:("))^1 -- was: (1-lpeg.S("/: ("))^0
@@ -175,26 +179,21 @@ local crapspec = spaces * lpeg.P("/") * (((1-lpeg.P(":"))^0)/isstyle) * spaces
-- ER: can't understand why the 'file:' thing doesn't work with fontnames starting by c:...
local filename = (lpeg.P("file:")/isfile * (namespec/thename)) + (lpeg.P("[") * lpeg.P(true)/isname * (((1-lpeg.P("]"))^0)/thename) * lpeg.P("]"))
local fontname = (lpeg.P("name:")/isname * (namespec/thename)) + lpeg.P(true)/issome * (namespec/thename)
-local sometext = (lpeg.R("az") + lpeg.R("AZ") + lpeg.R("09"))^1
+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 someval = (lpeg.S("+-.") + sometext)^1
-local keyvalue = (lpeg.C(sometext) * spaces * lpeg.P("=") * spaces * lpeg.C(someval))/iskey
+local keyvalue = (lpeg.C(sometext) * spaces * lpeg.P("=") * spaces * lpeg.C(sometext))/iskey
local somevalue = sometext/istrue
local subvalue = lpeg.P("(") * (lpeg.C(lpeg.P(1-lpeg.S("()"))^1)/issub) * lpeg.P(")") -- for Kim
local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces
local options = lpeg.P(":") * spaces * (lpeg.P(";")^0 * option)^0
local pattern = (filename + fontname) * subvalue^0 * crapspec^0 * options^0
+local normalize_meanings = fonts.otf.meanings.normalize
+
function fonts.define.specify.colonized(specification) -- xetex mode
list = { }
lpegmatch(pattern,specification.specification)
- for k, v in next, list do
- list[k] = v:is_boolean()
- if type(list[a]) == "nil" then
- list[k] = v
- end
- end
if list.style then
specification.style = list.style
list.style = nil
@@ -215,7 +214,8 @@ function fonts.define.specify.colonized(specification) -- xetex mode
specification.sub = list.sub
list.sub = nil
end
- specification.features.normal = list
+-- specification.features.normal = list
+ specification.features.normal = normalize_meanings(list)
return specification
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-dum.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-dum.lua
index ffabda8e114..3946b6f399e 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-dum.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-dum.lua
@@ -23,6 +23,11 @@ trackers = {
enable = dummyfunction,
disable = dummyfunction,
}
+experiments = {
+ register = dummyfunction,
+ enable = dummyfunction,
+ disable = dummyfunction,
+}
storage = {
register = dummyfunction,
shared = { },
@@ -37,6 +42,9 @@ tasks = {
appendaction = dummyfunction,
prependaction = dummyfunction,
}
+callbacks = {
+ register = function(n,f) return callback.register(n,f) end,
+}
-- we need to cheat a bit here
@@ -49,13 +57,14 @@ local remapper = {
ttf = "truetype fonts",
ttc = "truetype fonts",
dfont = "truetype dictionary",
- cid = "other text files", -- will become "cid files"
+ cid = "cid maps",
+ fea = "font feature files",
}
function resolvers.find_file(name,kind)
name = string.gsub(name,"\\","\/")
- kind = kind and string.lower(kind)
- return kpse.find_file(name,(kind and kind ~= "" and (remapper[kind] or kind)) or "tex")
+ 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)
@@ -64,3 +73,56 @@ function resolvers.findbinfile(name,kind)
end
return resolvers.find_file(name,(kind and remapper[kind]) or kind)
end
+
+-- Caches ... I will make a real stupid version some day when I'm in the
+-- mood. After all, the generic code does not need the more advanced
+-- ConTeXt features. Cached data is not shared between ConTeXt and other
+-- usage as I don't want any dependency at all. Also, ConTeXt might have
+-- different needs and tricks added.
+
+caches = { }
+
+--~ containers.usecache = true
+
+function caches.setpath(category,subcategory)
+-- local root = kpse.var_value("TEXMFCACHE") or ""
+-- if root == "" then
+-- root = kpse.var_value("VARTEXMF") or ""
+-- end
+ local var = kpse.var_value("TEXMFVAR")
+ local root = var and (var .. "/luatex/generic/luaotfload/") or ""
+ if root ~= "" then
+ root = file.join(root,category)
+ lfs.mkdir(root)
+ root = file.join(root,subcategory)
+ lfs.mkdir(root)
+ return lfs.isdir(root) and root
+ end
+end
+
+local function makefullname(path,name)
+ if path and path ~= "" then
+ name = "temp-" and name -- clash prevention
+ 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(path,name)
+ local fullname = makefullname(path,name)
+ if fullname then
+ local data = loadfile(fullname)
+ return data and data()
+ end
+end
+
+function caches.savedata(path,name,data)
+ local fullname = makefullname(path,name)
+ if fullname then
+ table.tofile(fullname,data,'return',false,true,false)
+ end
+end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-ovr.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-ovr.lua
new file mode 100644
index 00000000000..af5e05b364f
--- /dev/null
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-luat-ovr.lua
@@ -0,0 +1,35 @@
+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 = "GPL"
+}
+
+
+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.simple(fmt,...)
+ if fmt then
+ write_nl('log', format("%s | %s",name,format(fmt,...)))
+ else
+ write_nl('log', format("%s |",name))
+ end
+end
+
+tex.ctxcatcodes = luatexbase.catcodetables.latex
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-fnt.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-fnt.lua
index 72bb140ca3e..f2d8e1d7707 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-fnt.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-fnt.lua
@@ -51,7 +51,7 @@ function nodes.process_characters(head)
local usedfonts, attrfonts, done = { }, { }, false
local a, u, prevfont, prevattr = 0, 0, nil, 0
for n in traverse_id(glyph,head) do
- local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts, preset to 0 is faster (first match)
+ local font, attr = n.font, has_attribute(n,0) -- zero attribute is reserved for fonts in context
if attr and attr > 0 then
if font ~= prevfont or attr ~= prevattr then
local used = attrfonts[font]
@@ -107,7 +107,7 @@ function nodes.process_characters(head)
head, done = h or head, done or d
if n > 1 then
for i=2,n do
- local h, d = processors[i](head,font,0) -- false)
+ local h, d = processors[i](head,font,false)
head, done = h or head, done or d
end
end
@@ -119,7 +119,7 @@ function nodes.process_characters(head)
head, done = h or head, done or d
if n > 1 then
for i=2,n do
- local h, d = processors[i](head,font,0) -- false)
+ local h, d = processors[i](head,font,false)
head, done = h or head, done or d
end
end
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-ini.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-ini.lua
index 741e53d6bfd..36e240238e3 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-ini.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-ini.lua
@@ -108,10 +108,12 @@ local penalty = node.id('penalty')
local kern = node.id('kern')
local whatsit = node.id('whatsit')
-local traverse_id = node.traverse_id
-local traverse = node.traverse
-local free_node = node.free
-local remove_node = node.remove
+local traverse_id = node.traverse_id
+local traverse = node.traverse
+local free_node = node.free
+local remove_node = node.remove
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
function nodes.remove(head, current, free_too)
local t = current
@@ -131,8 +133,8 @@ function nodes.delete(head,current)
return nodes.remove(head,current,true)
end
-nodes.before = node.insert_before
-nodes.after = node.insert_after
+nodes.before = insert_node_before
+nodes.after = insert_node_after
-- we need to test this, as it might be fixed now
@@ -172,21 +174,31 @@ function nodes.after(h,c,n)
return n, n
end
-function nodes.replace(head,current,new)
- if current and next then
- local p, n = current.prev, current.next
- new.prev, new.next = p, n
- if p then
- p.next = new
- else
+-- local h, c = nodes.replace(head,current,new)
+-- local c = nodes.replace(false,current,new)
+-- local c = nodes.replace(current,new)
+
+function nodes.replace(head,current,new) -- no head returned if false
+ if not new then
+ head, current, new = false, head, current
+ end
+ local prev, next = current.prev, current.next
+ if next then
+ new.next, next.prev = next, new
+ end
+ if prev then
+ new.prev, prev.next = prev, new
+ end
+ if head then
+ if head == current then
head = new
end
- if n then
- n.prev = new
- end
free_node(current)
+ return head, new
+ else
+ free_node(current)
+ return new
end
- return head, current
end
-- will move
@@ -212,7 +224,7 @@ end
nodes.count = count
--- new
+-- new, will move
function attributes.ofnode(n)
local a = n.attr
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-inj.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-inj.lua
index 4c5840978c1..9c4612a2299 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-inj.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-inj.lua
@@ -70,7 +70,8 @@ function nodes.set_pair(current,factor,rlmode,r2lflag,spec,tfmchr)
local bound = has_attribute(current,kernpair)
if bound then
local kb = kerns[bound]
- kb[2], kb[3], kb[4], kb[5] = kb[2] + x, kb[3] + y, kb[4] + w, kb[5] + h
+ -- 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
set_attribute(current,kernpair,bound)
diff --git a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-res.lua b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-res.lua
index 49a1297eb9e..2657dfa1e71 100644
--- a/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-res.lua
+++ b/Master/texmf-dist/tex/luatex/luaotfload/otfl-node-res.lua
@@ -7,7 +7,10 @@ if not modules then modules = { } end modules ['node-res'] = {
}
local gmatch, format = string.gmatch, string.format
-local copy_node, free_node, free_list, new_node = node.copy, node.free, node.flush_list, node.new
+local copy_node, free_node, free_list, new_node, node_type, node_id = node.copy, node.free, node.flush_list, node.new, node.type, node.id
+local tonumber, round = tonumber, math.round
+
+local glyph_node = node_id("glyph")
--[[ldx--
<p>The next function is not that much needed but in <l n='context'/> we use
@@ -16,18 +19,30 @@ for debugging <l n='luatex'/> node management.</p>
nodes = nodes or { }
+nodes.whatsits = { } -- table.swapped(node.whatsits())
+
local reserved = { }
+local whatsits = nodes.whatsits
+
+for k, v in pairs(node.whatsits()) do
+ whatsits[k], whatsits[v] = v, k -- two way
+end
-function nodes.register(n)
+local function register_node(n)
reserved[#reserved+1] = n
return n
end
+nodes.register = register_node
+
function nodes.cleanup_reserved(nofboxes) -- todo
nodes.tracers.steppers.reset() -- todo: make a registration subsystem
local nr, nl = #reserved, 0
for i=1,nr do
- free_node(reserved[i])
+ local ri = reserved[i]
+ -- if not (ri.id == glue_spec and not ri.is_writable) then
+ free_node(reserved[i])
+ -- end
end
if nofboxes then
local tb = tex.box
@@ -51,19 +66,37 @@ function nodes.usage()
return t
end
-local disc = nodes.register(new_node("disc"))
-local kern = nodes.register(new_node("kern",1))
-local penalty = nodes.register(new_node("penalty"))
-local glue = nodes.register(new_node("glue"))
-local glue_spec = nodes.register(new_node("glue_spec"))
-local glyph = nodes.register(new_node("glyph",0))
-local textdir = nodes.register(new_node("whatsit",7))
-local rule = nodes.register(new_node("rule"))
-local latelua = nodes.register(new_node("whatsit",35))
-local user_n = nodes.register(new_node("whatsit",44)) user_n.type = 100
-local user_l = nodes.register(new_node("whatsit",44)) user_l.type = 110
-local user_s = nodes.register(new_node("whatsit",44)) user_s.type = 115
-local user_t = nodes.register(new_node("whatsit",44)) user_t.type = 116
+local disc = register_node(new_node("disc"))
+local kern = register_node(new_node("kern",1))
+local penalty = register_node(new_node("penalty"))
+local glue = register_node(new_node("glue")) -- glue.spec = nil
+local glue_spec = register_node(new_node("glue_spec"))
+local glyph = register_node(new_node("glyph",0))
+local textdir = register_node(new_node("whatsit",whatsits.dir)) -- 7 (6 is local par node)
+local rule = register_node(new_node("rule"))
+local latelua = register_node(new_node("whatsit",whatsits.late_lua)) -- 35
+local user_n = register_node(new_node("whatsit",whatsits.user_defined)) user_n.type = 100 -- 44
+local user_l = register_node(new_node("whatsit",whatsits.user_defined)) user_l.type = 110 -- 44
+local user_s = register_node(new_node("whatsit",whatsits.user_defined)) user_s.type = 115 -- 44
+local user_t = register_node(new_node("whatsit",whatsits.user_defined)) user_t.type = 116 -- 44
+local left_margin_kern = register_node(new_node("margin_kern",0))
+local right_margin_kern = register_node(new_node("margin_kern",1))
+local lineskip = register_node(new_node("glue",1))
+local baselineskip = register_node(new_node("glue",2))
+local leftskip = register_node(new_node("glue",8))
+local rightskip = register_node(new_node("glue",9))
+local temp = register_node(new_node("temp",0))
+
+function nodes.zeroglue(n)
+ local s = n.spec
+ return not writable or (
+ s.width == 0
+ and s.stretch == 0
+ and s.shrink == 0
+ and s.stretch_order == 0
+ and s.shrink_order == 0
+ )
+end
function nodes.glyph(fnt,chr)
local n = copy_node(glyph)
@@ -71,48 +104,156 @@ function nodes.glyph(fnt,chr)
if chr then n.char = chr end
return n
end
+
function nodes.penalty(p)
local n = copy_node(penalty)
n.penalty = p
return n
end
+
function nodes.kern(k)
local n = copy_node(kern)
n.kern = k
return n
end
-function nodes.glue(width,stretch,shrink)
- local n, s = copy_node(glue), copy_node(glue_spec)
- s.width, s.stretch, s.shrink = width, stretch, shrink
- n.spec = s
- return n
-end
+
function nodes.glue_spec(width,stretch,shrink)
local s = copy_node(glue_spec)
s.width, s.stretch, s.shrink = width, stretch, shrink
return s
end
+
+local function someskip(skip,width,stretch,shrink)
+ local n = copy_node(skip)
+ if not width then
+ -- no spec
+ elseif tonumber(width) then
+ local s = copy_node(glue_spec)
+ s.width, s.stretch, s.shrink = width, stretch, shrink
+ n.spec = s
+ else
+ -- shared
+ n.spec = copy_node(width)
+ end
+ return n
+end
+
+function nodes.glue(width,stretch,shrink)
+ return someskip(glue,width,stretch,shrink)
+end
+function nodes.leftskip(width,stretch,shrink)
+ return someskip(leftskip,width,stretch,shrink)
+end
+function nodes.rightskip(width,stretch,shrink)
+ return someskip(rightskip,width,stretch,shrink)
+end
+function nodes.lineskip(width,stretch,shrink)
+ return someskip(lineskip,width,stretch,shrink)
+end
+function nodes.baselineskip(width,stretch,shrink)
+ return someskip(baselineskip,width,stretch,shrink)
+end
+
function nodes.disc()
return copy_node(disc)
end
+
function nodes.textdir(dir)
local t = copy_node(textdir)
t.dir = dir
return t
end
-function nodes.rule(w,h,d)
+
+function nodes.rule(width,height,depth,dir)
local n = copy_node(rule)
- if w then n.width = w end
- if h then n.height = h end
- if d then n.depth = d end
+ if width then n.width = width end
+ if height then n.height = height end
+ if depth then n.depth = depth end
+ if dir then n.dir = dir end
return n
end
+
function nodes.latelua(code)
local n = copy_node(latelua)
n.data = code
return n
end
+function nodes.leftmarginkern(glyph,width)
+ local n = copy_node(left_margin_kern)
+ if not glyph then
+ logs.fatal("nodes","invalid pointer to left margin glyph node")
+ elseif glyph.id ~= glyph_node then
+ logs.fatal("nodes","invalid node type %s for left margin glyph node",node_type(glyph))
+ else
+ n.glyph = glyph
+ end
+ if width then
+ n.width = width
+ end
+ return n
+end
+
+function nodes.rightmarginkern(glyph,width)
+ local n = copy_node(right_margin_kern)
+ if not glyph then
+ logs.fatal("nodes","invalid pointer to right margin glyph node")
+ elseif glyph.id ~= glyph_node then
+ logs.fatal("nodes","invalid node type %s for right margin glyph node",node_type(p))
+ else
+ n.glyph = glyph
+ end
+ if width then
+ n.width = width
+ end
+ return n
+end
+
+function nodes.temp()
+ return copy_node(temp)
+end
+--[[
+<p>At some point we ran into a problem that the glue specification
+of the zeropoint dimension was overwritten when adapting a glue spec
+node. This is a side effect of glue specs being shared. After a
+couple of hours tracing and debugging Taco and I came to the
+conclusion that it made no sense to complicate the spec allocator
+and settled on a writable flag. This all is a side effect of the
+fact that some glues use reserved memory slots (with the zeropoint
+glue being a noticeable one). So, next we wrap this into a function
+and hide it for the user. And yes, LuaTeX now gives a warning as
+well.</p>
+]]--
+
+if tex.luatexversion > 51 then
+
+ function nodes.writable_spec(n)
+ local spec = n.spec
+ if not spec then
+ spec = copy_node(glue_spec)
+ n.spec = spec
+ elseif not spec.writable then
+ spec = copy_node(spec)
+ n.spec = spec
+ end
+ return spec
+ end
+
+else
+
+ function nodes.writable_spec(n)
+ local spec = n.spec
+ if not spec then
+ spec = copy_node(glue_spec)
+ else
+ spec = copy_node(spec)
+ end
+ n.spec = spec
+ return spec
+ end
+
+end
+
local cache = { }
function nodes.usernumber(num)