summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorPhilipp Gesang <phg@phi-gamma.net>2016-07-30 12:26:59 +0200
committerGitHub <noreply@github.com>2016-07-30 12:26:59 +0200
commit9e2db3ead715ceecf2afc879aefc020f84ea4f09 (patch)
tree89960031e5cf796661e7a6f10bdf9d32f36c01dd /src
parent2fcdccf7edfa1cfb0f03fe8f2163c7c5d8281984 (diff)
parentc0597dba961fb9f99c2bd5d2d7f442dc37382dc2 (diff)
downloadluaotfload-9e2db3ead715ceecf2afc879aefc020f84ea4f09.tar.gz
Merge pull request #374 from phi-gamma/master
lastest feature code
Diffstat (limited to 'src')
-rw-r--r--src/fontloader/misc/fontloader-font-con.lua358
-rw-r--r--src/fontloader/misc/fontloader-font-one.lua110
-rw-r--r--src/fontloader/misc/fontloader-font-otl.lua180
-rw-r--r--src/fontloader/misc/fontloader-font-ots.lua158
-rw-r--r--src/fontloader/misc/fontloader-font-tfm.lua44
-rw-r--r--src/fontloader/runtime/fontloader-reference.lua626
-rw-r--r--src/luaotfload-features.lua60
7 files changed, 829 insertions, 707 deletions
diff --git a/src/fontloader/misc/fontloader-font-con.lua b/src/fontloader/misc/fontloader-font-con.lua
index 9a6f3f8..931e4e7 100644
--- a/src/fontloader/misc/fontloader-font-con.lua
+++ b/src/fontloader/misc/fontloader-font-con.lua
@@ -12,9 +12,10 @@ local next, tostring, rawget = next, tostring, rawget
local format, match, lower, gsub, find = string.format, string.match, string.lower, string.gsub, string.find
local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy
local derivetable = table.derive
+local ioflush = io.flush
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end)
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_scaling = false trackers.register("fonts.scaling", function(v) trace_scaling = v end)
local report_defining = logs.reporter("fonts","defining")
@@ -1086,146 +1087,269 @@ setmetatableindex(formats, function(t,k)
return rawget(t,file.suffix(l))
end)
-local locations = { }
+do
-local function setindeed(mode,target,group,name,action,position)
- local t = target[mode]
- if not t then
- report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode)
- os.exit()
- elseif position then
- -- todo: remove existing
- insert(t, position, { name = name, action = action })
- else
- for i=1,#t do
- local ti = t[i]
- if ti.name == name then
- ti.action = action
- return
+ local function setindeed(mode,target,group,name,action,position)
+ local t = target[mode]
+ if not t then
+ report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode)
+ os.exit()
+ elseif position then
+ -- todo: remove existing
+ insert(t, position, { name = name, action = action })
+ else
+ for i=1,#t do
+ local ti = t[i]
+ if ti.name == name then
+ ti.action = action
+ return
+ end
end
+ insert(t, { name = name, action = action })
end
- insert(t, { name = name, action = action })
- end
-end
-
-local function set(group,name,target,source)
- target = target[group]
- if not target then
- report_defining("fatal target error in setting feature %a, group %a",name,group)
- os.exit()
- end
- local source = source[group]
- if not source then
- report_defining("fatal source error in setting feature %a, group %a",name,group)
- os.exit()
- end
- local node = source.node
- local base = source.base
- local position = source.position
- if node then
- setindeed("node",target,group,name,node,position)
end
- if base then
- setindeed("base",target,group,name,base,position)
- end
-end
-local function register(where,specification)
- local name = specification.name
- if name and name ~= "" then
- local default = specification.default
- local description = specification.description
- local initializers = specification.initializers
- local processors = specification.processors
- local manipulators = specification.manipulators
- local modechecker = specification.modechecker
- if default then
- where.defaults[name] = default
+ local function set(group,name,target,source)
+ target = target[group]
+ if not target then
+ report_defining("fatal target error in setting feature %a, group %a",name,group)
+ os.exit()
end
- if description and description ~= "" then
- where.descriptions[name] = description
+ local source = source[group]
+ if not source then
+ report_defining("fatal source error in setting feature %a, group %a",name,group)
+ os.exit()
end
- if initializers then
- set('initializers',name,where,specification)
+ local node = source.node
+ local base = source.base
+ local position = source.position
+ if node then
+ setindeed("node",target,group,name,node,position)
end
- if processors then
- set('processors', name,where,specification)
- end
- if manipulators then
- set('manipulators',name,where,specification)
+ if base then
+ setindeed("base",target,group,name,base,position)
end
- if modechecker then
- where.modechecker = modechecker
+ end
+
+ local function register(where,specification)
+ local name = specification.name
+ if name and name ~= "" then
+ local default = specification.default
+ local description = specification.description
+ local initializers = specification.initializers
+ local processors = specification.processors
+ local manipulators = specification.manipulators
+ local modechecker = specification.modechecker
+ if default then
+ where.defaults[name] = default
+ end
+ if description and description ~= "" then
+ where.descriptions[name] = description
+ end
+ if initializers then
+ set('initializers',name,where,specification)
+ end
+ if processors then
+ set('processors', name,where,specification)
+ end
+ if manipulators then
+ set('manipulators',name,where,specification)
+ end
+ if modechecker then
+ where.modechecker = modechecker
+ end
end
end
-end
-constructors.registerfeature = register
-
-function constructors.getfeatureaction(what,where,mode,name)
- what = handlers[what].features
- if what then
- where = what[where]
- if where then
- mode = where[mode]
- if mode then
- for i=1,#mode do
- local m = mode[i]
- if m.name == name then
- return m.action
+ constructors.registerfeature = register
+
+ function constructors.getfeatureaction(what,where,mode,name)
+ what = handlers[what].features
+ if what then
+ where = what[where]
+ if where then
+ mode = where[mode]
+ if mode then
+ for i=1,#mode do
+ local m = mode[i]
+ if m.name == name then
+ return m.action
+ end
end
end
end
end
end
+
+ local newfeatures = { }
+ constructors.newfeatures = newfeatures -- downward compatible
+ constructors.features = newfeatures
+
+ local function setnewfeatures(what)
+ local handler = handlers[what]
+ local features = handler.features
+ if not features then
+ local tables = handler.tables -- can be preloaded
+ local statistics = handler.statistics -- can be preloaded
+ features = allocate {
+ defaults = { },
+ descriptions = tables and tables.features or { },
+ used = statistics and statistics.usedfeatures or { },
+ initializers = { base = { }, node = { } },
+ processors = { base = { }, node = { } },
+ manipulators = { base = { }, node = { } },
+ }
+ features.register = function(specification) return register(features,specification) end
+ handler.features = features -- will also become hidden
+ end
+ return features
+ end
+
+ setmetatable(newfeatures, {
+ __call = function(t,k) local v = t[k] return v end,
+ __index = function(t,k) local v = setnewfeatures(k) t[k] = v return v end,
+ })
+
end
-local newhandler = { }
-constructors.handlers = newhandler -- downward compatible
-constructors.newhandler = newhandler
+do
-local function setnewhandler(what) -- could be a metatable newindex
- local handler = handlers[what]
- if not handler then
- handler = { }
- handlers[what] = handler
+ local newhandler = { }
+ constructors.handlers = newhandler -- downward compatible
+ constructors.newhandler = newhandler
+
+ local function setnewhandler(what) -- could be a metatable newindex
+ local handler = handlers[what]
+ if not handler then
+ handler = { }
+ handlers[what] = handler
+ end
+ return handler
end
- return handler
+
+ setmetatable(newhandler, {
+ __call = function(t,k) local v = t[k] return v end,
+ __index = function(t,k) local v = setnewhandler(k) t[k] = v return v end,
+ })
+
end
-setmetatable(newhandler, {
- __call = function(t,k) local v = t[k] return v end,
- __index = function(t,k) local v = setnewhandler(k) t[k] = v return v end,
-})
-
-local newfeatures = { }
-constructors.newfeatures = newfeatures -- downward compatible
-constructors.features = newfeatures
-
-local function setnewfeatures(what)
- local handler = handlers[what]
- local features = handler.features
- if not features then
- local tables = handler.tables -- can be preloaded
- local statistics = handler.statistics -- can be preloaded
- features = allocate {
- defaults = { },
- descriptions = tables and tables.features or { },
- used = statistics and statistics.usedfeatures or { },
- initializers = { base = { }, node = { } },
- processors = { base = { }, node = { } },
- manipulators = { base = { }, node = { } },
- }
- features.register = function(specification) return register(features,specification) end
- handler.features = features -- will also become hidden
+do
+ -- a pitty that we need to be generic as we have nicer mechanisms for this ...
+
+ local newenhancer = { }
+ constructors.enhancers = newenhancer
+ constructors.newenhancer = newenhancer
+
+ local function setnewenhancer(format)
+
+ local handler = handlers[format]
+ local enhancers = handler.enhancers
+
+ if not enhancers then
+
+ local actions = allocate()
+ local before = allocate()
+ local after = allocate()
+ local order = allocate()
+ local patches = { before = before, after = after }
+
+ local trace = false
+ local report = logs.reporter("fonts",format .. " enhancing")
+
+ trackers.register(format .. ".loading", function(v) trace = v end)
+
+ local function enhance(name,data,filename,raw)
+ local enhancer = actions[name]
+ if enhancer then
+ if trace then
+ report("apply enhancement %a to file %a",name,filename)
+ ioflush()
+ end
+ enhancer(data,filename,raw)
+ else
+ -- no message as we can have private ones
+ end
+ end
+
+ local function apply(data,filename,raw)
+ local basename = file.basename(lower(filename))
+ if trace then
+ report("%s enhancing file %a","start",filename)
+ end
+ ioflush() -- we want instant messages
+ for e=1,#order do
+ local enhancer = order[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
+ enhance(enhancer,data,filename,raw)
+ 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
+ if trace then
+ report("%s enhancing file %a","stop",filename)
+ end
+ ioflush() -- we want instant messages
+ end
+
+ local function register(what,action)
+ if action then
+ if actions[what] then
+ -- overloading, e.g."check extra features"
+ else
+ order[#order+1] = what
+ end
+ actions[what] = action
+ else
+ report("bad enhancer %a",what)
+ end
+ end
+
+ -- fonts.constructors.otf.enhancers.patch("before","migrate metadata","cambria",function() end)
+
+ local function patch(what,where,pattern,action)
+ local pw = patches[what]
+ if pw then
+ local ww = pw[where]
+ if ww then
+ ww[pattern] = action
+ else
+ pw[where] = { [pattern] = action}
+ end
+ end
+ end
+
+ enhancers = {
+ register = register,
+ apply = apply,
+ patch = patch,
+ patches = { register = patch }, -- for old times sake
+ }
+
+ handler.enhancers = enhancers
+ end
+ return enhancers
end
- return features
-end
-setmetatable(newfeatures, {
- __call = function(t,k) local v = t[k] return v end,
- __index = function(t,k) local v = setnewfeatures(k) t[k] = v return v end,
-})
+ setmetatable(newenhancer, {
+ __call = function(t,k) local v = t[k] return v end,
+ __index = function(t,k) local v = setnewenhancer(k) t[k] = v return v end,
+ })
+
+end
--[[ldx--
<p>We need to check for default features. For this we provide
diff --git a/src/fontloader/misc/fontloader-font-one.lua b/src/fontloader/misc/fontloader-font-one.lua
index 8629850..d9b9c65 100644
--- a/src/fontloader/misc/fontloader-font-one.lua
+++ b/src/fontloader/misc/fontloader-font-one.lua
@@ -29,42 +29,45 @@ local bxor, rshift = bit32.bxor, bit32.rshift
local P, S, R, Cmt, C, Ct, Cs, Carg = lpeg.P, lpeg.S, lpeg.R, lpeg.Cmt, lpeg.C, lpeg.Ct, lpeg.Cs, lpeg.Carg
local lpegmatch, patterns = lpeg.match, lpeg.patterns
-local trace_features = false trackers.register("afm.features", function(v) trace_features = v end)
-local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end)
-local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end)
-local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+local trace_features = false trackers.register("afm.features", function(v) trace_features = v end)
+local trace_indexing = false trackers.register("afm.indexing", function(v) trace_indexing = v end)
+local trace_loading = false trackers.register("afm.loading", function(v) trace_loading = v end)
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
-local report_afm = logs.reporter("fonts","afm loading")
+local report_afm = logs.reporter("fonts","afm loading")
-local setmetatableindex = table.setmetatableindex
-local derivetable = table.derive
+local setmetatableindex = table.setmetatableindex
+local derivetable = table.derive
-local findbinfile = resolvers.findbinfile
+local findbinfile = resolvers.findbinfile
-local definers = fonts.definers
-local readers = fonts.readers
-local constructors = fonts.constructors
+local definers = fonts.definers
+local readers = fonts.readers
+local constructors = fonts.constructors
-local afm = constructors.handlers.afm
-local pfb = constructors.handlers.pfb
-local otf = fonts.handlers.otf
+local afm = constructors.handlers.afm
+local pfb = constructors.handlers.pfb
+local otf = fonts.handlers.otf
-local otfreaders = otf.readers
-local otfenhancers = otf.enhancers
+local otfreaders = otf.readers
+local otfenhancers = otf.enhancers
-local afmfeatures = constructors.features.afm
-local registerafmfeature = afmfeatures.register
+local afmfeatures = constructors.features.afm
+local registerafmfeature = afmfeatures.register
-afm.version = 1.512 -- incrementing this number one up will force a re-cache
-afm.cache = containers.define("fonts", "afm", afm.version, true)
-afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*)
+local afmenhancers = constructors.enhancers.afm
+local registerafmenhancer = afmenhancers.register
-afm.helpdata = { } -- set later on so no local for this
-afm.syncspace = true -- when true, nicer stretch values
+afm.version = 1.512 -- incrementing this number one up will force a re-cache
+afm.cache = containers.define("fonts", "one", afm.version, true)
+afm.autoprefixed = true -- this will become false some day (catches texnansi-blabla.*)
-local overloads = fonts.mappings.overloads
+afm.helpdata = { } -- set later on so no local for this
+afm.syncspace = true -- when true, nicer stretch values
-local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes
+local overloads = fonts.mappings.overloads
+
+local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes
--[[ldx--
<p>We cache files. Caching is taken care of in the loader. We cheat a bit by adding
@@ -76,36 +79,6 @@ fashion and later we transform it to sequences. Then we apply some methods also
used in opentype fonts (like <t>tlig</t>).</p>
--ldx]]--
-local enhancers = {
- -- It's cleaner to implement them after we've seen what we are
- -- dealing with.
-}
-
-local steps = {
- "unify names",
- "add ligatures",
- "add extra kerns",
- "normalize features",
- "check extra features",
- "fix names", -- what a hack ...
--- "add tounicode data",
-}
-
-local function applyenhancers(data,filename)
- for i=1,#steps do
- local step = steps[i]
- local enhancer = enhancers[step]
- if enhancer then
- if trace_loading then
- report_afm("applying enhancer %a",step)
- end
- enhancer(data,filename)
- else
- report_afm("invalid enhancer %a",step)
- end
- end
-end
-
function afm.load(filename)
filename = resolvers.findfile(filename,'afm') or ""
if filename ~= "" and not fonts.names.ignoredfile(filename) then
@@ -129,7 +102,7 @@ function afm.load(filename)
report_afm("reading %a",filename)
data = afm.readers.loadfont(filename,pfbname)
if data then
- applyenhancers(data,filename)
+ afmenhancers.apply(data,filename)
-- otfreaders.addunicodetable(data) -- only when not done yet
fonts.mappings.addtounicode(data,filename)
-- otfreaders.extend(data)
@@ -162,7 +135,7 @@ end
local uparser = fonts.mappings.makenameparser() -- each time
-enhancers["unify names"] = function(data, filename)
+local function enhance_unify_names(data, filename)
local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context
local unicodes = { }
local names = { }
@@ -218,7 +191,7 @@ end
local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } }
local noflags = { false, false, false, false }
-enhancers["normalize features"] = function(data)
+local function enhance_normalize_features(data)
local ligatures = setmetatableindex("table")
local kerns = setmetatableindex("table")
local extrakerns = setmetatableindex("table")
@@ -319,9 +292,7 @@ enhancers["normalize features"] = function(data)
data.resources.sequences = sequences
end
-enhancers["check extra features"] = otf.enhancers.enhance
-
-enhancers["fix names"] = function(data)
+local function enhance_fix_names(data)
for k, v in next, data.descriptions do
local n = v.name
local r = overloads[n]
@@ -368,14 +339,10 @@ local addthem = function(rawdata,ligatures)
end
end
-enhancers["add ligatures"] = function(rawdata)
+local function enhance_add_ligatures(rawdata)
addthem(rawdata,afm.helpdata.ligatures)
end
--- enhancers["add tex ligatures"] = function(rawdata)
--- addthem(rawdata,afm.helpdata.texligatures)
--- end
-
--[[ldx--
<p>We keep the extra kerns in separate kerning tables so that we can use
them selectively.</p>
@@ -388,7 +355,7 @@ them selectively.</p>
-- we don't use the character database. (Ok, we can have a context specific
-- variant).
-enhancers["add extra kerns"] = function(rawdata) -- using shcodes is not robust here
+local function enhance_add_extra_kerns(rawdata) -- using shcodes is not robust here
local descriptions = rawdata.descriptions
local resources = rawdata.resources
local unicodes = resources.unicodes
@@ -851,3 +818,12 @@ function readers.pfb(specification,method) -- only called when forced
swap("specification")
return readers.afm(specification,method)
end
+
+-- now we register them
+
+registerafmenhancer("unify names", enhance_unify_names)
+registerafmenhancer("add ligatures", enhance_add_ligatures)
+registerafmenhancer("add extra kerns", enhance_add_extra_kerns)
+registerafmenhancer("normalize features", enhance_normalize_features)
+registerafmenhancer("check extra features", otfenhancers.enhance)
+registerafmenhancer("fix names", enhance_fix_names)
diff --git a/src/fontloader/misc/fontloader-font-otl.lua b/src/fontloader/misc/fontloader-font-otl.lua
index bdce80d..94f6a45 100644
--- a/src/fontloader/misc/fontloader-font-otl.lua
+++ b/src/fontloader/misc/fontloader-font-otl.lua
@@ -26,70 +26,67 @@ if not modules then modules = { } end modules ['font-otl'] = {
local gmatch, find, match, lower, strip = string.gmatch, string.find, string.match, string.lower, string.strip
local type, next, tonumber, tostring, unpack = type, next, tonumber, tostring, unpack
local abs = math.abs
-local ioflush = io.flush
local derivetable = table.derive
local formatters = string.formatters
-local setmetatableindex = table.setmetatableindex
-local allocate = utilities.storage.allocate
-local registertracker = trackers.register
-local registerdirective = directives.register
-local starttiming = statistics.starttiming
-local stoptiming = statistics.stoptiming
-local elapsedtime = statistics.elapsedtime
-local findbinfile = resolvers.findbinfile
+local setmetatableindex = table.setmetatableindex
+local allocate = utilities.storage.allocate
+local registertracker = trackers.register
+local registerdirective = directives.register
+local starttiming = statistics.starttiming
+local stoptiming = statistics.stoptiming
+local elapsedtime = statistics.elapsedtime
+local findbinfile = resolvers.findbinfile
------ trace_private = false registertracker("otf.private", function(v) trace_private = v end)
------ trace_subfonts = false registertracker("otf.subfonts", function(v) trace_subfonts = v end)
-local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end)
-local trace_features = false registertracker("otf.features", function(v) trace_features = v end)
------ trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end)
------ trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end)
------ trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end)
-local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end)
+----- trace_private = false registertracker("otf.private", function(v) trace_private = v end)
+----- trace_subfonts = false registertracker("otf.subfonts", function(v) trace_subfonts = v end)
+local trace_loading = false registertracker("otf.loading", function(v) trace_loading = v end)
+local trace_features = false registertracker("otf.features", function(v) trace_features = v end)
+----- trace_dynamics = false registertracker("otf.dynamics", function(v) trace_dynamics = v end)
+----- trace_sequences = false registertracker("otf.sequences", function(v) trace_sequences = v end)
+----- trace_markwidth = false registertracker("otf.markwidth", function(v) trace_markwidth = v end)
+local trace_defining = false registertracker("fonts.defining", function(v) trace_defining = v end)
-local report_otf = logs.reporter("fonts","otf loading")
+local report_otf = logs.reporter("fonts","otf loading")
-local fonts = fonts
-local otf = fonts.handlers.otf
+local fonts = fonts
+local otf = fonts.handlers.otf
-otf.version = 3.025 -- beware: also sync font-mis.lua and in mtx-fonts
-otf.cache = containers.define("fonts", "otl", otf.version, true)
-otf.svgcache = containers.define("fonts", "svg", otf.version, true)
-otf.pdfcache = containers.define("fonts", "pdf", otf.version, true)
+otf.version = 3.025 -- beware: also sync font-mis.lua and in mtx-fonts
+otf.cache = containers.define("fonts", "otl", otf.version, true)
+otf.svgcache = containers.define("fonts", "svg", otf.version, true)
+otf.pdfcache = containers.define("fonts", "pdf", otf.version, true)
-otf.svgenabled = false
+otf.svgenabled = false
-local otfreaders = otf.readers
+local otfreaders = otf.readers
-local hashes = fonts.hashes
-local definers = fonts.definers
-local readers = fonts.readers
-local constructors = fonts.constructors
+local hashes = fonts.hashes
+local definers = fonts.definers
+local readers = fonts.readers
+local constructors = fonts.constructors
-local otffeatures = constructors.features.otf
-local registerotffeature = otffeatures.register
+local otffeatures = constructors.features.otf
+local registerotffeature = otffeatures.register
-local enhancers = allocate()
-otf.enhancers = enhancers
-local patches = { }
-enhancers.patches = patches
+local otfenhancers = constructors.enhancers.otf
+local registerotfenhancer = otfenhancers.register
-local forceload = false
-local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M)
-local syncspace = true
-local forcenotdef = false
+local forceload = false
+local cleanup = 0 -- mk: 0=885M 1=765M 2=735M (regular run 730M)
+local syncspace = true
+local forcenotdef = false
-local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes
+local applyruntimefixes = fonts.treatments and fonts.treatments.applyfixes
-local wildcard = "*"
-local default = "dflt"
+local wildcard = "*"
+local default = "dflt"
-local formats = fonts.formats
+local formats = fonts.formats
-formats.otf = "opentype"
-formats.ttf = "truetype"
-formats.ttc = "truetype"
+formats.otf = "opentype"
+formats.ttf = "truetype"
+formats.ttc = "truetype"
registerdirective("fonts.otf.loader.cleanup", function(v) cleanup = tonumber(v) or (v and 1) or 0 end)
registerdirective("fonts.otf.loader.force", function(v) forceload = v end)
@@ -105,92 +102,9 @@ registerdirective("fonts.otf.loader.forcenotdef", function(v) forcenotdef =
-- end
-- end
--- Enhancers are used to apply fixes and extensions to fonts. For instance, we use them
--- to implement tlig and trep features. They are not neccessarily bound to opentype
--- fonts but can also apply to type one fonts, given that they obey the structure of an
--- opentype font. They are not to be confused with format specific features but maybe
--- some are so generic that they might eventually move to this mechanism.
+-- otfenhancers.patch("before","migrate metadata","cambria",function() end)
-local ordered_enhancers = {
- "check extra features",
-}
-
-local actions = allocate()
-local before = allocate()
-local after = allocate()
-
-patches.before = before
-patches.after = after
-
-local function enhance(name,data,filename,raw)
- local enhancer = actions[name]
- if enhancer then
- if trace_loading then
- report_otf("apply enhancement %a to file %a",name,filename)
- ioflush()
- end
- enhancer(data,filename,raw)
- else
- -- no message as we can have private ones
- end
-end
-
-function enhancers.apply(data,filename,raw)
- local basename = file.basename(lower(filename))
- if trace_loading then
- report_otf("%s enhancing file %a","start",filename)
- end
- 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
- enhance(enhancer,data,filename,raw)
- 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
- if trace_loading then
- report_otf("%s enhancing file %a","stop",filename)
- end
- ioflush() -- we want instant messages
-end
-
--- patches.register("before","migrate metadata","cambria",function() end)
-
-function patches.register(what,where,pattern,action)
- local pw = patches[what]
- if pw then
- local ww = pw[where]
- if ww then
- ww[pattern] = action
- else
- pw[where] = { [pattern] = action}
- end
- end
-end
-
-function patches.report(fmt,...)
- if trace_loading then
- report_otf("patching: %s",formatters[fmt](...))
- end
-end
-
-function enhancers.register(what,action) -- only already registered can be overloaded
- actions[what] = action
-end
+registerotfenhancer("check extra features", function() end) -- placeholder
function otf.load(filename,sub,featurefile) -- second argument (format) is gone !
--
@@ -329,7 +243,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone
otfreaders.expand(data) -- inline tables
otfreaders.addunicodetable(data) -- only when not done yet
--
- enhancers.apply(data,filename,data)
+ otfenhancers.apply(data,filename,data)
--
-- constructors.addcoreunicodes(data.resources.unicodes) -- still needed ?
--
diff --git a/src/fontloader/misc/fontloader-font-ots.lua b/src/fontloader/misc/fontloader-font-ots.lua
index 10f0518..d371156 100644
--- a/src/fontloader/misc/fontloader-font-ots.lua
+++ b/src/fontloader/misc/fontloader-font-ots.lua
@@ -275,6 +275,13 @@ local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.chec
local registerstep = (nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
local registermessage = (nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
+local function checkdisccontent(d)
+ local pre, post, replace = getdisc(d)
+ if pre then for n in traverse_id(glue_code,pre) do print("pre",nodes.idstostring(pre)) break end end
+ if post then for n in traverse_id(glue_code,post) do print("pos",nodes.idstostring(post)) break end end
+ if replace then for n in traverse_id(glue_code,replace) do print("rep",nodes.idstostring(replace)) break end end
+end
+
local function logprocess(...)
if trace_steps then
registermessage(...)
@@ -351,7 +358,7 @@ end
local function copy_glyph(g) -- next and prev are untouched !
local components = getfield(g,"components")
if components then
- setfield(g,"components",nil)
+ setfield(g,"components")
local n = copy_node(g)
copyinjection(n,g) -- we need to preserve the lig indices
setfield(g,"components",components)
@@ -364,11 +371,18 @@ local function copy_glyph(g) -- next and prev are untouched !
end
local function flattendisk(head,disc)
- local _, _, replace, _, _, replacetail = getdisc(disc,true)
- setfield(disc,"replace",nil)
+ local pre, post, replace, pretail, posttail, replacetail = getdisc(disc,true)
+ local prev, next = getboth(disc)
+ local ishead = head == disc
+ setdisc(disc)
flush_node(disc)
- if head == disc then
- local next = getnext(disc)
+ if pre then
+ flush_node_list(pre)
+ end
+ if post then
+ flush_node_list(post)
+ end
+ if ishead then
if replace then
if next then
setlink(replacetail,next)
@@ -380,7 +394,6 @@ local function flattendisk(head,disc)
return -- maybe warning
end
else
- local prev, next = getboth(disc)
if replace then
if next then
setlink(replacetail,next)
@@ -419,8 +432,8 @@ local function markstoligature(head,start,stop,char)
else
local prev = getprev(start)
local next = getnext(stop)
- setprev(start,nil)
- setnext(stop,nil)
+ setprev(start)
+ setnext(stop)
local base = copy_glyph(start)
if head == start then
head = base
@@ -482,8 +495,8 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local prev = getprev(start)
local next = getnext(stop)
local comp = start
- setprev(start,nil)
- setnext(stop,nil)
+ setprev(start)
+ setnext(stop)
local base = copy_glyph(start)
if start == head then
head = base
@@ -553,38 +566,37 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
-- anyway
local pre, post, replace, pretail, posttail, replacetail = getdisc(discfound,true)
if not replace then -- todo: signal simple hyphen
- local prev = getprev(base)
--- local copied = copy_node_list(comp)
-local current = comp
-local previous = nil
-local copied = nil
-while current do
- if getid(current) == glyph_code then
- local n = copy_node(current)
- if copied then
- setlink(previous,n)
- else
- copied = n
- end
- previous = n
- end
- current = getnext(current)
-end
- setprev(discnext,nil) -- also blocks funny assignments
- setnext(discprev,nil) -- also blocks funny assignments
+ local prev = getprev(base)
+ local current = comp
+ local previous = nil
+ local copied = nil
+ while current do
+ if getid(current) == glyph_code then
+ local n = copy_node(current)
+ if copied then
+ setlink(previous,n)
+ else
+ copied = n
+ end
+ previous = n
+ end
+ current = getnext(current)
+ end
+ setprev(discnext) -- also blocks funny assignments
+ setnext(discprev) -- also blocks funny assignments
if pre then
setlink(discprev,pre)
end
pre = comp
if post then
setlink(posttail,discnext)
- setprev(post,nil)
+ setprev(post)
else
post = discnext
end
setlink(prev,discfound)
setlink(discfound,next)
- setboth(base,nil,nil)
+ setboth(base)
setfield(base,"components",copied)
setdisc(discfound,pre,post,base,discretionary_code)
base = prev -- restart
@@ -1751,6 +1763,42 @@ end
-- order to handle that we need more complex code which also slows down even more. The main
-- loop variant could deal with that: test, collapse, backtrack.
+local new_kern = nuts.pool.kern
+
+local function checked(head)
+ local current = head
+ while current do
+ if getid(current) == glue_code then
+ local kern = new_kern(getfield(current,"width"))
+ if head == current then
+ local next = getnext(current)
+ if next then
+ setlink(kern,next)
+ end
+ flush_node(current)
+ head = kern
+ current = next
+ else
+ local prev, next = getboth(current)
+ setlink(prev,kern)
+ setlink(kern,next)
+ flush_node(current)
+ current = next
+ end
+ else
+ current = getnext(current)
+ end
+ end
+ return head
+end
+
+local function setdiscchecked(d,pre,post,replace)
+ if pre then pre = checked(pre) end
+ if post then post = checked(post) end
+ if replace then replace = checked(replace) end
+ setdisc(d,pre,post,replace)
+end
+
local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
if not start then
@@ -1773,8 +1821,10 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local current = start
local last = start
local prev = getprev(start)
+ local hasglue = false
-- fishy: so we can overflow and then go on in the sweep?
+ -- todo : id can also be glue_code as we checked spaces
local i = f
while i <= l do
@@ -1783,6 +1833,11 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
i = i + 1
last = current
current = getnext(current)
+ elseif id == glue_code then
+ i = i + 1
+ last = current
+ current = getnext(current)
+ hasglue = true
elseif id == disc_code then
if keepdisc then
keepdisc = false
@@ -1835,8 +1890,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
tail = find_node_tail(head)
end
setnext(sweepnode,current)
- setprev(head,nil)
- setnext(tail,nil)
+ setprev(head)
+ setnext(tail)
appenddisc(sweepnode,head)
end
end
@@ -1849,6 +1904,10 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if id == glyph_code then
i = i + 1
current = getnext(current)
+ elseif id == glue_code then
+ i = i + 1
+ current = getnext(current)
+ hasglue = true
elseif id == disc_code then
if keepdisc then
keepdisc = false
@@ -1891,6 +1950,9 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local id = getid(current)
if id == glyph_code then
i = i - 1
+ elseif id == glue_code then
+ i = i - 1
+ hasglue = true
elseif id == disc_code then
if keepdisc then
keepdisc = false
@@ -1939,8 +2001,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if cprev then
setnext(cprev,lookaheaddisc)
end
- setprev(cf,nil)
- setnext(cl,nil)
+ setprev(cf)
+ setnext(cl)
if startishead then
head = lookaheaddisc
end
@@ -1967,7 +2029,11 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local tail = find_node_tail(new)
setlink(tail,replace)
end
- setdisc(lookaheaddisc,cf,post,new)
+ if hasglue then
+ setdiscchecked(lookaheaddisc,cf,post,new)
+ else
+ setdisc(lookaheaddisc,cf,post,new)
+ end
start = getprev(lookaheaddisc)
sweephead[cf] = getnext(clast)
sweephead[new] = getnext(last)
@@ -1993,8 +2059,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setprev(cnext,backtrackdisc)
end
setnext(backtrackdisc,cnext)
- setprev(cf,nil)
- setnext(cl,nil)
+ setprev(cf)
+ setnext(cl)
local pre, post, replace, pretail, posttail, replacetail = getdisc(backtrackdisc,true)
local new = copy_node_list(cf)
local cnew = find_node_tail(new)
@@ -2021,7 +2087,11 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
else
replace = new
end
- setdisc(backtrackdisc,pre,post,replace)
+ if hasglue then
+ setdiscchecked(backtrackdisc,pre,post,replace)
+ else
+ setdisc(backtrackdisc,pre,post,replace)
+ end
start = getprev(backtrackdisc)
sweephead[post] = getnext(clast)
sweephead[replace] = getnext(last)
@@ -2744,7 +2814,7 @@ local function kernrun(disc,k_run,font,attr,...)
done = true
end
setprev(pre,nest)
--- setprev(pre,nil)
+-- setprev(pre)
setnext(prev,disc)
end
end
@@ -2758,7 +2828,7 @@ local function kernrun(disc,k_run,font,attr,...)
if k_run(posttail,"postinjections",next,font,attr,...) then
done = true
end
- setnext(posttail,nil)
+ setnext(posttail)
setprev(next,disc)
end
end
@@ -2774,7 +2844,7 @@ local function kernrun(disc,k_run,font,attr,...)
done = true
end
setprev(replace,nest)
--- setprev(replace,nil)
+-- setprev(replace)
setnext(prev,disc)
end
if next then
@@ -2782,7 +2852,7 @@ local function kernrun(disc,k_run,font,attr,...)
if k_run(replacetail,"replaceinjections",next,font,attr,...) then
done = true
end
- setnext(replacetail,nil)
+ setnext(replacetail)
setprev(next,disc)
end
elseif prev and next then
@@ -2862,7 +2932,7 @@ local function testrun(disc,t_run,c_run,...)
local ok, overflow = t_run(replace,next,...)
if ok and overflow then
-- so, we can have crossed the boundary
- setfield(disc,"replace",nil)
+ setfield(disc,"replace")
setlink(prev,replace)
-- setlink(replacetail,next)
setboth(disc)
diff --git a/src/fontloader/misc/fontloader-font-tfm.lua b/src/fontloader/misc/fontloader-font-tfm.lua
index 6565a0e..6584190 100644
--- a/src/fontloader/misc/fontloader-font-tfm.lua
+++ b/src/fontloader/misc/fontloader-font-tfm.lua
@@ -31,10 +31,14 @@ tfm.maxnestingdepth = 5
tfm.maxnestingsize = 65536*1024
local otf = fonts.handlers.otf
+local otfenhancers = otf.enhancers
local tfmfeatures = constructors.features.tfm
local registertfmfeature = tfmfeatures.register
+local tfmenhancers = constructors.enhancers.tfm
+local registertfmenhancer = tfmenhancers.register
+
constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua
fonts.formats.tfm = "type1" -- we need to have at least a value here
@@ -73,38 +77,7 @@ function tfm.setfeatures(tfmdata,features)
end
end
-local depth = { } -- table.setmetatableindex("number")
-local enhancers = { }
-
-local steps = {
- "normalize features",
- "check extra features"
-}
-
--- otf.enhancers.register("check extra features",enhance)
-
-enhancers["check extra features"] = otf.enhancers.enhance
-
---[[ PHG: begin hack for Luaotfload ]]--
-luaotfload_tfm_enhancers_reregister = function ()
- enhancers["check extra features"]=otf.enhancers.enhance
-end
---[[ PHG: end hack for Luaotfload ]]--
-
-local function applyenhancers(data,filename)
- for i=1,#steps do
- local step = steps[i]
- local enhancer = enhancers[step]
- if enhancer then
- if trace_loading then
- report_tfm("applying enhancer %a",step)
- end
- enhancer(data,filename)
- else
- report_tfm("invalid enhancer %a",step)
- end
- end
-end
+local depth = { } -- table.setmetatableindex("number")
-- Normally we just load the tfm data and go on. However there was some demand for
-- loading good old tfm /pfb files where afm files were lacking and even enc files
@@ -220,7 +193,7 @@ local function read_from_tfm(specification)
--
-- We make a pseudo opentype font, e.g. kerns and ligatures etc:
--
- applyenhancers(tfmdata,filename)
+ tfmenhancers.apply(tfmdata,filename)
--
-- Now user stuff can kick in.
--
@@ -622,7 +595,7 @@ do
local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } }
local noflags = { false, false, false, false }
- enhancers["normalize features"] = function(data)
+ local function enhance_normalize_features(data)
local ligatures = setmetatableindex("table")
local kerns = setmetatableindex("table")
local characters = data.characters
@@ -708,6 +681,9 @@ do
data.shared.resources = data.shared.resources or resources
end
+ registertfmenhancer("normalize features", enhance_normalize_features)
+ registertfmenhancer("check extra features", otfenhancers.enhance)
+
end
-- As with type one (afm) loading, we just use the opentype ones:
diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua
index 13c45aa..4cefe9a 100644
--- a/src/fontloader/runtime/fontloader-reference.lua
+++ b/src/fontloader/runtime/fontloader-reference.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 07/25/16 21:49:08
+-- merge date : 07/30/16 00:26:47
do -- begin closure to overcome local limits and interference
@@ -5722,6 +5722,7 @@ local next,tostring,rawget=next,tostring,rawget
local format,match,lower,gsub,find=string.format,string.match,string.lower,string.gsub,string.find
local sort,insert,concat,sortedkeys,serialize,fastcopy=table.sort,table.insert,table.concat,table.sortedkeys,table.serialize,table.fastcopy
local derivetable=table.derive
+local ioflush=io.flush
local trace_defining=false trackers.register("fonts.defining",function(v) trace_defining=v end)
local trace_scaling=false trackers.register("fonts.scaling",function(v) trace_scaling=v end)
local report_defining=logs.reporter("fonts","defining")
@@ -6547,134 +6548,233 @@ setmetatableindex(formats,function(t,k)
end
return rawget(t,file.suffix(l))
end)
-local locations={}
-local function setindeed(mode,target,group,name,action,position)
- local t=target[mode]
- if not t then
- report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode)
- os.exit()
- elseif position then
- insert(t,position,{ name=name,action=action })
- else
- for i=1,#t do
- local ti=t[i]
- if ti.name==name then
- ti.action=action
- return
+do
+ local function setindeed(mode,target,group,name,action,position)
+ local t=target[mode]
+ if not t then
+ report_defining("fatal error in setting feature %a, group %a, mode %a",name,group,mode)
+ os.exit()
+ elseif position then
+ insert(t,position,{ name=name,action=action })
+ else
+ for i=1,#t do
+ local ti=t[i]
+ if ti.name==name then
+ ti.action=action
+ return
+ end
end
+ insert(t,{ name=name,action=action })
end
- insert(t,{ name=name,action=action })
end
-end
-local function set(group,name,target,source)
- target=target[group]
- if not target then
- report_defining("fatal target error in setting feature %a, group %a",name,group)
- os.exit()
- end
- local source=source[group]
- if not source then
- report_defining("fatal source error in setting feature %a, group %a",name,group)
- os.exit()
- end
- local node=source.node
- local base=source.base
- local position=source.position
- if node then
- setindeed("node",target,group,name,node,position)
- end
- if base then
- setindeed("base",target,group,name,base,position)
- end
-end
-local function register(where,specification)
- local name=specification.name
- if name and name~="" then
- local default=specification.default
- local description=specification.description
- local initializers=specification.initializers
- local processors=specification.processors
- local manipulators=specification.manipulators
- local modechecker=specification.modechecker
- if default then
- where.defaults[name]=default
+ local function set(group,name,target,source)
+ target=target[group]
+ if not target then
+ report_defining("fatal target error in setting feature %a, group %a",name,group)
+ os.exit()
end
- if description and description~="" then
- where.descriptions[name]=description
+ local source=source[group]
+ if not source then
+ report_defining("fatal source error in setting feature %a, group %a",name,group)
+ os.exit()
end
- if initializers then
- set('initializers',name,where,specification)
+ local node=source.node
+ local base=source.base
+ local position=source.position
+ if node then
+ setindeed("node",target,group,name,node,position)
end
- if processors then
- set('processors',name,where,specification)
- end
- if manipulators then
- set('manipulators',name,where,specification)
+ if base then
+ setindeed("base",target,group,name,base,position)
end
- if modechecker then
- where.modechecker=modechecker
+ end
+ local function register(where,specification)
+ local name=specification.name
+ if name and name~="" then
+ local default=specification.default
+ local description=specification.description
+ local initializers=specification.initializers
+ local processors=specification.processors
+ local manipulators=specification.manipulators
+ local modechecker=specification.modechecker
+ if default then
+ where.defaults[name]=default
+ end
+ if description and description~="" then
+ where.descriptions[name]=description
+ end
+ if initializers then
+ set('initializers',name,where,specification)
+ end
+ if processors then
+ set('processors',name,where,specification)
+ end
+ if manipulators then
+ set('manipulators',name,where,specification)
+ end
+ if modechecker then
+ where.modechecker=modechecker
+ end
end
end
-end
-constructors.registerfeature=register
-function constructors.getfeatureaction(what,where,mode,name)
- what=handlers[what].features
- if what then
- where=what[where]
- if where then
- mode=where[mode]
- if mode then
- for i=1,#mode do
- local m=mode[i]
- if m.name==name then
- return m.action
+ constructors.registerfeature=register
+ function constructors.getfeatureaction(what,where,mode,name)
+ what=handlers[what].features
+ if what then
+ where=what[where]
+ if where then
+ mode=where[mode]
+ if mode then
+ for i=1,#mode do
+ local m=mode[i]
+ if m.name==name then
+ return m.action
+ end
end
end
end
end
end
-end
-local newhandler={}
-constructors.handlers=newhandler
-constructors.newhandler=newhandler
-local function setnewhandler(what)
- local handler=handlers[what]
- if not handler then
- handler={}
- handlers[what]=handler
+ local newfeatures={}
+ constructors.newfeatures=newfeatures
+ constructors.features=newfeatures
+ local function setnewfeatures(what)
+ local handler=handlers[what]
+ local features=handler.features
+ if not features then
+ local tables=handler.tables
+ local statistics=handler.statistics
+ features=allocate {
+ defaults={},
+ descriptions=tables and tables.features or {},
+ used=statistics and statistics.usedfeatures or {},
+ initializers={ base={},node={} },
+ processors={ base={},node={} },
+ manipulators={ base={},node={} },
+ }
+ features.register=function(specification) return register(features,specification) end
+ handler.features=features
+ end
+ return features
end
- return handler
+ setmetatable(newfeatures,{
+ __call=function(t,k) local v=t[k] return v end,
+ __index=function(t,k) local v=setnewfeatures(k) t[k]=v return v end,
+ })
end
-setmetatable(newhandler,{
- __call=function(t,k) local v=t[k] return v end,
- __index=function(t,k) local v=setnewhandler(k) t[k]=v return v end,
-})
-local newfeatures={}
-constructors.newfeatures=newfeatures
-constructors.features=newfeatures
-local function setnewfeatures(what)
- local handler=handlers[what]
- local features=handler.features
- if not features then
- local tables=handler.tables
- local statistics=handler.statistics
- features=allocate {
- defaults={},
- descriptions=tables and tables.features or {},
- used=statistics and statistics.usedfeatures or {},
- initializers={ base={},node={} },
- processors={ base={},node={} },
- manipulators={ base={},node={} },
- }
- features.register=function(specification) return register(features,specification) end
- handler.features=features
+do
+ local newhandler={}
+ constructors.handlers=newhandler
+ constructors.newhandler=newhandler
+ local function setnewhandler(what)
+ local handler=handlers[what]
+ if not handler then
+ handler={}
+ handlers[what]=handler
+ end
+ return handler
+ end
+ setmetatable(newhandler,{
+ __call=function(t,k) local v=t[k] return v end,
+ __index=function(t,k) local v=setnewhandler(k) t[k]=v return v end,
+ })
+end
+do
+ local newenhancer={}
+ constructors.enhancers=newenhancer
+ constructors.newenhancer=newenhancer
+ local function setnewenhancer(format)
+ local handler=handlers[format]
+ local enhancers=handler.enhancers
+ if not enhancers then
+ local actions=allocate()
+ local before=allocate()
+ local after=allocate()
+ local order=allocate()
+ local patches={ before=before,after=after }
+ local trace=false
+ local report=logs.reporter("fonts",format.." enhancing")
+ trackers.register(format..".loading",function(v) trace=v end)
+ local function enhance(name,data,filename,raw)
+ local enhancer=actions[name]
+ if enhancer then
+ if trace then
+ report("apply enhancement %a to file %a",name,filename)
+ ioflush()
+ end
+ enhancer(data,filename,raw)
+ else
+ end
+ end
+ local function apply(data,filename,raw)
+ local basename=file.basename(lower(filename))
+ if trace then
+ report("%s enhancing file %a","start",filename)
+ end
+ ioflush()
+ for e=1,#order do
+ local enhancer=order[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
+ enhance(enhancer,data,filename,raw)
+ 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()
+ end
+ if trace then
+ report("%s enhancing file %a","stop",filename)
+ end
+ ioflush()
+ end
+ local function register(what,action)
+ if action then
+ if actions[what] then
+ else
+ order[#order+1]=what
+ end
+ actions[what]=action
+ else
+ report("bad enhancer %a",what)
+ end
+ end
+ local function patch(what,where,pattern,action)
+ local pw=patches[what]
+ if pw then
+ local ww=pw[where]
+ if ww then
+ ww[pattern]=action
+ else
+ pw[where]={ [pattern]=action}
+ end
+ end
+ end
+ enhancers={
+ register=register,
+ apply=apply,
+ patch=patch,
+ patches={ register=patch },
+ }
+ handler.enhancers=enhancers
+ end
+ return enhancers
end
- return features
+ setmetatable(newenhancer,{
+ __call=function(t,k) local v=t[k] return v end,
+ __index=function(t,k) local v=setnewenhancer(k) t[k]=v return v end,
+ })
end
-setmetatable(newfeatures,{
- __call=function(t,k) local v=t[k] return v end,
- __index=function(t,k) local v=setnewfeatures(k) t[k]=v return v end,
-})
function constructors.checkedfeatures(what,features)
local defaults=handlers[what].features.defaults
if features and next(features) then
@@ -15228,7 +15328,6 @@ if not modules then modules={} end modules ['font-otl']={
local gmatch,find,match,lower,strip=string.gmatch,string.find,string.match,string.lower,string.strip
local type,next,tonumber,tostring,unpack=type,next,tonumber,tostring,unpack
local abs=math.abs
-local ioflush=io.flush
local derivetable=table.derive
local formatters=string.formatters
local setmetatableindex=table.setmetatableindex
@@ -15257,10 +15356,8 @@ local readers=fonts.readers
local constructors=fonts.constructors
local otffeatures=constructors.features.otf
local registerotffeature=otffeatures.register
-local enhancers=allocate()
-otf.enhancers=enhancers
-local patches={}
-enhancers.patches=patches
+local otfenhancers=constructors.enhancers.otf
+local registerotfenhancer=otfenhancers.register
local forceload=false
local cleanup=0
local syncspace=true
@@ -15276,76 +15373,7 @@ registerdirective("fonts.otf.loader.cleanup",function(v) cleanup=tonumber(v) or
registerdirective("fonts.otf.loader.force",function(v) forceload=v end)
registerdirective("fonts.otf.loader.syncspace",function(v) syncspace=v end)
registerdirective("fonts.otf.loader.forcenotdef",function(v) forcenotdef=v end)
-local ordered_enhancers={
- "check extra features",
-}
-local actions=allocate()
-local before=allocate()
-local after=allocate()
-patches.before=before
-patches.after=after
-local function enhance(name,data,filename,raw)
- local enhancer=actions[name]
- if enhancer then
- if trace_loading then
- report_otf("apply enhancement %a to file %a",name,filename)
- ioflush()
- end
- enhancer(data,filename,raw)
- else
- end
-end
-function enhancers.apply(data,filename,raw)
- local basename=file.basename(lower(filename))
- if trace_loading then
- report_otf("%s enhancing file %a","start",filename)
- end
- ioflush()
- 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
- enhance(enhancer,data,filename,raw)
- 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()
- end
- if trace_loading then
- report_otf("%s enhancing file %a","stop",filename)
- end
- ioflush()
-end
-function patches.register(what,where,pattern,action)
- local pw=patches[what]
- if pw then
- local ww=pw[where]
- if ww then
- ww[pattern]=action
- else
- pw[where]={ [pattern]=action}
- end
- end
-end
-function patches.report(fmt,...)
- if trace_loading then
- report_otf("patching: %s",formatters[fmt](...))
- end
-end
-function enhancers.register(what,action)
- actions[what]=action
-end
+registerotfenhancer("check extra features",function() end)
function otf.load(filename,sub,featurefile)
local featurefile=nil
local base=file.basename(file.removesuffix(filename))
@@ -15445,7 +15473,7 @@ function otf.load(filename,sub,featurefile)
otfreaders.unpack(data)
otfreaders.expand(data)
otfreaders.addunicodetable(data)
- enhancers.apply(data,filename,data)
+ otfenhancers.apply(data,filename,data)
if applyruntimefixes then
applyruntimefixes(filename,data)
end
@@ -18165,6 +18193,12 @@ local getthreshold=injections.getthreshold
local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end
local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end
local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end
+local function checkdisccontent(d)
+ local pre,post,replace=getdisc(d)
+ if pre then for n in traverse_id(glue_code,pre) do print("pre",nodes.idstostring(pre)) break end end
+ if post then for n in traverse_id(glue_code,post) do print("pos",nodes.idstostring(post)) break end end
+ if replace then for n in traverse_id(glue_code,replace) do print("rep",nodes.idstostring(replace)) break end end
+end
local function logprocess(...)
if trace_steps then
registermessage(...)
@@ -18225,7 +18259,7 @@ end
local function copy_glyph(g)
local components=getfield(g,"components")
if components then
- setfield(g,"components",nil)
+ setfield(g,"components")
local n=copy_node(g)
copyinjection(n,g)
setfield(g,"components",components)
@@ -18237,11 +18271,18 @@ local function copy_glyph(g)
end
end
local function flattendisk(head,disc)
- local _,_,replace,_,_,replacetail=getdisc(disc,true)
- setfield(disc,"replace",nil)
+ local pre,post,replace,pretail,posttail,replacetail=getdisc(disc,true)
+ local prev,next=getboth(disc)
+ local ishead=head==disc
+ setdisc(disc)
flush_node(disc)
- if head==disc then
- local next=getnext(disc)
+ if pre then
+ flush_node_list(pre)
+ end
+ if post then
+ flush_node_list(post)
+ end
+ if ishead then
if replace then
if next then
setlink(replacetail,next)
@@ -18253,7 +18294,6 @@ local function flattendisk(head,disc)
return
end
else
- local prev,next=getboth(disc)
if replace then
if next then
setlink(replacetail,next)
@@ -18288,8 +18328,8 @@ local function markstoligature(head,start,stop,char)
else
local prev=getprev(start)
local next=getnext(stop)
- setprev(start,nil)
- setnext(stop,nil)
+ setprev(start)
+ setnext(stop)
local base=copy_glyph(start)
if head==start then
head=base
@@ -18336,8 +18376,8 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local prev=getprev(start)
local next=getnext(stop)
local comp=start
- setprev(start,nil)
- setnext(stop,nil)
+ setprev(start)
+ setnext(stop)
local base=copy_glyph(start)
if start==head then
head=base
@@ -18401,36 +18441,36 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local pre,post,replace,pretail,posttail,replacetail=getdisc(discfound,true)
if not replace then
local prev=getprev(base)
-local current=comp
-local previous=nil
-local copied=nil
-while current do
- if getid(current)==glyph_code then
- local n=copy_node(current)
- if copied then
- setlink(previous,n)
- else
- copied=n
- end
- previous=n
- end
- current=getnext(current)
-end
- setprev(discnext,nil)
- setnext(discprev,nil)
+ local current=comp
+ local previous=nil
+ local copied=nil
+ while current do
+ if getid(current)==glyph_code then
+ local n=copy_node(current)
+ if copied then
+ setlink(previous,n)
+ else
+ copied=n
+ end
+ previous=n
+ end
+ current=getnext(current)
+ end
+ setprev(discnext)
+ setnext(discprev)
if pre then
setlink(discprev,pre)
end
pre=comp
if post then
setlink(posttail,discnext)
- setprev(post,nil)
+ setprev(post)
else
post=discnext
end
setlink(prev,discfound)
setlink(discfound,next)
- setboth(base,nil,nil)
+ setboth(base)
setfield(base,"components",copied)
setdisc(discfound,pre,post,base,discretionary_code)
base=prev
@@ -19434,6 +19474,39 @@ end
local function show_skip(dataset,sequence,char,ck,class)
logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(dataset,sequence),gref(char),class,ck[1],ck[8] or ck[2])
end
+local new_kern=nuts.pool.kern
+local function checked(head)
+ local current=head
+ while current do
+ if getid(current)==glue_code then
+ local kern=new_kern(getfield(current,"width"))
+ if head==current then
+ local next=getnext(current)
+ if next then
+ setlink(kern,next)
+ end
+ flush_node(current)
+ head=kern
+ current=next
+ else
+ local prev,next=getboth(current)
+ setlink(prev,kern)
+ setlink(kern,next)
+ flush_node(current)
+ current=next
+ end
+ else
+ current=getnext(current)
+ end
+ end
+ return head
+end
+local function setdiscchecked(d,pre,post,replace)
+ if pre then pre=checked(pre) end
+ if post then post=checked(post) end
+ if replace then replace=checked(replace) end
+ setdisc(d,pre,post,replace)
+end
local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
if not start then
return head,start,false
@@ -19454,6 +19527,7 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local current=start
local last=start
local prev=getprev(start)
+ local hasglue=false
local i=f
while i<=l do
local id=getid(current)
@@ -19461,6 +19535,11 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
i=i+1
last=current
current=getnext(current)
+ elseif id==glue_code then
+ i=i+1
+ last=current
+ current=getnext(current)
+ hasglue=true
elseif id==disc_code then
if keepdisc then
keepdisc=false
@@ -19510,8 +19589,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
tail=find_node_tail(head)
end
setnext(sweepnode,current)
- setprev(head,nil)
- setnext(tail,nil)
+ setprev(head)
+ setnext(tail)
appenddisc(sweepnode,head)
end
end
@@ -19523,6 +19602,10 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if id==glyph_code then
i=i+1
current=getnext(current)
+ elseif id==glue_code then
+ i=i+1
+ current=getnext(current)
+ hasglue=true
elseif id==disc_code then
if keepdisc then
keepdisc=false
@@ -19564,6 +19647,9 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local id=getid(current)
if id==glyph_code then
i=i-1
+ elseif id==glue_code then
+ i=i-1
+ hasglue=true
elseif id==disc_code then
if keepdisc then
keepdisc=false
@@ -19608,8 +19694,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
if cprev then
setnext(cprev,lookaheaddisc)
end
- setprev(cf,nil)
- setnext(cl,nil)
+ setprev(cf)
+ setnext(cl)
if startishead then
head=lookaheaddisc
end
@@ -19636,7 +19722,11 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
local tail=find_node_tail(new)
setlink(tail,replace)
end
- setdisc(lookaheaddisc,cf,post,new)
+ if hasglue then
+ setdiscchecked(lookaheaddisc,cf,post,new)
+ else
+ setdisc(lookaheaddisc,cf,post,new)
+ end
start=getprev(lookaheaddisc)
sweephead[cf]=getnext(clast)
sweephead[new]=getnext(last)
@@ -19659,8 +19749,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setprev(cnext,backtrackdisc)
end
setnext(backtrackdisc,cnext)
- setprev(cf,nil)
- setnext(cl,nil)
+ setprev(cf)
+ setnext(cl)
local pre,post,replace,pretail,posttail,replacetail=getdisc(backtrackdisc,true)
local new=copy_node_list(cf)
local cnew=find_node_tail(new)
@@ -19687,7 +19777,11 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
else
replace=new
end
- setdisc(backtrackdisc,pre,post,replace)
+ if hasglue then
+ setdiscchecked(backtrackdisc,pre,post,replace)
+ else
+ setdisc(backtrackdisc,pre,post,replace)
+ end
start=getprev(backtrackdisc)
sweephead[post]=getnext(clast)
sweephead[replace]=getnext(last)
@@ -20341,7 +20435,7 @@ local function kernrun(disc,k_run,font,attr,...)
if k_run(posttail,"postinjections",next,font,attr,...) then
done=true
end
- setnext(posttail,nil)
+ setnext(posttail)
setprev(next,disc)
end
end
@@ -20363,7 +20457,7 @@ local function kernrun(disc,k_run,font,attr,...)
if k_run(replacetail,"replaceinjections",next,font,attr,...) then
done=true
end
- setnext(replacetail,nil)
+ setnext(replacetail)
setprev(next,disc)
end
elseif prev and next then
@@ -20430,7 +20524,7 @@ local function testrun(disc,t_run,c_run,...)
setlink(replacetail,next)
local ok,overflow=t_run(replace,next,...)
if ok and overflow then
- setfield(disc,"replace",nil)
+ setfield(disc,"replace")
setlink(prev,replace)
setboth(disc)
flush_node_list(disc)
@@ -23653,37 +23747,15 @@ local otfreaders=otf.readers
local otfenhancers=otf.enhancers
local afmfeatures=constructors.features.afm
local registerafmfeature=afmfeatures.register
+local afmenhancers=constructors.enhancers.afm
+local registerafmenhancer=afmenhancers.register
afm.version=1.512
-afm.cache=containers.define("fonts","afm",afm.version,true)
+afm.cache=containers.define("fonts","one",afm.version,true)
afm.autoprefixed=true
afm.helpdata={}
afm.syncspace=true
local overloads=fonts.mappings.overloads
local applyruntimefixes=fonts.treatments and fonts.treatments.applyfixes
-local enhancers={
-}
-local steps={
- "unify names",
- "add ligatures",
- "add extra kerns",
- "normalize features",
- "check extra features",
- "fix names",
-}
-local function applyenhancers(data,filename)
- for i=1,#steps do
- local step=steps[i]
- local enhancer=enhancers[step]
- if enhancer then
- if trace_loading then
- report_afm("applying enhancer %a",step)
- end
- enhancer(data,filename)
- else
- report_afm("invalid enhancer %a",step)
- end
- end
-end
function afm.load(filename)
filename=resolvers.findfile(filename,'afm') or ""
if filename~="" and not fonts.names.ignoredfile(filename) then
@@ -23706,7 +23778,7 @@ function afm.load(filename)
report_afm("reading %a",filename)
data=afm.readers.loadfont(filename,pfbname)
if data then
- applyenhancers(data,filename)
+ afmenhancers.apply(data,filename)
fonts.mappings.addtounicode(data,filename)
otfreaders.pack(data)
data.size=size
@@ -23731,7 +23803,7 @@ function afm.load(filename)
end
end
local uparser=fonts.mappings.makenameparser()
-enhancers["unify names"]=function(data,filename)
+local function enhance_unify_names(data,filename)
local unicodevector=fonts.encodings.agl.unicodes
local unicodes={}
local names={}
@@ -23783,7 +23855,7 @@ enhancers["unify names"]=function(data,filename)
end
local everywhere={ ["*"]={ ["*"]=true } }
local noflags={ false,false,false,false }
-enhancers["normalize features"]=function(data)
+local function enhance_normalize_features(data)
local ligatures=setmetatableindex("table")
local kerns=setmetatableindex("table")
local extrakerns=setmetatableindex("table")
@@ -23881,8 +23953,7 @@ enhancers["normalize features"]=function(data)
data.resources.features=features
data.resources.sequences=sequences
end
-enhancers["check extra features"]=otf.enhancers.enhance
-enhancers["fix names"]=function(data)
+local function enhance_fix_names(data)
for k,v in next,data.descriptions do
local n=v.name
local r=overloads[n]
@@ -23921,10 +23992,10 @@ local addthem=function(rawdata,ligatures)
end
end
end
-enhancers["add ligatures"]=function(rawdata)
+local function enhance_add_ligatures(rawdata)
addthem(rawdata,afm.helpdata.ligatures)
end
-enhancers["add extra kerns"]=function(rawdata)
+local function enhance_add_extra_kerns(rawdata)
local descriptions=rawdata.descriptions
local resources=rawdata.resources
local unicodes=resources.unicodes
@@ -24332,6 +24403,12 @@ function readers.pfb(specification,method)
swap("specification")
return readers.afm(specification,method)
end
+registerafmenhancer("unify names",enhance_unify_names)
+registerafmenhancer("add ligatures",enhance_add_ligatures)
+registerafmenhancer("add extra kerns",enhance_add_extra_kerns)
+registerafmenhancer("normalize features",enhance_normalize_features)
+registerafmenhancer("check extra features",otfenhancers.enhance)
+registerafmenhancer("fix names",enhance_fix_names)
end -- closure
@@ -24532,8 +24609,11 @@ tfm.version=1.000
tfm.maxnestingdepth=5
tfm.maxnestingsize=65536*1024
local otf=fonts.handlers.otf
+local otfenhancers=otf.enhancers
local tfmfeatures=constructors.features.tfm
local registertfmfeature=tfmfeatures.register
+local tfmenhancers=constructors.enhancers.tfm
+local registertfmenhancer=tfmenhancers.register
constructors.resolvevirtualtoo=false
fonts.formats.tfm="type1"
fonts.formats.ofm="type1"
@@ -24545,27 +24625,7 @@ function tfm.setfeatures(tfmdata,features)
return {}
end
end
-local depth={}
-local enhancers={}
-local steps={
- "normalize features",
- "check extra features"
-}
-enhancers["check extra features"]=otf.enhancers.enhance
-local function applyenhancers(data,filename)
- for i=1,#steps do
- local step=steps[i]
- local enhancer=enhancers[step]
- if enhancer then
- if trace_loading then
- report_tfm("applying enhancer %a",step)
- end
- enhancer(data,filename)
- else
- report_tfm("invalid enhancer %a",step)
- end
- end
-end
+local depth={}
local function read_from_tfm(specification)
local filename=specification.filename
local size=specification.size
@@ -24620,7 +24680,7 @@ local function read_from_tfm(specification)
tfmdata.descriptions=tfmdata.characters
end
otf.readers.addunicodetable(tfmdata)
- applyenhancers(tfmdata,filename)
+ tfmenhancers.apply(tfmdata,filename)
constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm)
otf.readers.unifymissing(tfmdata)
fonts.mappings.addtounicode(tfmdata,filename)
@@ -24921,7 +24981,7 @@ end
do
local everywhere={ ["*"]={ ["*"]=true } }
local noflags={ false,false,false,false }
- enhancers["normalize features"]=function(data)
+ local function enhance_normalize_features(data)
local ligatures=setmetatableindex("table")
local kerns=setmetatableindex("table")
local characters=data.characters
@@ -25003,6 +25063,8 @@ do
data.resources.sequences=sequences
data.shared.resources=data.shared.resources or resources
end
+ registertfmenhancer("normalize features",enhance_normalize_features)
+ registertfmenhancer("check extra features",otfenhancers.enhance)
end
registertfmfeature {
name="mode",
diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua
index 5905c19..3f2c527 100644
--- a/src/luaotfload-features.lua
+++ b/src/luaotfload-features.lua
@@ -31,6 +31,10 @@ local definers = fonts.definers
local handlers = fonts.handlers
local fontidentifiers = fonts.hashes and fonts.hashes.identifiers
+local otf = handlers.otf
+local otfenhancers = otf.enhancers
+local otffeatures = otf.features
+
local config = config or { luaotfload = { run = { } } }
local as_script = true
@@ -43,10 +47,16 @@ end
--HH A bit of tuning for definitions.
-if fonts.constructors then
- fonts.constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload
+local constructors = fonts.constructors
+
+if constructors then
+ constructors.namemode = "specification" -- somehow latex needs this (changed name!) => will change into an overload
end
+local tfm = constructors.handlers.tfm
+local tfmfeatures = constructors.features.tfm
+local tfmenhancers = constructors.enhancers.tfm
+
--[[HH--
tricky: we sort of bypass the parser and directly feed all into
the sub parser
@@ -2081,44 +2091,33 @@ local add_auto_features = function ()
end
end
-local function enhance(data,filename,raw)
- for slot=1,#extrafeatures do
- local specification = extrafeatures[slot]
- addfeature(data,specification.name,specification)
- end
-end
-
-otf.enhancers.enhance = enhance
-
local install_extra_features = function (data, filename, raw)
- local metadata = data and data.metadata
- if not metadata then
+ local format = data.format
+ if not format then
+ --- font not fully loaded, happens with TFM/PFB when loaded the
+ --- classical fashion
+ logreport ("both", 4, "features",
+ "no format info for font “%s”", filename)
+ elseif not data.metadata and format ~= "type1" then
logreport ("both", 4, "features",
"no metadata received from font “%s”; not \z
installing extra features.", filename)
return
end
- local format = data.format
- if not format then
- --- font not fully loaded, happens with TFM/PFB
- logreport ("both", 4, "features",
- "no format info for font “%s”; not \z
- installing extra features.",
- filename)
- --return
- end
for i = 1, #extrafeatures do
local specification = extrafeatures [i]
local feature = specification.name
- local fontname = tostring (data.metadata.fontname) or "<unknown>"
- local subfont = tonumber (metadata.subfontindex) or -1
+ local metadata = data.metadata
+ local fontname = metadata and tostring (metadata.fontname)
+ or data.name or "<unknown>"
+ local subfont = metadata and tonumber (metadata.subfontindex)
+ or -1
if not fontname then fontname = filename end
if not subfont then subfont = -1 end
logreport ("both", 3, "features",
"register synthetic feature “%s” for %s font “%s”(%d)",
feature, format or "tfm", filename, subfont)
- otf.features.register { name = feature, description = specification[2] }
- otf.enhancers.addfeature (data, feature, specification[1])
+ addfeature (data, feature, specification) --> for otf and type1
end
end
@@ -2137,10 +2136,11 @@ return {
add_auto_features ()
otf = fonts.handlers.otf
- otf.enhancers.addfeature = addfeature
- luaotfload_tfm_enhancers_reregister ()
- otf.enhancers.register ("check extra features",
- install_extra_features)
+ otfenhancers.addfeature = addfeature
+ tfmenhancers.register ("check extra features",
+ install_extra_features)
+ otfenhancers.register ("check extra features",
+ install_extra_features)
return true
end