summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/font-def.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/font-def.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/font-def.lua747
1 files changed, 331 insertions, 416 deletions
diff --git a/Master/texmf-dist/tex/context/base/font-def.lua b/Master/texmf-dist/tex/context/base/font-def.lua
index af6f5f39460..28afe670b55 100644
--- a/Master/texmf-dist/tex/context/base/font-def.lua
+++ b/Master/texmf-dist/tex/context/base/font-def.lua
@@ -6,7 +6,13 @@ if not modules then modules = { } end modules ['font-def'] = {
license = "see context related readme files"
}
--- check reuse of lmroman1o-regular vs lmr10
+local format, concat, gmatch, match, find, lower = string.format, table.concat, string.gmatch, string.match, string.find, string.lower
+local tostring, next = tostring, next
+
+local trace_defining = false trackers.register("fonts.defining", function(v) trace_defining = v end)
+
+trackers.register("fonts.loading", "fonts.defining", "otf.loading", "afm.loading", "tfm.loading")
+trackers.register("fonts.all", "fonts.*", "otf.*", "afm.*", "tfm.*")
--[[ldx--
<p>Here we deal with defining fonts. We do so by intercepting the
@@ -16,40 +22,31 @@ default loader that only handles <l n='tfm'/>.</p>
fonts = fonts or { }
fonts.define = fonts.define or { }
fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
fonts.vf = fonts.vf or { }
fonts.used = fonts.used or { }
-fonts.tfm.version = 1.01
-fonts.tfm.cache = containers.define("fonts", "tfm", fonts.tfm.version, false) -- better in font-tfm
+local tfm = fonts.tfm
+local vf = fonts.vf
+local define = fonts.define
---[[ldx--
-<p>Choosing a font by name and specififying its size is only part of the
-game. In order to prevent complex commands, <l n='xetex'/> introduced
-a method to pass feature information as part of the font name. At the
-risk of introducing nasty parsing and compatinility problems, this
-syntax was expanded over time.</p>
-
-<p>For the sake of users who have defined fonts using that syntax, we
-will support it, but we will provide additional methods as well.
-Normally users will not use this direct way, but use a more abstract
-interface.</p>
- --ldx]]--
-
---~ name, kind, features = fonts.features.split_xetex("blabla / B : + lnum ; foo = bar ; - whatever ; whow ; + hans ; test = yes")
-
-fonts.define.method = 3 -- 1: tfm 2: tfm and if not then afm 3: afm and if not then tfm
-fonts.define.auto_afm = true
-fonts.define.auto_otf = true
-fonts.define.specify = fonts.define.specify or { }
-fonts.define.splitsymbols = ""
-fonts.define.methods = fonts.define.methods or { }
-
-fonts.tfm.fonts = fonts.tfm.fonts or { }
-fonts.tfm.readers = fonts.tfm.readers or { }
-fonts.tfm.internalized = fonts.tfm.internalized or { } -- internal tex numbers
-fonts.tfm.id = fonts.tfm.id or { } -- font data, maybe use just fonts.ids (faster lookup)
-
-fonts.tfm.readers.sequence = { 'otf', 'ttf', 'afm', 'tfm' }
+tfm.version = 1.01
+tfm.cache = containers.define("fonts", "tfm", tfm.version, false) -- better in font-tfm
+
+define.method = "afm or tfm" -- afm, tfm, afm or tfm, tfm or afm
+define.specify = fonts.define.specify or { }
+define.methods = fonts.define.methods or { }
+
+tfm.fonts = tfm.fonts or { }
+tfm.readers = tfm.readers or { }
+tfm.internalized = tfm.internalized or { } -- internal tex numbers
+
+tfm.readers.sequence = { 'otf', 'ttf', 'afm', 'tfm' }
+
+tfm.auto_afm = true
+
+local readers = tfm.readers
+local sequence = readers.sequence
--[[ldx--
<p>We hardly gain anything when we cache the final (pre scaled)
@@ -72,28 +69,52 @@ synonym table.</p>
and prepares a table that will move along as we proceed.</p>
--ldx]]--
-function fonts.define.analyze(name, size, id)
- name = name or 'unknown'
- local specification = name
- local lookup, rest = specification:match("^(.-):(.+)$")
- local sub = ""
- if lookup == 'file' or lookup == 'name' then
- name = rest
- else
- lookup = 'file'
- end
- local font, method, detail = name:match("^(.-)(["..fonts.define.splitsymbols.."])(.+)$")
- if method and detail then
- name = font
- else
- method, detail = "", ""
+-- beware, we discard additional specs
+--
+-- method:name method:name(sub) method:name(sub)*spec method:name*spec
+-- name name(sub) name(sub)*spec name*spec
+-- name@spec*oeps
+
+local splitter, specifiers = nil, ""
+
+function define.add_specifier(symbol)
+ specifiers = specifiers .. symbol
+ local left = lpeg.P("(")
+ local right = lpeg.P(")")
+ local colon = lpeg.P(":")
+ local method = lpeg.S(specifiers)
+ local lookup = lpeg.C(lpeg.P("file")+lpeg.P("name")) * colon -- hard test, else problems with : method
+ local sub = left * lpeg.C(lpeg.P(1-left-right-method)^1) * right
+--~ local specification = lpeg.C(method) * lpeg.C(lpeg.P(1-method)^1)
+ local specification = lpeg.C(method) * lpeg.C(lpeg.P(1)^1)
+ local name = lpeg.C((1-sub-specification)^1)
+ splitter = lpeg.P((lookup + lpeg.Cc("")) * name * (sub + lpeg.Cc("")) * (specification + lpeg.Cc("")))
+end
+
+function define.get_specification(str)
+ return splitter:match(str)
+end
+
+function define.register_split(symbol,action)
+ define.add_specifier(symbol)
+ define.specify[symbol] = action
+end
+
+function define.makespecification(specification, lookup, name, sub, method, detail, size)
+ size = size or 655360
+ if trace_defining then
+ logs.report("define font","%s -> lookup: %s, name: %s, sub: %s, method: %s, detail: %s",
+ specification, (lookup ~= "" and lookup) or "[file]", (name ~= "" and name) or "-",
+ (sub ~= "" and sub) or "-", (method ~= "" and method) or "-", (detail ~= "" and detail) or "-")
end
- local mainfont, subfont = name:match("^(.*-)(%(.*-)(%)$")
- if mainfont and subfont then
- name, sub = mainfont, subfont
+--~ if specification.lookup then
+--~ lookup = specification.lookup -- can come from xetex [] syntax
+--~ specification.lookup = nil
+--~ end
+ if lookup ~= 'name' then -- for the moment only two lookups, maybe some day also system:
+ lookup = 'file'
end
- size = size or (65536*10)
- return {
+ local t = {
lookup = lookup, -- forced type
specification = specification, -- full specification
size = size, -- size in scaled points or -1000*n
@@ -103,55 +124,55 @@ function fonts.define.analyze(name, size, id)
detail = detail, -- specification
resolved = "", -- resolved font name
forced = "", -- forced loader
- id = id, -- font id
features = { }, -- preprocessed features
- -- hash = nil
- -- filename = nil,
- -- encoding = nil,
- -- format = nil,
}
+ return t
end
-function fonts.define.register_split(symbol,action)
- fonts.define.splitsymbols = fonts.define.splitsymbols .. "%" .. symbol
- fonts.define.specify[symbol] = action
+function define.analyze(specification, size)
+ -- can be optimized with locals
+ local lookup, name, sub, method, detail = define.get_specification(specification or "")
+ return define.makespecification(specification,lookup, name, sub, method, detail, size)
end
--[[ldx--
<p>A unique hash value is generated by:</p>
--ldx]]--
-function fonts.tfm.hash_features(specification)
- if specification.features then
+local sortedhashkeys = table.sortedhashkeys
+
+function tfm.hash_features(specification)
+ local features = specification.features
+ if features then
local t = { }
- local normal = specification.features.normal
- if not table.is_empty(normal) then
- for _, v in pairs(table.sortedkeys(normal)) do
- if v ~= "number" then
+ 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
t[#t+1] = v .. '=' .. tostring(normal[v])
end
end
end
- local vtf = specification.features.vtf
- if not table.is_empty(vtf) then
- for _, v in pairs(table.sortedkeys(vtf)) do
+ local vtf = features.vtf
+ if vtf and next(vtf) then
+ local f = sortedhashkeys(vtf)
+ for i=1,#f do
+ local v = f[i]
t[#t+1] = v .. '=' .. tostring(vtf[v])
end
end
- if next(t) then
- return table.concat(t,"+")
+--~ if specification.mathsize then
+--~ t[#t+1] = "mathsize=" .. specification.mathsize
+--~ end
+ if #t > 0 then
+ return concat(t,"+")
end
end
return "unknown"
end
---~ function fonts.tfm.hash_instance(specification)
---~ if not specification.hash then
---~ specification.hash = fonts.tfm.hash_features(specification)
---~ end
---~ return specification.hash .. ' @ ' .. tostring(specification.size)
---~ end
-
fonts.designsizes = { }
--[[ldx--
@@ -162,38 +183,57 @@ when we get rid of base mode we can optimize even further by sharing, but then w
loose our testcases for <l n='luatex'/>.</p>
--ldx]]--
-function fonts.tfm.hash_instance(specification,force)
- local hash, size = specification.hash, specification.size
+function tfm.hash_instance(specification,force)
+ local hash, size, fallbacks = specification.hash, specification.size, specification.fallbacks
if force or not hash then
- hash = fonts.tfm.hash_features(specification)
+ hash = tfm.hash_features(specification)
specification.hash = hash
end
if size < 1000 and fonts.designsizes[hash] then
- size = fonts.tfm.scaled(size, fonts.designsizes[hash])
+ size = math.round(tfm.scaled(size, fonts.designsizes[hash]))
specification.size = size
end
- return hash .. ' @ ' .. tostring(size)
+--~ 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]]--
-function fonts.define.resolve(specification)
- if specification.lookup == 'name' then
- specification.resolved, specification.sub = fonts.names.resolve(specification.name,specification.sub)
- if specification.resolved then
- specification.forced = file.extname(specification.resolved)
- specification.name = file.removesuffix(specification.resolved)
+function define.resolve(specification)
+ if not specification.resolved or specification.resolved == "" then -- resolved itself not per se in mapping hash
+ if specification.lookup == 'name' then
+ specification.resolved, specification.sub = fonts.names.resolve(specification.name,specification.sub)
+ if specification.resolved then
+ specification.forced = file.extname(specification.resolved)
+ specification.name = file.removesuffix(specification.resolved)
+ end
+ elseif specification.lookup == 'file' then
+ specification.forced = file.extname(specification.name)
+ specification.name = file.removesuffix(specification.name)
end
- elseif specification.lookup == 'file' then
- specification.forced = file.extname(specification.name)
- specification.name = file.removesuffix(specification.name)
end
if specification.forced == "" then
specification.forced = nil
+ else
+ specification.forced = specification.forced
end
- specification.hash = specification.name .. ' @ ' .. fonts.tfm.hash_features(specification)
+--~ specification.hash = specification.name .. ' @ ' .. tfm.hash_features(specification)
+ specification.hash = lower(specification.name .. ' @ ' .. tfm.hash_features(specification))
if specification.sub and specification.sub ~= "" then
specification.hash = specification.sub .. ' @ ' .. specification.hash
end
@@ -216,25 +256,29 @@ features (esp in virtual fonts) so let's not do that now.</p>
specification yet.</p>
--ldx]]--
-function fonts.tfm.read(specification)
- garbagecollector.push()
- input.starttiming(fonts)
- local hash = fonts.tfm.hash_instance(specification)
- local tfmtable = fonts.tfm.fonts[hash] -- hashes by size !
+function tfm.read(specification)
+ local hash = tfm.hash_instance(specification)
+ local tfmtable = tfm.fonts[hash] -- hashes by size !
if not tfmtable then
- if specification.forced and specification.forced ~= "" then
- tfmtable = fonts.tfm.readers[specification.forced](specification)
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = readers[lower(forced)](specification)
if not tfmtable then
- logs.error("define font",string.format("forced type %s of %s not found",specification.forced,specification.name))
+ logs.report("define font","forced type %s of %s not found",forced,specification.name)
end
else
- for _, reader in ipairs(fonts.tfm.readers.sequence) do
- if fonts.tfm.readers[reader] then -- not really needed
- if fonts.trace then
- logs.report("define font",string.format("trying type %s for %s with file %s",reader,specification.name,specification.filename or "unknown"))
+ for s=1,#sequence do -- reader sequence
+ local reader = sequence[s]
+ if readers[reader] then -- not really needed
+ if trace_defining then
+ logs.report("define font","trying (sequence driven) type %s for %s with file %s",reader,specification.name,specification.filename or "unknown")
+ end
+ tfmtable = readers[reader](specification)
+ if tfmtable then
+ break
+ else
+ specification.filename = nil
end
- tfmtable = fonts.tfm.readers[reader](specification)
- if tfmtable then break end
end
end
end
@@ -244,15 +288,13 @@ function fonts.tfm.read(specification)
else
tfmtable.embedding = "subset"
end
- fonts.tfm.fonts[hash] = tfmtable
+ 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"
end
end
- input.stoptiming(fonts)
- garbagecollector.pop()
if not tfmtable then
- logs.error("define font",string.format("font with name %s is not found",specification.name))
+ logs.report("define font","font with name %s is not found",specification.name)
end
return tfmtable
end
@@ -261,319 +303,159 @@ end
<p>For virtual fonts we need a slightly different approach:</p>
--ldx]]--
-function fonts.tfm.read_and_define(name,size) -- no id
- local specification = fonts.define.analyze(name,size,nil)
- if specification.method and fonts.define.specify[specification.method] then
- specification = fonts.define.specify[specification.method](specification)
+function tfm.read_and_define(name,size) -- no id
+ local specification = define.analyze(name,size)
+ local method = specification.method
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
end
- specification = fonts.define.resolve(specification)
- local hash = fonts.tfm.hash_instance(specification)
- local id = fonts.tfm.internalized[hash]
+ specification = define.resolve(specification)
+ local hash = tfm.hash_instance(specification)
+ local id = define.registered(hash)
if not id then
- local fontdata = fonts.tfm.read(specification)
+ local fontdata = tfm.read(specification)
if fontdata then
- if not fonts.tfm.internalized[hash] then
- id = font.define(fontdata)
- fonts.tfm.id[id] = fontdata
- fonts.tfm.internalized[hash] = id
- if fonts.trace then
- logs.report("define font", string.format("loading at 1 id %s, hash: %s",id,hash))
- end
- else
- id = fonts.tfm.internalized[hash]
- end
+ fontdata.hash = hash
+ id = font.define(fontdata)
+ define.register(fontdata,id)
+ tfm.cleanup_table(fontdata)
else
id = 0 -- signal
end
end
- return fonts.tfm.id[id], id
+ return fonts.ids[id], id
end
--[[ldx--
-<p>A naive callback could be the following:</p>
-
-<code>
-callback.register('define_font', function(name,size,id)
- return fonts.define.read(fonts.define.resolve(fonts.define.analyze(name,size,id)))
-end)
-</code>
---ldx]]--
-
-
---[[ldx--
<p>Next follow the readers. This code was written while <l n='luatex'/>
evolved. Each one has its own way of dealing with its format.</p>
--ldx]]--
-function fonts.tfm.readers.opentype(specification,suffix,what)
- if fonts.define.auto_otf then
- local fullname, tfmtable = nil, nil
- fullname = input.findbinfile(texmf.instance,specification.name,suffix) or ""
- if fullname == "" then
- local fb = fonts.names.old_to_new[specification.name]
- if fb then
- fullname = input.findbinfile(texmf.instance,fb,suffix) or ""
- end
- end
- if fullname == "" then
- local fb = fonts.names.new_to_old[specification.name]
- if fb then
- fullname = input.findbinfile(texmf.instance,fb,suffix) or ""
- end
- end
- if fullname ~= "" then
- specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
- tfmtable = fonts.tfm.read_from_open_type(specification) -- we need to do it for all matches / todo
- end
- return tfmtable
- else
- return nil
+local function check_tfm(specification,fullname)
+ -- ofm directive blocks local path search unless set; btw, in context we
+ -- don't support ofm files anyway as this format is obsolete
+ local foundname = resolvers.findbinfile(fullname, 'tfm') or "" -- just to be sure
+ if foundname == "" then
+ foundname = resolvers.findbinfile(fullname, 'ofm') or "" -- bonus for usage outside context
end
-end
-
-function fonts.tfm.readers.otf(specification) return fonts.tfm.readers.opentype(specification,"otf","opentype") end
-function fonts.tfm.readers.ttf(specification) return fonts.tfm.readers.opentype(specification,"ttf","truetype") end
-function fonts.tfm.readers.ttc(specification) return fonts.tfm.readers.opentype(specification,"ttf","truetype") end -- !!
-
-function fonts.tfm.readers.afm(specification,method)
- local fullname, tfmtable = nil, nil
- method = method or fonts.define.method
- if method == 2 then
- fullname = input.findbinfile(texmf.instance,specification.name,"ofm") or ""
- if fullname == "" then
- tfmtable = fonts.tfm.read_from_afm(specification)
- else -- redundant
- specification.filename = fullname
- tfmtable = fonts.tfm.read_from_tfm(specification)
- end
- elseif method == 3 then -- maybe also findbinfile here
- if fonts.define.auto_afm then
- tfmtable = fonts.tfm.read_from_afm(specification)
- end
- elseif method == 4 then -- maybe also findbinfile here
- tfmtable = fonts.tfm.read_from_afm(specification)
- end
- return tfmtable
-end
-
-function fonts.tfm.readers.tfm(specification)
- local fullname, tfmtable = nil, nil
- tfmtable = fonts.tfm.read_from_tfm(specification)
- return tfmtable
-end
-
---[[ldx--
-<p>So far we haven't really dealt with features (or whatever we want
-to pass along with the font definition. We distinguish the following
-situations:</p>
-situations:</p>
-
-<code>
-name:xetex like specs
-name@virtual font spec
-name*context specification
-</code>
-
-<p>Of course one can always define more.</p>
---ldx]]--
-
-function fonts.define.specify.predefined(specification)
- if specification.detail ~= "" and fonts.define.methods[specification.detail] then
- specification.features.vtf = { preset = specification.detail }
+ if foundname ~= "" then
+ specification.filename, specification.format = foundname, "ofm"
+ return tfm.read_from_tfm(specification)
end
- return specification
end
-fonts.define.register_split("@", fonts.define.specify.predefined)
-
-function fonts.define.specify.colonized(specification) -- xetex mode
- local list = { }
- if specification.detail and specification.detail ~= "" then
- local expanded_features = { }
- local function expand(features)
- for _,v in pairs(features:split(";")) do
- expanded_features[#expanded_features+1] = v
- end
- end
- expand(specification.detail)
- for _,v in pairs(expanded_features) do
- local a, b = v:match("^%s*(%S+)%s*=%s*(%S+)%s*$")
- if a and b then
- list[a] = b:is_boolean()
- if type(list[a]) == "nil" then
- list[a] = b
- end
- else
- local a, b = v:match("^%s*([%+%-]?)%s*(%S+)%s*$")
- if a and b then
- list[b] = a ~= "-"
+local function check_afm(specification,fullname)
+ local foundname = resolvers.findbinfile(fullname, 'afm') or "" -- just to be sure
+ if foundname == "" and tfm.auto_afm then
+ local encoding, shortname = match(fullname,"^(.-)%-(.*)$") -- context: encoding-name.*
+ if encoding and shortname and fonts.enc.known[encoding] then
+ shortname = resolvers.findbinfile(shortname,'afm') or "" -- just to be sure
+ if shortname ~= "" then
+ foundname = shortname
+ -- tfm.set_normal_feature(specification,'encoding',encoding) -- will go away
+ if trace_loading then
+ logs.report("load afm","stripping encoding prefix from filename %s",afmname)
end
end
end
end
- specification.features.normal = list
- return specification
+ if foundname ~= "" then
+ specification.filename, specification.format = foundname, "afm"
+ return tfm.read_from_afm(specification)
+ end
end
-function fonts.tfm.make(specification)
- local fvm = fonts.define.methods[specification.features.vtf.preset]
- if fvm then
- return fvm(specification)
+function readers.tfm(specification)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_tfm(specification,specification.name .. "." .. forced)
+ end
+ if not tfmtable then
+ tfmtable = check_tfm(specification,specification.name)
+ end
else
- return nil
+ tfmtable = check_tfm(specification,fullname)
end
+ return tfmtable
end
-fonts.define.register_split(":", fonts.define.specify.colonized)
-
-fonts.define.specify.context_setups = fonts.define.specify.context_setups or { }
-fonts.define.specify.context_numbers = fonts.define.specify.context_numbers or { }
-fonts.define.specify.synonyms = fonts.define.specify.synonyms or { }
-
-input.storage.register(false,"fonts/setups" , fonts.define.specify.context_setups , "fonts.define.specify.context_setups" )
-input.storage.register(false,"fonts/numbers", fonts.define.specify.context_numbers, "fonts.define.specify.context_numbers")
-
---~ local t = aux.settings_to_hash(features)
---~ for k,v in pairs(t) do
---~ k = synonyms[k] or k
---~ t[k] = v:is_boolean()
---~ if type(t[k]) == "nil" then
---~ t[k] = v
---~ end
---~ end
-
-fonts.triggers = fonts.triggers or { }
-
-function fonts.define.specify.preset_context(name,parent,features)
- if features == "" then
- if parent:find("=") then
- features = parent
- parent = ""
+function readers.afm(specification,method)
+ local fullname, tfmtable = specification.filename or "", nil
+ if fullname == "" then
+ local forced = specification.forced or ""
+ if forced ~= "" then
+ tfmtable = check_afm(specification,specification.name .. "." .. forced)
end
- end
- local fds = fonts.define.specify
- local setups, numbers, synonyms = fds.context_setups, fds.context_numbers, fds.synonyms
- local number = (setups[name] and setups[name].number) or 0
- local t = (features == "" and { }) or fonts.otf.meanings.normalize(aux.settings_to_hash(features))
- -- todo: synonyms, and not otf bound
- if parent ~= "" then
- for p in parent:gmatch("[^, ]+") do
- local s = setups[p]
- if s then
- for k,v in pairs(s) do
- if t[k] == nil then
- t[k] = v
- end
- end
+ if not tfmtable then
+ method = method or define.method or "afm or tfm"
+ if method == "tfm" then
+ tfmtable = check_tfm(specification,specification.name)
+ elseif method == "afm" then
+ tfmtable = check_afm(specification,specification.name)
+ elseif method == "tfm or afm" then
+ tfmtable = check_tfm(specification,specification.name) or check_afm(specification,specification.name)
+ else -- method == "afm or tfm" or method == "" then
+ tfmtable = check_afm(specification,specification.name) or check_tfm(specification,specification.name)
end
end
- end
- -- these are auto set so in order to prevent redundant definitions
- -- we need to preset them (we hash the features and adding a default
- -- setting during initialization may result in a different hash)
- local default = fonts.otf.features.default
- for k,v in pairs(fonts.triggers) do
- if type(t[v]) == "nil" then
- local vv = default[v]
- if vv then t[v] = vv end
- end
- end
- -- sparse 'm so that we get a better hash and less test (experimental
- -- optimization)
- local tt = { }
- for k,v in pairs(t) do
- if v then tt[k] = v end
- end
- -- needed for dynamic features
- if number == 0 then
- numbers[#numbers+1] = name
- tt.number = #numbers
else
- tt.number = number
+ tfmtable = check_afm(specification,fullname)
end
- setups[name] = tt
+ return tfmtable
end
---~ function fonts.define.specify.context_number(name)
---~ local s = fonts.define.specify.context_setups[name]
---~ return (s and s.number) or -1
---~ end
-
-do
-
- -- here we clone features according to languages
-
- local default = 0
- local setups = fonts.define.specify.context_setups
- local numbers = fonts.define.specify.context_numbers
-
- function fonts.define.specify.context_number(name)
- local t = setups[name]
- if not t then
- return default
- elseif t.auto then
- local lng = tonumber(tex.language)
- local tag = name .. ":" .. lng
- local s = setups[tag]
- if s then
- return s.number or default
- else
- local script, language = languages.association(lng)
- if t.script ~= script or t.language ~= language then
- local s = table.fastcopy(t)
- local n = #numbers + 1
- setups[tag] = s
- numbers[n] = tag
- s.number = n
- s.script = script
- s.language = language
- return n
- else
- setups[tag] = t
- return t.number or default
- end
- end
- else
- return t.number or default
+local function check_otf(specification,suffix,what)
+ local fullname, tfmtable = resolvers.findbinfile(specification.name,suffix) or "", nil
+ if fullname == "" then
+ local fb = fonts.names.old_to_new[specification.name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
end
end
-
-end
-
-function fonts.define.specify.context_tostring(name,kind,separator,yes,no,strict,omit)
- return aux.hash_to_string(table.merged(fonts[kind].features.default or {},fonts.define.specify.context_setups[name] or {}),separator,yes,no,strict,omit)
-end
-
-function fonts.define.specify.split_context(features)
- if fonts.define.specify.context_setups[features] then
- return fonts.define.specify.context_setups[features]
- else -- ? ? ?
- return fonts.define.specify.preset_context("***",features)
+ if fullname == "" then
+ local fb = fonts.names.new_to_old[specification.name]
+ if fb then
+ fullname = resolvers.findbinfile(fb,suffix) or ""
+ end
end
+ if fullname ~= "" then
+ specification.filename, specification.format = fullname, what -- hm, so we do set the filename, then
+ tfmtable = tfm.read_from_open_type(specification) -- we need to do it for all matches / todo
+ end
+ return tfmtable
end
-function fonts.define.specify.starred(features)
- if features.detail and features.detail ~= "" then
- features.features.normal = fonts.define.specify.split_context(features.detail)
+function readers.opentype(specification,suffix,what)
+ local forced = specification.forced or ""
+ if forced == "otf" then
+ return check_otf(specification,forced,"opentype")
+ elseif forced == "ttf" then
+ return check_otf(specification,forced,"truetype")
+ elseif forced == "ttf" then
+ return check_otf(specification,forced,"truetype")
else
- features.features.normal = { }
+ return check_otf(specification,suffix,what)
end
- return features
end
-fonts.define.register_split('*',fonts.define.specify.starred)
+function readers.otf (specification) return readers.opentype(specification,"otf","opentype") end
+function readers.ttf (specification) return readers.opentype(specification,"ttf","truetype") end
+function readers.ttc (specification) return readers.opentype(specification,"ttf","truetype") end -- !!
+function readers.dfont(specification) return readers.opentype(specification,"ttf","truetype") end -- !!
--[[ldx--
<p>We need to check for default features. For this we provide
a helper function.</p>
--ldx]]--
-function fonts.define.check(features,defaults) -- nb adapts features !
+function define.check(features,defaults) -- nb adapts features !
local done = false
if table.is_empty(features) then
features, done = table.fastcopy(defaults), true
else
- for k,v in pairs(defaults) do
+ for k,v in next, defaults do
if features[k] == nil then
features[k], done = v, true
end
@@ -594,43 +476,84 @@ not gain much. By the way, passing id's back to in the callback was
introduced later in the development.</p>
--ldx]]--
-function fonts.define.read(name,size,id)
- local specification = fonts.define.analyze(name,size,id)
- if specification.method and fonts.define.specify[specification.method] then
- specification = fonts.define.specify[specification.method](specification)
+define.last = nil
+
+function define.register(fontdata,id)
+ if fontdata and id then
+ local hash = fontdata.hash
+ if not tfm.internalized[hash] then
+ if trace_defining then
+ logs.report("define font","loading at 2 id %s, hash: %s",id or "?",hash or "?")
+ end
+ fonts.ids[id] = fontdata
+ tfm.internalized[hash] = id
+ end
end
- specification = fonts.define.resolve(specification)
- local hash = fonts.tfm.hash_instance(specification)
- if true then
- --~ local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes
+end
+
+function define.registered(hash)
+ local id = tfm.internalized[hash]
+ return id, id and fonts.ids[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 = define.methods[specification.features.vtf.preset]
+ if fvm then
+ return fvm(specification)
+ else
+ return nil
+ end
+end
+
+function define.read(specification,size,id) -- id can be optional, name can already be table
+ statistics.starttiming(fonts)
+ if type(specification) == "string" then
+ specification = define.analyze(specification,size)
+ end
+ local method = specification.method
+ if method and define.specify[method] then
+ specification = define.specify[method](specification)
+ end
+ specification = define.resolve(specification)
+ local hash = tfm.hash_instance(specification)
+ if cache_them then
+ local fontdata = containers.read(fonts.cache(),hash) -- for tracing purposes
end
- local fontdata = fonts.tfm.internalized[hash] -- id
+ local fontdata = define.registered(hash) -- id
if not fontdata then
if specification.features.vtf and specification.features.vtf.preset then
- fontdata = fonts.tfm.make(specification)
+ fontdata = tfm.make(specification)
else
- fontdata = fonts.tfm.read(specification)
+ fontdata = tfm.read(specification)
if fontdata then
- fonts.tfm.check_virtual_id(fontdata)
+ tfm.check_virtual_id(fontdata)
end
end
- if true then
- --~ fontdata = containers.write(fonts.cache(),hash,fontdata) -- for tracing purposes
+ if cache_them then
+ fontdata = containers.write(fonts.cache(),hash,fontdata) -- for tracing purposes
end
- if not fonts.tfm.internalized[hash] then
- fonts.tfm.id[id] = fontdata
- fonts.tfm.internalized[hash] = id
- if fonts.trace then
- logs.report("define font", string.format("loading at 2 id %s, hash: %s",id,hash))
+ if fontdata then
+ fontdata.hash = hash
+ fontdata.cache = "no"
+ if id then
+ define.register(fontdata,id)
end
- else
- fontdata = fonts.tfm.internalized[hash]
end
end
+ define.last = fontdata or id -- todo ! ! ! ! !
if not fontdata then
- logs.error("define font", string.format("unknown font %s, loading aborted",specification.name))
- elseif fonts.trace and type(fontdata) == "table" then
- logs.report("define font",string.format("using %s font with id %s, n:%s s:%s b:%s e:%s p:%s f:%s",
+ logs.report("define font", "unknown font %s, loading aborted",specification.name)
+ elseif trace_defining and type(fontdata) == "table" then
+ logs.report("define font","using %s font with id %s, name:%s size:%s bytes:%s encoding:%s fullname:%s filename:%s",
fontdata.type or "unknown",
id or "?",
fontdata.name or "?",
@@ -638,41 +561,33 @@ function fonts.define.read(name,size,id)
fontdata.encodingbytes or "?",
fontdata.encodingname or "unicode",
fontdata.fullname or "?",
- file.basename(fontdata.filename or "?")))
+ file.basename(fontdata.filename or "?"))
+
end
+ statistics.stoptiming(fonts)
return fontdata
end
---~ table.insert(fonts.tfm.readers.sequence,1,'vtf')
-
---~ function fonts.tfm.readers.vtf(specification)
---~ if specification.features.vtf and specification.features.vtf.preset then
---~ return fonts.tfm.make(specification)
---~ else
---~ return nil
---~ end
---~ end
-
-function fonts.vf.find(name)
+function vf.find(name)
name = file.removesuffix(file.basename(name))
- if fonts.tfm.resolve_vf then
+ if tfm.resolve_vf then
local format = fonts.logger.format(name)
if format == 'tfm' or format == 'ofm' then
- if fonts.trace then
- logs.report("define font",string.format("locating vf for %s",name))
+ if trace_defining then
+ logs.report("define font","locating vf for %s",name)
end
- return input.findbinfile(texmf.instance,name,"ovf")
+ return resolvers.findbinfile(name,"ovf")
else
- if fonts.trace then
- logs.report("define font",string.format("vf for %s is already taken care of",name))
+ if trace_defining then
+ logs.report("define font","vf for %s is already taken care of",name)
end
return nil -- ""
end
else
- if fonts.trace then
- logs.report("define font",string.format("locating vf for %s",name))
+ if trace_defining then
+ logs.report("define font","locating vf for %s",name)
end
- return input.findbinfile(texmf.instance,name,"ovf")
+ return resolvers.findbinfile(name,"ovf")
end
end
@@ -680,5 +595,5 @@ end
<p>We overload both the <l n='tfm'/> and <l n='vf'/> readers.</p>
--ldx]]--
-callback.register('define_font' , fonts.define.read)
-callback.register('find_vf_file', fonts.vf.find ) -- not that relevant any more
+callback.register('define_font' , define.read)
+callback.register('find_vf_file', vf.find ) -- not that relevant any more