diff options
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua')
-rw-r--r-- | Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua | 448 |
1 files changed, 247 insertions, 201 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua b/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua index 0059e6296cc..6e4f8698052 100644 --- a/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua +++ b/Master/texmf-dist/tex/context/base/mkiv/font-tfm.lua @@ -9,6 +9,7 @@ if not modules then modules = { } end modules ['font-tfm'] = { local next, type = next, type local match, format = string.match, string.format local concat, sortedhash = table.concat, table.sortedhash +local idiv = number.idiv local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end) local trace_features = false trackers.register("tfm.features", function(v) trace_features = v end) @@ -21,6 +22,7 @@ local setmetatableindex = table.setmetatableindex local fonts = fonts local handlers = fonts.handlers +local helpers = fonts.helpers local readers = fonts.readers local constructors = fonts.constructors local encodings = fonts.encodings @@ -39,6 +41,8 @@ local registertfmfeature = tfmfeatures.register local tfmenhancers = constructors.enhancers.tfm local registertfmenhancer = tfmenhancers.register +local charcommand = helpers.commands.char + constructors.resolvevirtualtoo = false -- wil be set in font-ctx.lua fonts.formats.tfm = "type1" -- we need to have at least a value here @@ -114,219 +118,266 @@ local depth = { } -- table.setmetatableindex("number") -- -- So "czechdqcheat=yes" is then a valid feature. And yes, it's a cheat. +local read_from_tfm, check_tfm do -local function read_from_tfm(specification) - local filename = specification.filename - local size = specification.size - depth[filename] = (depth[filename] or 0) + 1 - if trace_defining then - report_defining("loading tfm file %a at size %s",filename,size) - end - local tfmdata = font.read_tfm(filename,size) -- not cached, fast enough - if tfmdata then - - local features = specification.features and specification.features.normal or { } - local features = constructors.checkedfeatures("tfm",features) - specification.features.normal = features + local tfmreaders = context and tfm.readers + local loadtfmvf = tfmreaders and tfmreaders.loadtfmvf + local loadtfm = font.read_tfm + local loadvf = font.read_vf - -- If reencode returns a new table, we assume that we're doing something - -- special. An 'auto' reencode pickt up its vector from the pfb file. + directives.register("fonts.tfm.builtin",function(v) + loadtfmvf = tfmreaders and tfmreaders.loadtfmvf + if v and loadtfm then + loadtfmvf = false + end + end) - local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification) - if newtfmdata then - tfmdata = newtfmdata + read_from_tfm = function(specification) + local filename = specification.filename + local size = specification.size + depth[filename] = (depth[filename] or 0) + 1 + if trace_defining then + report_defining("loading tfm file %a at size %s",filename,size) + end + local tfmdata -- not cached, fast enough + if loadtfmvf then + tfmdata = loadtfmvf(filename,size) + else + tfmdata = loadtfm(filename,size) end + if tfmdata then - local resources = tfmdata.resources or { } - local properties = tfmdata.properties or { } - local parameters = tfmdata.parameters or { } - local shared = tfmdata.shared or { } - -- - shared.features = features - shared.resources = resources - -- - properties.name = tfmdata.name -- todo: fallback - properties.fontname = tfmdata.fontname -- todo: fallback - properties.psname = tfmdata.psname -- todo: fallback - properties.fullname = tfmdata.fullname -- todo: fallback - properties.filename = specification.filename -- todo: fallback - properties.format = fonts.formats.tfm -- better than nothing - -- - tfmdata.properties = properties - tfmdata.resources = resources - tfmdata.parameters = parameters - tfmdata.shared = shared - -- - shared.rawdata = { resources = resources } - shared.features = features - -- - -- The next branch is only entered when we have a proper encoded file i.e. - -- unicodes and such. It really nakes no sense to do feature juggling when - -- we have no names and unicodes. - -- - if newtfmdata then - -- - -- Some opentype processing assumes these to be present: - -- - if not resources.marks then - resources.marks = { } - end - if not resources.sequences then - resources.sequences = { } - end - if not resources.features then - resources.features = { - gsub = { }, - gpos = { }, - } - end - if not tfmdata.changed then - tfmdata.changed = { } - end - if not tfmdata.descriptions then - tfmdata.descriptions = tfmdata.characters + local features = specification.features and specification.features.normal or { } + local features = constructors.checkedfeatures("tfm",features) + specification.features.normal = features + + -- If reencode returns a new table, we assume that we're doing something + -- special. An 'auto' reencode picks up its vector from the pfb file. + + local newtfmdata = (depth[filename] == 1) and tfm.reencode(tfmdata,specification) + if newtfmdata then + tfmdata = newtfmdata end + + local resources = tfmdata.resources or { } + local properties = tfmdata.properties or { } + local parameters = tfmdata.parameters or { } + local shared = tfmdata.shared or { } -- - -- It might be handy to have this: - -- - otf.readers.addunicodetable(tfmdata) - -- - -- We make a pseudo opentype font, e.g. kerns and ligatures etc: - -- - tfmenhancers.apply(tfmdata,filename) - -- - -- Now user stuff can kick in. - -- - constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) - -- - -- As that can also mess with names and such, we are now ready for finalizing - -- the unicode information. This is a different order that for instance type one - -- (afm) files. First we try to deduce unicodes from already present information. + shared.features = features + shared.resources = resources -- - otf.readers.unifymissing(tfmdata) + properties.name = tfmdata.name -- todo: fallback + properties.fontname = tfmdata.fontname -- todo: fallback + properties.psname = tfmdata.psname -- todo: fallback + properties.fullname = tfmdata.fullname -- todo: fallback + properties.filename = specification.filename -- todo: fallback + properties.format = tfmdata.format or fonts.formats.tfm -- better than nothing + properties.usedbitmap = tfmdata.usedbitmap -- - -- Next we fill in the gaps, based on names from teh agl. Probably not much will - -- happen here. + tfmdata.properties = properties + tfmdata.resources = resources + tfmdata.parameters = parameters + tfmdata.shared = shared -- - fonts.mappings.addtounicode(tfmdata,filename) + shared.rawdata = { resources = resources } + shared.features = features -- - -- The tounicode data is passed to the backend that constructs the vectors for us. + -- The next branch is only entered when we have a proper encoded file i.e. + -- unicodes and such. It really nakes no sense to do feature juggling when + -- we have no names and unicodes. -- - tfmdata.tounicode = 1 - local tounicode = fonts.mappings.tounicode - for unicode, v in next, tfmdata.characters do - local u = v.unicode - if u then - v.tounicode = tounicode(u) + if newtfmdata then + -- + -- Some opentype processing assumes these to be present: + -- + if not resources.marks then + resources.marks = { } + end + if not resources.sequences then + resources.sequences = { } + end + if not resources.features then + resources.features = { + gsub = { }, + gpos = { }, + } + end + if not tfmdata.changed then + tfmdata.changed = { } + end + if not tfmdata.descriptions then + tfmdata.descriptions = tfmdata.characters + end + -- + -- It might be handy to have this: + -- + otf.readers.addunicodetable(tfmdata) + -- + -- We make a pseudo opentype font, e.g. kerns and ligatures etc: + -- + tfmenhancers.apply(tfmdata,filename) + -- + -- Now user stuff can kick in. + -- + constructors.applymanipulators("tfm",tfmdata,features,trace_features,report_tfm) + -- + -- As that can also mess with names and such, we are now ready for finalizing + -- the unicode information. This is a different order that for instance type one + -- (afm) files. First we try to deduce unicodes from already present information. + -- + otf.readers.unifymissing(tfmdata) + -- + -- Next we fill in the gaps, based on names from teh agl. Probably not much will + -- happen here. + -- + fonts.mappings.addtounicode(tfmdata,filename) + -- + -- The tounicode data is passed to the backend that constructs the vectors for us. + -- + tfmdata.tounicode = 1 + local tounicode = fonts.mappings.tounicode + for unicode, v in next, tfmdata.characters do + local u = v.unicode + if u then + v.tounicode = tounicode(u) + end + end + -- + -- However, when we use a bitmap font those vectors can't be constructed because + -- that information is not carried with those fonts (there is no name info, nor + -- proper index info, nor unicodes at that end). So, we provide it ourselves. + -- + if tfmdata.usedbitmap then + tfm.addtounicode(tfmdata) end end -- - -- However, when we use a bitmap font those vectors can't be constructed because - -- that information is not carried with those fonts (there is no name info, nor - -- proper index info, nor unicodes at that end). So, we provide it ourselves. + shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil -- - if tfmdata.usedbitmap then - tfm.addtounicode(tfmdata) + if size < 0 then + size = idiv(65536 * -size,100) end - end - -- - shared.processes = next(features) and tfm.setfeatures(tfmdata,features) or nil - -- - parameters.factor = 1 -- already scaled - parameters.size = size - parameters.slant = parameters.slant or parameters[1] or 0 - parameters.space = parameters.space or parameters[2] or 0 - parameters.space_stretch = parameters.space_stretch or parameters[3] or 0 - parameters.space_shrink = parameters.space_shrink or parameters[4] or 0 - parameters.x_height = parameters.x_height or parameters[5] or 0 - parameters.quad = parameters.quad or parameters[6] or 0 - parameters.extra_space = parameters.extra_space or parameters[7] or 0 - -- - constructors.enhanceparameters(parameters) -- official copies for us - -- - properties.private = properties.private or tfmdata.private or privateoffset - -- - if newtfmdata then + parameters.factor = 1 -- already scaled + parameters.units = 1000 -- just in case + parameters.size = size + parameters.slant = parameters.slant or parameters[1] or 0 + parameters.space = parameters.space or parameters[2] or 0 + parameters.space_stretch = parameters.space_stretch or parameters[3] or 0 + parameters.space_shrink = parameters.space_shrink or parameters[4] or 0 + parameters.x_height = parameters.x_height or parameters[5] or 0 + parameters.quad = parameters.quad or parameters[6] or 0 + parameters.extra_space = parameters.extra_space or parameters[7] or 0 -- - -- We do nothing as we assume flat tfm files. It would become real messy - -- otherwise and I don't have something for testing on my system anyway. + constructors.enhanceparameters(parameters) -- official copies for us -- - elseif constructors.resolvevirtualtoo then - fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here - local vfname = findbinfile(specification.name, 'ovf') - if vfname and vfname ~= "" then - local vfdata = font.read_vf(vfname,size) -- not cached, fast enough - if vfdata then - local chars = tfmdata.characters - for k,v in next, vfdata.characters do - chars[k].commands = v.commands + properties.private = properties.private or tfmdata.private or privateoffset + -- + if newtfmdata then + -- + -- We do nothing as we assume flat tfm files. It would become real messy + -- otherwise and I don't have something for testing on my system anyway. + -- + elseif loadtfmvf then + -- already loaded + local fonts = tfmdata.fonts + if fonts then + for i=1,#fonts do + local font = fonts[i] + local id = font.id + if not id then + local name = font.name + local size = font.size + if name and size then + local data, id = constructors.readanddefine(name,size) + if id then + font.id = id + font.name = nil + font.size = nil + end + end + end end - properties.virtualized = true - tfmdata.fonts = vfdata.fonts - tfmdata.type = "virtual" -- else nested calls with cummulative scaling - local fontlist = vfdata.fonts - local name = file.nameonly(filename) - for i=1,#fontlist do - local n = fontlist[i].name - local s = fontlist[i].size - local d = depth[filename] - s = constructors.scaled(s,vfdata.designsize) - if d > tfm.maxnestingdepth then - report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) - fontlist[i] = { id = 0 } - elseif (d > 1) and (s > tfm.maxnestingsize) then - report_defining("virtual font %a exceeds size %s",n,s) - fontlist[i] = { id = 0 } - else - local t, id = fonts.constructors.readanddefine(n,s) - fontlist[i] = { id = id } + end + elseif constructors.resolvevirtualtoo then + fonts.loggers.register(tfmdata,file.suffix(filename),specification) -- strange, why here + local vfname = findbinfile(specification.name, 'ovf') + if vfname and vfname ~= "" then + local vfdata = loadvf(vfname,size) + if vfdata then + local chars = tfmdata.characters + for k,v in next, vfdata.characters do + chars[k].commands = v.commands + end + properties.virtualized = true + tfmdata.fonts = vfdata.fonts + tfmdata.type = "virtual" -- else nested calls with cummulative scaling + local fontlist = vfdata.fonts + local name = file.nameonly(filename) + for i=1,#fontlist do + local n = fontlist[i].name + local s = fontlist[i].size + local d = depth[filename] + s = constructors.scaled(s,vfdata.designsize) + if d > tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i] = { id = 0 } + elseif (d > 1) and (s > tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i] = { id = 0 } + else + local t, id = constructors.readanddefine(n,s) + fontlist[i] = { id = id } + end end end end end + -- + -- This is for old times sake (and context specific) so we comment it. It has + -- to do with encoding prefixes (a context naming that was later adopted by + -- the lm/gyre project) + -- + -- if not features.encoding then + -- local encoding, filename = match(properties.filename,"^(.-)%-(.*)$") + -- if filename and encoding and encodings.known and encodings.known[encoding] then + -- features.encoding = encoding + -- end + -- end + -- + -- Some afterthoughts: + -- + properties.haskerns = true + properties.hasligatures = true + properties.hasitalics = true + resources.unicodes = { } + resources.lookuptags = { } + -- + depth[filename] = depth[filename] - 1 + -- + return tfmdata + else + depth[filename] = depth[filename] - 1 end - -- - -- This is for old times sake (and context specific) so we comment it. It has - -- to do with encoding prefixes (a context naming that was later adopted by - -- the lm/gyre project) - -- - -- if not features.encoding then - -- local encoding, filename = match(properties.filename,"^(.-)%-(.*)$") - -- if filename and encoding and encodings.known and encodings.known[encoding] then - -- features.encoding = encoding - -- end - -- end - -- - -- Some afterthoughts: - -- - properties.haskerns = true - properties.hasligatures = true - resources.unicodes = { } - resources.lookuptags = { } - -- - depth[filename] = depth[filename] - 1 - -- - return tfmdata - else - depth[filename] = depth[filename] - 1 end -end -local function check_tfm(specification,fullname) -- we could split up like afm/otf - local foundname = findbinfile(fullname, 'tfm') or "" - if foundname == "" then - foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context - end - if foundname == "" then - foundname = fonts.names.getfilename(fullname,"tfm") or "" - end - if foundname ~= "" then - specification.filename = foundname - specification.format = "ofm" - return read_from_tfm(specification) - elseif trace_defining then - report_defining("loading tfm with name %a fails",specification.name) + check_tfm = function(specification,fullname) -- we could split up like afm/otf + local foundname = findbinfile(fullname, 'tfm') or "" + if foundname == "" then + foundname = findbinfile(fullname, 'ofm') or "" -- not needed in context + end + if foundname == "" then + foundname = fonts.names.getfilename(fullname,"tfm") or "" + end + if foundname ~= "" then + specification.filename = foundname + specification.format = "ofm" + return read_from_tfm(specification) + elseif trace_defining then + report_defining("loading tfm with name %a fails",specification.name) + end end + end readers.check_tfm = check_tfm @@ -409,7 +460,7 @@ do local vector = false if type(pfbfile) == "string" then - local pfb = fonts.constructors.handlers.pfb + local pfb = constructors.handlers.pfb if pfb and pfb.loadvector then local v, e = pfb.loadvector(pfbfile) if v then @@ -438,7 +489,7 @@ do local originals = tfmdata.characters local indices = { } local parentfont = { "font", 1 } - local private = tfmdata or fonts.constructors.privateoffset + local private = tfmdata.privateoffset or constructors.privateoffset local reported = encdone[tfmfile][encfile] -- create characters table @@ -463,9 +514,9 @@ do indices[index] = unicode original.name = name -- so one can lookup weird names if backmap then - original.index = backmap[name] + original.index = backmap[name] else -- probably bitmap - original.commands = { parentfont, { "char", index } } + original.commands = { parentfont, charcommand[index] } -- or "slot" original.oindex = index end done[name] = true @@ -512,6 +563,7 @@ do tfmdata.psname = file.nameonly(pfbfile or tfmdata.name) tfmdata.filename = pfbfile tfmdata.encodingbytes = 2 + -- tfmdata.format = bitmap and "type3" or "type1" tfmdata.format = "type1" tfmdata.tounicode = 1 tfmdata.embedding = "subset" @@ -548,24 +600,18 @@ end end ]] - local flushstreamobject = lpdf and lpdf.flushstreamobject - local setfontattributes = pdf.setfontattributes + local flushstreamobject = lpdf and lpdf.flushstreamobject -- context + local setfontattributes = lpdf and lpdf.setfontattributes -- context - if flushstreamobject then - -- we're in context - else + if not flushstreamobject then flushstreamobject = function(data) - return pdf.obj { - immediate = true, - type = "stream", - string = data, - } + return pdf.obj { immediate = true, type = "stream", string = data } -- generic end end if not setfontattributes then setfontattributes = function(id,data) - print(format("your luatex is too old so no tounicode bitmap font%i",id)) + return pdf.setfontattributes(id,data) -- generic end end @@ -593,7 +639,7 @@ end -- Now we implement the regular features handlers. We need to convert the -- tfm specific structures to opentype structures. In basemode they are --- converted back so that is a bti of a waste but it's fast enough. +-- converted back so that is a bit of a waste but it's fast enough. do |