diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-ctx.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-ctx.lua | 468 |
1 files changed, 365 insertions, 103 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-ctx.lua b/Master/texmf-dist/tex/context/base/font-ctx.lua index 887aa99841e..4b324a6db79 100644 --- a/Master/texmf-dist/tex/context/base/font-ctx.lua +++ b/Master/texmf-dist/tex/context/base/font-ctx.lua @@ -11,7 +11,8 @@ if not modules then modules = { } end modules ['font-ctx'] = { local texcount, texsetcount = tex.count, tex.setcount local format, gmatch, match, find, lower, gsub, byte = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub, string.byte -local concat, serialize, sort = table.concat, table.serialize, table.sort +local concat, serialize, sort, fastcopy, mergedtable = table.concat, table.serialize, table.sort, table.fastcopy, table.merged +local sortedhash, sortedkeys, sequenced = table.sortedhash, table.sortedkeys, table.sequenced local settings_to_hash, hash_to_string = utilities.parsers.settings_to_hash, utilities.parsers.hash_to_string local formatcolumns = utilities.formatters.formatcolumns @@ -21,11 +22,14 @@ local round = math.round local P, S, C, Cc, Cf, Cg, Ct, lpegmatch = lpeg.P, lpeg.S, lpeg.C, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Ct, lpeg.match -local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) -local trace_usage = false trackers.register("fonts.usage", function(v) trace_usage = v end) -local trace_mapfiles = false trackers.register("fonts.mapfiles", function(v) trace_mapfiles = v end) -local trace_automode = false trackers.register("fonts.automode", function(v) trace_automode = v end) +local trace_features = false trackers.register("fonts.features", function(v) trace_features = v end) +local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) +local trace_designsize = false trackers.register("fonts.designsize", function(v) trace_designsize = v end) +local trace_usage = false trackers.register("fonts.usage", function(v) trace_usage = v end) +local trace_mapfiles = false trackers.register("fonts.mapfiles", function(v) trace_mapfiles = v end) +local trace_automode = false trackers.register("fonts.automode", function(v) trace_automode = v end) +local report_features = logs.reporter("fonts","features") local report_defining = logs.reporter("fonts","defining") local report_status = logs.reporter("fonts","status") local report_mapfiles = logs.reporter("fonts","mapfiles") @@ -40,17 +44,24 @@ local definers = fonts.definers local specifiers = fonts.specifiers local constructors = fonts.constructors local loggers = fonts.loggers +local fontgoodies = fonts.goodies local helpers = fonts.helpers local hashes = fonts.hashes local fontdata = hashes.identifiers local currentfont = font.current local texattribute = tex.attribute +local designsizefilename = fontgoodies.designsizes.filename + local otffeatures = fonts.constructors.newfeatures("otf") local registerotffeature = otffeatures.register local baseprocessors = otffeatures.processors.base local baseinitializers = otffeatures.initializers.base +local sequencers = utilities.sequencers +local appendgroup = sequencers.appendgroup +local appendaction = sequencers.appendaction + specifiers.contextsetups = specifiers.contextsetups or { } specifiers.contextnumbers = specifiers.contextnumbers or { } specifiers.contextmerged = specifiers.contextmerged or { } @@ -75,42 +86,76 @@ local nulldata = { characters = { }, descriptions = { }, properties = { }, - parameters = { -- lmromanregular @ 12pt - slant = 0, -- 1 - space = 256377, -- 2 - spacestretch = 128188, -- 3 - spaceshrink = 85459, -- 4 - xheight = 338952, -- 5 - quad = 786432, -- 6 - extraspace = 85459, -- 7 + parameters = { -- lmromanregular @ 12pt + slant = 0, -- 1 + space = 256377, -- 2 + space_stretch = 128188, -- 3 + space_shrink = 85459, -- 4 + x_height = 338952, -- 5 + quad = 786432, -- 6 + extra_space = 85459, -- 7 }, } +constructors.enhanceparameters(nulldata.parameters) -- official copies for us + +local limited = false + +directives.register("system.inputmode", function(v) + if not limited then + local i_limiter = io.i_limiter(v) + if i_limiter then + fontloader.open = i_limiter.protect(fontloader.open) + fontloader.info = i_limiter.protect(fontloader.info) + limited = true + end + end +end) + function definers.resetnullfont() -- resetting is needed because tikz misuses nullfont local parameters = nulldata.parameters - parameters.slant = 0 -- 1 - parameters.space = 0 -- 2 - parameters.spacestretch = 0 -- 3 - parameters.spaceshrink = 0 -- 4 - parameters.xheight = 0 -- 5 - parameters.quad = 0 -- 6 - parameters.extraspace = 0 -- 7 + -- + parameters.slant = 0 -- 1 + parameters.space = 0 -- 2 + parameters.space_stretch = 0 -- 3 + parameters.space_shrink = 0 -- 4 + parameters.x_height = 0 -- 5 + parameters.quad = 0 -- 6 + parameters.extra_space = 0 -- 7 + -- + constructors.enhanceparameters(parameters) -- official copies for us + -- definers.resetnullfont = function() end end +commands.resetnullfont = definers.resetnullfont + setmetatableindex(fontdata, function(t,k) return nulldata end) +-- we might make an font-hsh.lua + local chardata = allocate() -- chardata +local descriptions = allocate() local parameters = allocate() +local properties = allocate() +local resources = allocate() +local quaddata = allocate() -- maybe also spacedata +local markdata = allocate() +local xheightdata = allocate() local csnames = allocate() -- namedata -local quaddata = allocate() -- quaddata -local xheightdata = allocate() -- xheightdata +local italicsdata = allocate() hashes.characters = chardata +hashes.descriptions = descriptions hashes.parameters = parameters +hashes.properties = properties +hashes.resources = resources hashes.quads = quaddata +hashes.marks = markdata hashes.xheights = xheightdata +hashes.csnames = csnames +hashes.italics = italicsdata setmetatableindex(chardata, function(t,k) local characters = fontdata[k].characters @@ -118,12 +163,32 @@ setmetatableindex(chardata, function(t,k) return characters end) +setmetatableindex(descriptions, function(t,k) + local descriptions = fontdata[k].descriptions + t[k] = descriptions + return descriptions +end) + setmetatableindex(parameters, function(t,k) local parameters = fontdata[k].parameters t[k] = parameters return parameters end) +setmetatableindex(properties, function(t,k) + local properties = fontdata[k].properties + t[k] = properties + return properties +end) + +setmetatableindex(resources, function(t,k) + local shared = fontdata[k].shared + local rawdata = shared and shared.rawdata + local resources = rawdata and rawdata.resources + t[k] = resources or false -- better than resolving each time + return resources +end) + setmetatableindex(quaddata, function(t,k) local parameters = parameters[k] local quad = parameters and parameters.quad or 0 @@ -131,6 +196,13 @@ setmetatableindex(quaddata, function(t,k) return quad end) +setmetatableindex(markdata, function(t,k) + local resources = fontdata[k].resources or { } + local marks = resources.marks or { } + t[k] = marks + return marks +end) + setmetatableindex(xheightdata, function(t,k) local parameters = parameters[k] local xheight = parameters and parameters.xheight or 0 @@ -138,6 +210,18 @@ setmetatableindex(xheightdata, function(t,k) return quad end) +setmetatableindex(italicsdata, function(t,k) -- is test ! + local properties = fontdata[k].properties + local hasitalics = properties and properties.hasitalics + if hasitalics then + hasitalics = chardata[k] -- convenient return + else + hasitalics = false + end + t[k] = hasitalics + return hasitalics +end) + -- this cannot be a feature initializer as there is no auto namespace -- so we never enter the loop then; we can store the defaults in the tma -- file (features.gpos.mkmk = 1 etc) @@ -148,42 +232,71 @@ local needsnodemode = { gpos_mark2ligature = true, } -local function modechecker(tfmdata,features,mode) -- we cannot adapt features as they are shared! - if mode == "auto" then - local rawdata = tfmdata.shared.rawdata - local resources = rawdata and rawdata.resources - local sequences = resources.sequences - if sequences and #sequences > 0 then - local script = features.script or "dflt" - local language = features.language or "dflt" - for feature, value in next, features do - if value then - local found = false - for i=1,#sequences do - local sequence = sequences[i] - local features = sequence.features - if features then - local scripts = features[feature] - if scripts then - local languages = scripts[script] - if languages and languages[language] then - if found then - -- more than one lookup - if trace_automode then - report_defining("forcing node mode in font %s for feature %s, script %s, language %s (multiple lookups)",file.basename(tfmdata.properties.name),feature,script,language) - end - features.mode = "node" - return "node" - elseif needsnodemode[sequence.type] then - if trace_automode then - report_defining("forcing node mode in font %s for feature %s, script %s, language %s (no base support)",file.basename(tfmdata.properties.name),feature,script,language) - end - features.mode = "node" - return "node" - else - -- at least one lookup - found = true +fonts.handlers.otf.tables.scripts.auto = "automatic fallback to latn when no dflt present" + +local privatefeatures = { + tlig = true, + trep = true, + anum = true, +} + +local function checkedscript(tfmdata,resources,features) + local latn = false + local script = false + for g, list in next, resources.features do + for f, scripts in next, list do + if privatefeatures[f] then + -- skip + elseif scripts.dflt then + script = "dflt" + break + elseif scripts.latn then + latn = true + end + end + end + if not script then + script = latn and "latn" or "dflt" + end + if trace_automode then + report_defining("auto script mode: using script '%s' in font '%s'",script,file.basename(tfmdata.properties.name)) + end + features.script = script + return script +end + +local function checkedmode(tfmdata,resources,features) + local sequences = resources.sequences + if sequences and #sequences > 0 then + local script = features.script or "dflt" + local language = features.language or "dflt" + for feature, value in next, features do + if value then + local found = false + for i=1,#sequences do + local sequence = sequences[i] + local features = sequence.features + if features then + local scripts = features[feature] + if scripts then + local languages = scripts[script] + if languages and languages[language] then + if found then + -- more than one lookup + if trace_automode then + report_defining("forcing node mode in font %s for feature %s, script %s, language %s (multiple lookups)",file.basename(tfmdata.properties.name),feature,script,language) end + features.mode = "node" + return "node" + elseif needsnodemode[sequence.type] then + if trace_automode then + report_defining("forcing node mode in font %s for feature %s, script %s, language %s (no base support)",file.basename(tfmdata.properties.name),feature,script,language) + end + features.mode = "node" + return "node" + else + -- at least one lookup + found = true end end end @@ -191,10 +304,32 @@ local function modechecker(tfmdata,features,mode) -- we cannot adapt features as end end end - return "base" + end + features.mode = "base" -- new, or is this wrong? + return "base" +end + +definers.checkedscript = checkedscript +definers.checkedmode = checkedmode + +local function modechecker(tfmdata,features,mode) -- we cannot adapt features as they are shared! + if trace_features then + report_features(serialize(features,"used")) + end + local rawdata = tfmdata.shared.rawdata + local resources = rawdata and rawdata.resources + local script = features.script + if resources then + if script == "auto" then + script = checkedscript(tfmdata,resources,features) + end + if mode == "auto" then + mode = checkedmode(tfmdata,resources,features) + end else - return mode + report_features("missing resources for font''%s'",file.basename(tfmdata.properties.name)) end + return mode end registerotffeature { @@ -222,6 +357,38 @@ registerotffeature { -- }, -- } +local beforecopyingcharacters = sequencers.new { + name = "beforecopyingcharacters", + arguments = "target,original", +} + +appendgroup(beforecopyingcharacters,"before") -- user +appendgroup(beforecopyingcharacters,"system") -- private +appendgroup(beforecopyingcharacters,"after" ) -- user + +function constructors.beforecopyingcharacters(original,target) + local runner = beforecopyingcharacters.runner + if runner then + runner(original,target) + end +end + +local aftercopyingcharacters = sequencers.new { + name = "aftercopyingcharacters", + arguments = "target,original", +} + +appendgroup(aftercopyingcharacters,"before") -- user +appendgroup(aftercopyingcharacters,"system") -- private +appendgroup(aftercopyingcharacters,"after" ) -- user + +function constructors.aftercopyingcharacters(original,target) + local runner = aftercopyingcharacters.runner + if runner then + runner(original,target) + end +end + --[[ldx-- <p>So far we haven't really dealt with features (or whatever we want to pass along with the font definition. We distinguish the following @@ -346,7 +513,7 @@ local function contextnumber(name) -- will be replaced else local script, language = languages.association(lng) if t.script ~= script or t.language ~= language then - local s = table.fastcopy(t) + local s = fastcopy(t) local n = #numbers + 1 setups[tag] = s numbers[n] = tag @@ -479,8 +646,11 @@ end -- todo: support a,b,c +-- we need a copy as we will add (fontclass) goodies to the features and +-- that is bad for a shared table + local function splitcontext(features) -- presetcontext creates dummy here - return setups[features] or (presetcontext(features,"","") and setups[features]) + return fastcopy(setups[features] or (presetcontext(features,"","") and setups[features])) end --~ local splitter = lpeg.splitat("=") @@ -527,7 +697,7 @@ end specifiers.splitcontext = splitcontext function specifiers.contexttostring(name,kind,separator,yes,no,strict,omit) -- not used - return hash_to_string(table.merged(handlers[kind].features.defaults or {},setups[name] or {}),separator,yes,no,strict,omit) + return hash_to_string(mergedtable(handlers[kind].features.defaults or {},setups[name] or {}),separator,yes,no,strict,omit) end local function starred(features) -- no longer fallbacks here @@ -592,8 +762,12 @@ local setsomefontname = context.fntsetsomename local setemptyfontsize = context.fntsetnopsize local setsomefontsize = context.fntsetsomesize -function definers.stage_one(str) +function commands.definefont_one(str) statistics.starttiming(fonts) + if trace_defining then + report_defining("memory usage before: %s",statistics.memused()) + report_defining("start stage one: %s",str) + end local fullname, size = lpegmatch(splitpattern,str) local lookup, name, sub, method, detail = getspecification(fullname) if not name then @@ -623,6 +797,9 @@ function definers.stage_one(str) setemptyfontsize() end specification = definers.makespecification(str,lookup,name,sub,method,detail,size) + if trace_defining then + report_defining("stop stage one") + end end local n = 0 @@ -630,14 +807,34 @@ local n = 0 -- we can also move rscale to here (more consistent) -- the argument list will become a table -function definers.stage_two(global,cs,str,size,inheritancemode,classfeatures,fontfeatures,classfallbacks,fontfallbacks, - mathsize,textsize,relativeid,classgoodies,goodies) +local function nice_cs(cs) + return (gsub(cs,".->", "")) +end + +function commands.definefont_two(global,cs,str,size,inheritancemode,classfeatures,fontfeatures,classfallbacks,fontfallbacks, + mathsize,textsize,relativeid,classgoodies,goodies,classdesignsize,fontdesignsize) if trace_defining then - report_defining("memory usage before: %s",statistics.memused()) + report_defining("start stage two: %s (%s)",str,size) end -- name is now resolved and size is scaled cf sa/mo local lookup, name, sub, method, detail = getspecification(str or "") - -- asome settings can be overloaded + -- new (todo: inheritancemode) + local designsize = fontdesignsize ~= "" and fontdesignsize or classdesignsize or "" + local designname = designsizefilename(name,designsize,size) + if designname and designname ~= "" then + if trace_defining or trace_designsize then + report_defining("remapping name: %s, specification: %s, size: %s => designsize: %s",name,designsize,size,designname) + end + -- we don't catch detail here + local o_lookup, o_name, o_sub, o_method, o_detail = getspecification(designname) + if o_lookup and o_lookup ~= "" then lookup = o_lookup end + if o_method and o_method ~= "" then method = o_method end + if o_detail and o_detail ~= "" then detail = o_detail end + name = o_name + sub = o_sub + end + -- so far + -- some settings can have been overloaded if lookup and lookup ~= "" then specification.lookup = lookup end @@ -645,14 +842,14 @@ function definers.stage_two(global,cs,str,size,inheritancemode,classfeatures,fon local id = tonumber(relativeid) or 0 specification.relativeid = id > 0 and id end - specification.name = name - specification.size = size - specification.sub = (sub and sub ~= "" and sub) or specification.sub - specification.mathsize = mathsize - specification.textsize = textsize - specification.goodies = goodies - specification.cs = cs - specification.global = global + specification.name = name + specification.size = size + specification.sub = (sub and sub ~= "" and sub) or specification.sub + specification.mathsize = mathsize + specification.textsize = textsize + specification.goodies = goodies + specification.cs = cs + specification.global = global if detail and detail ~= "" then specification.method = method or "*" specification.detail = detail @@ -707,36 +904,42 @@ function definers.stage_two(global,cs,str,size,inheritancemode,classfeatures,fon specification.fallbacks = fontfallbacks end end - local tfmdata = definers.read(specification,size) -- id not yet known - local cs = specification.cs - if cs then - csnames[cs] = tfmdata -- new (beware: locals can be forgotten) - end + local tfmdata = definers.read(specification,size) -- id not yet known (size in spec?) if not tfmdata then - report_defining("unable to define %s as \\%s",name,cs) + report_defining("unable to define %s as [%s]",name,nice_cs(cs)) texsetcount("global","lastfontid",-1) context.letvaluerelax(cs) -- otherwise the current definition takes the previous one elseif type(tfmdata) == "number" then if trace_defining then - report_defining("reusing %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s, goodies: %s/%s)", - name,tfmdata,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies) + report_defining("reusing %s with id %s as [%s] (features: %s/%s, fallbacks: %s/%s, goodies: %s/%s, designsize: %s/%s)", + name,tfmdata,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies,classdesignsize,fontdesignsize) end + csnames[tfmdata] = specification.cs tex.definefont(global,cs,tfmdata) -- resolved (when designsize is used): setsomefontsize(fontdata[tfmdata].parameters.size .. "sp") texsetcount("global","lastfontid",tfmdata) else -tfmdata.characters[0] = nil -- we use char0 as signal - -- local t = os.clock(t) + -- setting the extra characters will move elsewhere + local characters = tfmdata.characters + local parameters = tfmdata.parameters + -- we use char0 as signal + characters[0] = nil + -- cf the spec pdf can handle this (no char in slot) + -- characters[0x00A0] = { width = parameters.space } + -- characters[0x2007] = { width = characters[0x0030] and characters[0x0030].width or parameters.space } -- figure + -- characters[0x2008] = { width = characters[0x002E] and characters[0x002E].width or parameters.space } -- period + -- local id = font.define(tfmdata) - -- print(name,os.clock()-t) + csnames[id] = specification.cs tfmdata.properties.id = id definers.register(tfmdata,id) -- to be sure, normally already done tex.definefont(global,cs,id) constructors.cleanuptable(tfmdata) constructors.finalize(tfmdata) if trace_defining then - report_defining("defining %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,id,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks) + report_defining("defining %s with id %s as [%s] (features: %s/%s, fallbacks: %s/%s)", + name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks) end -- resolved (when designsize is used): setsomefontsize((tfmdata.parameters.size or 655360) .. "sp") @@ -747,6 +950,7 @@ tfmdata.characters[0] = nil -- we use char0 as signal end if trace_defining then report_defining("memory usage after: %s",statistics.memused()) + report_defining("stop stage two") end statistics.stoptiming(fonts) end @@ -771,6 +975,10 @@ function definers.define(specification) specification.method = specification.method or (method ~= "" and method) or "*" specification.detail = specification.detail or (detail ~= "" and detail) or "" -- + if type(specification.size) == "string" then + specification.size = tex.sp(specification.size) or 655260 + end + -- specification.specification = "" -- not used specification.resolved = "" specification.forced = "" @@ -836,6 +1044,50 @@ function constructors.calculatescale(tfmdata,scaledpoints,relativeid) return scaledpoints, delta end +-- We overload the (generic) resolver: + +local resolvers = definers.resolvers +local hashfeatures = constructors.hashfeatures + +function definers.resolve(specification) -- overload function in font-con.lua + if not specification.resolved or specification.resolved == "" then -- resolved itself not per se in mapping hash + local r = resolvers[specification.lookup] + if r then + r(specification) + end + end + if specification.forced == "" then + specification.forced = nil + else + specification.forced = specification.forced + end + -- goodies are a context specific thing and not always defined + -- as feature, so we need to make sure we add them here before + -- hashing because otherwise we get funny goodies applied + local goodies = specification.goodies + if goodies and goodies ~= "" then + -- this adapts the features table so it has best be a copy + local normal = specification.features.normal + if not normal then + specification.features.normal = { goodies = goodies } + elseif not normal.goodies then + local g = normal.goodies + if g and g ~= "" then + normal.goodies = format("%s,%s",g,goodies) + else + normal.goodies = goodies + end + end + end + -- so far for goodie hacks + specification.hash = lower(specification.name .. ' @ ' .. hashfeatures(specification)) + if specification.sub and specification.sub ~= "" then + specification.hash = specification.sub .. ' @ ' .. specification.hash + end + return specification +end + + -- soon to be obsolete: local mappings = fonts.mappings @@ -905,7 +1157,7 @@ helpers.nametoslot = nametoslot function loggers.reportdefinedfonts() if trace_usage then local t, tn = { }, 0 - for id, data in table.sortedhash(fontdata) do + for id, data in sortedhash(fontdata) do local properties = data.properties or { } local parameters = data.parameters or { } tn = tn + 1 @@ -918,7 +1170,7 @@ function loggers.reportdefinedfonts() properties.psname or "", properties.fullname or "", } -report_status("%s: %s",properties.name,concat(table.sortedkeys(data)," ")) +report_status("%s: %s",properties.name,concat(sortedkeys(data)," ")) end formatcolumns(t," ") report_status() @@ -941,7 +1193,7 @@ function loggers.reportusedfeatures() local setup = setups[name] local n = setup.number setup.number = nil -- we have no reason to show this - t[i] = { i, name, table.sequenced(setup,false,true) } -- simple mode + t[i] = { i, name, sequenced(setup,false,true) } -- simple mode setup.number = n -- restore it (normally not needed as we're done anyway) end formatcolumns(t," ") @@ -1014,7 +1266,7 @@ function fonts.definetypeface(name,t) context.definefontsynonym( { format("%sBoldItalic", Shape) }, { format("spec:%s-%s-italic-%s", fontname, boldweight, boldwidth ) } ) context.definefontsynonym( { format("%sItalic", Shape) }, { format("spec:%s-%s-italic-%s", fontname, normalweight, normalwidth) } ) context.stopfontclass() - local settings = table.sequenced({ features= t.features },",") + local settings = sequenced({ features= t.features },",") context.dofastdefinetypeface(name, shortcut, shape, size, settings) end @@ -1057,7 +1309,7 @@ function commands.nbfs(amount,precision) end function commands.featureattribute(tag) - tex.write(contextnumber(tag)) + context(contextnumber(tag)) end function commands.setfontfeature(tag) @@ -1199,17 +1451,15 @@ if environment.initex then for what, handler in table.sortedpairs(handlers) do local features = handler.features if features then - local t = { } - t[#t+1] = "[" - t[#t+1] = what - t[#t+1] = format("(base initializers: %s)",names(features.initializers.base)) - t[#t+1] = format("(base processors: %s)", names(features.processors .base)) - t[#t+1] = format("(base manipulators: %s)",names(features.manipulators.base)) - t[#t+1] = format("(node initializers: %s)",names(features.initializers.node)) - t[#t+1] = format("(node processors: %s)", names(features.processors .node)) - t[#t+1] = format("(node manipulators: %s)",names(features.manipulators.node)) - t[#t+1] = "]" - l[#l+1] = concat(t, " ") + l[#l+1] = format("[%s (base initializers: %s) (base processors: %s) (base manipulators: %s) (node initializers: %s) (node processors: %s) (node manipulators: %s)]", + what, + names(features.initializers.base), + names(features.processors .base), + names(features.manipulators.base), + names(features.initializers.node), + names(features.processors .node), + names(features.manipulators.node) + ) end end return concat(l, " | ") @@ -1279,3 +1529,15 @@ to scale virtual characters.</p> -- end -- end -- end + +function commands.setfontofid(id) + context.getvalue(csnames[id]) +end + +-- more interfacing: + +commands.definefontfeature = fonts.specifiers.presetcontext + +function commands.featurelist(...) + context(fonts.specifiers.contexttostring(...)) +end |