summaryrefslogtreecommitdiff
path: root/tex/generic/context/luatex-fonts-merged.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/generic/context/luatex-fonts-merged.lua')
-rw-r--r--tex/generic/context/luatex-fonts-merged.lua1676
1 files changed, 865 insertions, 811 deletions
diff --git a/tex/generic/context/luatex-fonts-merged.lua b/tex/generic/context/luatex-fonts-merged.lua
index 3e64855a8..25c0f2d9d 100644
--- a/tex/generic/context/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 09/05/10 13:23:12
+-- merge date : 09/09/10 23:45:11
do -- begin closure to overcome local limits and interference
@@ -830,20 +830,22 @@ function table.imerged(...)
return tmp
end
-local function fastcopy(old) -- fast one
+local function fastcopy(old,metatabletoo) -- fast one
if old then
local new = { }
for k,v in next, old do
if type(v) == "table" then
- new[k] = fastcopy(v) -- was just table.copy
+ new[k] = fastcopy(v,metatabletoo) -- was just table.copy
else
new[k] = v
end
end
- -- optional second arg
- local mt = getmetatable(old)
- if mt then
- setmetatable(new,mt)
+ if metatabletoo then
+ -- optional second arg
+ local mt = getmetatable(old)
+ if mt then
+ setmetatable(new,mt)
+ end
end
return new
else
@@ -851,6 +853,8 @@ local function fastcopy(old) -- fast one
end
end
+-- todo : copy without metatable
+
local function copy(t, tables) -- taken from lua wiki, slightly adapted
tables = tables or { }
local tcopy = {}
@@ -1297,6 +1301,7 @@ function table.tofile(filename,root,name,reduce,noquotes,hexify)
serialize(root,name,flush,reduce,noquotes,hexify)
end
f:close()
+ io.flush()
end
end
@@ -1961,6 +1966,7 @@ function io.savedata(filename,data,joiner)
f:write(data or "")
end
f:close()
+ io.flush()
return true
else
return false
@@ -5283,7 +5289,11 @@ fonts.map.addtounicode = function(data,filename)
t[#t+1] = u
end
end
- if #t > 0 then -- done then
+ if #t == 0 then -- done then
+ -- nothing
+ elseif #t == 1 then
+ originals[index], tounicode[index], nl, unicode = t[1], tounicode16(t[1]), nl + 1, true
+ else
originals[index], tounicode[index], nl, unicode = t, tounicode16sequence(t), nl + 1, true
end
end
@@ -5434,6 +5444,11 @@ if not modules then modules = { } end modules ['font-otf'] = {
license = "see context related readme files"
}
+-- langs -> languages enz
+-- anchor_classes vs kernclasses
+-- modification/creationtime in subfont is runtime dus zinloos
+-- to_table -> totable
+
local utf = unicode.utf8
local concat, utfbyte = table.concat, utf.byte
@@ -5442,6 +5457,8 @@ local type, next, tonumber, tostring = type, next, tonumber, tostring
local abs = math.abs
local getn = table.getn
local lpegmatch = lpeg.match
+local reverse = table.reverse
+local ioflush = io.flush
local allocate = utilities.storage.allocate
@@ -5455,42 +5472,7 @@ local trace_defining = false trackers.register("fonts.defining", function(v
local report_otf = logs.new("load otf")
---~ trackers.enable("otf.loading")
-
---[[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]]--
+local starttiming, stoptiming, elapsedtime = statistics.starttiming, statistics.stoptiming, statistics.elapsedtime
local fonts = fonts
@@ -5500,38 +5482,114 @@ local tfm = fonts.tfm
local fontdata = fonts.ids
---~ otf.tables = otf.tables 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 = allocate()
local enhancers = otf.enhancers
+enhancers.patches = { }
local definers = fonts.definers
otf.glists = { "gsub", "gpos" }
-otf.version = 2.653 -- beware: also sync font-mis.lua
-otf.pack = true -- beware: also sync font-mis.lua
-otf.syncspace = true
-otf.notdef = false
+otf.version = 2.702 -- beware: also sync font-mis.lua
otf.cache = containers.define("fonts", "otf", otf.version, true)
-local wildcard = "*"
-local default = "dflt"
+local loadmethod = "table" -- table, mixed, sparse
+local forceload = false
+local cleanup = 0
+local usemetatables = false -- .4 slower on mk but 30 M less mem so we might change the default -- will be directive
+local packdata = true
+local syncspace = true
+local forcenotdef = false
+
+local wildcard = "*"
+local default = "dflt"
+
+local fontloaderfields = fontloader.fields
+local mainfields = nil
+local glyphfields = nil -- not used yet
+
+directives.register("fonts.otf.loader.method", function(v)
+ if v == "sparse" and fontloaderfields then
+ loadmethod = "sparse"
+ elseif v == "mixed" then
+ loadmethod = "mixed"
+ elseif v == "table" then
+ loadmethod = "table"
+ else
+ loadmethod = "table"
+ report_otf("no loader method '%s', using '%s' instead",v,loadmethod)
+ end
+end)
+
+directives.register("fonts.otf.loader.cleanup",function(v)
+ cleanup = tonumber(v) or (v and 1) or 0
+end)
+
+directives.register("fonts.otf.loader.force", function(v) forceload = v end)
+directives.register("fonts.otf.loader.usemetatables", function(v) usemetatables = v end)
+directives.register("fonts.otf.loader.pack", function(v) packdata = v end)
+directives.register("fonts.otf.loader.syncspace", function(v) syncspace = v end)
+directives.register("fonts.otf.loader.forcenotdef", function(v) forcenotdef = v end)
+
+local function load_featurefile(raw,featurefile)
+ if featurefile and featurefile ~= "" then
+ if trace_loading then
+ report_otf("featurefile: %s", featurefile)
+ end
+ fontloader.apply_featurefile(raw, featurefile)
+ end
+end
+
+local function showfeatureorder(otfdata,filename)
+ local sequences = otfdata.luatex.sequences
+ if sequences and #sequences > 0 then
+ if trace_loading then
+ report_otf("font %s has %s sequences",filename,#sequences)
+ report_otf(" ")
+ 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
+ report_otf("%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
+ report_otf(" %s: %s",feature,concat(tt," "))
+ end
+ end
+ end
+ end
+ if trace_loading then
+ report_otf("\n")
+ end
+ elseif trace_loading then
+ report_otf("font %s has no sequences",filename)
+ end
+end
--[[ldx--
<p>We start with a lot of tables and related functions.</p>
--ldx]]--
--- we can have more local functions
-
-otf.tables.global_fields = allocate( table.tohash {
+local global_fields = table.tohash {
+ "metadata",
"lookups",
"glyphs",
"subfonts",
@@ -5542,20 +5600,20 @@ otf.tables.global_fields = allocate( table.tohash {
"names",
"unicodes",
"names",
---~ "math",
+ -- "math",
"anchor_classes",
"kern_classes",
"gpos",
"gsub"
-} )
+}
-otf.tables.valid_fields = allocate( {
- "anchor_classes",
+local valid_fields = table.tohash {
+ -- "anchor_classes",
"ascent",
- "cache_version",
+ -- "cache_version",
"cidinfo",
"copyright",
- "creationtime",
+ -- "creationtime",
"descent",
"design_range_bottom",
"design_range_top",
@@ -5567,23 +5625,23 @@ otf.tables.valid_fields = allocate( {
"fontstyle_id",
"fontstyle_name",
"fullname",
- "glyphs",
+ -- "glyphs",
"hasvmetrics",
"head_optimized_for_cleartype",
"horiz_base",
"issans",
"isserif",
"italicangle",
- "kerns",
- "lookups",
+ -- "kerns",
+ -- "lookups",
-- "luatex",
"macstyle",
- "modificationtime",
+ -- "modificationtime",
"onlybitmaps",
"origname",
"os2_version",
- "pfminfo",
- "private",
+ -- "pfminfo",
+ -- "private",
"serifcheck",
"sfd_version",
-- "size",
@@ -5600,59 +5658,111 @@ otf.tables.valid_fields = allocate( {
"upos",
"use_typo_metrics",
"uwidth",
- "validation_state",
+ -- "validation_state",
"verbose",
"version",
"vert_base",
"weight",
"weight_width_slope_only",
- "xuid",
-} )
+ -- "xuid",
+}
+
+local ordered_enhancers = {
+ "prepare tables",
+ "prepare glyphs",
+ "prepare unicodes",
+ "prepare lookups",
+
+ "analyze glyphs",
+ "analyze math",
+
+ "prepare tounicode", -- maybe merge with prepare
+
+ "reorganize lookups",
+ "reorganize mark classes",
+ "reorganize anchor classes",
+
+ "reorganize glyph kerns",
+ "reorganize glyph lookups",
+ "reorganize glyph anchors",
+
+ "reorganize features",
+ "reorganize subtables",
+
+ "check glyphs",
+ "check metadata",
+ "check math parameters",
+ "check extra features", -- after metadata
+}
--[[ldx--
<p>Here we go.</p>
--ldx]]--
-local function load_featurefile(ff,featurefile)
- if featurefile and featurefile ~= "" then
- if trace_loading then
- report_otf("featurefile: %s", featurefile)
+local actions = { }
+
+enhancers.patches.before = allocate()
+enhancers.patches.after = allocate()
+
+local before = enhancers.patches.before
+local after = enhancers.patches.after
+
+local function enhance(name,data,filename,raw,verbose)
+ local enhancer = actions[name]
+ if enhancer then
+ if verbose then
+ report_otf("enhance: %s (%s)",name,filename)
+ ioflush()
end
- fontloader.apply_featurefile(ff, featurefile)
+ enhancer(data,filename,raw)
+ else
+ report_otf("enhance: %s is undefined",name)
end
end
-local function enhance(name,data,filename,verbose)
- local enhancer = enhancers[name]
- if enhancer then
- if (verbose ~= nil and verbose) or trace_loading then
- report_otf("enhance: %s (%s)",name,filename)
+function enhancers.apply(data,filename,raw,verbose)
+ local basename = file.basename(lower(filename))
+ report_otf("start enhancing: %s",filename)
+ ioflush() -- we want instant messages
+ for e=1,#ordered_enhancers do
+ local enhancer = ordered_enhancers[e]
+ local b = before[enhancer]
+ if b then
+ for pattern, action in next, b do
+ if find(basename,pattern) then
+ action(data,filename,raw)
+ end
+ end
end
- enhancer(data,filename)
+ enhance(enhancer,data,filename,raw,verbose)
+ local a = after[enhancer]
+ if a then
+ for pattern, action in next, a do
+ if find(basename,pattern) then
+ action(data,filename,raw)
+ end
+ end
+ end
+ ioflush() -- we want instant messages
end
+ report_otf("stop enhancing")
+ ioflush() -- we want instant messages
end
-local ordered_enhancers = { -- implemented later
- -- 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",
- "simplify glyph lookups", -- some saving
- "prepare luatex tables",
- "analyze features", "rehash features",
- "analyze anchors", "analyze marks", "analyze unicodes", "analyze subtables",
- "check italic correction","check math",
- "share widths",
- "strip not needed data",
- "migrate metadata",
- "check math parameters",
-}
+-- enhancers.patches.register("before","migrate metadata","cambria",function() end)
+
+function enhancers.patches.register(what,where,pattern,action)
+ local ww = what[where]
+ if ww then
+ ww[pattern] = action
+ else
+ ww = { [pattern] = action}
+ end
+end
-local adddimensions, showfeatureorder -- implemented later
+function enhancers.register(what,action) -- only already registered can be overloaded
+ actions[what] = action
+end
function otf.load(filename,format,sub,featurefile)
local name = file.basename(file.removesuffix(filename))
@@ -5689,6 +5799,10 @@ function otf.load(filename,format,sub,featurefile)
end
local data = containers.read(otf.cache,hash)
local reload = not data or data.verbose ~= fonts.verbose or data.size ~= size or data.time ~= time
+ if forceload then
+ report_otf("loading: forced reload due to hard coded flag")
+ reload = true
+ end
if not reload then
local featuredata = data.featuredata
if featurefiles then
@@ -5712,11 +5826,14 @@ function otf.load(filename,format,sub,featurefile)
end
if reload then
report_otf("loading: %s (hash: %s)",filename,hash)
- local ff, messages
+ local fontdata, messages, rawdata
if sub then
- ff, messages = fontloader.open(filename,sub)
+ fontdata, messages = fontloader.open(filename,sub)
else
- ff, messages = fontloader.open(filename)
+ fontdata, messages = fontloader.open(filename)
+ end
+ if fontdata then
+ mainfields = mainfields or (fontloaderfields and fontloaderfields(fontdata))
end
if trace_loading and messages and #messages > 0 then
if type(messages) == "string" then
@@ -5729,23 +5846,27 @@ function otf.load(filename,format,sub,featurefile)
else
report_otf("font loaded okay")
end
- if ff then
+ if fontdata then
if featurefiles then
for i=1,#featurefiles do
- load_featurefile(ff,featurefiles[i].name)
+ load_featurefile(fontdata,featurefiles[i].name)
end
end
- data = fontloader.to_table(ff)
- fontloader.close(ff)
- if data then
+ report_otf("loading method: %s",loadmethod)
+ if loadmethod == "sparse" then
+ rawdata = fontdata
+ else
+ rawdata = fontloader.to_table(fontdata)
+ fontloader.close(fontdata)
+ end
+ if rawdata then
+ data = { }
+ starttiming(data)
+ local verboseindeed = verbose ~= nil and verbose or trace_loading
report_otf("file size: %s", size)
- report_otf("enhancing ...")
- for e=1,#ordered_enhancers do
- enhance(ordered_enhancers[e],data,filename)
- io.flush() -- we want instant messages
- end
- if otf.pack and not fonts.verbose then
- enhance("pack",data,filename)
+ enhancers.apply(data,filename,rawdata,verboseindeed)
+ if packdata and not fonts.verbose then
+ enhance("pack",data,filename,nil,verboseindeed)
end
data.size = size
data.time = time
@@ -5755,13 +5876,27 @@ function otf.load(filename,format,sub,featurefile)
data.verbose = fonts.verbose
report_otf("saving in cache: %s",filename)
data = containers.write(otf.cache, hash, data)
- collectgarbage("collect")
+ if cleanup > 0 then
+ collectgarbage("collect")
+ end
+ stoptiming(data)
+ report_otf("preprocessing and caching took %s seconds",elapsedtime(data))
data = containers.read(otf.cache, hash) -- this frees the old table and load the sparse one
- collectgarbage("collect")
+ if cleanup > 1 then
+ collectgarbage("collect")
+ end
else
+ data = nil
report_otf("loading failed (table conversion error)")
end
+ if loadmethod == "sparse" then
+ fontloader.close(fontdata)
+ if cleanup > 2 then
+ -- collectgarbage("collect")
+ end
+ end
else
+ data = nil
report_otf("loading failed (file read error)")
end
end
@@ -5769,8 +5904,8 @@ function otf.load(filename,format,sub,featurefile)
if trace_defining then
report_otf("loading from cache: %s",hash)
end
- enhance("unpack",data,filename,false) -- no message here
- adddimensions(data)
+ enhance("unpack",data,filename,nil,false)
+ enhance("add dimensions",data,filename,nil,false)
if trace_sequences then
showfeatureorder(data,filename)
end
@@ -5778,89 +5913,321 @@ function otf.load(filename,format,sub,featurefile)
return data
end
-adddimensions = function(data)
+local mt = {
+ __index = function(t,k) -- maybe set it
+ if k == "height" then
+ local ht = t.boundingbox[4]
+ return ht < 0 and 0 or ht
+ elseif k == "depth" then
+ local dp = -t.boundingbox[2]
+ return dp < 0 and 0 or dp
+ elseif k == "width" then
+ return 0
+ elseif k == "name" then -- or maybe uni*
+ return forcenotdef and ".notdef"
+ end
+ end
+}
+
+actions["add dimensions"] = function(data,filename)
-- 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
+ if usemetatables then
+ for _, d in next, data.glyphs do
+ local wd = d.width
+ if not wd then
+ d.width = defaultwidth
+ elseif wd ~= 0 and d.class == "mark" then
+ d.width = -wd
+ end
+ setmetatable(d,mt)
+ end
+ else
+ 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 forcenotdef 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
+ -- not set
+ else
+ d.height = ht
+ end
+ if dp == 0 or dp < 0 then
+ -- not set
+ else
+ d.depth = dp
+ end
+ end
+ end
+ end
+ end
+end
+
+actions["prepare tables"] = function(data,filename,raw)
+ local luatex = {
+ filename = filename,
+ version = otf.version,
+ creator = "context mkiv",
+ }
+ data.luatex = luatex
+ data.metadata = { }
+end
+
+local function somecopy(old) -- fast one
+ if old then
+ local new = { }
+ if type(old) == "table" then
+ for k, v in next, old do
+ if k == "glyphs" then
+ -- skip
+ elseif type(v) == "table" then
+ new[k] = somecopy(v)
else
- d.height = ht
+ new[k] = v
end
- if dp == 0 or dp < 0 then
- -- no negative depths and no negative depths, nil == 0
+ end
+ else
+ for i=1,#mainfields do
+ local k = mainfields[i]
+ local v = old[k]
+ if k == "glyphs" then
+ -- skip
+ elseif type(v) == "table" then
+ new[k] = somecopy(v)
else
- d.depth = dp
+ new[k] = v
end
end
end
+ return new
+ else
+ return { }
end
end
-local function showfeatureorder(otfdata,filename)
- local sequences = otfdata.luatex.sequences
- if sequences and #sequences > 0 then
- if trace_loading then
- report_otf("font %s has %s sequences",filename,#sequences)
- report_otf(" ")
+actions["prepare glyphs"] = function(data,filename,raw)
+ -- we can also move the names to data.luatex.names which might
+ -- save us some more memory (at the cost of harder tracing)
+ local rawglyphs = raw.glyphs
+ local glyphs, udglyphs
+ if loadmethod == "sparse" then
+ glyphs, udglyphs = { }, { }
+ elseif loadmethod == "mixed" then
+ glyphs, udglyphs = { }, rawglyphs
+ else
+ glyphs, udglyphs = rawglyphs, rawglyphs
+ end
+ data.glyphs, data.udglyphs = glyphs, udglyphs
+ local subfonts = raw.subfonts
+ if subfonts then
+ if data.glyphs and next(data.glyphs) then
+ report_otf("replacing existing glyph table due to subfonts")
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
- report_otf("%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
+ local cidinfo = raw.cidinfo
+ if cidinfo.registry then
+ local cidmap, cidname = fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
+ if cidmap then
+ cidinfo.usedname = cidmap.usedname
+ local uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, 0, 0
+ local unicodes, names = cidmap.unicodes, cidmap.names
+ for cidindex=1,#subfonts do
+ local subfont = subfonts[cidindex]
+ if loadmethod == "sparse" then
+ local rawglyphs = subfont.glyphs
+ for index=0,subfont.glyphmax - 1 do
+ local g = rawglyphs[index]
+ if g then
+ local unicode, name = unicodes[index], names[index]
+ if unicode then
+ uni_to_int[unicode] = index
+ int_to_uni[index] = unicode
+ nofunicodes = nofunicodes + 1
+ elseif name then
+ nofnames = nofnames + 1
+ end
+ udglyphs[index] = g
+ glyphs[index] = {
+ width = g.width,
+ italic = g.italic_correction,
+ boundingbox = g.boundingbox,
+ class = g.class,
+ name = g.name or name or "unknown", -- uniXXXX
+ cidindex = cidindex,
+ unicode = unicode,
+ }
+ end
end
- tt[#tt+1] = format("[%s: %s]",script,concat(ttt," "))
- end
- if trace_loading then
- report_otf(" %s: %s",feature,concat(tt," "))
+ -- If we had more userdata, we would need more of this
+ -- and it would start working against us in terms of
+ -- convenience and speed.
+ subfont = somecopy(subfont)
+ subfont.glyphs = nil
+ subfont[cidindex] = subfont
+ elseif loadmethod == "mixed" then
+ for index, g in next, subfont.glyphs do
+ local unicode, name = unicodes[index], names[index]
+ if unicode then
+ uni_to_int[unicode] = index
+ int_to_uni[index] = unicode
+ nofunicodes = nofunicodes + 1
+ elseif name then
+ nofnames = nofnames + 1
+ end
+ udglyphs[index] = g
+ glyphs[index] = {
+ width = g.width,
+ italic = g.italic_correction,
+ boundingbox = g.boundingbox,
+ class = g.class,
+ name = g.name or name or "unknown", -- uniXXXX
+ cidindex = cidindex,
+ unicode = unicode,
+ }
+ end
+ subfont.glyphs = nil
+ else
+ for index, g in next, subfont.glyphs do
+ local unicode, name = unicodes[index], names[index]
+ 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
+ end
+ g.cidindex = cidindex
+ glyphs[index] = g
+ end
+ subfont.glyphs = nil
end
end
+ if trace_loading then
+ report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
+ end
+ data.map = data.map or { }
+ data.map.map = uni_to_int
+ data.map.backmap = int_to_uni
+ elseif trace_loading then
+ report_otf("unable to remap cid font, missing cid file for %s",filename)
end
+ data.subfonts = subfonts
+ elseif trace_loading then
+ report_otf("font %s has no glyphs",filename)
end
- if trace_loading then
- report_otf("\n")
+ else
+ if loadmethod == "sparse" then
+ -- we get fields from the userdata glyph table and create
+ -- a minimal entry first
+ for index=0,raw.glyphmax - 1 do
+ local g = rawglyphs[index]
+ if g then
+ udglyphs[index] = g
+ glyphs[index] = {
+ width = g.width,
+ italic = g.italic_correction,
+ boundingbox = g.boundingbox,
+ class = g.class,
+ name = g.name,
+ unicode = g.unicode,
+ }
+ end
+ end
+ elseif loadmethod == "mixed" then
+ -- we get fields from the totable glyph table and copy to the
+ -- final glyph table so first we create a minimal entry
+ for index, g in next, rawglyphs do
+ udglyphs[index] = g
+ glyphs[index] = {
+ width = g.width,
+ italic = g.italic_correction,
+ boundingbox = g.boundingbox,
+ class = g.class,
+ name = g.name,
+ unicode = g.unicode,
+ }
+ end
+ else
+ -- we use the totable glyph table directly and manipulate the
+ -- entries in this (also final) table
end
- elseif trace_loading then
- report_otf("font %s has no sequences",filename)
+ data.map = raw.map
end
+ data.cidinfo = raw.cidinfo -- hack
end
--- todo: normalize, design_size => designsize
+-- watch copy of cidinfo: we can best make some more copies to data
-enhancers["reorganize mark classes"] = function(data,filename)
- if data.mark_classes then
- local unicodes = data.luatex.unicodes
+actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this in the previous
+ local glyphs = data.glyphs
+ -- collect info
+ local has_italic, widths, marks = false, { }, { }
+ for index, glyph in next, glyphs do
+ local italic = glyph.italic_correction
+ if not italic then
+ -- skip
+ elseif italic == 0 then
+ glyph.italic_correction = nil
+ glyph.italic = nil
+ else
+ glyph.italic_correction = nil
+ glyph.italic = italic
+ has_italic = true
+ end
+ local width = glyph.width
+ widths[width] = (widths[width] or 0) + 1
+ if glyph.class == "mark" then
+ marks[glyph.unicode] = true
+ end
+ local a = glyph.altuni if a then glyph.altuni = nil end
+ local d = glyph.dependents if d then glyph.dependents = nil end
+ local v = glyph.vwidth if v then glyph.vwidth = nil end
+ end
+ -- flag italic
+ data.metadata.has_italic = has_italic
+ -- flag marks
+ data.luatex.marks = marks
+ -- share most common 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 -- maybe 500
+ if trace_loading then
+ report_otf("most common width: %s (%s times), sharing (cjk font)",wd,most)
+ end
+ for index, glyph in next, glyphs do
+ if glyph.width == wd then
+ glyph.width = nil
+ end
+ end
+ data.luatex.defaultwidth = wd
+ end
+end
+
+actions["reorganize mark classes"] = function(data,filename,raw)
+ local mark_classes = raw.mark_classes
+ if mark_classes then
+ local luatex = data.luatex
+ local unicodes = luatex.unicodes
local reverse = { }
- for name, class in next, data.mark_classes do
+ luatex.markclasses = reverse
+ for name, class in next, mark_classes do
local t = { }
for s in gmatch(class,"[^ ]+") do
local us = unicodes[s]
@@ -5874,53 +6241,15 @@ enhancers["reorganize mark classes"] = function(data,filename)
end
reverse[name] = t
end
- data.luatex.markclasses = reverse
- data.mark_classes = nil
- end
-end
-
-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
-
-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
+ data.mark_classes = nil -- when using table
end
- return nil
-end
-
-enhancers["analyze features"] = function(data,filename)
- -- local luatex = data.luatex
- -- luatex.gposfeatures = analyze_features(data.gpos)
- -- luatex.gsubfeatures = analyze_features(data.gsub)
end
-enhancers["rehash features"] = function(data,filename)
+actions["reorganize features"] = function(data,filename,raw) -- combine with other
local features = { }
data.luatex.features = features
for k, what in next, otf.glists do
- local dw = data[what]
+ local dw = raw[what]
if dw then
local f = { }
features[what] = f
@@ -5933,8 +6262,10 @@ enhancers["rehash features"] = function(data,filename)
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))
+ for i=1,#dscripts do
+ local d = dscripts[i]
+ local languages = d.langs
+ local script = strip(lower(d.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
@@ -5947,8 +6278,8 @@ enhancers["rehash features"] = function(data,filename)
end
end
-enhancers["analyze anchors"] = function(data,filename)
- local classes = data.anchor_classes
+actions["reorganize anchor classes"] = function(data,filename,raw)
+ local classes = raw.anchor_classes -- anchor classes not in final table
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
@@ -5973,148 +6304,97 @@ enhancers["analyze anchors"] = function(data,filename)
end
end
-enhancers["analyze 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
+actions["prepare tounicode"] = function(data,filename,raw)
+ fonts.map.addtounicode(data,filename)
end
-enhancers["analyze unicodes"] = fonts.map.addtounicode
-
-enhancers["analyze subtables"] = function(data,filename)
- data.luatex = data.luatex or { }
+actions["reorganize subtables"] = function(data,filename,raw)
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
-
-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 then
- if data.glyphs and next(data.glyphs) then
- report_otf("replacing existing glyph table due to subfonts")
- end
- local cidinfo = data.cidinfo
- local verbose = fonts.verbose
- if cidinfo.registry then
- local cidmap, cidname = fonts.cid.getmap(cidinfo.registry,cidinfo.ordering,cidinfo.supplement)
- if cidmap then
- cidinfo.usedname = cidmap.usedname
- local glyphs, uni_to_int, int_to_uni, nofnames, nofunicodes = { }, { }, { }, 0, 0
- local unicodes, names = cidmap.unicodes, cidmap.names
- for n, subfont in next, data.subfonts do
- for index, g in next, subfont.glyphs do
- if not next(g) then
- -- 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
+ local sequences, lookups = { }, { }
+ luatex.sequences, luatex.lookups = sequences, lookups
+ for _, what in next, otf.glists do
+ local dw = raw[what]
+ if dw then
+ for k=1,#dw do
+ local gk = dw[k]
+ local typ = gk.type
+ local chain =
+ (typ == "gsub_contextchain" or typ == "gpos_contextchain") and 1 or
+ (typ == "gsub_reversecontextchain" or typ == "gpos_reversecontextchain") and -1 or 0
+ --
+ 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
+ subtables = t
+ end
+ local flags, markclass = gk.flags, nil
+ if flags then
+ local t = { -- 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,
+ }
+ markclass = flags.mark_class
+ if markclass then
+ markclass = luatex.markclasses[markclass]
+ end
+ flags = t
+ end
+ --
+ local name = gk.name
+ --
+ local features = gk.features
+ if features then
+ -- scripts, tag, ismac
+ local f = { }
+ for i=1,#features do
+ local df = features[i]
+ local tag = strip(lower(df.tag))
+ local ft = f[tag] if not ft then ft = {} f[tag] = ft end
+ local dscripts = df.scripts
+ for i=1,#dscripts do
+ local d = dscripts[i]
+ local languages = d.langs
+ local script = strip(lower(d.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
- glyphs[index] = g
end
end
- subfont.glyphs = nil
- end
- if trace_loading then
- report_otf("cid font remapped, %s unicode points, %s symbolic names, %s glyphs",nofunicodes, nofnames, nofunicodes+nofnames)
+ sequences[#sequences+1] = {
+ type = typ,
+ chain = chain,
+ flags = flags,
+ name = name,
+ subtables = subtables,
+ markclass = markclass,
+ features = f,
+ }
+ else
+ lookups[name] = {
+ type = typ,
+ chain = chain,
+ flags = flags,
+ subtables = subtables,
+ markclass = markclass,
+ }
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
- report_otf("unable to remap cid font, missing cid file for %s",filename)
end
- elseif trace_loading then
- report_otf("font %s has no glyphs",filename)
end
end
end
-enhancers["prepare unicode"] = function(data,filename)
+actions["prepare unicodes"] = function(data,filename,raw)
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
+ local mapmap = data.map or raw.map
if not mapmap then
report_otf("no map in %s",filename)
mapmap = { }
@@ -6128,12 +6408,13 @@ enhancers["prepare unicode"] = function(data,filename)
end
local criterium = fonts.privateoffset
local private = criterium
+ local glyphs = data.glyphs
for index, glyph in next, glyphs do
if index > 0 then
- local name = glyph.name
+ local name = glyph.name -- really needed ?
if name then
local unicode = glyph.unicode
- if unicode == -1 or unicode >= criterium then
+ if not unicode or unicode == -1 or unicode >= criterium then
glyph.unicode = private
indices[private] = index
unicodes[name] = private
@@ -6146,6 +6427,8 @@ enhancers["prepare unicode"] = function(data,filename)
indices[unicode] = index
unicodes[name] = unicode
end
+ else
+ -- message that something is wrong
end
end
end
@@ -6157,7 +6440,7 @@ enhancers["prepare unicode"] = function(data,filename)
local un = unicodes[name]
if not un then
unicodes[name] = unicode -- or 0
- elseif type(un) == "number" then
+ elseif type(un) == "number" then -- tonumber(un)
if un ~= unicode then
multiples[#multiples+1] = name
unicodes[name] = { un, unicode }
@@ -6182,9 +6465,9 @@ enhancers["prepare unicode"] = function(data,filename)
end
if trace_loading then
if #multiples > 0 then
- report_otf("%s glyph are reused: %s",#multiples, concat(multiples," "))
+ report_otf("%s glyphs are reused: %s",#multiples, concat(multiples," "))
else
- report_otf("no glyph are reused")
+ report_otf("no glyphs are reused")
end
end
luatex.indices = indices
@@ -6192,26 +6475,14 @@ enhancers["prepare unicode"] = function(data,filename)
luatex.private = private
end
-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
-
-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
+actions["prepare lookups"] = function(data,filename,raw)
+ local lookups = raw.lookups
+ if lookups then
+ data.lookups = lookups
end
end
-enhancers["reverse coverage"] = function(data,filename)
+actions["reorganize lookups"] = function(data,filename,raw)
-- we prefer the before lookups in a normal order
if data.lookups then
for _, v in next, data.lookups do
@@ -6219,7 +6490,7 @@ enhancers["reverse coverage"] = function(data,filename)
for _, vv in next, v.rules do
local c = vv.coverage
if c and c.before then
- c.before = table.reverse(c.before)
+ c.before = reverse(c.before)
end
end
end
@@ -6227,35 +6498,18 @@ enhancers["reverse coverage"] = function(data,filename)
end
end
-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
-
-enhancers["check math"] = function(data,filename)
- if data.math then
+actions["analyze math"] = function(data,filename,raw)
+ if raw.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 glyphs, udglyphs = data.glyphs, data.udglyphs
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
+ for index, udglyph in next, udglyphs do
+ local mk = udglyph.mathkern
+ local hv = udglyph.horiz_variants
+ local vv = udglyph.vert_variants
if mk or hv or vv then
+ local glyph = glyphs[index]
local math = { }
glyph.math = math
if mk then
@@ -6265,7 +6519,6 @@ enhancers["check math"] = function(data,filename)
end
end
math.kerns = mk
- glyph.mathkern = nil
end
if hv then
math.horiz_variants = hv.variants
@@ -6281,7 +6534,6 @@ enhancers["check math"] = function(data,filename)
if ic and ic ~= 0 then
math.horiz_italic_correction = ic
end
- glyph.horiz_variants = nil
end
if vv then
local uc = unicodes[index]
@@ -6298,221 +6550,48 @@ enhancers["check math"] = function(data,filename)
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
-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
- report_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
-
--- Weird, as maxfirst and maxseconds can have holes, first seems to be indexed, but
--- seconds can start at 2 .. this need to be fixed as getn as well as # are sort of
--- unpredictable alternatively we could force an [1] if not set (maybe I will do that
--- anyway).
-
---~ 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, 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
---~ report_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
---~ report_otf("replacing 'kerns' tables by 'mykerns' tables")
---~ end
---~ if data.kerns then
---~ if trace_loading then
---~ report_otf("removing global 'kern' table")
---~ end
---~ data.kerns = nil
---~ end
---~ local dgpos = data.gpos
---~ if dgpos then
---~ local separator = lpeg.P(" ")
---~ local other = ((1 - separator)^0) / unicodes
---~ local splitter = lpeg.Ct(other * (separator * other)^0)
---~ for gp=1,#dgpos do
---~ local gpos = dgpos[gp]
---~ local subtables = gpos.subtables
---~ if subtables then
---~ for s=1,#subtables do
---~ local subtable = subtables[s]
---~ local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes
---~ if kernclass then -- the next one is quite slow
---~ local split = { } -- saves time
---~ 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 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
---~ for l=1,#lookups do
---~ local lookup = lookups[l]
---~ 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
---~ local lookupkerns = mykerns[lookup]
---~ if not lookupkerns then
---~ lookupkerns = { }
---~ mykerns[lookup] = lookupkerns
---~ end
---~ local baseoffset = (fk-1) * maxseconds
---~ for sk=2,maxseconds do -- we can avoid this loop with a table
---~ local sv = seconds[sk]
---~ local splt = split[sv]
---~ if splt then
---~ local offset = offsets[baseoffset + sk]
---~ --~ local offset = offsets[sk] -- (fk-1) * maxseconds + sk]
---~ if offset 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
---~ end
---~ end
---~ end
---~ elseif trace_loading then
---~ report_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
---~ 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
-
-enhancers["reorganize kerns"] = function(data,filename)
- local glyphs, mapmap, unicodes = data.glyphs, data.luatex.indices, data.luatex.unicodes
+actions["reorganize glyph kerns"] = function(data,filename,raw)
+ local luatex = data.luatex
+ local udglyphs, glyphs, mapmap, unicodes = data.udglyphs, data.glyphs, luatex.indices, luatex.unicodes
local mkdone = false
- local function do_it(lookup,first_unicode,kerns)
+ local function do_it(lookup,first_unicode,extrakerns) -- can be moved inline but seldom used
local glyph = glyphs[mapmap[first_unicode]]
if glyph then
- local mykerns = glyph.mykerns
- if not mykerns then
- mykerns = { } -- unicode indexed !
- glyph.mykerns = mykerns
+ local kerns = glyph.kerns
+ if not kerns then
+ kerns = { } -- unicode indexed !
+ glyph.kerns = kerns
end
- local lookupkerns = mykerns[lookup]
+ local lookupkerns = kerns[lookup]
if not lookupkerns then
lookupkerns = { }
- mykerns[lookup] = lookupkerns
+ kerns[lookup] = lookupkerns
end
- for second_unicode, kern in next, kerns do
+ for second_unicode, kern in next, extrakerns do
lookupkerns[second_unicode] = kern
end
elseif trace_loading then
report_otf("no glyph data for U+%04X", first_unicode)
end
end
- for index, glyph in next, glyphs do
- if glyph.kerns then
- local mykerns = { }
- for k,v in next, glyph.kerns do
+ for index, udglyph in next, data.udglyphs do
+ local kerns = udglyph.kerns
+ if kerns then
+ local glyph = glyphs[index]
+ local newkerns = { }
+ for k,v in next, 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]
@@ -6526,10 +6605,10 @@ enhancers["reorganize kerns"] = function(data,filename)
end
for l=1,#vl do
local vll = vl[l]
- local mkl = mykerns[vll]
+ local mkl = newkerns[vll]
if not mkl then
mkl = { }
- mykerns[vll] = mkl
+ newkerns[vll] = mkl
end
if type(uvc) == "table" then
for u=1,#uvc do
@@ -6542,21 +6621,14 @@ enhancers["reorganize kerns"] = function(data,filename)
end
end
end
- glyph.mykerns = mykerns
- glyph.kerns = nil -- saves space and time
+ glyph.kerns = newkerns -- udglyph.kerns = nil when in mixed mode
mkdone = true
end
end
if trace_loading and mkdone then
- report_otf("replacing 'kerns' tables by 'mykerns' tables")
+ report_otf("replacing 'kerns' tables by a new 'kerns' tables")
end
- if data.kerns then
- if trace_loading then
- report_otf("removing global 'kern' table")
- end
- data.kerns = nil
- end
- local dgpos = data.gpos
+ local dgpos = raw.gpos
if dgpos then
local separator = lpeg.P(" ")
local other = ((1 - separator)^0) / unicodes
@@ -6621,7 +6693,7 @@ enhancers["reorganize kerns"] = function(data,filename)
end
end
end
- subtable.comment = "The kernclass table is merged into mykerns in the indexed glyph tables."
+ subtable.comment = "The kernclass table is merged into kerns in the indexed glyph tables."
subtable.kernclass = { }
end
end
@@ -6630,14 +6702,10 @@ enhancers["reorganize kerns"] = function(data,filename)
end
end
-enhancers["strip not needed data"] = function(data,filename)
+actions["check glyphs"] = function(data,filename,raw)
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?
@@ -6660,32 +6728,57 @@ enhancers["strip not needed data"] = function(data,filename)
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
+ data.luatex.comment = "Glyph tables have their original index. When present, kern tables are indexed by unicode."
end
-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
+actions["check metadata"] = function(data,filename,raw)
+ local metadata = data.metadata
+ metadata.method = loadmethod
+ if loadmethod == "sparse" then
+ for _, k in next, mainfields do
+ if valid_fields[k] then
+ local v = raw[k]
+ if global_fields[k] then
+ if not data[k] then
+ data[k] = v
+ end
+ else
+ if not metadata[k] then
+ metadata[k] = v
+ end
+ end
+ end
+ end
+ else
+ for k, v in next, raw do
+ if valid_fields[k] then
+ if global_fields[k] then
+ if not data[k] then
+ data[v] = v
+ end
+ else
+ if not metadata[k] then
+ metadata[k] = v
+ end
+ end
+ end
+ end
+ end
+ local pfminfo = raw.pfminfo
+ if pfminfo then
+ data.pfminfo = pfminfo
+ metadata.isfixedpitch = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion == "Monospaced")
+ metadata.charwidth = pfminfo and pfminfo.avgwidth
+ end
+ local ttftables = metadata.ttf_tables
+ if ttftables then
+ for i=1,#ttftables do
+ ttftables[i].data = "deleted"
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
+ metadata.xuid = nil
+ data.udglyphs = nil
+ data.map = nil
end
local private_math_parameters = {
@@ -6693,7 +6786,7 @@ local private_math_parameters = {
"FractionDelimiterDisplayStyleSize",
}
-enhancers["check math parameters"] = function(data,filename)
+actions["check math parameters"] = function(data,filename,raw)
local mathdata = data.metadata.math
if mathdata then
for m=1,#private_math_parameters do
@@ -6708,123 +6801,101 @@ enhancers["check math parameters"] = function(data,filename)
end
end
-enhancers["flatten glyph lookups"] = function(data,filename)
- for k, v in next, data.glyphs do
- local lookups = v.lookups
+
+-- kern: ttf has a table with kerns
+--
+-- Weird, as maxfirst and maxseconds can have holes, first seems to be indexed, but
+-- seconds can start at 2 .. this need to be fixed as getn as well as # are sort of
+-- unpredictable alternatively we could force an [1] if not set (maybe I will do that
+-- anyway).
+
+actions["reorganize glyph lookups"] = function(data,filename,raw)
+ local glyphs = data.glyphs
+ for index, udglyph in next, data.udglyphs do
+ local lookups = udglyph.lookups
if lookups then
+ local glyph = glyphs[index]
+ local l = { }
for kk, vv in next, lookups do
+ local aa = { }
+ l[kk] = aa
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
+ local t = vvv.type
+ -- #aa+1
+ if t == "ligature" then
+ aa[kkk] = { "ligature", s.components, s.char }
+ elseif t == "alternate" then
+ aa[kkk] = { "alternate", s.components }
+ elseif t == "substitution" then
+ aa[kkk] = { "substitution", s.variant }
+ elseif t == "multiple" then
+ aa[kkk] = { "multiple", s.components }
+ elseif t == "position" then
+ aa[kkk] = { "position", { s.x or 0, s.y or 0, s.h or 0, s.v or 0 } }
+ elseif t == "pair" then
+ -- maybe flatten this one
+ local one, two, paired = s.offsets[1], s.offsets[2], s.paired or ""
+ if one then
+ if two then
+ aa[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
- 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
+ aa[kkk] = { "pair", paired, { one.x or 0, one.y or 0, one.h or 0, one.v or 0 } }
end
else
- if trace_loading then
- report_otf("flattening needed, report to context list")
- end
- for a, b in next, s do
- if trace_loading and vvv[a] then
- report_otf("flattening conflict, report to context list")
- end
- vvv[a] = b
+ if two then
+ aa[kkk] = { "pair", paired, { }, { two.x or 0, two.y or 0, two.h or 0, two.v or 0} } -- maybe nil instead of { }
+ else
+ aa[kkk] = { "pair", paired }
end
- vvv.specification = nil
end
end
end
end
- end
- end
-end
-
-enhancers["simplify glyph lookups"] = function(data,filename)
- for k, v in next, data.glyphs do
- local lookups = v.lookups
- if lookups then
+ -- we could combine this
local slookups, mlookups
- for kk, vv in next, lookups do
+ for kk, vv in next, l do
if #vv == 1 then
if not slookups then
slookups = { }
- v.slookups = slookups
+ glyph.slookups = slookups
end
slookups[kk] = vv[1]
else
if not mlookups then
mlookups = { }
- v.mlookups = mlookups
+ glyph.mlookups = mlookups
end
mlookups[kk] = vv
end
end
- v.lookups = nil
+ glyph.lookups = nil -- when using table
end
end
end
-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
+actions["reorganize glyph anchors"] = function(data,filename,raw)
+ local glyphs = data.glyphs
+ for index, udglyph in next, data.udglyphs do
+ local anchors = udglyph.anchors
+ if anchors then
+ local glyph = glyphs[index]
+ local a = { }
+ glyph.anchors = a
+ for kk, vv in next, anchors do
+ local aa = { }
+ a[kk] = aa
for kkk, vvv in next, vv do
if vvv.x or vvv.y then
- vv[kkk] = { vvv.x or 0, vvv.y or 0 }
+ aa[kkk] = { vvv.x , vvv.y }
else
+ local aaa = { }
+ aa[kkk] = aaa
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
-
-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
- report_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
+ aaa[kkkk] = { vvvv.x, vvvv.y }
end
- vv.scripts = t
end
end
end
@@ -6832,22 +6903,12 @@ enhancers["flatten feature tables"] = function(data,filename)
end
end
-enhancers.patches = allocate()
-
-enhancers["patch bugs"] = function(data,filename)
- local basename = file.basename(lower(filename))
- for pattern, action in next, enhancers.patches do
- if find(basename,pattern) then
- action(data,filename)
- end
- end
-end
-
--- tex features
+--~ actions["check extra features"] = function(data,filename,raw)
+--~ -- later, ctx only
+--~ end
-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
@@ -6924,25 +6985,6 @@ tfmdata.mode = mode
return processes, features
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)
@@ -7050,7 +7092,7 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
local filename = fonts.tfm.checkedfilename(luatex)
local fontname = metadata.fontname
local fullname = metadata.fullname or fontname
- local cidinfo = data.cidinfo
+ local cidinfo = data.cidinfo -- or { }
local units = metadata.units_per_em or 1000
--
cidinfo.registry = cidinfo and cidinfo.registry or "" -- weird here, fix upstream
@@ -7071,7 +7113,7 @@ local function copytotfm(data,cache_id) -- we can save a copy when we reorder th
if metadata.isfixedpitch then
parameters.space_stretch = 0
parameters.space_shrink = 0
- elseif otf.syncspace then --
+ elseif syncspace then --
parameters.space_stretch = spaceunits/2
parameters.space_shrink = spaceunits/3
end
@@ -7697,7 +7739,7 @@ local function preparebasekerns(tfmdata,kind,value) -- todo what kind of kerns,
for u, chr in next, characters do
local d = descriptions[u]
if d then
- local dk = d.mykerns -- shared
+ local dk = d.kerns -- shared
if dk then
local s = sharedkerns[dk]
if s == false then
@@ -10285,7 +10327,7 @@ local function prepare_lookups(tfmdata)
end
end
end
- local list = glyph.mykerns
+ local list = glyph.kerns
if list then
for lookup, krn in next, list do
local k = kerns[lookup]
@@ -10831,6 +10873,12 @@ local report_otf = logs.new("load otf")
--
-- we could have a tnum variant as well
+-- In the userdata interface we can not longer tweak the loaded font as
+-- conveniently as before. For instance, instead of pushing extra data in
+-- in the table using the original structure, we now have to operate on
+-- the mkiv representation. And as the fontloader interface is modelled
+-- after fontforge we cannot change that one too much either.
+
local extra_lists = {
tlig = {
{
@@ -10881,116 +10929,120 @@ local extra_lists = {
local extra_features = { -- maybe just 1..n so that we prescribe order
tlig = {
{
- features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "tlig", comment = "added bij mkiv" }, },
+ features = { ["*"] = { ["*"] = true } },
name = "ctx_tlig_1",
- subtables = { { name = "ctx_tlig_1_s" } },
+ subtables = { "ctx_tlig_1_s" },
type = "gsub_ligature",
flags = { },
},
},
trep = {
{
- features = { { scripts = { { script = "*", langs = { "*" }, } }, tag = "trep", comment = "added bij mkiv" }, },
+ features = { ["*"] = { ["*"] = true } },
name = "ctx_trep_1",
- subtables = { { name = "ctx_trep_1_s" } },
+ subtables = { "ctx_trep_1_s" },
type = "gsub_single",
flags = { },
},
},
anum = {
{
- features = { { scripts = { { script = "arab", langs = { "dflt", "FAR" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ features = { arab = { URD = true, dflt = true } },
name = "ctx_anum_1",
- subtables = { { name = "ctx_anum_1_s" } },
+ subtables = { "ctx_anum_1_s" },
type = "gsub_single",
flags = { },
},
{
- features = { { scripts = { { script = "arab", langs = { "URD" }, } }, tag = "anum", comment = "added bij mkiv" }, },
+ features = { arab = { URD = true } },
name = "ctx_anum_2",
- subtables = { { name = "ctx_anum_2_s" } },
+ subtables = { "ctx_anum_2_s" },
type = "gsub_single",
flags = { },
},
},
}
-otf.enhancers["add some missing characters"] = function(data,filename)
- -- todo
-end
-
-otf.enhancers["enrich with features"] = function(data,filename)
- -- could be done elsewhere (true can be #)
- local used = { }
- for i=1,#otf.glists do
- local g = data[otf.glists[i]]
- if g then
- for i=1,#g do
- local f = g[i].features
- if f then
- for i=1,#f do
- local t = f[i].tag
- if t then used[t] = true end
- end
- end
- end
- end
- end
- --
+local function enhancedata(data,filename,raw)
+ local luatex = data.luatex
+ local lookups = luatex.lookups
+ local sequences = luatex.sequences
local glyphs = data.glyphs
- local indices = data.map.map
- data.gsub = data.gsub or { }
+ local indices = luatex.indices
+ local gsubfeatures = luatex.features.gsub
for kind, specifications in next, extra_features do
- if not used[kind] then
+ if gsub and gsub[kind] then
+ -- already present
+ else
local done = 0
for s=1,#specifications do
local added = false
local specification = specifications[s]
+ local features, subtables = specification.features, specification.subtables
+ local name, type, flags = specification.name, specification.type, specification.flags
+ local full = subtables[1]
local list = extra_lists[kind][s]
- local name = specification.name .. "_s"
- if specification.type == "gsub_ligature" then
+ if type == "gsub_ligature" then
+ -- inefficient loop
for unicode, index in next, indices do
local glyph = glyphs[index]
local ligature = list[glyph.name]
if ligature then
- local o = glyph.lookups or { }
- -- o[name] = { "ligature", ligature, glyph.name }
- o[name] = {
- {
- ["type"] = "ligature",
- ["specification"] = {
- char = glyph.name,
- components = ligature,
- }
- }
- }
- glyph.lookups, done, added = o, done+1, true
+ if glyph.slookups then
+ glyph.slookups [full] = { "ligature", ligature, glyph.name }
+ else
+ glyph.slookups = { [full] = { "ligature", ligature, glyph.name } }
+ end
+ done, added = done+1, true
end
end
- elseif specification.type == "gsub_single" then
+ elseif type == "gsub_single" then
+ -- inefficient loop
for unicode, index in next, indices do
local glyph = glyphs[index]
local r = list[unicode]
if r then
local replacement = indices[r]
if replacement and glyphs[replacement] then
- local o = glyph.lookups or { }
- -- o[name] = { { "substitution", glyphs[replacement].name } }
- o[name] = {
- {
- ["type"] = "substitution",
- ["specification"] = {
- variant = glyphs[replacement].name,
- }
- }
- }
- glyph.lookups, done, added = o, done+1, true
+ if glyph.slookups then
+ glyph.slookups [full] = { "substitution", glyphs[replacement].name }
+ else
+ glyph.slookups = { [full] = { "substitution", glyphs[replacement].name } }
+ end
+ done, added = done+1, true
end
end
end
end
if added then
- insert(data.gsub,s,table.fastcopy(specification)) -- right order
+ sequences[#sequences+1] = {
+ chain = 0,
+ features = { [kind] = features },
+ flags = flags,
+ name = name,
+ subtables = subtables,
+ type = type,
+ }
+ -- register in metadata (merge as there can be a few)
+ if not gsubfeatures then
+ gsubfeatures = { }
+ luatex.features.gsub = gsubfeatures
+ end
+ local k = gsubfeatures[kind]
+ if not k then
+ k = { }
+ gsubfeatures[kind] = k
+ end
+ for script, languages in next, features do
+ local kk = k[script]
+ if not kk then
+ kk = { }
+ k[script] = kk
+ end
+ for language, value in next, languages do
+ kk[language] = value
+ end
+ end
end
end
if done > 0 then
@@ -11002,6 +11054,8 @@ otf.enhancers["enrich with features"] = function(data,filename)
end
end
+otf.enhancers.register("check extra features",enhancedata)
+
local features = otf.tables.features
features['tlig'] = 'TeX Ligatures'