diff options
author | Karl Berry <karl@freefriends.org> | 2017-04-19 23:04:15 +0000 |
---|---|---|
committer | Karl Berry <karl@freefriends.org> | 2017-04-19 23:04:15 +0000 |
commit | f74161ca4e7eb3c5af9afcbe92522ae3b58987c1 (patch) | |
tree | 3c30a13df5ac7968195c85070a2b074578e669d2 /Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua | |
parent | 1d5a55ac8f5506a7ae9cfca52f4b588182e199d4 (diff) |
context beta/cont-tmf.zip (Apr 16 12:55)
git-svn-id: svn://tug.org/texlive/trunk@43931 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua | 720 |
1 files changed, 492 insertions, 228 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua b/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua index be233e5702d..9e53b2c25a6 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-ctx.lua @@ -14,7 +14,7 @@ if not modules then modules = { } end modules ['font-ctx'] = { local context, commands = context, commands -local format, gmatch, match, find, lower, gsub, byte = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub, string.byte +local format, gmatch, match, find, lower, gsub, byte, topattern = string.format, string.gmatch, string.match, string.find, string.lower, string.gsub, string.byte, string.topattern 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 @@ -42,6 +42,7 @@ local report_cummulative = logs.reporter("fonts","cummulative") local report_defining = logs.reporter("fonts","defining") local report_status = logs.reporter("fonts","status") local report_mapfiles = logs.reporter("fonts","mapfiles") +local report_newline = logs.newline local setmetatableindex = table.setmetatableindex @@ -63,6 +64,8 @@ local hashes = fonts.hashes local currentfont = font.current local definefont = font.define +local cleanname = names.cleanname + local encodings = fonts.encodings ----- aglunicodes = encodings.agl.unicodes local aglunicodes = nil -- delayed loading @@ -102,15 +105,13 @@ local parameters = hashes.parameters local designsizefilename = fontgoodies.designsizes.filename -local context_char = context.char -local context_getvalue = context.getvalue +local ctx_char = context.char +local ctx_getvalue = context.getvalue local otffeatures = otf.features local otftables = otf.tables local registerotffeature = otffeatures.register -local baseprocessors = otffeatures.processors.base -local baseinitializers = otffeatures.initializers.base local sequencers = utilities.sequencers local appendgroup = sequencers.appendgroup @@ -153,17 +154,19 @@ local function getfontname(tfmdata) return basename(type(tfmdata) == "number" and properties[tfmdata].name or tfmdata.properties.name) end -fonts.helpers.name = getfontname +helpers.name = getfontname + +local addformatter = utilities.strings.formatters.add if _LUAVERSION < 5.2 then - utilities.strings.formatters.add(formatters,"font:name", [["'"..fontname(%s).."'"]], "local fontname = fonts.helpers.name") - utilities.strings.formatters.add(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],"local sequenced = table.sequenced") + addformatter(formatters,"font:name", [["'"..fontname(%s).."'"]], "local fontname = fonts.helpers.name") + addformatter(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],"local sequenced = table.sequenced") else - utilities.strings.formatters.add(formatters,"font:name", [["'"..fontname(%s).."'"]], { fontname = fonts.helpers.name }) - utilities.strings.formatters.add(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],{ sequenced = table.sequenced }) + addformatter(formatters,"font:name", [["'"..fontname(%s).."'"]], { fontname = helpers.name }) + addformatter(formatters,"font:features",[["'"..sequenced(%s," ",true).."'"]],{ sequenced = table.sequenced }) end @@ -176,58 +179,109 @@ constructors.nofsharedhashes = 0 constructors.nofsharedvectors = 0 constructors.noffontsloaded = 0 -local shares = { } -local hashes = { } - -function constructors.trytosharefont(target,tfmdata) - constructors.noffontsloaded = constructors.noffontsloaded + 1 - if constructors.sharefonts then - local fonthash = target.specification.hash - if fonthash then - local properties = target.properties - local fullname = target.fullname - local sharedname = hashes[fonthash] - if sharedname then - -- this is ok for context as we know that only features can mess with font definitions - -- so a similar hash means that the fonts are similar too - if trace_defining then - report_defining("font %a uses backend resources of font %a (%s)",target.fullname,sharedname,"common hash") - end - target.fullname = sharedname - properties.sharedwith = sharedname - constructors.nofsharedfonts = constructors.nofsharedfonts + 1 - constructors.nofsharedhashes = constructors.nofsharedhashes + 1 - else - -- the one takes more time (in the worst case of many cjk fonts) but it also saves - -- embedding time - local characters = target.characters - local n = 1 - local t = { target.psname } - local u = sortedkeys(characters) - for i=1,#u do - local k = u[i] - n = n + 1 ; t[n] = k - n = n + 1 ; t[n] = characters[k].index or k - end - local checksum = md5.HEX(concat(t," ")) - local sharedname = shares[checksum] +do + + local shares = { } + local hashes = { } + + local nofinstances = 0 + local instances = table.setmetatableindex(function(t,k) + nofinstances = nofinstances + 1 + t[k] = nofinstances + return nofinstances + end) + + function constructors.trytosharefont(target,tfmdata) + constructors.noffontsloaded = constructors.noffontsloaded + 1 + if constructors.sharefonts then + local fonthash = target.specification.hash + if fonthash then + local properties = target.properties local fullname = target.fullname + local fontname = target.fontname + local psname = target.psname + -- for the moment here: + local instance = properties.instance + if instance then + local format = tfmdata.properties.format + if format == "opentype" then + target.streamprovider = 1 + elseif format == "truetype" then + target.streamprovider = 2 + else + target.streamprovider = 0 + end + if target.streamprovider > 0 then + if fullname then + fullname = fullname .. ":" .. instances[instance] + target.fullname = fullname + end + if fontname then + fontname = fontname .. ":" .. instances[instance] + target.fontname = fontname + end + if psname then + -- this one is used for the funny prefix in font names in pdf + -- so it has ot be kind of unique in order to avoid subset prefix + -- clashes being reported + psname = psname .. ":" .. instances[instance] + target.psname = psname + end + end + end + -- + local sharedname = hashes[fonthash] if sharedname then + -- this is ok for context as we know that only features can mess with font definitions + -- so a similar hash means that the fonts are similar too if trace_defining then - report_defining("font %a uses backend resources of font %a (%s)",fullname,sharedname,"common vector") + report_defining("font %a uses backend resources of font %a (%s)",target.fullname,sharedname,"common hash") end - fullname = sharedname - properties.sharedwith= sharedname + target.fullname = sharedname + properties.sharedwith = sharedname constructors.nofsharedfonts = constructors.nofsharedfonts + 1 - constructors.nofsharedvectors = constructors.nofsharedvectors + 1 + constructors.nofsharedhashes = constructors.nofsharedhashes + 1 else - shares[checksum] = fullname + -- the one takes more time (in the worst case of many cjk fonts) but it also saves + -- embedding time .. haha, this is interesting: when i got a clash on subset tag + -- collision i saw in the source that these tags are also using a hash like below + -- so maybe we should have an option to pass it from lua + local characters = target.characters + local n = 1 + local t = { target.psname } + -- for the moment here: + if instance then + n = n + 1 + t[n] = instance + end + -- + local u = sortedkeys(characters) + for i=1,#u do + local k = u[i] + n = n + 1 ; t[n] = k + n = n + 1 ; t[n] = characters[k].index or k + end + local checksum = md5.HEX(concat(t," ")) + local sharedname = shares[checksum] + local fullname = target.fullname + if sharedname then + if trace_defining then + report_defining("font %a uses backend resources of font %a (%s)",fullname,sharedname,"common vector") + end + fullname = sharedname + properties.sharedwith= sharedname + constructors.nofsharedfonts = constructors.nofsharedfonts + 1 + constructors.nofsharedvectors = constructors.nofsharedvectors + 1 + else + shares[checksum] = fullname + end + target.fullname = fullname + hashes[fonthash] = fullname end - target.fullname = fullname - hashes[fonthash] = fullname end end end + end directives.register("fonts.checksharing",function(v) @@ -294,21 +348,13 @@ otftables.scripts.auto = "automatic fallback to latn when no dflt present" -- setmetatableindex(otffeatures.descriptions,otftables.features) -local privatefeatures = { - tlig = true, - trep = true, - anum = true, -} - local function checkedscript(tfmdata,resources,features) local latn = false local script = false if resources.features then for g, list in next, resources.features do for f, scripts in next, list do - if privatefeatures[f] then - -- skip - elseif scripts.dflt then + if scripts.dflt then script = "dflt" break elseif scripts.latn then @@ -537,10 +583,11 @@ local function presetcontext(name,parent,features) -- will go to con and shared for p in gmatch(parent,"[^, ]+") do local s = setups[p] if s then - for k,v in next, s do - if features[k] == nil then + for k, v in next, s do +-- no, as then we cannot overload: e.g. math,mathextra +-- if features[k] == nil then features[k] = v - end +-- end end else -- just ignore an undefined one .. i.e. we can refer to not yet defined @@ -570,7 +617,7 @@ local function presetcontext(name,parent,features) -- will go to con and shared -- optimization) local t = { } -- can we avoid t ? for k,v in next, features do --- if v then t[k] = v end + -- if v then t[k] = v end t[k] = v end -- needed for dynamic features @@ -585,42 +632,57 @@ local function presetcontext(name,parent,features) -- will go to con and shared return number, t end -local function contextnumber(name) -- will be replaced - local t = setups[name] - if not t then - return 0 - elseif t.auto then - local lng = tonumber(tex.language) - local tag = name .. ":" .. lng - local s = setups[tag] - if s then - return s.number or 0 - else - local script, language = languages.association(lng) - if t.script ~= script or t.language ~= language then - local s = fastcopy(t) - local n = #numbers + 1 - setups[tag] = s - numbers[n] = tag - s.number = n - s.script = script - s.language = language - return n - else - setups[tag] = t - return t.number or 0 - end +local function adaptcontext(pattern,features) + local pattern = topattern(pattern,false,true) + for name in next, setups do + if find(name,pattern) then + presetcontext(name,name,features) end - else - return t.number or 0 end end +-- local function contextnumber(name) -- will be replaced +-- local t = setups[name] +-- if not t then +-- return 0 +-- elseif t.auto then -- check where used, autolanguage / autoscript? +-- local lng = tonumber(tex.language) +-- local tag = name .. ":" .. lng +-- local s = setups[tag] +-- if s then +-- return s.number or 0 +-- else +-- local script, language = languages.association(lng) +-- if t.script ~= script or t.language ~= language then +-- local s = fastcopy(t) +-- local n = #numbers + 1 +-- setups[tag] = s +-- numbers[n] = tag +-- s.number = n +-- s.script = script +-- s.language = language +-- return n +-- else +-- setups[tag] = t +-- return t.number or 0 +-- end +-- end +-- else +-- return t.number or 0 +-- end +-- end + +local function contextnumber(name) -- will be replaced + local t = setups[name] + return t and t.number or 0 +end + local function mergecontext(currentnumber,extraname,option) -- number string number (used in scrp-ini local extra = setups[extraname] if extra then local current = setups[numbers[currentnumber]] - local mergedfeatures, mergedname = { }, nil + local mergedfeatures = { } + local mergedname = nil if option < 0 then if current then for k, v in next, current do @@ -941,13 +1003,13 @@ local rightparent = (P")") local value = C((leftparent * (1-rightparent)^0 * rightparent + (1-space))^1) local dimension = C((space/"" + P(1))^1) local rest = C(P(1)^0) -local scale_none = Cc(0) -local scale_at = P("at") * Cc(1) * spaces * dimension -- dimension -local scale_sa = P("sa") * Cc(2) * spaces * dimension -- number -local scale_mo = P("mo") * Cc(3) * spaces * dimension -- number -local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- number -local scale_ht = P("ht") * Cc(5) * spaces * dimension -- dimension -local scale_cp = P("cp") * Cc(6) * spaces * dimension -- dimension +local scale_none = Cc(0) +local scale_at = (P("at") +P("@")) * Cc(1) * spaces * dimension -- dimension +local scale_sa = P("sa") * Cc(2) * spaces * dimension -- number +local scale_mo = P("mo") * Cc(3) * spaces * dimension -- number +local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- number +local scale_ht = P("ht") * Cc(5) * spaces * dimension -- dimension +local scale_cp = P("cp") * Cc(6) * spaces * dimension -- dimension local specialscale = { [5] = "ht", [6] = "cp" } @@ -973,6 +1035,8 @@ local getspecification = definers.getspecification -- we can make helper macros which saves parsing (but normaly not -- that many calls, e.g. in mk a couple of 100 and in metafun 3500) +local specifiers = { } + do -- else too many locals ----- ctx_setdefaultfontname = context.fntsetdefname @@ -987,6 +1051,7 @@ do -- else too many locals local scanners = tokens.scanners local scanstring = scanners.string local scaninteger = scanners.integer + local scannumber = scanners.number local scanboolean = scanners.boolean local setmacro = tokens.setters.macro @@ -1072,7 +1137,7 @@ do -- else too many locals local scaledfontmode = scaninteger() -- \scaledfontmode if trace_defining then - report_defining("start stage two: %s (size %s)",str,size) + report_defining("start stage two: %s, size %s, features %a & %a",str,size,classfeatures,fontfeatures) end -- name is now resolved and size is scaled cf sa/mo local lookup, name, sub, method, detail = getspecification(str or "") @@ -1220,6 +1285,7 @@ do -- else too many locals end -- texsetcount("global","lastfontid",lastfontid) + specifiers[lastfontid] = { str, size } if not mathsize then -- forget about it elseif mathsize == 0 then @@ -1231,6 +1297,26 @@ do -- else too many locals stoptiming(fonts) end + function scanners.specifiedfontspec() + local f = specifiers[scaninteger()] + if f then + context(f[1]) + end + end + function scanners.specifiedfontsize() + local f = specifiers[scaninteger()] + if f then + context(f[2]) + end + end + function scanners.specifiedfont() + local f = specifiers[scaninteger()] + local s = scannumber() + if f and s then + context("%s at %0.2p",f[1],s * f[2]) -- we round to 2 decimals (as at the tex end) + end + end + -- function definers.define(specification) @@ -1383,7 +1469,7 @@ function constructors.calculatescale(tfmdata,scaledpoints,relativeid,specificati local scaledpoints, delta = calculatescale(tfmdata,scaledpoints) -- if enable_auto_r_scale and relativeid then -- for the moment this is rather context specific (we need to hash rscale then) -- local relativedata = fontdata[relativeid] - -- local rfmdata = relativedata and relativedata.unscaled and relativedata.unscaled + -- local rfmdata = relativedata and relativedata.unscaled and relativedata.unscaled -- just use metadata instead -- local id_x_height = rfmdata and rfmdata.parameters and rfmdata.parameters.x_height -- local tf_x_height = tfmdata and tfmdata.parameters and tfmdata.parameters.x_height -- if id_x_height and tf_x_height then @@ -1397,14 +1483,19 @@ end local designsizes = constructors.designsizes +-- called quite often when in mp labels +-- otf.normalizedaxis + function constructors.hashinstance(specification,force) - local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks + local hash = specification.hash + local size = specification.size + local fallbacks = specification.fallbacks if force or not hash then hash = constructors.hashfeatures(specification) specification.hash = hash end if size < 1000 and designsizes[hash] then - size = math.round(constructors.scaled(size,designsizes[hash])) + size = round(constructors.scaled(size,designsizes[hash])) specification.size = size end if fallbacks then @@ -1437,7 +1528,7 @@ function definers.resolve(specification) -- overload function in font-con.lua else specification.forced = specification.forced end - -- goodies are a context specific thing and not always defined + -- goodies are a context specific thing and are 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 @@ -1456,14 +1547,18 @@ function definers.resolve(specification) -- overload function in font-con.lua 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 + local hash = hashfeatures(specification) + local name = specification.name + local sub = specification.sub + if sub and sub ~= "" then + specification.hash = lower(name .. " @ " .. sub .. ' @ ' .. hash) + else + specification.hash = lower(name .. " @ " .. ' @ ' .. hash) end + -- return specification end - -- soon to be obsolete: local mappings = fonts.mappings @@ -1665,13 +1760,13 @@ do -- else too many locals implement { name = "fontchar", - actions = { nametoslot, context_char }, + actions = { nametoslot, ctx_char }, arguments = "string", } implement { name = "fontcharbyindex", - actions = { indextoslot, context_char }, + actions = { indextoslot, ctx_char }, arguments = "integer", } @@ -1702,15 +1797,16 @@ function loggers.reportdefinedfonts() properties.fullname or "", properties.sharedwith or "", } - report_status("%s: % t",properties.name,sortedkeys(data)) end formatcolumns(t," ") - report_status() + logs.pushtarget("logfile") + report_newline() report_status("defined fonts:") - report_status() + report_newline() for k=1,tn do report_status(t[k]) end + logs.poptarget() end end @@ -1729,12 +1825,14 @@ function loggers.reportusedfeatures() setup.number = n -- restore it (normally not needed as we're done anyway) end formatcolumns(t," ") - report_status() + logs.pushtarget("logfile") + report_newline() report_status("defined featuresets:") - report_status() + report_newline() for k=1,n do report_status(t[k]) end + logs.poptarget() end end @@ -2023,15 +2121,7 @@ end do - -- local scanners = tokens.scanners - -- local scanstring = scanners.string - -- local scaninteger = scanners.integer - -- local scandimen = scanners.dimen - -- local scanboolean = scanners.boolean - - -- local scanners = interfaces.scanners - - local setmacro = tokens.setters.macro + local setmacro = tokens.setters.macro function constructors.currentfonthasfeature(n) local f = fontdata[currentfont()] @@ -2048,25 +2138,9 @@ do arguments = "string" } - -- local p, f = 1, formatters["%0.1fpt"] -- normally this value is changed only once - -- - -- local stripper = lpeg.patterns.stripzeros - -- - -- function commands.nbfs(amount,precision) - -- if precision ~= p then - -- p = precision - -- f = formatters["%0." .. p .. "fpt"] - -- end - -- context(lpegmatch(stripper,f(amount/65536))) - -- end - local f_strip = formatters["%0.2fpt"] -- normally this value is changed only once local stripper = lpeg.patterns.stripzeros - -- scanners.nbfs = function() - -- context(lpegmatch(stripper,f_strip(scandimen()/65536))) - -- end - implement { name = "nbfs", arguments = "dimen", @@ -2075,18 +2149,6 @@ do end } - -- commands.featureattribute = function(tag) context(contextnumber(tag)) end - -- commands.setfontfeature = function(tag) texsetattribute(0,contextnumber(tag)) end - -- commands.resetfontfeature = function() texsetattribute(0,0) end - -- commands.setfontofid = function(id) context_getvalue(csnames[id]) end - -- commands.definefontfeature = presetcontext - - -- scanners.featureattribute = function() context(contextnumber(scanstring())) end - -- scanners.setfontfeature = function() texsetattribute(0,contextnumber(scanstring())) end - -- scanners.resetfontfeature = function() texsetattribute(0,0) end - -- scanners.setfontofid = function() context_getvalue(csnames[scaninteger()]) end - -- scanners.definefontfeature = function() presetcontext(scanstring(),scanstring(),scanstring()) end - implement { name = "featureattribute", arguments = "string", @@ -2109,7 +2171,7 @@ do name = "setfontofid", arguments = "integer", actions = function(id) - context_getvalue(csnames[id]) + ctx_getvalue(csnames[id]) end } @@ -2119,6 +2181,12 @@ do actions = presetcontext } + implement { + name = "adaptfontfeature", + arguments = { "string", "string" }, + actions = adaptcontext + } + local cache = { } local hows = { @@ -2189,6 +2257,9 @@ do end end + constructors.setfeature = setfeature + constructors.resetfeature = resetfeature + implement { name = "resetfeature", actions = resetfeature } implement { name = "addfeature", actions = setfeature, arguments = { "'+'", "string", "string" } } implement { name = "subtractfeature", actions = setfeature, arguments = { "'-'", "string", "string" } } @@ -2202,8 +2273,8 @@ do } implement { - name = "registerlanguagefeatures", - actions = registerlanguagefeatures, + name = "registerlanguagefeatures", + actions = registerlanguagefeatures, } end @@ -2216,7 +2287,7 @@ do local copy_node = nuts.copy local kern = nuts.pool.register(nuts.pool.kern()) - setattr(kern,attributes.private('fontkern'),1) + setattr(kern,attributes.private('fontkern'),1) -- no gain in setprop as it's shared nodes.injections.installnewkern(function(k) local c = copy_node(kern) @@ -2275,100 +2346,106 @@ end -- make a closure (200 limit): -local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end) +do -local analyzers = fonts.analyzers -local methods = analyzers.methods + local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end) -local unsetvalue = attributes.unsetvalue + local analyzers = fonts.analyzers + local methods = analyzers.methods -local traverse_id = nuts.traverse_id + local unsetvalue = attributes.unsetvalue -local a_color = attributes.private('color') -local a_colormodel = attributes.private('colormodel') -local a_state = attributes.private('state') -local m_color = attributes.list[a_color] or { } + local traverse_id = nuts.traverse_id -local glyph_code = nodes.nodecodes.glyph + local a_color = attributes.private('color') + local a_colormodel = attributes.private('colormodel') + local a_state = attributes.private('state') + local m_color = attributes.list[a_color] or { } -local states = analyzers.states + local glyph_code = nodes.nodecodes.glyph -local colornames = { - [states.init] = "font:1", - [states.medi] = "font:2", - [states.fina] = "font:3", - [states.isol] = "font:4", - [states.mark] = "font:5", - [states.rest] = "font:6", - [states.rphf] = "font:1", - [states.half] = "font:2", - [states.pref] = "font:3", - [states.blwf] = "font:4", - [states.pstf] = "font:5", -} + local states = analyzers.states + + local colornames = { + [states.init] = "font:1", + [states.medi] = "font:2", + [states.fina] = "font:3", + [states.isol] = "font:4", + [states.mark] = "font:5", + [states.rest] = "font:6", + [states.rphf] = "font:1", + [states.half] = "font:2", + [states.pref] = "font:3", + [states.blwf] = "font:4", + [states.pstf] = "font:5", + } -local function markstates(head) - if head then - head = tonut(head) - local model = getattr(head,a_colormodel) or 1 - for glyph in traverse_id(glyph_code,head) do - local a = getprop(glyph,a_state) - if a then - local name = colornames[a] - if name then - local color = m_color[name] - if color then - setattr(glyph,a_colormodel,model) - setattr(glyph,a_color,color) + local function markstates(head) + if head then + head = tonut(head) + local model = getattr(head,a_colormodel) or 1 + for glyph in traverse_id(glyph_code,head) do + local a = getprop(glyph,a_state) + if a then + local name = colornames[a] + if name then + local color = m_color[name] + if color then + setattr(glyph,a_colormodel,model) + setattr(glyph,a_color,color) + end end end end end end -end -local function analyzeprocessor(head,font,attr) - local tfmdata = fontdata[font] - local script, language = otf.scriptandlanguage(tfmdata,attr) - local action = methods[script] - if not action then - return head, false - end - if type(action) == "function" then - local head, done = action(head,font,attr) - if done and trace_analyzing then - markstates(head) + local function analyzeprocessor(head,font,attr) + local tfmdata = fontdata[font] + local script, language = otf.scriptandlanguage(tfmdata,attr) + local action = methods[script] + if not action then + return head, false end - return head, done - end - action = action[language] - if action then - local head, done = action(head,font,attr) - if done and trace_analyzing then - markstates(head) + if type(action) == "function" then + local head, done = action(head,font,attr) + if done and trace_analyzing then + markstates(head) + end + return head, done + end + action = action[language] + if action then + local head, done = action(head,font,attr) + if done and trace_analyzing then + markstates(head) + end + return head, done + else + return head, false end - return head, done - else - return head, false end -end -registerotffeature { -- adapts - name = "analyze", - processors = { - node = analyzeprocessor, + registerotffeature { -- adapts + name = "analyze", + processors = { + node = analyzeprocessor, + } } -} -function methods.nocolor(head,font,attr) - for n in traverse_id(glyph_code,head) do - if not font or getfont(n) == font then - setattr(n,a_color,unsetvalue) + + function methods.nocolor(head,font,attr) + for n in traverse_id(glyph_code,head) do + if not font or getfont(n) == font then + setattr(n,a_color,unsetvalue) + end end + return head, true end - return head, true + end + local function purefontname(name) if type(name) == "number" then name = getfontname(name) @@ -2385,6 +2462,7 @@ implement { } local list = storage.shared.bodyfontsizes or { } + storage.shared.bodyfontsizes = list implement { @@ -2421,7 +2499,7 @@ implement { implement { name = "cleanfontname", - actions = { names.cleanname, context }, + actions = { cleanname, context }, arguments = "string" } @@ -2496,3 +2574,189 @@ implement { actions = { names.exists, commands.doifelse }, arguments = "string" } + +-- we use 0xFE000+ and 0xFF000+ in math and for runtime (text) extensions we +-- use 0xFD000+ + +constructors.privateslots = constructors.privateslots or { } + +storage.register("fonts/constructors/privateslots", constructors.privateslots, "fonts.constructors.privateslots") + +do + + local privateslots = constructors.privateslots + local lastprivateslot = 0xFD000 + + constructors.privateslots = setmetatableindex(privateslots,function(t,k) + local v = lastprivateslot + lastprivateslot = lastprivateslot + 1 + t[k] = v + return v + end) + + implement { + name = "getprivateglyphslot", + actions = function(name) context(privateslots[name]) end, + arguments = "string", + } + +end + +-- an extra helper + +function helpers.getcoloredglyphs(tfmdata) + if type(tfmdata) == "number" then + tfmdata = fontdata[tfmdata] + end + if not tfmdata then + tfmdata = fontdata[true] + end + local characters = tfmdata.characters + local descriptions = tfmdata.descriptions + local collected = { } + for unicode, character in next, characters do + local description = descriptions[unicode] + if description and (description.colors or character.svg) then + collected[#collected+1] = unicode + end + end + table.sort(collected) + return collected +end + +-- for the font manual + +statistics.register("used fonts",function() + if trace_usage then + local filename = file.nameonly(environment.jobname) .. "-fonts-usage.lua" + if next(fontdata) then + local files = { } + local list = { } + for id, tfmdata in sortedhash(fontdata) do + local filename = tfmdata.properties.filename + if filename then + local filedata = files[filename] + if filedata then + filedata.instances = filedata.instances + 1 + else + local rawdata = tfmdata.shared and tfmdata.shared.rawdata + local metadata = rawdata and rawdata.metadata + files[filename] = { + instances = 1, + filename = filename, + version = metadata and metadata.version, + size = rawdata and rawdata.size, + } + end + else + -- what to do + end + end + for k, v in sortedhash(files) do + list[#list+1] = v + end + table.save(filename,list) + else + os.remove(filename) + end + end +end) + +-- new + +do + + local settings_to_array = utilities.parsers.settings_to_array + local namedcolorattributes = attributes.colors.namedcolorattributes + local colorvalues = attributes.colors.values + + implement { + name = "definefontcolorpalette", + arguments = { "string", "string" }, + actions = function(name,set) + set = settings_to_array(set) + for i=1,#set do + local name = set[i] + local space, color = namedcolorattributes(name) + local values = colorvalues[color] + if values then + set[i] = { r = values[3], g = values[4], b = values[5] } + else + set[i] = { r = 0, g = 0, b = 0 } + end + end + otf.registerpalette(name,set) + end + } + +end + +do + + local pattern = C((1-S("* "))^1) -- strips all after * or ' at' + + implement { + name = "truefontname", + arguments = "string", + actions = function(s) + -- context(match(s,"[^* ]+") or s) + context(lpegmatch(pattern,s) or s) + end + } + +end + +do + + local function getinstancespec(id) + local data = fontdata[id or true] + local shared = data.shared + local resources = shared and shared.rawdata.resources + if resources then + local instancespec = data.properties.instance + if instancespec then + local variabledata = resources.variabledata + if variabledata then + local instances = variabledata.instances + if instances then + for i=1,#instances do + local instance = instances[i] + if cleanname(instance.subfamily)== instancespec then + local values = table.copy(instance.values) + local axis = variabledata.axis + for i=1,#values do + for j=1,#axis do + if values[i].axis == axis[j].tag then + values[i].name = axis[j].name + break + end + end + end + return values + end + end + end + end + end + end + end + + helpers.getinstancespec = getinstancespec + + implement { + name = "currentfontinstancespec", + actions = function() + local t = getinstancespec() -- current font + if t then + for i=1,#t do + if i > 1 then + context.space() + end + local ti = t[i] + context("%s=%s",ti.name,ti.value) + end + end + end + } + +end |