summaryrefslogtreecommitdiff
path: root/src/luaotfload-resolvers.lua
diff options
context:
space:
mode:
Diffstat (limited to 'src/luaotfload-resolvers.lua')
-rw-r--r--src/luaotfload-resolvers.lua256
1 files changed, 256 insertions, 0 deletions
diff --git a/src/luaotfload-resolvers.lua b/src/luaotfload-resolvers.lua
new file mode 100644
index 0000000..42ea2fd
--- /dev/null
+++ b/src/luaotfload-resolvers.lua
@@ -0,0 +1,256 @@
+#!/usr/bin/env texlua
+-----------------------------------------------------------------------
+-- FILE: luaotfload-resolvers.lua
+-- USAGE: ./luaotfload-resolvers.lua
+-- DESCRIPTION: Resolvers for hooking into the fontloader
+-- REQUIREMENTS: Luaotfload and a decent bit of courage
+-- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net>
+-- VERSION: 1.0
+-- CREATED: 2015-07-23 07:31:50+0200
+-----------------------------------------------------------------------
+--
+--- The bare fontloader uses a set of simplistic file name resolvers
+--- that must be overloaded by the user (i. e. us).
+
+if not lualibs then error "this module requires Luaotfload" end
+if not luaotfload then error "this module requires Luaotfload" end
+
+--[[doc--
+
+ Relying on the \verb|name:| resolver for everything has been the
+ source of permanent trouble with the database.
+ With the introduction of the new syntax parser we now have enough
+ granularity to distinguish between the \XETEX emulation layer and
+ the genuine \verb|name:| and \verb|file:| lookups of \LUATEX-Fonts.
+ Another benefit is that we can now easily plug in or replace new
+ lookup behaviors if necessary.
+ The name resolver remains untouched, but it calls
+ \luafunction{fonts.names.resolve()} internally anyways (see
+ \fileent{luaotfload-database.lua}).
+
+--doc]]--
+
+local next = next
+local kpsefind_file = kpse.find_file
+local lfsisfile = lfs.isfile
+local stringlower = string.lower
+local stringformat = string.format
+local filesuffix = file.suffix
+local fileremovesuffix = file.removesuffix
+local formats = fonts.formats
+local names = fonts.names
+local encodings = fonts.encodings
+local luatexbase = luatexbase
+local logreport = luaotfload.log.report
+
+formats.ofm = "type1"
+encodings.known = encodings.known or { }
+
+--[[doc--
+
+ \identifier{luaotfload} promises easy access to system fonts.
+ Without additional precautions, this cannot be achieved by
+ \identifier{kpathsea} alone, because it searches only the
+ \fileent{texmf} directories by default.
+ Although it is possible for \identifier{kpathsea} to include extra
+ paths by adding them to the \verb|OSFONTDIR| environment variable,
+ this is still short of the goal »\emphasis{it just works!}«.
+ When building the font database \identifier{luaotfload} scans
+ system font directories anyways, so we already have all the
+ information for looking sytem fonts.
+ With the release version 2.2 the file names are indexed in the
+ database as well and we are ready to resolve \verb|file:| lookups
+ this way.
+ Thus we no longer need to call the \identifier{kpathsea} library in
+ most cases when looking up font files, only when generating the
+ database, and when verifying the existence of a file in the
+ \fileent{texmf} tree.
+
+--doc]]--
+
+local resolve_file
+resolve_file = function (specification)
+ local name = names.lookup_font_file (specification.name)
+ local suffix = filesuffix (name)
+ if formats[suffix] then
+ specification.forced = stringlower (suffix)
+ specification.forcedname = fileremovesuffix(name)
+ else
+ specification.name = name
+ end
+end
+
+--[[doc--
+
+ Prior to version 2.2, \identifier{luaotfload} did not distinguish
+ \verb|file:| and \verb|path:| lookups, causing complications with
+ the resolver.
+ Now we test if the requested name is an absolute path in the file
+ system, otherwise we fall back to the \verb|file:| lookup.
+
+--doc]]--
+
+local resolve_path
+resolve_path = function (specification)
+ local name = specification.name
+ local exists, _ = lfsisfile(name)
+ if not exists then -- resort to file: lookup
+ logreport ("log", 0, "load",
+ "path lookup of %q unsuccessful, falling back to file:",
+ name)
+ resolve_file (specification)
+ else
+ local suffix = filesuffix (name)
+ if formats[suffix] then
+ specification.forced = stringlower (suffix)
+ specification.name = fileremovesuffix(name)
+ specification.forcedname = name
+ else
+ specification.name = name
+ end
+ end
+end
+
+--[[doc--
+
+ The \verb|name:| resolver.
+
+--doc]]--
+
+--- fonts.names.resolvers.name -- Customized version of the
+--- generic name resolver.
+
+local resolve_name
+resolve_name = function (specification)
+ local resolver = names.lookup_font_name_cached
+ if config.luaotfload.run.resolver == "normal" then
+ resolver = names.lookup_font_name
+ end
+ local resolved, subfont = resolver (specification)
+ if resolved then
+ logreport ("log", 0, "load", "Lookup/name: %q -> \"%s%s\"",
+ specification.name,
+ resolved,
+ subfont and stringformat ("(%d)", subfont) or "")
+ specification.resolved = resolved
+ specification.sub = subfont
+ specification.forced = stringlower (filesuffix (resolved) or "")
+ specification.forcedname = resolved
+ specification.name = fileremovesuffix (resolved)
+ else
+ resolve_file (specification)
+ end
+end
+
+--[[doc--
+
+ We classify as \verb|anon:| those requests that have neither a
+ prefix nor brackets. According to Khaled\footnote{%
+ % XXX dead link‽
+ \url{https://github.com/phi-gamma/luaotfload/issues/4#issuecomment-17090553}.
+ }
+ they are the \XETEX equivalent of a \verb|name:| request, so we
+ will be treating them as such or, at least, in a similar fashion.
+
+ Not distinguishing between “anon” and “name” requests has a serious
+ drawback: The syntax is overloaded for requesting fonts in
+ \identifier{Type1} (\abbrev{tfm}, \abbrev{ofm}) format.
+ These are essentially \verb|file:| lookups and must be caught
+ before the \verb|name:| resolver kicks in, lest they cause the
+ database to update.
+ Even if we were to require the \verb|file:| prefix for all
+ \identifier{Type1} requests, tests have shown that certain fonts
+ still include further fonts (e.~g. \fileent{omlgcb.ofm} will ask
+ for \fileent{omsecob.tfm}) \emphasis{using the old syntax}.
+ For this reason, we introduce an extra check with an early return.
+
+--doc]]--
+
+local type1_formats = { "tfm", "ofm", "TFM", "OFM", }
+
+local resolve_anon
+resolve_anon = function (specification)
+ local name = specification.name
+ for i=1, #type1_formats do
+ local format = type1_formats[i]
+ local suffix = filesuffix (name)
+ if resolvers.findfile(name, format) then
+ local usename = suffix == format and fileremovesuffix (name) or name
+ specification.forcedname = file.addsuffix (usename, format)
+ specification.forced = format
+ return
+ end
+ end
+ --- under some weird circumstances absolute paths get
+ --- passed to the definer; we have to catch them
+ --- before the name: resolver misinterprets them.
+ name = specification.specification
+ local exists, _ = lfsisfile(name)
+ if exists then --- garbage; we do this because we are nice,
+ --- not because it is correct
+ logreport ("log", 1, "load", "file %q exists", name)
+ logreport ("log", 1, "load",
+ "... overriding borked anon: lookup with path: lookup")
+ specification.name = name
+ resolve_path (specification)
+ return
+ end
+ resolve_name (specification)
+end
+
+--[[doc--
+
+ {\bfseries EXPERIMENTAL}:
+ \identifier{kpse}-only resolver, for those who can do without
+ system fonts.
+
+--doc]]--
+
+local resolve_kpse
+resolve_kpse = function (specification)
+ local name = specification.name
+ local suffix = filesuffix (name)
+ if suffix and formats[suffix] then
+ name = fileremovesuffix (name)
+ if resolvers.findfile (name, suffix) then
+ specification.forced = stringlower (suffix)
+ specification.forcedname = name
+ return
+ end
+ end
+ for t, format in next, formats do --- brute force
+ if kpsefind_file (name, format) then
+ specification.forced = t
+ specification.name = name
+ return
+ end
+ end
+end
+
+--[[doc--
+
+ Also {\bfseries EXPERIMENTAL}: custom file resolvers via callback.
+
+--doc]]--
+
+local resolve_my = function (specification)
+ luatexbase.call_callback ("luaotfload.resolve_font", specification)
+end
+
+return {
+ install = function ( )
+ luatexbase.create_callback ("luaotfload.resolve_font", "simple", function () end)
+ logreport ("log", 5, "resolvers", "installing font resolvers", name)
+ local request_resolvers = fonts.definers.resolvers
+ request_resolvers.file = resolve_file
+ request_resolvers.name = resolve_name
+ request_resolvers.anon = resolve_anon
+ request_resolvers.path = resolve_path
+ request_resolvers.kpse = resolve_kpse
+ request_resolvers.my = resolve_my
+ return true
+ end, --- [.install]
+}
+
+--- vim:ft=lua:ts=8:sw=4:et
+