diff options
Diffstat (limited to 'tex/context/base/font-ctx.lua')
-rw-r--r-- | tex/context/base/font-ctx.lua | 236 |
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, } |