diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-ctx.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-ctx.lua | 314 |
1 files changed, 273 insertions, 41 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-ctx.lua b/Master/texmf-dist/tex/context/base/font-ctx.lua index 2f51c5229bc..76e9f095a48 100644 --- a/Master/texmf-dist/tex/context/base/font-ctx.lua +++ b/Master/texmf-dist/tex/context/base/font-ctx.lua @@ -1,14 +1,19 @@ if not modules then modules = { } end modules ['font-ctx'] = { version = 1.001, - comment = "companion to font-ini.tex", + comment = "companion to font-ini.mkiv", author = "Hans Hagen, PRAGMA-ADE, Hasselt NL", copyright = "PRAGMA ADE / ConTeXt Development Team", license = "see context related readme files" } -local texsprint, count = tex.sprint, tex.count -local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower -local tostring, next = tostring, next +-- needs a cleanup: merge of replace, lang/script etc + +local texsprint, count, texsetcount = tex.sprint, tex.count, tex.setcount +local format, concat, gmatch, match, find, lower, gsub, byte = string.format, table.concat, string.gmatch, string.match, string.find, string.lower, string.gsub, string.byte + +local tostring, next, type = tostring, next, type +local lpegmatch = lpeg.match +local round = math.round local ctxcatcodes = tex.ctxcatcodes @@ -16,7 +21,7 @@ local trace_defining = false trackers.register("fonts.defining", function(v) tr local tfm = fonts.tfm local define = fonts.define -local fontdata = fonts.ids +local fontdata = fonts.identifiers local specify = define.specify specify.context_setups = specify.context_setups or { } @@ -46,7 +51,7 @@ name*context specification function specify.predefined(specification) local detail = specification.detail if detail ~= "" then - -- detail = detail:gsub("["..define.splitsymbols.."].*$","") -- get rid of *whatever specs and such + -- detail = gsub(detail,"["..define.splitsymbols.."].*$","") -- get rid of *whatever specs and such if define.methods[detail] then -- since these may be appended at the specification.features.vtf = { preset = detail } -- tex end by default end @@ -66,22 +71,25 @@ local settings_to_hash = aux.settings_to_hash local default_features = fonts.otf.features.default local function preset_context(name,parent,features) -- currently otf only + if features == "" and find(parent,"=") then + features = parent + parent = "" + end if features == "" then - if find(parent,"=") then - features = parent - parent = "" - end + features = { } + elseif type(features) == "string" then + features = normalize_meanings(settings_to_hash(features)) + else + features = normalize_meanings(features) end - local number = (setups[name] and setups[name].number) or 0 - local t = (features == "" and { }) or normalize_meanings(settings_to_hash(features)) -- todo: synonyms, and not otf bound if parent ~= "" then for p in gmatch(parent,"[^, ]+") do local s = setups[p] if s then for k,v in next, s do - if t[k] == nil then - t[k] = v + if features[k] == nil then + features[k] = v end end end @@ -91,25 +99,26 @@ local function preset_context(name,parent,features) -- currently otf only -- 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 type(t[v]) == "nil" then + if features[v] == nil then -- not false ! local vv = default_features[v] - if vv then t[v] = vv end + if vv then features[v] = vv end end end -- sparse 'm so that we get a better hash and less test (experimental -- optimization) - local tt = { } -- maybe avoid tt - for k,v in next, t do - if v then tt[k] = v end + local t = { } -- can we avoid t ? + for k,v in next, features do + if v then t[k] = v end end -- needed for dynamic features + local number = (setups[name] and setups[name].number) or 0 if number == 0 then number = #numbers + 1 numbers[number] = name end - tt.number = number - setups[name] = tt - return number + t.number = number + setups[name] = t + return number, t end local function context_number(name) -- will be replaced @@ -267,13 +276,16 @@ local P, C, Cc = lpeg.P, lpeg.C, lpeg.Cc local space = P(" ") local spaces = space^0 -local value = C((1-space)^1) +local leftparent = (P"(") +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 * value -local scale_sa = P("sa") * Cc(2) * spaces * value -local scale_mo = P("mo") * Cc(3) * spaces * value -local scale_scaled = P("scaled") * Cc(4) * spaces * value +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 sizepattern = spaces * (scale_at + scale_sa + scale_mo + scale_scaled + scale_none) local splitpattern = spaces * value * spaces * rest @@ -287,7 +299,7 @@ local get_specification = define.get_specification function define.command_1(str) statistics.starttiming(fonts) - local fullname, size = splitpattern:match(str) + local fullname, size = lpegmatch(splitpattern,str) local lookup, name, sub, method, detail = get_specification(fullname) if not name then logs.report("define font","strange definition '%s'",str) @@ -295,40 +307,50 @@ function define.command_1(str) elseif name == "unknown" then texsprint(ctxcatcodes,"\\fcglet\\somefontname\\defaultfontfile") else - texsprint(ctxcatcodes,format("\\fcxdef\\somefontname{%s}",name)) + texsprint(ctxcatcodes,"\\fcxdef\\somefontname{",name,"}") end -- we can also use a count for the size if size and size ~= "" then - local mode, size = sizepattern:match(size) + local mode, size = lpegmatch(sizepattern,size) if size and mode then count.scaledfontmode = mode - texsprint(ctxcatcodes,format("\\def\\somefontsize{%s}",size)) + texsprint(ctxcatcodes,"\\def\\somefontsize{",size,"}") else count.scaledfontmode = 0 - texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size)) + texsprint(ctxcatcodes,"\\let\\somefontsize\\empty") end elseif true then -- so we don't need to check in tex count.scaledfontmode = 2 ---~ texsprint(ctxcatcodes,format("\\def\\somefontsize{*}",size)) - texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size)) + texsprint(ctxcatcodes,"\\let\\somefontsize\\empty") else count.scaledfontmode = 0 - texsprint(ctxcatcodes,format("\\let\\somefontsize\\empty",size)) + texsprint(ctxcatcodes,"\\let\\somefontsize\\empty") end specification = define.makespecification(str,lookup,name,sub,method,detail,size) end local n = 0 -function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfallbacks,fontfallbacks,mathsize,textsize) +-- we can also move rscale to here (more consistent) + +function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfallbacks,fontfallbacks,mathsize,textsize,relativeid) + if trace_defining then + logs.report("define font","memory usage before: %s",statistics.memused()) + end -- name is now resolved and size is scaled cf sa/mo local lookup, name, sub, method, detail = get_specification(str or "") -- asome settings can be overloaded - if lookup and lookup ~= "" then specification.lookup = lookup end + if lookup and lookup ~= "" then + specification.lookup = lookup + end + if relativeid and relativeid ~= "" then -- experimental hook + local id = tonumber(relativeid) or 0 + specification.relativeid = id > 0 and id + end specification.name = name specification.size = size - specification.sub = sub + specification.sub = (sub and sub ~= "" and sub) or specification.sub specification.mathsize = mathsize specification.textsize = textsize if detail and detail ~= "" then @@ -340,9 +362,6 @@ function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfal elseif classfeatures and classfeatures ~= "" then specification.method, specification.detail = "*", classfeatures end - if trace_defining then - logs.report("define font","memory usage before: %s",statistics.memused()) - end if fontfallbacks and fontfallbacks ~= "" then specification.fallbacks = fontfallbacks elseif classfallbacks and classfallbacks ~= "" then @@ -351,6 +370,7 @@ function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfal local tfmdata = define.read(specification,size) -- id not yet known if not tfmdata then logs.report("define font","unable to define %s as \\%s",name,cs) + texsetcount("global","lastfontid",-1) elseif type(tfmdata) == "number" then if trace_defining then logs.report("define font","reusing %s with id %s as \\%s (features: %s/%s, fallbacks: %s/%s)",name,tfmdata,cs,classfeatures,fontfeatures,classfallbacks,fontfallbacks) @@ -358,6 +378,7 @@ function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfal tex.definefont(global,cs,tfmdata) -- resolved (when designsize is used): texsprint(ctxcatcodes,format("\\def\\somefontsize{%isp}",fontdata[tfmdata].size)) + texsetcount("global","lastfontid",tfmdata) else -- local t = os.clock(t) local id = font.define(tfmdata) @@ -374,6 +395,7 @@ function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfal --~ if specification.fallbacks then --~ fonts.collections.prepare(specification.fallbacks) --~ end + texsetcount("global","lastfontid",id) end if trace_defining then logs.report("define font","memory usage after: %s",statistics.memused()) @@ -381,6 +403,28 @@ function define.command_2(global,cs,str,size,classfeatures,fontfeatures,classfal statistics.stoptiming(fonts) end +local enable_auto_r_scale = false + +experiments.register("fonts.autorscale", function(v) + enable_auto_r_scale = v +end) + +local calculate_scale = fonts.tfm.calculate_scale + +function fonts.tfm.calculate_scale(tfmtable, scaledpoints, relativeid) + local scaledpoints, delta, units = calculate_scale(tfmtable, scaledpoints, relativeid) + if enable_auto_r_scale and relativeid then -- for the moment this is rather context specific + local relativedata = fontdata[relativeid] + local id_x_height = relativedata and relativedata.parameters and relativedata.parameters.x_height + local tf_x_height = id_x_height and tfmtable.parameters and tfmtable.parameters.x_height * delta + if tf_x_height then + scaledpoints = (id_x_height/tf_x_height) * scaledpoints + delta = scaledpoints/units + end + end + return scaledpoints, delta, units +end + --~ table.insert(readers.sequence,1,'vtf') --~ function readers.vtf(specification) @@ -390,3 +434,191 @@ end --~ return nil --~ end --~ end + +-- we need a place for this .. outside the generic scope + +local dimenfactors = number.dimenfactors + +function fonts.dimenfactor(unit,tfmdata) + if unit == "ex" then + return (tfmdata and tfmdata.parameters.x_height) or 655360 + elseif unit == "em" then + return (tfmdata and tfmdata.parameters.em_height) or 655360 + else + return dimenfactors[unit] or unit + end +end + +function fonts.cleanname(name) + texsprint(ctxcatcodes,fonts.names.cleanname(name)) +end + +local p, f = 1, "%0.1fpt" -- normally this value is changed only once + +local stripper = lpeg.patterns.strip_zeros + +function fonts.nbfs(amount,precision) + if precision ~= p then + p = precision + f = "%0." .. p .. "fpt" + end + texsprint(ctxcatcodes,lpegmatch(stripper,format(f,amount/65536))) +end + +-- for the moment here, this will become a chain of extras that is +-- hooked into the ctx registration (or scaler or ...) + +function fonts.set_digit_width(font) + local tfmtable = fontdata[font] + local parameters = tfmtable.parameters + local width = parameters.digitwidth + if not width then + width = round(parameters.quad/2) -- maybe tex.scale + local characters = tfmtable.characters + for i=48,57 do + local wd = round(characters[i].width) + if wd > width then + width = wd + end + end + parameters.digitwidth = width + end + return width +end + +fonts.get_digit_width = fonts.set_digit_width + +-- soon to be obsolete: + +local loaded = { -- prevent loading (happens in cont-sys files) + ["original-base.map" ] = true, + ["original-ams-base.map" ] = true, + ["original-ams-euler.map"] = true, + ["original-public-lm.map"] = true, +} + +function fonts.map.loadfile(name) + name = file.addsuffix(name,"map") + if not loaded[name] then + pdf.mapfile(name) + loaded[name] = true + end +end + +local loaded = { -- prevent double loading +} + +function fonts.map.loadline(how,line) + if line then + how = how .. " " .. line + elseif how == "" then + how = "= " .. line + end + if not loaded[how] then + pdf.mapline(how) + loaded[how] = true + end +end + +function fonts.map.reset() + pdf.mapfile("") +end + +fonts.map.reset() -- resets the default file + +-- we need an 'do after the banner hook' + +-- pdf.mapfile("mkiv-base.map") -- loads the default file + +local nounicode = byte("?") + +local function name_to_slot(name) -- maybe some day rawdata + local tfmdata = fonts.ids[font.current()] + local shared = tfmdata and tfmdata.shared + local fntdata = shared and shared.otfdata or shared.afmdata + if fntdata then + local unicode = fntdata.luatex.unicodes[name] + if not unicode then + return nounicode + elseif type(unicode) == "number" then + return unicode + else -- multiple unicodes + return unicode[1] + end + end + return nounicode +end + +fonts.name_to_slot = name_to_slot + +function fonts.char(n) -- todo: afm en tfm + if type(n) == "string" then + n = name_to_slot(n) + end + if type(n) == "number" then + texsprint(ctxcatcodes,format("\\char%s ",n)) + end +end + +-- moved from ini: + +fonts.color = { } -- dummy in ini + +local attribute = attributes.private('color') +local mapping = (attributes and attributes.list[attribute]) or { } + +local set_attribute = node.set_attribute +local unset_attribute = node.unset_attribute + +function fonts.color.set(n,c) + local mc = mapping[c] + if not mc then + unset_attribute(n,attribute) + else + set_attribute(n,attribute,mc) + end +end + +function fonts.color.reset(n) + unset_attribute(n,attribute) +end + +-- this will become obsolete: + +fonts.otf.name_to_slot = name_to_slot +fonts.afm.name_to_slot = name_to_slot + +fonts.otf.char = fonts.char +fonts.afm.char = fonts.char + +-- this will change ... + +function fonts.show_char_data(n) + local tfmdata = fonts.ids[font.current()] + if tfmdata then + if type(n) == "string" then + n = utf.byte(n) + end + local chr = tfmdata.characters[n] + if chr then + write_nl(format("%s @ %s => U%04X => %s => ",tfmdata.fullname,tfmdata.size,n,utf.char(n)) .. serialize(chr,false)) + end + end +end + +function fonts.show_font_parameters() + local tfmdata = fonts.ids[font.current()] + if tfmdata then + local parameters, mathconstants = tfmdata.parameters, tfmdata.MathConstants + local hasparameters, hasmathconstants = parameters and next(parameters), mathconstants and next(mathconstants) + if hasparameters then + write_nl(format("%s @ %s => parameters => ",tfmdata.fullname,tfmdata.size) .. serialize(parameters,false)) + end + if hasmathconstants then + write_nl(format("%s @ %s => math constants => ",tfmdata.fullname,tfmdata.size) .. serialize(mathconstants,false)) + end + if not hasparameters and not hasmathconstants then + write_nl(format("%s @ %s => no parameters and/or mathconstants",tfmdata.fullname,tfmdata.size)) + end + end +end |