summaryrefslogtreecommitdiff
path: root/tex/context/base/font-ctx.lua
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/font-ctx.lua')
-rw-r--r--tex/context/base/font-ctx.lua236
1 files changed, 179 insertions, 57 deletions
diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua
index 2583c6520..6c3402683 100644
--- a/tex/context/base/font-ctx.lua
+++ b/tex/context/base/font-ctx.lua
@@ -14,7 +14,6 @@ if not modules then modules = { } end modules ['font-ctx'] = {
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
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
@@ -35,6 +34,7 @@ local trace_designsize = false trackers.register("fonts.designsize", functio
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_merge = false trackers.register("fonts.merge", function(v) trace_merge = v end)
local report_features = logs.reporter("fonts","features")
local report_cummulative = logs.reporter("fonts","cummulative")
@@ -56,8 +56,15 @@ local fontgoodies = fonts.goodies
local helpers = fonts.helpers
local hashes = fonts.hashes
local currentfont = font.current
-local texattribute = tex.attribute
-local texdimen = tex.dimen
+
+local texgetattribute = tex.getattribute
+local texsetattribute = tex.setattribute
+local texgetdimen = tex.getdimen
+local texsetcount = tex.setcount
+local texget = tex.get
+
+local texdefinefont = tex.definefont
+local texsp = tex.sp
local fontdata = hashes.identifiers
local characters = hashes.chardata
@@ -67,6 +74,8 @@ local resources = hashes.resources
local csnames = hashes.csnames
local marks = hashes.markdata
local lastmathids = hashes.lastmathids
+local exheights = hashes.exheights
+local emwidths = hashes.emwidths
local designsizefilename = fontgoodies.designsizes.filename
@@ -114,7 +123,11 @@ end
-- this will move elsewhere ...
-utilities.strings.formatters.add(formatters,"font:name", [["'"..file.basename(%s.properties.name).."'"]])
+function fonts.helpers.name(tfmdata)
+ return file.basename(type(tfmdata) == "number" and properties[tfmdata].name or tfmdata.properties.name)
+end
+
+utilities.strings.formatters.add(formatters,"font:name", [["'"..fonts.helpers.name(%s).."'"]])
utilities.strings.formatters.add(formatters,"font:features",[["'"..table.sequenced(%s," ",true).."'"]])
-- ... like font-sfm or so
@@ -157,10 +170,24 @@ commands.resetnullfont = definers.resetnullfont
-- so we never enter the loop then; we can store the defaults in the tma
-- file (features.gpos.mkmk = 1 etc)
-local needsnodemode = {
- gpos_mark2mark = true,
- gpos_mark2base = true,
- gpos_mark2ligature = true,
+local needsnodemode = { -- we will have node mode by default anyway
+ -- gsub_single = true,
+ gsub_multiple = true,
+ -- gsub_alternate = true,
+ -- gsub_ligature = true,
+ gsub_context = true,
+ gsub_contextchain = true,
+ gsub_reversecontextchain = true,
+ -- chainsub = true,
+ -- reversesub = true,
+ gpos_mark2base = true,
+ gpos_mark2ligature = true,
+ gpos_mark2mark = true,
+ gpos_cursive = true,
+ -- gpos_single = true,
+ -- gpos_pair = true,
+ gpos_context = true,
+ gpos_contextchain = true,
}
otftables.scripts.auto = "automatic fallback to latn when no dflt present"
@@ -198,6 +225,8 @@ local function checkedscript(tfmdata,resources,features)
return script
end
+-- basemode combined with dynamics is somewhat tricky
+
local function checkedmode(tfmdata,resources,features)
local sequences = resources.sequences
if sequences and #sequences > 0 then
@@ -240,6 +269,9 @@ local function checkedmode(tfmdata,resources,features)
end
end
end
+ if trace_automode then
+ report_defining("forcing mode base, font %!font:name!",tfmdata)
+ end
features.mode = "base" -- new, or is this wrong?
return "base"
end
@@ -540,6 +572,9 @@ local function mergecontextfeatures(currentname,extraname,how,mergedname) -- str
for k, v in next, extra do
mergedfeatures[k] = v
end
+ if trace_merge then
+ report_features("merge %a, method %a, current %|T, extra %|T, result %|T",mergedname,"add",current or { },extra,mergedfeatures)
+ end
elseif how == "-" then
if current then
for k, v in next, current do
@@ -552,10 +587,16 @@ local function mergecontextfeatures(currentname,extraname,how,mergedname) -- str
mergedfeatures[k] = false
end
end
+ if trace_merge then
+ report_features("merge %a, method %a, current %|T, extra %|T, result %|T",mergedname,"subtract",current or { },extra,mergedfeatures)
+ end
else -- =
for k, v in next, extra do
mergedfeatures[k] = v
end
+ if trace_merge then
+ report_features("merge %a, method %a, result %|T",mergedname,"replace",mergedfeatures)
+ end
end
local number = #numbers + 1
mergedfeatures.number = number
@@ -617,19 +658,39 @@ specifiers.definecontext = definecontext
-- we extend the hasher:
+-- constructors.hashmethods.virtual = function(list)
+-- local s = { }
+-- local n = 0
+-- for k, v in next, list do
+-- n = n + 1
+-- s[n] = k -- no checking on k
+-- end
+-- if n > 0 then
+-- sort(s)
+-- for i=1,n do
+-- local k = s[i]
+-- s[i] = k .. '=' .. tostring(list[k])
+-- end
+-- return concat(s,"+")
+-- end
+-- end
+
constructors.hashmethods.virtual = function(list)
local s = { }
local n = 0
for k, v in next, list do
n = n + 1
- s[n] = k -- no checking on k
+ -- if v == true then
+ -- s[n] = k .. '=true'
+ -- elseif v == false then
+ -- s[n] = k .. '=false'
+ -- else
+ -- s[n] = k .. "=" .. v
+ -- end
+ s[n] = k .. "=" .. tostring(v)
end
if n > 0 then
sort(s)
- for i=1,n do
- local k = s[i]
- s[i] = k .. '=' .. tostring(list[k])
- end
return concat(s,"+")
end
end
@@ -639,14 +700,14 @@ end
-- local withcache = { } -- concat might be less efficient than nested tables
--
-- local function withset(name,what)
--- local zero = texattribute[0]
+-- local zero = texgetattribute(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
+-- texsetattribute(0,done)
-- end
--
-- local function withfnt(name,what,font)
@@ -657,7 +718,7 @@ end
-- done = registercontext(font,name,what)
-- withcache[hash] = done
-- end
--- texattribute[0] = done
+-- texsetattribute(0,done)
-- end
function specifiers.showcontext(name)
@@ -775,12 +836,16 @@ local value = C((leftparent * (1-rightparent)^0 * rightparent + (1-space)
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 -- value
-local scale_sa = P("sa") * Cc(2) * spaces * dimension -- value
-local scale_mo = P("mo") * Cc(3) * spaces * dimension -- value
-local scale_scaled = P("scaled") * Cc(4) * spaces * dimension -- value
+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 specialscale = { [5] = "ht", [6] = "cp" }
-local sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_scaled + scale_none)
+local sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_ht + scale_cp + scale_scaled + scale_none)
local splitpattern = spaces * value * spaces * rest
function helpers.splitfontpattern(str)
@@ -828,18 +893,18 @@ function commands.definefont_one(str)
if size and size ~= "" then
local mode, size = lpegmatch(sizepattern,size)
if size and mode then
- texcount.scaledfontmode = mode
+ texsetcount("scaledfontmode",mode)
setsomefontsize(size)
else
- texcount.scaledfontmode = 0
+ texsetcount("scaledfontmode",0)
setemptyfontsize()
end
elseif true then
-- so we don't need to check in tex
- texcount.scaledfontmode = 2
+ texsetcount("scaledfontmode",2)
setemptyfontsize()
else
- texcount.scaledfontmode = 0
+ texsetcount("scaledfontmode",0)
setemptyfontsize()
end
specification = definers.makespecification(str,lookup,name,sub,method,detail,size)
@@ -858,7 +923,7 @@ local function nice_cs(cs)
end
function commands.definefont_two(global,cs,str,size,inheritancemode,classfeatures,fontfeatures,classfallbacks,fontfallbacks,
- mathsize,textsize,relativeid,classgoodies,goodies,classdesignsize,fontdesignsize)
+ mathsize,textsize,relativeid,classgoodies,goodies,classdesignsize,fontdesignsize,scaledfontmode)
if trace_defining then
report_defining("start stage two: %s (size %s)",str,size)
end
@@ -888,6 +953,7 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
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
@@ -896,6 +962,7 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
specification.goodies = goodies
specification.cs = cs
specification.global = global
+ specification.scalemode = scaledfontmode -- context specific
if detail and detail ~= "" then
specification.method = method or "*"
specification.detail = detail
@@ -963,9 +1030,11 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
name,tfmdata,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks,classgoodies,goodies,classdesignsize,fontdesignsize)
end
csnames[tfmdata] = specification.cs
- tex.definefont(global,cs,tfmdata)
+ texdefinefont(global,cs,tfmdata)
-- resolved (when designsize is used):
- setsomefontsize((fontdata[tfmdata].parameters.size or 0) .. "sp")
+ local size = fontdata[tfmdata].parameters.size or 0
+ setsomefontsize(size .. "sp")
+ texsetcount("scaledfontsize",size)
lastfontid = tfmdata
else
-- setting the extra characters will move elsewhere
@@ -977,11 +1046,12 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
-- 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
--
+ constructors.checkvirtualids(tfmdata) -- experiment, will become obsolete when slots can selfreference
local id = font.define(tfmdata)
csnames[id] = specification.cs
tfmdata.properties.id = id
definers.register(tfmdata,id) -- to be sure, normally already done
- tex.definefont(global,cs,id)
+ texdefinefont(global,cs,id)
constructors.cleanuptable(tfmdata)
constructors.finalize(tfmdata)
if trace_defining then
@@ -989,7 +1059,9 @@ function commands.definefont_two(global,cs,str,size,inheritancemode,classfeature
name,id,nice_cs(cs),classfeatures,fontfeatures,classfallbacks,fontfallbacks)
end
-- resolved (when designsize is used):
- setsomefontsize((tfmdata.parameters.size or 655360) .. "sp")
+ local size = tfmdata.parameters.size or 655360
+ setsomefontsize(size .. "sp")
+ texsetcount("scaledfontsize",size)
lastfontid = id
end
if trace_defining then
@@ -1030,7 +1102,7 @@ function definers.define(specification)
specification.detail = specification.detail or (detail ~= "" and detail) or ""
--
if type(specification.size) == "string" then
- specification.size = tex.sp(specification.size) or 655260
+ specification.size = texsp(specification.size) or 655260
end
--
specification.specification = "" -- not used
@@ -1054,16 +1126,17 @@ function definers.define(specification)
return -1, nil
elseif type(tfmdata) == "number" then
if cs then
- tex.definefont(specification.global,cs,tfmdata)
+ texdefinefont(specification.global,cs,tfmdata)
csnames[tfmdata] = cs
end
return tfmdata, fontdata[tfmdata]
else
+ constructors.checkvirtualids(tfmdata) -- experiment, will become obsolete when slots can selfreference
local id = font.define(tfmdata)
tfmdata.properties.id = id
definers.register(tfmdata,id)
if cs then
- tex.definefont(specification.global,cs,id)
+ texdefinefont(specification.global,cs,id)
csnames[id] = cs
end
constructors.cleanuptable(tfmdata)
@@ -1083,7 +1156,7 @@ local n = 0
function definers.internal(specification,cs)
specification = specification or { }
local name = specification.name
- local size = specification.size and number.todimen(specification.size) or texdimen.bodyfontsize
+ local size = specification.size and number.todimen(specification.size) or texgetdimen("bodyfontsize")
local number = tonumber(specification.number)
local id = nil
if number then
@@ -1121,9 +1194,25 @@ end)
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
+function constructors.calculatescale(tfmdata,scaledpoints,relativeid,specification)
+ if specification then
+ local scalemode = specification.scalemode
+ local special = scalemode and specialscale[scalemode]
+ if special then
+ -- we also have available specification.textsize
+ local parameters = tfmdata.parameters
+ local designsize = parameters.designsize
+ if special == "ht" then
+ local height = parameters.ascender * designsize / parameters.units
+ scaledpoints = (scaledpoints/height) * designsize
+ elseif special == "cp" then
+ local height = (tfmdata.descriptions[utf.byte("X")].height or parameters.ascender) * designsize / parameters.units
+ scaledpoints = (scaledpoints/height) * designsize
+ end
+ end
+ end
+ 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 id_x_height = rfmdata and rfmdata.parameters and rfmdata.parameters.x_height
@@ -1137,6 +1226,31 @@ function constructors.calculatescale(tfmdata,scaledpoints,relativeid)
return scaledpoints, delta
end
+local designsizes = constructors.designsizes
+
+function constructors.hashinstance(specification,force)
+ local hash, size, fallbacks = specification.hash, specification.size, 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]))
+ specification.size = size
+ end
+ if fallbacks then
+ return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks
+ else
+ local scalemode = specification.scalemode
+ local special = scalemode and specialscale[scalemode]
+ if special then
+ return hash .. ' @ ' .. tostring(size) .. ' @ ' .. special
+ else
+ return hash .. ' @ ' .. tostring(size)
+ end
+ end
+end
+
-- We overload the (generic) resolver:
local resolvers = definers.resolvers
@@ -1403,11 +1517,11 @@ function commands.featureattribute(tag)
end
function commands.setfontfeature(tag)
- texattribute[0] = contextnumber(tag)
+ texsetattribute(0,contextnumber(tag))
end
function commands.resetfontfeature()
- texattribute[0] = 0
+ texsetattribute(0,0)
end
-- function commands.addfs(tag) withset(tag, 1) end
@@ -1463,11 +1577,11 @@ end
local dimenfactors = number.dimenfactors
-function helpers.dimenfactor(unit,tfmdata) -- could be a method of a font instance
+function helpers.dimenfactor(unit,id)
if unit == "ex" then
- return (tfmdata and tfmdata.parameters.x_height) or 655360
+ return id and exheights[id] or 282460 -- lm 10pt
elseif unit == "em" then
- return (tfmdata and tfmdata.parameters.em_width) or 655360
+ return id and emwidths [id] or 655360 -- lm 10pt
else
local du = dimenfactors[unit]
return du and 1/du or tonumber(unit) or 1
@@ -1558,19 +1672,24 @@ end
local quads = hashes.quads
local xheights = hashes.xheights
-setmetatableindex(number.dimenfactors, function(t,k)
+setmetatableindex(dimenfactors, function(t,k)
if k == "ex" then
- return xheigths[currentfont()]
+ return 1/xheights[currentfont()]
elseif k == "em" then
- return quads[currentfont()]
- elseif k == "%" then
- return dimen.hsize/100
+ return 1/quads[currentfont()]
+ elseif k == "pct" or k == "%" then
+ return 1/(texget("hsize")/100)
else
-- error("wrong dimension: " .. (s or "?")) -- better a message
return false
end
end)
+dimenfactors.ex = nil
+dimenfactors.em = nil
+dimenfactors["%"] = nil
+dimenfactors.pct = nil
+
--[[ldx--
<p>Before a font is passed to <l n='tex'/> we scale it. Here we also need
to scale virtual characters.</p>
@@ -1582,8 +1701,11 @@ function constructors.checkvirtualids(tfmdata)
local selfid = font.nextid()
if fonts and #fonts > 0 then
for i=1,#fonts do
- if fonts[i][2] == 0 then
- fonts[i][2] = selfid
+ local fi = fonts[i]
+ if fi[2] == 0 then
+ fi[2] = selfid
+ elseif fi.id == 0 then
+ fi.id = selfid
end
end
else
@@ -1646,19 +1768,19 @@ local hows = {
["="] = "replace",
}
-function commands.feature(how,parent,name,font)
- if not how then
- if trace_features and texattribute[0] ~= 0 then
+function commands.feature(how,parent,name,font) -- 0/1 test temporary for testing
+ if not how or how == 0 then
+ if trace_features and texgetattribute(0) ~= 0 then
report_cummulative("font %!font:name!, reset",fontdata[font or true])
end
- texattribute[0] = 0
- elseif how == true then
+ texsetattribute(0,0)
+ elseif how == true or how == 1 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
+ texsetattribute(0,done or 0)
else
local full = parent .. how .. name
local hash = "feature > " .. full
@@ -1676,7 +1798,7 @@ function commands.feature(how,parent,name,font)
report_cummulative("font %!font:name!, %s %a : %!font:features!",fontdata[font or true],hows[how],full,setups[numbers[done]])
end
end
- texattribute[0] = done
+ texsetattribute(0,done)
end
end
@@ -1803,7 +1925,7 @@ local function analyzeprocessor(head,font,attr)
end
registerotffeature { -- adapts
- name = "analyze",
+ name = "analyze",
processors = {
node = analyzeprocessor,
}