diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-con.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/font-con.lua | 359 |
1 files changed, 278 insertions, 81 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-con.lua b/Master/texmf-dist/tex/context/base/font-con.lua index 5d30842ef7f..92809968857 100644 --- a/Master/texmf-dist/tex/context/base/font-con.lua +++ b/Master/texmf-dist/tex/context/base/font-con.lua @@ -7,12 +7,15 @@ if not modules then modules = { } end modules ['font-con'] = { } +-- some names of table entries will be changed (no _) + local utf = unicode.utf8 local next, tostring, rawget = next, tostring, rawget local format, match, lower, gsub = string.format, string.match, string.lower, string.gsub local utfbyte = utf.byte local sort, insert, concat, sortedkeys, serialize, fastcopy = table.sort, table.insert, table.concat, table.sortedkeys, table.serialize, table.fastcopy +local derivetable = table.derive local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) local trace_scaling = false trackers.register("fonts.scaling" , function(v) trace_scaling = v end) @@ -25,32 +28,128 @@ local report_defining = logs.reporter("fonts","defining") <p>Here we only implement a few helper functions.</p> --ldx]]-- -local fonts = fonts -local constructors = { } -fonts.constructors = constructors -local handlers = { } -fonts.handlers = handlers +local fonts = fonts +local constructors = { } +fonts.constructors = constructors +local handlers = { } +fonts.handlers = handlers -local specifiers = fonts.specifiers -local contextsetups = specifiers.contextsetups -local contextnumbers = specifiers.contextnumbers +local specifiers = fonts.specifiers +local contextsetups = specifiers.contextsetups +local contextnumbers = specifiers.contextnumbers -local allocate = utilities.storage.allocate -local setmetatableindex = table.setmetatableindex +local allocate = utilities.storage.allocate +local setmetatableindex = table.setmetatableindex -- will be directives -constructors.dontembed = allocate() -constructors.mathactions = { } -constructors.autocleanup = true -constructors.namemode = "fullpath" -- will be a function +constructors.dontembed = allocate() +constructors.autocleanup = true +constructors.namemode = "fullpath" -- will be a function + +constructors.version = 1.01 +constructors.cache = containers.define("fonts", "constructors", constructors.version, false) + +constructors.privateoffset = 0xF0000 -- 0x10FFFF + +-- Some experimental helpers (handy for tracing): +-- +-- todo: extra: +-- +-- extra_space => space.extra +-- space => space.width +-- space_stretch => space.stretch +-- space_shrink => space.shrink -constructors.version = 1.01 -constructors.cache = containers.define("fonts", "constructors", constructors.version, false) +-- We do keep the x-height, extra_space, space_shrink and space_stretch +-- around as these are low level official names. -constructors.privateoffset = 0xF0000 -- 0x10FFFF +constructors.keys = { + properties = { + encodingbytes = "number", + embedding = "number", + cidinfo = { + }, + format = "string", + fontname = "string", + fullname = "string", + filename = "filename", + psname = "string", + name = "string", + virtualized = "boolean", + hasitalics = "boolean", + autoitalicamount = "basepoints", + nostackmath = "boolean", + noglyphnames = "boolean", + mode = "string", + hasmath = "boolean", + mathitalics = "boolean", + textitalics = "boolean", + finalized = "boolean", + }, + parameters = { + mathsize = "number", + scriptpercentage = "float", + scriptscriptpercentage = "float", + units = "cardinal", + designsize = "scaledpoints", + expansion = { + stretch = "integerscale", -- might become float + shrink = "integerscale", -- might become float + step = "integerscale", -- might become float + auto = "boolean", + }, + protrusion = { + auto = "boolean", + }, + slantfactor = "float", + extendfactor = "float", + factor = "float", + hfactor = "float", + vfactor = "float", + size = "scaledpoints", + units = "scaledpoints", + scaledpoints = "scaledpoints", + slantperpoint = "scaledpoints", + spacing = { + width = "scaledpoints", + stretch = "scaledpoints", + shrink = "scaledpoints", + extra = "scaledpoints", + }, + xheight = "scaledpoints", + quad = "scaledpoints", + ascender = "scaledpoints", + descender = "scaledpoints", + synonyms = { + space = "spacing.width", + spacestretch = "spacing.stretch", + spaceshrink = "spacing.shrink", + extraspace = "spacing.extra", + x_height = "xheight", + space_stretch = "spacing.stretch", + space_shrink = "spacing.shrink", + extra_space = "spacing.extra", + em = "quad", + ex = "xheight", + slant = "slantperpoint", + }, + }, + description = { + width = "basepoints", + height = "basepoints", + depth = "basepoints", + boundingbox = { }, + }, + character = { + width = "scaledpoints", + height = "scaledpoints", + depth = "scaledpoints", + italic = "scaledpoints", + }, +} --- This might become an interface; +-- This might become an interface: local designsizes = allocate() constructors.designsizes = designsizes @@ -99,7 +198,7 @@ excessive memory usage in CJK fonts, we no longer pass the boundingbox.)</p> -- The scaler is only used for otf and afm and virtual fonts. If -- a virtual font has italic correction make sure to set the --- italic_correction flag. Some more flags will be added in +-- hasitalics flag. Some more flags will be added in -- the future. --[[ldx-- @@ -145,39 +244,75 @@ function constructors.calculatescale(tfmdata,scaledpoints) return scaledpoints, scaledpoints / (parameters.units or 1000) -- delta end -function constructors.assignmathparameters(target,tfmdata) +local unscaled = { + ScriptPercentScaleDown = true, + ScriptScriptPercentScaleDown = true, + RadicalDegreeBottomRaisePercent = true +} + +function constructors.assignmathparameters(target,original) -- simple variant, not used in context -- when a tfm file is loaded, it has already been scaled - -- and it never enters the scaled so this is otf only + -- and it never enters the scaled so this is otf only and + -- even then we do some extra in the context math plugins local mathparameters = original.mathparameters if mathparameters and next(mathparameters) then local targetparameters = target.parameters + local targetproperties = target.properties local targetmathparameters = { } - local factor = targetparameters.factor + local factor = targetproperties.math_is_scaled and 1 or targetparameters.factor for name, value in next, mathparameters do - if name == "RadicalDegreeBottomRaisePercent" then + if unscaled[name] then targetmathparameters[name] = value else targetmathparameters[name] = value * factor end end - if not targetmathparameters.AccentBaseHeight then - targetmathparameters.AccentBaseHeight = nil -- safeguard, still needed? - end if not targetmathparameters.FractionDelimiterSize then - targetmathparameters.FractionDelimiterSize = 0 + targetmathparameters.FractionDelimiterSize = 1.01 * targetparameters.size end if not mathparameters.FractionDelimiterDisplayStyleSize then - targetmathparameters.FractionDelimiterDisplayStyleSize = 0 + targetmathparameters.FractionDelimiterDisplayStyleSize = 2.40 * targetparameters.size end target.mathparameters = targetmathparameters end end +function constructors.beforecopyingcharacters(target,original) + -- can be used for additional tweaking +end + +function constructors.aftercopyingcharacters(target,original) + -- can be used for additional tweaking +end + +function constructors.enhanceparameters(parameters) + local xheight = parameters.x_height + local quad = parameters.quad + local space = parameters.space + local stretch = parameters.space_stretch + local shrink = parameters.space_shrink + local extra = parameters.extra_space + local slant = parameters.slant + parameters.xheight = xheight + parameters.spacestretch = stretch + parameters.spaceshrink = shrink + parameters.extraspace = extra + parameters.em = quad + parameters.ex = xheight + parameters.slantperpoint = slant + parameters.spacing = { + width = space, + stretch = stretch, + shrink = shrink, + extra = extra, + } +end + function constructors.scale(tfmdata,specification) local target = { } -- the new table -- if tonumber(specification) then - specification = { size = specification } + specification = { size = specification } end -- local scaledpoints = specification.size @@ -194,10 +329,9 @@ function constructors.scale(tfmdata,specification) local mathparameters = tfmdata.mathparameters or { } -- local targetcharacters = { } - local targetdescriptions = table.derive(descriptions) - local targetparameters = table.derive(parameters) - -- local targetmathparameters = table.fastcopy(mathparameters) -- happens elsewhere - local targetproperties = table.derive(properties) + local targetdescriptions = derivetable(descriptions) + local targetparameters = derivetable(parameters) + local targetproperties = derivetable(properties) local targetgoodies = goodies -- we need to loop so no metatable target.characters = targetcharacters target.descriptions = targetdescriptions @@ -213,9 +347,10 @@ function constructors.scale(tfmdata,specification) -- specification.textsize : natural (text)size -- parameters.mathsize : 1=text 2=script 3=scriptscript >1000 enforced size (feature value other than yes) -- - local mathsize = tonumber(specification.mathsize) or 0 - local textsize = tonumber(specification.textsize) or scaledpoints - local forcedsize = tonumber(parameters.mathsize ) or 0 + local mathsize = tonumber(specification.mathsize) or 0 + local textsize = tonumber(specification.textsize) or scaledpoints + local forcedsize = tonumber(parameters.mathsize ) or 0 + local extrafactor = tonumber(specification.factor ) or 1 if (mathsize == 2 or forcedsize == 2) and parameters.scriptpercentage then scaledpoints = parameters.scriptpercentage * textsize / 100 elseif (mathsize == 3 or forcedsize == 3) and parameters.scriptscriptpercentage then @@ -302,17 +437,17 @@ function constructors.scale(tfmdata,specification) target.auto_protrude = protrusion.auto end -- widening - local extend_factor = parameters.extend_factor or 0 - if extend_factor ~= 0 and extend_factor ~= 1 then - hdelta = hdelta * extend_factor - target.extend = extend_factor * 1000 -- extent ? + local extendfactor = parameters.extendfactor or 0 + if extendfactor ~= 0 and extendfactor ~= 1 then + hdelta = hdelta * extendfactor + target.extend = extendfactor * 1000 -- extent ? else target.extend = 1000 -- extent ? end -- slanting - local slant_factor = parameters.slant_factor or 0 - if slant_factor ~= 0 then - target.slant = slant_factor * 1000 + local slantfactor = parameters.slantfactor or 0 + if slantfactor ~= 0 then + target.slant = slantfactor * 1000 else target.slant = 0 end @@ -324,19 +459,20 @@ function constructors.scale(tfmdata,specification) targetparameters.units = units targetparameters.scaledpoints = askedscaledpoints -- - local isvirtual = properties.virtualized or tfmdata.type == "virtual" - local hasquality = target.auto_expand or target.auto_protrude - local hasitalic = properties.italic_correction - local stackmath = not properties.no_stackmath - local nonames = properties.noglyphnames - local nodemode = properties.mode == "node" + local isvirtual = properties.virtualized or tfmdata.type == "virtual" + local hasquality = target.auto_expand or target.auto_protrude + local hasitalics = properties.hasitalics + local autoitalicamount = properties.autoitalicamount + local stackmath = not properties.nostackmath + local nonames = properties.noglyphnames + local nodemode = properties.mode == "node" -- if changed and not next(changed) then changed = false end -- target.type = isvirtual and "virtual" or "real" - -- this will move to some subtable so that it is copied at once + -- target.postprocessors = tfmdata.postprocessors -- local targetslant = (parameters.slant or parameters[1] or 0) @@ -347,7 +483,7 @@ function constructors.scale(tfmdata,specification) local targetquad = (parameters.quad or parameters[6] or 0)*hdelta local targetextra_space = (parameters.extra_space or parameters[7] or 0)*hdelta -- - targetparameters.slant = targetslant + targetparameters.slant = targetslant -- slantperpoint targetparameters.space = targetspace targetparameters.space_stretch = targetspace_stretch targetparameters.space_shrink = targetspace_shrink @@ -363,25 +499,27 @@ function constructors.scale(tfmdata,specification) if descender then targetparameters.descender = delta * descender end - -- copies, might disappear - targetparameters.xheight = targetparameters.xheight or parameters.x_height - targetparameters.extraspace = targetparameters.extraspace or parameters.extra_space - targetparameters.spacestretch = targetparameters.spacestretch or parameters.space_stretch - targetparameters.spaceshrink = targetparameters.spaceshrink or parameters.space_shrink + -- + constructors.enhanceparameters(targetparameters) -- official copies for us -- local protrusionfactor = (targetquad ~= 0 and 1000/targetquad) or 0 local scaledwidth = defaultwidth * hdelta local scaledheight = defaultheight * vdelta local scaleddepth = defaultdepth * vdelta -- - local hasmath = (properties.has_math or next(mathparameters)) and true + if trace_defining then + report_defining("scaling by (%s,%s): name '%s', fullname: '%s', filename: '%s'", + hdelta,vdelta,name or "noname",fullname or "nofullname",filename or "nofilename") + end + -- + local hasmath = (properties.hasmath or next(mathparameters)) and true if hasmath then if trace_defining then report_defining("math enabled for: name '%s', fullname: '%s', filename: '%s'", name or "noname",fullname or "nofullname",filename or "nofilename") end constructors.assignmathparameters(target,tfmdata) -- does scaling and whatever is needed - properties.has_math = true + properties.hasmath = true target.nomath = false target.MathConstants = target.mathparameters else @@ -389,29 +527,75 @@ function constructors.scale(tfmdata,specification) report_defining("math disabled for: name '%s', fullname: '%s', filename: '%s'", name or "noname",fullname or "nofullname",filename or "nofilename") end - properties.has_math = false + properties.hasmath = false target.nomath = true target.mathparameters = nil -- nop end -- - local sharedkerns = { } + local italickey = "italic" + -- + -- some context specific trickery (this will move to a plugin) + -- + if hasmath then + if properties.mathitalics then + italickey = "italic_correction" + if trace_defining then + report_defining("math italics disabled for: name '%s', fullname: '%s', filename: '%s'", + name or "noname",fullname or "nofullname",filename or "nofilename") + end + end + autoitalicamount = false -- new + else + if properties.textitalics then + italickey = "italic_correction" + if trace_defining then + report_defining("text italics disabled for: name '%s', fullname: '%s', filename: '%s'", + name or "noname",fullname or "nofullname",filename or "nofilename") + end + if properties.delaytextitalics then + autoitalicamount = false + end + end + end + -- + -- end of context specific trickery + -- + constructors.beforecopyingcharacters(target,tfmdata) + -- + local sharedkerns = { } + -- + -- we can have a dumb mode (basemode without math etc) that skips most -- for unicode, character in next, characters do - local chr, description, index + local chr, description, index, touni if changed then - -- basemode hack + -- basemode hack (we try to catch missing tounicodes, e.g. needed for ssty in math cambria) local c = changed[unicode] if c then - description = descriptions[c] or character + description = descriptions[c] or descriptions[unicode] or character character = characters[c] or character index = description.index or c + if tounicode then + touni = tounicode[index] -- nb: index! + if not touni then -- goodie + local d = descriptions[unicode] or characters[unicode] + local i = d.index or unicode + touni = tounicode[i] -- nb: index! + end + end else description = descriptions[unicode] or character index = description.index or unicode + if tounicode then + touni = tounicode[index] -- nb: index! + end end else description = descriptions[unicode] or character index = description.index or unicode + if tounicode then + touni = tounicode[index] -- nb: index! + end end local width = description.width local height = description.height @@ -454,15 +638,12 @@ function constructors.scale(tfmdata,specification) } end end + if touni then + chr.tounicode = touni + end -- if trace_scaling then -- report_defining("t=%s, u=%s, i=%s, n=%s c=%s",k,chr.tounicode or "",index or 0,description.name or '-',description.class or '-') -- end - if tounicode then - local tu = tounicode[index] -- nb: index! - if tu then - chr.tounicode = tu - end - end if hasquality then -- we could move these calculations elsewhere (saves calculations) local ve = character.expansion_factor @@ -478,11 +659,21 @@ function constructors.scale(tfmdata,specification) chr.right_protruding = protrusionfactor*width*vr end end - -- todo: hasitalic - if hasitalic then - local vi = description.italic or character.italic + -- + if autoitalicamount then + local vi = description.italic + if not vi then + local vi = description.boundingbox[3] - description.width + autoitalicamount + if vi > 0 then -- < 0 indicates no overshoot or a very small auto italic + chr[italickey] = vi*hdelta + end + elseif vi ~= 0 then + chr[italickey] = vi*hdelta + end + elseif hasitalics then + local vi = description.italic if vi and vi ~= 0 then - chr.italic = vi*hdelta + chr[italickey] = vi*hdelta end end -- to be tested @@ -613,6 +804,9 @@ function constructors.scale(tfmdata,specification) end targetcharacters[unicode] = chr end + -- + constructors.aftercopyingcharacters(target,tfmdata) + -- return target end @@ -653,12 +847,12 @@ function constructors.finalize(tfmdata) parameters.size = tfmdata.size end -- - if not parameters.extend_factor then - parameters.extend_factor = tfmdata.extend or 0 + if not parameters.extendfactor then + parameters.extendfactor = tfmdata.extend or 0 end -- - if not parameters.slant_factor then - parameters.slant_factor = tfmdata.slant or 0 + if not parameters.slantfactor then + parameters.slantfactor = tfmdata.slant or 0 end -- if not parameters.designsize then @@ -711,8 +905,8 @@ function constructors.finalize(tfmdata) -- tfmdata.fonts -- tfmdata.unscaled -- - if not properties.has_math then - properties.has_math = not tfmdata.nomath + if not properties.hasmath then + properties.hasmath = not tfmdata.nomath end -- tfmdata.MathConstants = nil @@ -997,7 +1191,7 @@ a helper function.</p> function constructors.checkedfeatures(what,features) local defaults = handlers[what].features.defaults if features and next(features) then - features = fastcopy(features) -- can be inherited + features = fastcopy(features) -- can be inherited (mt) but then no loops possible for key, value in next, defaults do if features[key] == nil then features[key] = value @@ -1031,7 +1225,7 @@ function constructors.initializefeatures(what,tfmdata,features,trace,report) for i=1,#initializers do local step = initializers[i] local feature = step.name --- we could intercept mode here .. needs a rewrite of this whole loop then btu it's cleaner that way +-- we could intercept mode here .. needs a rewrite of this whole loop then but it's cleaner that way local value = features[feature] if not value then -- disabled @@ -1100,6 +1294,9 @@ function constructors.collectprocessors(what,tfmdata,features,trace,report) end end end + elseif trace then + report("no feature processors for mode %s for font %s", + mode or 'unknown', tfmdata.properties.fullname or 'unknown') end end return processes |