summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/font-ctx.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-ctx.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/font-ctx.lua703
1 files changed, 460 insertions, 243 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-ctx.lua b/Master/texmf-dist/tex/context/base/font-ctx.lua
index 4b324a6db79..cb640b892e2 100644
--- a/Master/texmf-dist/tex/context/base/font-ctx.lua
+++ b/Master/texmf-dist/tex/context/base/font-ctx.lua
@@ -8,6 +8,11 @@ if not modules then modules = { } end modules ['font-ctx'] = {
-- At some point I will clean up the code here so that at the tex end
-- the table interface is used.
+--
+-- Todo: make a proper 'next id' mechanism (register etc) or wait till 'true'
+-- in virtual fonts indices is implemented.
+
+local context, commands = context, commands
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
@@ -15,8 +20,9 @@ local concat, serialize, sort, fastcopy, mergedtable = table.concat, table.seria
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
+local mergehashes = utilities.parsers.mergehashes
-local tostring, next, type = tostring, next, type
+local tostring, next, type, rawget = tostring, next, type, rawget
local utfchar, utfbyte = utf.char, utf.byte
local round = math.round
@@ -30,6 +36,7 @@ local trace_mapfiles = false trackers.register("fonts.mapfiles", functio
local trace_automode = false trackers.register("fonts.automode", function(v) trace_automode = v end)
local report_features = logs.reporter("fonts","features")
+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")
@@ -47,13 +54,21 @@ 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 fontdata = hashes.identifiers
+local characters = hashes.chardata
+local descriptions = hashes.descriptions
+local properties = hashes.properties
+local resources = hashes.resources
+local csnames = hashes.csnames
+local marks = hashes.markdata
+local lastmathids = hashes.lastmathids
+
local designsizefilename = fontgoodies.designsizes.filename
-local otffeatures = fonts.constructors.newfeatures("otf")
+local otffeatures = handlers.otf.features
local registerotffeature = otffeatures.register
local baseprocessors = otffeatures.processors.base
local baseinitializers = otffeatures.initializers.base
@@ -77,27 +92,30 @@ storage.register("fonts/numbers", numbers, "fonts.specifiers.contextnumbers")
storage.register("fonts/merged", merged, "fonts.specifiers.contextmerged")
storage.register("fonts/synonyms", synonyms, "fonts.specifiers.synonyms")
-constructors.resolvevirtualtoo = true -- context specific (due to resolver)
+-- inspect(setups)
-local allocate, mark = utilities.storage.allocate, utilities.storage.mark
-
-local nulldata = {
- name = "nullfont",
- characters = { },
- descriptions = { },
- properties = { },
- 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
- },
-}
+if environment.initex then
+ setmetatableindex(setups,function(t,k)
+ return type(k) == "number" and rawget(t,numbers[k]) or nil
+ end)
+else
+ setmetatableindex(setups,function(t,k)
+ local v = type(k) == "number" and rawget(t,numbers[k])
+ if v then
+ t[k] = v
+ return v
+ end
+ end)
+end
-constructors.enhanceparameters(nulldata.parameters) -- official copies for us
+-- this will move elsewhere ...
+
+utilities.strings.formatters.add(string.formatters,"font:name", [["'"..file.basename(%s.properties.name).."'"]])
+utilities.strings.formatters.add(string.formatters,"font:features",[["'"..table.sequenced(%s," ",true).."'"]])
+
+-- ... like font-sfm or so
+
+constructors.resolvevirtualtoo = true -- context specific (due to resolver)
local limited = false
@@ -114,7 +132,7 @@ end)
function definers.resetnullfont()
-- resetting is needed because tikz misuses nullfont
- local parameters = nulldata.parameters
+ local parameters = fonts.nulldata.parameters
--
parameters.slant = 0 -- 1
parameters.space = 0 -- 2
@@ -131,97 +149,6 @@ 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 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
- t[k] = characters
- 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
- t[k] = quad
- 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
- t[k] = xheight
- 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)
@@ -259,7 +186,7 @@ local function checkedscript(tfmdata,resources,features)
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))
+ report_defining("auto script mode, using script %a in font %!font:name!",script,tfmdata)
end
features.script = script
return script
@@ -284,13 +211,15 @@ local function checkedmode(tfmdata,resources,features)
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)
+ report_defining("forcing mode %a, font %!font:name!, feature %a, script %a, language %a, %s",
+ "node",tfmdata,feature,script,language,"multiple lookups")
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)
+ report_defining("forcing mode %a, font %!font:name!, feature %a, script %a, language %a, %s",
+ "node",tfmdata,feature,script,language,"no base support")
end
features.mode = "node"
return "node"
@@ -314,7 +243,7 @@ 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"))
+ report_features("fontname %!font:name!, features %!font:features!",tfmdata,features)
end
local rawdata = tfmdata.shared.rawdata
local resources = rawdata and rawdata.resources
@@ -327,7 +256,7 @@ local function modechecker(tfmdata,features,mode) -- we cannot adapt features as
mode = checkedmode(tfmdata,resources,features)
end
else
- report_features("missing resources for font''%s'",file.basename(tfmdata.properties.name))
+ report_features("missing resources for font %!font:name!",tfmdata)
end
return mode
end
@@ -440,12 +369,23 @@ definers.registersplit("@", predefined,"virtual")
local normalize_features = otffeatures.normalize -- should be general
+local function definecontext(name,t) -- can be shared
+ local number = setups[name] and setups[name].number or 0 -- hm, numbers[name]
+ if number == 0 then
+ number = #numbers + 1
+ numbers[number] = name
+ end
+ t.number = number
+ setups[name] = t
+ return number, t
+end
+
local function presetcontext(name,parent,features) -- will go to con and shared
if features == "" and find(parent,"=") then
features = parent
parent = ""
end
- if features == "" then
+ if not features or features == "" then
features = { }
elseif type(features) == "string" then
features = normalize_features(settings_to_hash(features))
@@ -462,18 +402,22 @@ local function presetcontext(name,parent,features) -- will go to con and shared
features[k] = v
end
end
+ else
+ -- just ignore an undefined one .. i.e. we can refer to not yet defined
end
end
end
-- these are auto set so in order to prevent redundant definitions
-- we need to preset them (we hash the features and adding a default
-- setting during initialization may result in a different hash)
---~ for k,v in next, triggers do
---~ if features[v] == nil then -- not false !
---~ local vv = default_features[v]
---~ if vv then features[v] = vv end
---~ end
---~ end
+ --
+ -- for k,v in next, triggers do
+ -- if features[v] == nil then -- not false !
+ -- local vv = default_features[v]
+ -- if vv then features[v] = vv end
+ -- end
+ -- end
+ --
for feature,value in next, features do
if value == nil then -- not false !
local default = default_features[feature]
@@ -486,11 +430,12 @@ 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
-- maybe number should always be renewed as we can redefine features
- local number = (setups[name] and setups[name].number) or 0 -- hm, numbers[name]
+ local number = setups[name] and setups[name].number or 0 -- hm, numbers[name]
if number == 0 then
number = #numbers + 1
numbers[number] = name
@@ -531,10 +476,10 @@ local function contextnumber(name) -- will be replaced
end
end
-local function mergecontext(currentnumber,extraname,option)
- local current = setups[numbers[currentnumber]]
+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
if option < 0 then
if current then
@@ -567,6 +512,56 @@ local function mergecontext(currentnumber,extraname,option)
end
end
+local extrasets = { }
+
+setmetatableindex(extrasets,function(t,k)
+ local v = mergehashes(setups,k)
+ t[k] = v
+ return v
+end)
+
+local function mergecontextfeatures(currentname,extraname,how,mergedname) -- string string
+ local extra = setups[extraname] or extrasets[extraname]
+ if extra then
+ local current = setups[currentname]
+ local mergedfeatures = { }
+ if how == "+" then
+ if current then
+ for k, v in next, current do
+ mergedfeatures[k] = v
+ end
+ end
+ for k, v in next, extra do
+ mergedfeatures[k] = v
+ end
+ elseif how == "-" then
+ if current then
+ for k, v in next, current do
+ mergedfeatures[k] = v
+ end
+ end
+ for k, v in next, extra do
+ -- only boolean features
+ if v == true then
+ mergedfeatures[k] = false
+ end
+ end
+ else -- =
+ for k, v in next, extra do
+ mergedfeatures[k] = v
+ end
+ end
+ local number = #numbers + 1
+ mergedfeatures.number = number
+ numbers[number] = mergedname
+ merged[number] = option
+ setups[mergedname] = mergedfeatures
+ return number
+ else
+ return numbers[currentname] or 0
+ end
+end
+
local function registercontext(fontnumber,extraname,option)
local extra = setups[extraname]
if extra then
@@ -590,10 +585,29 @@ local function registercontext(fontnumber,extraname,option)
end
end
+local function registercontextfeature(mergedname,extraname,how)
+ local extra = setups[extraname]
+ if extra then
+ local mergedfeatures = { }
+ for k, v in next, extra do
+ mergedfeatures[k] = v
+ end
+ local number = #numbers + 1
+ mergedfeatures.number = number
+ numbers[number] = mergedname
+ merged[number] = how == "=" and 1 or 2 -- 1=replace, 2=combine
+ setups[mergedname] = mergedfeatures
+ return number -- contextnumber(mergedname)
+ else
+ return 0
+ end
+end
+
specifiers.presetcontext = presetcontext
specifiers.contextnumber = contextnumber
specifiers.mergecontext = mergecontext
specifiers.registercontext = registercontext
+specifiers.definecontext = definecontext
-- we extend the hasher:
@@ -602,7 +616,7 @@ constructors.hashmethods.virtual = function(list)
local n = 0
for k, v in next, list do
n = n + 1
- s[n] = k
+ s[n] = k -- no checking on k
end
if n > 0 then
sort(s)
@@ -616,83 +630,96 @@ end
-- end of redefine
-local cache = { } -- concat might be less efficient than nested tables
-
-local function withset(name,what)
- local zero = texattribute[0]
- local hash = zero .. "+" .. name .. "*" .. what
- local done = cache[hash]
- if not done then
- done = mergecontext(zero,name,what)
- cache[hash] = done
- end
- texattribute[0] = done
-end
-
-local function withfnt(name,what)
- local font = currentfont()
- local hash = font .. "*" .. name .. "*" .. what
- local done = cache[hash]
- if not done then
- done = registercontext(font,name,what)
- cache[hash] = done
- end
- texattribute[0] = done
-end
+-- local withcache = { } -- concat might be less efficient than nested tables
+--
+-- local function withset(name,what)
+-- local zero = texattribute[0]
+-- local hash = zero .. "+" .. name .. "*" .. what
+-- local done = withcache[hash]
+-- if not done then
+-- done = mergecontext(zero,name,what)
+-- withcache[hash] = done
+-- end
+-- texattribute[0] = done
+-- end
+--
+-- local function withfnt(name,what,font)
+-- local font = font or currentfont()
+-- local hash = font .. "*" .. name .. "*" .. what
+-- local done = withcache[hash]
+-- if not done then
+-- done = registercontext(font,name,what)
+-- withcache[hash] = done
+-- end
+-- texattribute[0] = done
+-- end
function specifiers.showcontext(name)
return setups[name] or setups[numbers[name]] or setups[numbers[tonumber(name)]] or { }
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 fastcopy(setups[features] or (presetcontext(features,"","") and setups[features]))
+-- end
+
local function splitcontext(features) -- presetcontext creates dummy here
- return fastcopy(setups[features] or (presetcontext(features,"","") and setups[features]))
+ local sf = setups[features]
+ if not sf then
+ local n -- number
+ if find(features,",") then
+ -- let's assume a combination which is not yet defined but just specified (as in math)
+ n, sf = presetcontext(features,features,"")
+ else
+ -- we've run into an unknown feature and or a direct spec so we create a dummy
+ n, sf = presetcontext(features,"","")
+ end
+ end
+ return fastcopy(sf)
end
---~ local splitter = lpeg.splitat("=")
-
---~ local function splitcontext(features)
---~ local setup = setups[features]
---~ if setup then
---~ return setup
---~ elseif find(features,",") then
---~ -- This is not that efficient but handy anyway for quick and dirty tests
---~ -- beware, due to the way of caching setups you can get the wrong results
---~ -- when components change. A safeguard is to nil the cache.
---~ local merge = nil
---~ for feature in gmatch(features,"[^, ]+") do
---~ if find(feature,"=") then
---~ local k, v = lpegmatch(splitter,feature)
---~ if k and v then
---~ if not merge then
---~ merge = { k = v }
---~ else
---~ merge[k] = v
---~ end
---~ end
---~ else
---~ local s = setups[feature]
---~ if not s then
---~ -- skip
---~ elseif not merge then
---~ merge = s
---~ else
---~ for k, v in next, s do
---~ merge[k] = v
---~ end
---~ end
---~ end
---~ end
---~ setup = merge and presetcontext(features,"",merge) and setups[features]
---~ -- actually we have to nil setups[features] in order to permit redefinitions
---~ setups[features] = nil
---~ end
---~ return setup or (presetcontext(features,"","") and setups[features]) -- creates dummy
---~ end
+-- local splitter = lpeg.splitat("=")
+--
+-- local function splitcontext(features)
+-- local setup = setups[features]
+-- if setup then
+-- return setup
+-- elseif find(features,",") then
+-- -- This is not that efficient but handy anyway for quick and dirty tests
+-- -- beware, due to the way of caching setups you can get the wrong results
+-- -- when components change. A safeguard is to nil the cache.
+-- local merge = nil
+-- for feature in gmatch(features,"[^, ]+") do
+-- if find(feature,"=") then
+-- local k, v = lpegmatch(splitter,feature)
+-- if k and v then
+-- if not merge then
+-- merge = { k = v }
+-- else
+-- merge[k] = v
+-- end
+-- end
+-- else
+-- local s = setups[feature]
+-- if not s then
+-- -- skip
+-- elseif not merge then
+-- merge = s
+-- else
+-- for k, v in next, s do
+-- merge[k] = v
+-- end
+-- end
+-- end
+-- end
+-- setup = merge and presetcontext(features,"",merge) and setups[features]
+-- -- actually we have to nil setups[features] in order to permit redefinitions
+-- setups[features] = nil
+-- end
+-- return setup or (presetcontext(features,"","") and setups[features]) -- creates dummy
+-- end
specifiers.splitcontext = splitcontext
@@ -750,6 +777,18 @@ local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- value
local sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_scaled + scale_none)
local splitpattern = spaces * value * spaces * rest
+function helpers.splitfontpattern(str)
+ local name, size = lpegmatch(splitpattern,str)
+ local kind, size = lpegmatch(sizepattern,size)
+ return name, kind, size
+end
+
+function helpers.fontpatternhassize(str)
+ local name, size = lpegmatch(splitpattern,str)
+ local kind, size = lpegmatch(sizepattern,size)
+ return size or false
+end
+
local specification -- still needed as local ?
local getspecification = definers.getspecification
@@ -761,6 +800,7 @@ local setdefaultfontname = context.fntsetdefname
local setsomefontname = context.fntsetsomename
local setemptyfontsize = context.fntsetnopsize
local setsomefontsize = context.fntsetsomesize
+local letvaluerelax = context.letvaluerelax
function commands.definefont_one(str)
statistics.starttiming(fonts)
@@ -771,7 +811,7 @@ function commands.definefont_one(str)
local fullname, size = lpegmatch(splitpattern,str)
local lookup, name, sub, method, detail = getspecification(fullname)
if not name then
- report_defining("strange definition '%s'",str)
+ report_defining("strange definition %a",str)
setdefaultfontname()
elseif name == "unknown" then
setdefaultfontname()
@@ -814,7 +854,7 @@ 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("start stage two: %s (%s)",str,size)
+ report_defining("start stage two: %s (size %s)",str,size)
end
-- name is now resolved and size is scaled cf sa/mo
local lookup, name, sub, method, detail = getspecification(str or "")
@@ -823,7 +863,7 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
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)
+ report_defining("remapping name %a, specification %a, size %a, designsize %a",name,designsize,size,designname)
end
-- we don't catch detail here
local o_lookup, o_name, o_sub, o_method, o_detail = getspecification(designname)
@@ -905,27 +945,28 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
end
end
local tfmdata = definers.read(specification,size) -- id not yet known (size in spec?)
+ --
+ local lastfontid = 0
if not tfmdata then
- 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
+ report_defining("unable to define %a as %a",name,nice_cs(cs))
+ lastfontid = -1
+ 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, designsize: %s/%s)",
+ report_defining("reusing %s, id %a, target %a, features %a / %a, fallbacks %a / %a, goodies %a / %a, designsize %a / %a",
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)
+ lastfontid = tfmdata
else
-- setting the extra characters will move elsewhere
local characters = tfmdata.characters
local parameters = tfmdata.parameters
- -- we use char0 as signal
+ -- we use char0 as signal; cf the spec pdf can handle this (no char in slot)
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
@@ -938,20 +979,27 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
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)",
+ report_defining("defining %a, id %a, target %a, features %a / %a, fallbacks %a / %a",
name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks)
end
-- resolved (when designsize is used):
setsomefontsize((tfmdata.parameters.size or 655360) .. "sp")
- --~ if specification.fallbacks then
- --~ fonts.collections.prepare(specification.fallbacks)
- --~ end
- texsetcount("global","lastfontid",id)
+ lastfontid = id
end
if trace_defining then
report_defining("memory usage after: %s",statistics.memused())
report_defining("stop stage two")
end
+ --
+ texsetcount("global","lastfontid",lastfontid)
+ if not mathsize then
+ -- forget about it
+ elseif mathsize == 0 then
+ lastmathids[1] = lastfontid
+ else
+ lastmathids[mathsize] = lastfontid
+ end
+ --
statistics.stoptiming(fonts)
end
@@ -1030,17 +1078,17 @@ local calculatescale = constructors.calculatescale
function constructors.calculatescale(tfmdata,scaledpoints,relativeid)
local scaledpoints, delta = calculatescale(tfmdata,scaledpoints)
---~ if enable_auto_r_scale and relativeid then -- for the moment this is rather context specific
---~ local relativedata = fontdata[relativeid]
---~ local rfmdata = relativedata and relativedata.unscaled and relativedata.unscaled
---~ 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
---~ local rscale = id_x_height/tf_x_height
---~ delta = rscale * delta
---~ scaledpoints = rscale * scaledpoints
---~ end
---~ end
+ -- if enable_auto_r_scale and relativeid then -- for the moment this is rather context specific
+ -- local relativedata = fontdata[relativeid]
+ -- local rfmdata = relativedata and relativedata.unscaled and relativedata.unscaled
+ -- 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
+ -- local rscale = id_x_height/tf_x_height
+ -- delta = rscale * delta
+ -- scaledpoints = rscale * scaledpoints
+ -- end
+ -- end
return scaledpoints, delta
end
@@ -1103,7 +1151,7 @@ function mappings.loadfile(name)
name = file.addsuffix(name,"map")
if not loaded[name] then
if trace_mapfiles then
- report_mapfiles("loading map file '%s'",name)
+ report_mapfiles("loading map file %a",name)
end
pdf.mapfile(name)
loaded[name] = true
@@ -1121,7 +1169,7 @@ function mappings.loadline(how,line)
end
if not loaded[how] then
if trace_mapfiles then
- report_mapfiles("processing map line '%s'",line)
+ report_mapfiles("processing map line %a",line)
end
pdf.mapline(how)
loaded[how] = true
@@ -1141,10 +1189,7 @@ mappings.reset() -- resets the default file
local function nametoslot(name)
local t = type(name)
if t == "string" then
- local tfmdata = fonts.hashes.identifiers[currentfont()]
- local shared = tfmdata and tfmdata.shared
- local fntdata = shared and shared.rawdata
- return fntdata and fntdata.resources.unicodes[name]
+ return resources[true].unicodes[name]
elseif t == "number" then
return n
end
@@ -1162,7 +1207,7 @@ function loggers.reportdefinedfonts()
local parameters = data.parameters or { }
tn = tn + 1
t[tn] = {
- format("%03i",id or 0),
+ format("%03i",id or 0),
format("%09i",parameters.size or 0),
properties.type or "real",
properties.format or "unknown",
@@ -1170,7 +1215,7 @@ function loggers.reportdefinedfonts()
properties.psname or "",
properties.fullname or "",
}
-report_status("%s: %s",properties.name,concat(sortedkeys(data)," "))
+ report_status("%s: % t",properties.name,sortedkeys(data))
end
formatcolumns(t," ")
report_status()
@@ -1320,15 +1365,10 @@ function commands.resetfontfeature()
texattribute[0] = 0
end
-function commands.addfs(tag) withset(tag, 1) end
-function commands.subfs(tag) withset(tag,-1) end
-function commands.addff(tag) withfnt(tag, 2) end
-function commands.subff(tag) withfnt(tag,-2) end
-
--- function commands.addfontfeaturetoset (tag) withset(tag, 1) end
--- function commands.subtractfontfeaturefromset (tag) withset(tag,-1) end
--- function commands.addfontfeaturetofont (tag) withfnt(tag, 2) end
--- function commands.subtractfontfeaturefromfont(tag) withfnt(tag,-2) end
+-- function commands.addfs(tag) withset(tag, 1) end
+-- function commands.subfs(tag) withset(tag,-1) end
+-- function commands.addff(tag) withfnt(tag, 2) end -- on top of font features
+-- function commands.subff(tag) withfnt(tag,-2) end -- on top of font features
function commands.cleanfontname (name) context(names.cleanname(name)) end
@@ -1347,7 +1387,7 @@ function commands.showchardata(n)
end
local chr = tfmdata.characters[n]
if chr then
- report_status("%s @ %s => U%05X => %s => %s",tfmdata.properties.fullname,tfmdata.parameters.size,n,utfchar(n),serialize(chr,false))
+ report_status("%s @ %s => %U => %c => %s",tfmdata.properties.fullname,tfmdata.parameters.size,n,n,serialize(chr,false))
end
end
end
@@ -1384,7 +1424,8 @@ function helpers.dimenfactor(unit,tfmdata) -- could be a method of a font instan
elseif unit == "em" then
return (tfmdata and tfmdata.parameters.em_width) or 655360
else
- return dimenfactors[unit] or unit
+ local du = dimenfactors[unit]
+ return du and 1/du or tonumber(unit) or 1
end
end
@@ -1536,8 +1577,184 @@ end
-- more interfacing:
-commands.definefontfeature = fonts.specifiers.presetcontext
+commands.definefontfeature = presetcontext
+
+local cache = { }
+
+local hows = {
+ ["+"] = "add",
+ ["-"] = "subtract",
+ ["="] = "replace",
+}
+
+function commands.feature(how,parent,name,font)
+ if not how then
+ if trace_features and texattribute[0] ~= 0 then
+ report_cummulative("font %!font:name!, reset",fontdata[font or true])
+ end
+ texattribute[0] = 0
+ elseif how == true then
+ local hash = "feature > " .. parent
+ local done = cache[hash]
+ if trace_features and done then
+ report_cummulative("font %!font:name!, revive %a : %!font:features!",fontdata[font or true],parent,setups[numbers[done]])
+ end
+ texattribute[0] = done or 0
+ else
+ local full = parent .. how .. name
+ local hash = "feature > " .. full
+ local done = cache[hash]
+ if not done then
+ local n = setups[full]
+ if n then
+ -- already defined
+ else
+ n = mergecontextfeatures(parent,name,how,full)
+ end
+ done = registercontextfeature(hash,full,how)
+ cache[hash] = done
+ if trace_features then
+ report_cummulative("font %!font:name!, %s %a : %!font:features!",fontdata[font or true],hows[how],full,setups[numbers[done]])
+ end
+ end
+ texattribute[0] = done
+ end
+end
function commands.featurelist(...)
context(fonts.specifiers.contexttostring(...))
end
+
+function commands.registerlanguagefeatures()
+ local specifications = languages.data.specifications
+ for i=1,#specifications do
+ local specification = specifications[i]
+ local language = specification.opentype
+ if language then
+ local script = specification.opentypescript or specification.script
+ if script then
+ local context = specification.context
+ if type(context) == "table" then
+ for i=1,#context do
+ definecontext(context[i], { language = language, script = script})
+ end
+ elseif type(context) == "string" then
+ definecontext(context, { language = language, script = script})
+ end
+ end
+ end
+ end
+end
+
+-- a fontkern plug:
+
+local copy_node = node.copy
+local kern = nodes.pool.register(nodes.pool.kern())
+
+node.set_attribute(kern,attributes.private('fontkern'),1) -- we can have several, attributes are shared
+
+nodes.injections.installnewkern(function(k)
+ local c = copy_node(kern)
+ c.kern = k
+ return c
+end)
+
+directives.register("nodes.injections.fontkern", function(v) kern.subtype = v and 0 or 1 end)
+
+-- here
+
+local trace_analyzing = false trackers.register("otf.analyzing", function(v) trace_analyzing = v end)
+
+local otffeatures = fonts.constructors.newfeatures("otf")
+local registerotffeature = otffeatures.register
+
+local analyzers = fonts.analyzers
+local methods = analyzers.methods
+
+local unsetvalue = attributes.unsetvalue
+
+local traverse_by_id = node.traverse_id
+
+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 glyph_code = nodes.nodecodes.glyph
+
+local states = analyzers.states
+
+local names = {
+ [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
+ local model = head[a_colormodel] or 1
+ for glyph in traverse_by_id(glyph_code,head) do
+ local a = glyph[a_state]
+ if a then
+ local name = names[a]
+ if name then
+ local color = m_color[name]
+ if color then
+ glyph[a_colormodel] = model
+ glyph[a_color] = color
+ 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)
+ 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
+end
+
+registerotffeature { -- adapts
+ name = "analyze",
+ processors = {
+ node = analyzeprocessor,
+ }
+}
+
+function methods.nocolor(head,font,attr)
+ for n in traverse_by_id(glyph_code,head) do
+ if not font or n.font == font then
+ n[a_color] = unsetvalue
+ end
+ end
+ return head, true
+end