diff options
author | Philipp Gesang <phg@phi-gamma.net> | 2016-07-30 12:26:59 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-07-30 12:26:59 +0200 |
commit | 9e2db3ead715ceecf2afc879aefc020f84ea4f09 (patch) | |
tree | 89960031e5cf796661e7a6f10bdf9d32f36c01dd /src | |
parent | 2fcdccf7edfa1cfb0f03fe8f2163c7c5d8281984 (diff) | |
parent | c0597dba961fb9f99c2bd5d2d7f442dc37382dc2 (diff) | |
download | luaotfload-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.lua | 358 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-one.lua | 110 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-otl.lua | 180 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-ots.lua | 158 | ||||
-rw-r--r-- | src/fontloader/misc/fontloader-font-tfm.lua | 44 | ||||
-rw-r--r-- | src/fontloader/runtime/fontloader-reference.lua | 626 | ||||
-rw-r--r-- | src/luaotfload-features.lua | 60 |
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 |