diff options
Diffstat (limited to 'otfl-font-def.lua')
-rw-r--r-- | otfl-font-def.lua | 360 |
1 files changed, 113 insertions, 247 deletions
diff --git a/otfl-font-def.lua b/otfl-font-def.lua index d56520b..533d1ec 100644 --- a/otfl-font-def.lua +++ b/otfl-font-def.lua @@ -27,44 +27,32 @@ default loader that only handles <l n='tfm'/>.</p> --ldx]]-- local fonts = fonts -local tfm = fonts.tfm -local vf = fonts.vf - -fonts.used = allocate() - -tfm.readers = tfm.readers or { } -tfm.fonts = allocate() - -local readers = tfm.readers -local sequence = allocate { 'otf', 'ttf', 'afm', 'tfm', 'lua' } -readers.sequence = sequence - -tfm.version = 1.01 -tfm.cache = containers.define("fonts", "tfm", tfm.version, false) -- better in font-tfm -tfm.autoprefixedafm = true -- this will become false some day (catches texnansi-blabla.*) - -fonts.definers = fonts.definers or { } +local fontdata = fonts.hashes.identifiers +local readers = fonts.readers local definers = fonts.definers +local specifiers = fonts.specifiers +local constructors = fonts.constructors -definers.specifiers = definers.specifiers or { } -local specifiers = definers.specifiers +readers.sequence = allocate { 'otf', 'ttf', 'afm', 'tfm', 'lua' } -- dfont ttc -specifiers.variants = allocate() -local variants = specifiers.variants +local variants = allocate() +specifiers.variants = variants -definers.method = "afm or tfm" -- afm, tfm, afm or tfm, tfm or afm definers.methods = definers.methods or { } -local findbinfile = resolvers.findbinfile +local internalized = allocate() -- internal tex numbers (private) + + +local loadedfonts = constructors.loadedfonts +local designsizes = constructors.designsizes --[[ldx-- <p>We hardly gain anything when we cache the final (pre scaled) -<l n='tfm'/> table. But it can be handy for debugging.</p> +<l n='tfm'/> table. But it can be handy for debugging, so we no +longer carry this code along. Also, we now have quite some reference +to other tables so we would end up with lots of catches.</p> --ldx]]-- -fonts.version = 1.05 -fonts.cache = containers.define("fonts", "def", fonts.version, false) - --[[ldx-- <p>We can prefix a font specification by <type>name:</type> or <type>file:</type>. The first case will result in a lookup in the @@ -131,7 +119,7 @@ function definers.registersplit(symbol,action,verbosename) end end -function definers.makespecification(specification, lookup, name, sub, method, detail, size) +function definers.makespecification(specification,lookup,name,sub,method,detail,size) size = size or 655360 if trace_defining then report_defining("%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s", @@ -163,84 +151,6 @@ function definers.analyze(specification, size) end --[[ldx-- -<p>A unique hash value is generated by:</p> ---ldx]]-- - -local sortedhashkeys = table.sortedhashkeys - -function tfm.hashfeatures(specification) - local features = specification.features - if features then - local t, tn = { }, 0 - local normal = features.normal - if normal and next(normal) then - local f = sortedhashkeys(normal) - for i=1,#f do - local v = f[i] - if v ~= "number" and v ~= "features" then -- i need to figure this out, features - tn = tn + 1 - t[tn] = v .. '=' .. tostring(normal[v]) - end - end - end - local vtf = features.vtf - if vtf and next(vtf) then - local f = sortedhashkeys(vtf) - for i=1,#f do - local v = f[i] - tn = tn + 1 - t[tn] = v .. '=' .. tostring(vtf[v]) - end - end - -- if specification.mathsize then - -- tn = tn + 1 - -- t[tn] = "mathsize=" .. specification.mathsize - -- end - if tn > 0 then - return concat(t,"+") - end - end - return "unknown" -end - -fonts.designsizes = allocate() - ---[[ldx-- -<p>In principle we can share tfm tables when we are in node for a font, but then -we need to define a font switch as an id/attr switch which is no fun, so in that -case users can best use dynamic features ... so, we will not use that speedup. Okay, -when we get rid of base mode we can optimize even further by sharing, but then we -loose our testcases for <l n='luatex'/>.</p> ---ldx]]-- - -function tfm.hashinstance(specification,force) - local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks - if force or not hash then - hash = tfm.hashfeatures(specification) - specification.hash = hash - end - if size < 1000 and fonts.designsizes[hash] then - size = math.round(tfm.scaled(size,fonts.designsizes[hash])) - specification.size = size - end - -- local mathsize = specification.mathsize or 0 - -- if mathsize > 0 then - -- local textsize = specification.textsize - -- if fallbacks then - -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ] @ ' .. fallbacks - -- else - -- return hash .. ' @ ' .. tostring(size) .. ' [ ' .. tostring(mathsize) .. ' : ' .. tostring(textsize) .. ' ]' - -- end - -- else - if fallbacks then - return hash .. ' @ ' .. tostring(size) .. ' @ ' .. fallbacks - else - return hash .. ' @ ' .. tostring(size) - end - -- end -end - ---[[ldx-- <p>We can resolve the filename using the next function:</p> --ldx]]-- @@ -260,7 +170,7 @@ end function resolvers.name(specification) local resolve = fonts.names.resolve if resolve then - local resolved, sub = fonts.names.resolve(specification) + local resolved, sub = fonts.names.resolve(specification.name,specification.sub) specification.resolved, specification.sub = resolved, sub if resolved then local suffix = file.suffix(resolved) @@ -279,7 +189,7 @@ end function resolvers.spec(specification) local resolvespec = fonts.names.resolvespec if resolvespec then - specification.resolved, specification.sub = fonts.names.resolvespec(specification) + specification.resolved, specification.sub = fonts.names.resolvespec(specification.name,specification.sub) if specification.resolved then specification.forced = file.extname(specification.resolved) specification.name = file.removesuffix(specification.resolved) @@ -304,13 +214,15 @@ function definers.resolve(specification) -- for the moment here (goodies set outside features) local goodies = specification.goodies if goodies and goodies ~= "" then - local normalgoodies = specification.features.normal.goodies - if not normalgoodies or normalgoodies == "" then - specification.features.normal.goodies = goodies + local normal = specification.features.normal + if not normal then + specification.features.normal = { goodies = goodies } + elseif not normal.goodies then + normal.goodies = goodies end end -- - specification.hash = lower(specification.name .. ' @ ' .. tfm.hashfeatures(specification)) + specification.hash = lower(specification.name .. ' @ ' .. constructors.hashfeatures(specification)) if specification.sub and specification.sub ~= "" then specification.hash = specification.sub .. ' @ ' .. specification.hash end @@ -333,26 +245,48 @@ features (esp in virtual fonts) so let's not do that now.</p> specification yet.</p> --ldx]]-- -function tfm.read(specification) - local hash = tfm.hashinstance(specification) - local tfmtable = tfm.fonts[hash] -- hashes by size ! - if not tfmtable then +-- not in context, at least not now: +-- +-- function definers.applypostprocessors(tfmdata) +-- local postprocessors = tfmdata.postprocessors +-- if postprocessors then +-- for i=1,#postprocessors do +-- local extrahash = postprocessors[i](tfmdata) -- after scaling etc +-- if type(extrahash) == "string" and extrahash ~= "" then +-- -- e.g. a reencoding needs this +-- extrahash = gsub(lower(extrahash),"[^a-z]","-") +-- tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash) +-- end +-- end +-- end +-- return tfmdata +-- end + +function definers.applypostprocessors(tfmdata) + return tfmdata +end + +function definers.loadfont(specification) + local hash = constructors.hashinstance(specification) + local tfmdata = loadedfonts[hash] -- hashes by size ! + if not tfmdata then local forced = specification.forced or "" if forced ~= "" then local reader = readers[lower(forced)] - tfmtable = reader and reader(specification) - if not tfmtable then + tfmdata = reader and reader(specification) + if not tfmdata then report_defining("forced type %s of %s not found",forced,specification.name) end else - for s=1,#sequence do -- reader sequence + local sequence = readers.sequence -- can be overloaded so only a shortcut here + for s=1,#sequence do local reader = sequence[s] - if readers[reader] then -- not really needed + if readers[reader] then -- we skip not loaded readers if trace_defining then report_defining("trying (reader sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown") end - tfmtable = readers[reader](specification) - if tfmtable then + tfmdata = readers[reader](specification) + if tfmdata then break else specification.filename = nil @@ -360,82 +294,56 @@ function tfm.read(specification) end end end - if tfmtable then + if tfmdata then + local properties = tfmdata.properties + local embedding if directive_embedall then - tfmtable.embedding = "full" - elseif tfmtable.filename and fonts.dontembed[tfmtable.filename] then - tfmtable.embedding = "no" + embedding = "full" + elseif properties.filename and constructors.dontembed[properties.filename] then + embedding = "no" else - tfmtable.embedding = "subset" + embedding = "subset" end - -- fonts.goodies.postprocessors.apply(tfmdata) -- only here - local postprocessors = tfmtable.postprocessors - if postprocessors then - for i=1,#postprocessors do - local extrahash = postprocessors[i](tfmtable) -- after scaling etc - if type(extrahash) == "string" and extrahash ~= "" then - -- e.g. a reencoding needs this - extrahash = gsub(lower(extrahash),"[^a-z]","-") - tfmtable.fullname = format("%s-%s",tfmtable.fullname,extrahash) - end - end + if properties then + properties.embedding = embedding + else + tfmdata.properties = { embedding = embedding } end - -- - tfm.fonts[hash] = tfmtable - fonts.designsizes[specification.hash] = tfmtable.designsize -- we only know this for sure after loading once - --~ tfmtable.mode = specification.features.normal.mode or "base" + tfmdata = definers.applypostprocessors(tfmdata) + loadedfonts[hash] = tfmdata + designsizes[specification.hash] = tfmdata.parameters.designsize end end - if not tfmtable then + if not tfmdata then report_defining("font with asked name '%s' is not found using lookup '%s'",specification.name,specification.lookup) end - return tfmtable + return tfmdata end --[[ldx-- <p>For virtual fonts we need a slightly different approach:</p> --ldx]]-- -function tfm.readanddefine(name,size) -- no id +function constructors.readanddefine(name,size) -- no id -- maybe a dummy first local specification = definers.analyze(name,size) local method = specification.method if method and variants[method] then specification = variants[method](specification) end specification = definers.resolve(specification) - local hash = tfm.hashinstance(specification) + local hash = constructors.hashinstance(specification) local id = definers.registered(hash) if not id then - local tfmdata = tfm.read(specification) + local tfmdata = definers.loadfont(specification) if tfmdata then - tfmdata.hash = hash + tfmdata.properties.hash = hash id = font.define(tfmdata) definers.register(tfmdata,id) - tfm.cleanuptable(tfmdata) else id = 0 -- signal end end - return fonts.identifiers[id], id -end - ---[[ldx-- -<p>We need to check for default features. For this we provide -a helper function.</p> ---ldx]]-- - -function definers.check(features,defaults) -- nb adapts features ! - local done = false - if features and next(features) then - for k,v in next, defaults do - if features[k] == nil then - features[k], done = v, true - end - end - else - features, done = table.fastcopy(defaults), true - end - return features, done -- done signals a change + return fontdata[id], id end --[[ldx-- @@ -457,42 +365,24 @@ function definers.current() -- or maybe current return lastdefined end -function definers.register(tfmdata,id) -- will be overloaded +function definers.registered(hash) + local id = internalized[hash] + return id, id and fontdata[id] +end + +function definers.register(tfmdata,id) if tfmdata and id then - local hash = tfmdata.hash + local hash = tfmdata.properties.hash if not internalized[hash] then + internalized[hash] = id if trace_defining then report_defining("registering font, id: %s, hash: %s",id or "?",hash or "?") end - fonts.identifiers[id] = tfmdata - internalized[hash] = id + fontdata[id] = tfmdata end end end -function definers.registered(hash) -- will be overloaded - local id = internalized[hash] - return id, id and fonts.identifiers[id] -end - -local cache_them = false - -function tfm.make(specification) - -- currently fonts are scaled while constructing the font, so we - -- have to do scaling of commands in the vf at that point using - -- e.g. "local scale = g.factor or 1" after all, we need to work - -- with copies anyway and scaling needs to be done at some point; - -- however, when virtual tricks are used as feature (makes more - -- sense) we scale the commands in fonts.tfm.scale (and set the - -- factor there) - local fvm = definers.methods.variants[specification.features.vtf.preset] - if fvm then - return fvm(specification) - else - return nil - end -end - function definers.read(specification,size,id) -- id can be optional, name can already be table statistics.starttiming(fonts) if type(specification) == "string" then @@ -503,75 +393,51 @@ function definers.read(specification,size,id) -- id can be optional, name can al specification = variants[method](specification) end specification = definers.resolve(specification) - local hash = tfm.hashinstance(specification) - if cache_them then - local tfmdata = containers.read(fonts.cache,hash) -- for tracing purposes - end + local hash = constructors.hashinstance(specification) local tfmdata = definers.registered(hash) -- id - if not tfmdata then - if specification.features.vtf and specification.features.vtf.preset then - tfmdata = tfm.make(specification) - else - tfmdata = tfm.read(specification) - if tfmdata then - tfm.checkvirtualid(tfmdata) - end - end - if cache_them then - tfmdata = containers.write(fonts.cache,hash,tfmdata) -- for tracing purposes + if tfmdata then + if trace_defining then + report_defining("already hashed: %s",hash) end + else + tfmdata = definers.loadfont(specification) -- can be overloaded if tfmdata then - tfmdata.hash = hash - tfmdata.cache = "no" + if trace_defining then + report_defining("loaded and hashed: %s",hash) + end + --~ constructors.checkvirtualid(tfmdata) -- interferes + tfmdata.properties.hash = hash if id then definers.register(tfmdata,id) end + else + if trace_defining then + report_defining("not loaded and hashed: %s",hash) + end end end lastdefined = tfmdata or id -- todo ! ! ! ! ! if not tfmdata then -- or id? report_defining( "unknown font %s, loading aborted",specification.name) elseif trace_defining and type(tfmdata) == "table" then + local properties = tfmdata.properties or { } + local parameters = tfmdata.parameters or { } report_defining("using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s", - tfmdata.type or "unknown", - id or "?", - tfmdata.name or "?", - tfmdata.size or "default", - tfmdata.encodingbytes or "?", - tfmdata.encodingname or "unicode", - tfmdata.fullname or "?", - file.basename(tfmdata.filename or "?")) + properties.format or "unknown", + id or "?", + properties.name or "?", + parameters.size or "default", + properties.encodingbytes or "?", + properties.encodingname or "unicode", + properties.fullname or "?", + file.basename(properties.filename or "?")) end statistics.stoptiming(fonts) return tfmdata end -function vf.find(name) - name = file.removesuffix(file.basename(name)) - if tfm.resolvevirtualtoo then - local format = fonts.logger.format(name) - if format == 'tfm' or format == 'ofm' then - if trace_defining then - report_defining("locating vf for %s",name) - end - return findbinfile(name,"ovf") - else - if trace_defining then - report_defining("vf for %s is already taken care of",name) - end - return nil -- "" - end - else - if trace_defining then - report_defining("locating vf for %s",name) - end - return findbinfile(name,"ovf") - end -end - --[[ldx-- -<p>We overload both the <l n='tfm'/> and <l n='vf'/> readers.</p> +<p>We overload the <l n='tfm'/> reader.</p> --ldx]]-- -callbacks.register('define_font' , definers.read, "definition of fonts (tfmtable preparation)") -callbacks.register('find_vf_file', vf.find, "locating virtual fonts, insofar needed") -- not that relevant any more +callbacks.register('define_font', definers.read, "definition of fonts (tfmdata preparation)") |