From 0acf9a04ff947deb9c7593e4ed87efab5d0e98a7 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 23 Jul 2015 08:14:18 +0200 Subject: [main,init,db,resolvers] separate resolvers from main into separate file --- src/luaotfload-database.lua | 63 +++++------ src/luaotfload-init.lua | 2 + src/luaotfload-main.lua | 234 +-------------------------------------- src/luaotfload-resolvers.lua | 256 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 295 insertions(+), 260 deletions(-) create mode 100644 src/luaotfload-resolvers.lua (limited to 'src') diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index 1831ca3..381185b 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -454,22 +454,19 @@ end --- define locals in scope local access_font_index local collect_families -local font_file_lookup local find_closest local flush_lookup_cache local generate_filedata local get_font_filter local group_modifiers -local load_lookups local load_names +local lookup_font_name local getmetadata local order_design_sizes local ot_fullinfo local read_blacklist local reload_db -local resolve_cached -local resolve_fullpath -local resolve_name +local lookup_fullpath local save_lookups local save_names local set_font_filter @@ -558,6 +555,7 @@ getmetadata = function () end --- unit -> unit +local load_lookups load_lookups = function ( ) local foundname, data = load_lua_file(config.luaotfload.paths.lookup_path_lua) if data then @@ -638,7 +636,7 @@ end --[[doc-- - font_file_lookup -- The ``file:`` are ultimately delegated here. + lookup_font_file -- The ``file:`` are ultimately delegated here. The lookups are kind of a blunt instrument since they try locating the file using every conceivable method, which is quite inefficient. Nevertheless, resolving files that way is rarely the @@ -647,7 +645,8 @@ end --doc]]-- --- string -> string * string * bool -font_file_lookup = function (filename) +local lookup_font_file +lookup_font_file = function (filename) local found = lookup_filename (filename) if not found then @@ -667,7 +666,7 @@ font_file_lookup = function (filename) if not fonts_reloaded and config.luaotfload.db.update_live == true then return reload_db (stringformat ("File not found: %s.", filename), - font_file_lookup, + lookup_font_file, filename) end return filename, nil, false @@ -715,7 +714,7 @@ font managment we have to check both the system path and the texmf. --doc]]-- local verify_font_file = function (basename) - local path = resolve_fullpath (basename) + local path = lookup_fullpath (basename) if path and lfsisfile(path) then return true end @@ -748,7 +747,7 @@ Idk what the “spec” resolver is for. spec: name, sub resolved, sub, name, forced [*] name: contains both the name resolver from luatex-fonts and - resolve_name() below + lookup_font_name () below From my reading of font-def.lua, what a resolver does is basically rewrite the “name” field of the specification record @@ -777,7 +776,8 @@ local hash_request = function (specification) end --- 'a -> 'a -> table -> (string * int|boolean * boolean) -resolve_cached = function (specification) +local lookup_font_name_cached +lookup_font_name_cached = function (specification) if not lookup_cache then load_lookups () end local request = hash_request(specification) report("both", 4, "cache", "Looking for %q in cache ...", @@ -801,7 +801,7 @@ resolve_cached = function (specification) --- case 2) cache negative ---------------------------------------- --- first we resolve normally ... - local filename, subfont = resolve_name (specification) + local filename, subfont = lookup_font_name (specification) if not filename then return nil, nil end @@ -935,13 +935,13 @@ end --[[doc-- - resolve_familyname -- Query the families table for an entry + lookup_familyname -- Query the families table for an entry matching the specification. The parameters “name” and “style” are pre-sanitized. --doc]]-- --- spec -> string -> string -> int -> string * int -local resolve_familyname = function (specification, name, style, askedsize) +local lookup_familyname = function (specification, name, style, askedsize) local families = name_index.families local mappings = name_index.mappings local candidates = nil @@ -978,7 +978,7 @@ local resolve_familyname = function (specification, name, style, askedsize) return resolved, subfont end -local resolve_fontname = function (specification, name, style) +local lookup_fontname = function (specification, name, style) local mappings = name_index.mappings local fallback = nil local lastresort = nil @@ -1021,7 +1021,7 @@ end --[[doc-- - resolve_name -- Perform a name: lookup. This first queries the + lookup_font_name -- Perform a name: lookup. This first queries the font families table and, if there is no match for the spec, the font names table. The return value is a pair consisting of the file name and the @@ -1059,7 +1059,7 @@ end multiple design sizes to a given font/style combination, we put a workaround in place that chooses that unmarked version. - The first return value of “resolve_name” is the file name of the + The first return value of “lookup_font_name” is the file name of the requested font (string). It can be passed to the fullname resolver get_font_file(). The second value is either “false” or an integer indicating the @@ -1068,7 +1068,7 @@ end --doc]]-- --- table -> string * (int | bool) -resolve_name = function (specification) +lookup_font_name = function (specification) local resolved, subfont if not name_index then name_index = load_names () end local name = sanitize_fontname (specification.name) @@ -1086,28 +1086,28 @@ resolve_name = function (specification) end end - resolved, subfont = resolve_familyname (specification, - name, - style, - askedsize) + resolved, subfont = lookup_familyname (specification, + name, + style, + askedsize) if not resolved then - resolved, subfont = resolve_fontname (specification, - name, - style) + resolved, subfont = lookup_fontname (specification, + name, + style) end if not resolved then if not fonts_reloaded and config.luaotfload.db.update_live == true then return reload_db (stringformat ("Font %s not found.", specification.name or ""), - resolve_name, + lookup_font_name, specification) end end return resolved, subfont end -resolve_fullpath = function (fontname, ext) --- getfilename() +lookup_fullpath = function (fontname, ext) --- getfilename() if not name_index then name_index = load_names () end local files = name_index.files local basedata = files.base @@ -3449,17 +3449,18 @@ names.access_font_index = access_font_index names.data = function () return name_index end names.save = save_names names.update = update_names -names.font_file_lookup = font_file_lookup +names.lookup_font_file = lookup_font_file +names.lookup_font_name = lookup_font_name +names.lookup_font_name_cached = lookup_font_name_cached +names.getfilename = lookup_fullpath +names.lookup_fullpath = lookup_fullpath names.read_blacklist = read_blacklist names.sanitize_fontname = sanitize_fontname -names.getfilename = resolve_fullpath names.getmetadata = getmetadata names.set_location_precedence = set_location_precedence names.count_font_files = count_font_files names.nth_font_filename = nth_font_filename names.font_slice = font_slice -names.resolve_cached = resolve_cached -names.resolve_name = resolve_name --- font cache names.purge_cache = purge_cache diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index 0ef968d..a493cc1 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -9,6 +9,8 @@ ----------------------------------------------------------------------- -- +local setmetatable = setmetatable + --[[doc-- Initialization phases: diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 5ac1421..b633ed7 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -65,16 +65,8 @@ luaotfload.module = { --doc]]-- local luatexbase = luatexbase - local require = require -local setmetatable = setmetatable -local type, next = type, next -local stringlower = string.lower -local stringformat = string.format - -local kpsefind_file = kpse.find_file -local lfsisfile = lfs.isfile - +local type = type local add_to_callback = luatexbase.add_to_callback local create_callback = luatexbase.create_callback local reset_callback = luatexbase.reset_callback @@ -177,228 +169,12 @@ load_luaotfload_module "loaders" --- Type1 font wrappers load_luaotfload_module "database" --- Font management. load_luaotfload_module "colors" --- Per-font colors. -if not config.actions.reconfigure () then - logreport ("log", 0, "load", "Post-configuration hooks failed.") -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 filesuffix = file.suffix -local fileremovesuffix = file.removesuffix -local request_resolvers = fonts.definers.resolvers -local formats = fonts.formats -local names = fonts.names -formats.ofm = "type1" - -fonts.encodings.known = fonts.encodings.known or { } - ---[[doc-- +luaotfload.resolvers = load_luaotfload_module "resolvers" --- Font lookup - \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 = names.font_file_lookup - -local file_resolver = function (specification) - local name = resolve_file (specification.name) - local suffix = filesuffix(name) - if formats[suffix] then - specification.forced = stringlower (suffix) - specification.forcedname = file.removesuffix(name) - else - specification.name = name - end -end - -request_resolvers.file = file_resolver - ---[[doc-- - - We classify as \verb|anon:| those requests that have neither a - prefix nor brackets. According to Khaled\footnote{% - \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. - ---doc]]-- - ---request_resolvers.anon = request_resolvers.name - ---[[doc-- - - There is one drawback, though. - This syntax is also used 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", } - -request_resolvers.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 file.removesuffix (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 - request_resolvers.path(specification) - return - end - request_resolvers.name(specification) -end +luaotfload.resolvers.install () ---[[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]]-- - -request_resolvers.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) - file_resolver (specification) - else - local suffix = filesuffix (name) - if formats[suffix] then - specification.forced = stringlower (suffix) - specification.name = file.removesuffix(name) - specification.forcedname = name - else - specification.name = name - end - end -end - ---[[doc-- - - {\bfseries EXPERIMENTAL}: - \identifier{kpse}-only resolver, for those who can do without - system fonts. - ---doc]]-- - -request_resolvers.kpse = function (specification) - local name = specification.name - local suffix = filesuffix(name) - if suffix and formats[suffix] then - name = file.removesuffix(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 kpse.find_file (name, format) then - specification.forced = t - specification.name = name - return - end - end -end - ---[[doc-- - - The \verb|name:| resolver. - ---doc]]-- - ---- fonts.names.resolvers.name -- Customized version of the ---- generic name resolver. - -request_resolvers.name = function (specification) - local resolver = names.resolve_cached - if config.luaotfload.run.resolver == "normal" then - resolver = names.resolve_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 - file_resolver (specification) - end -end - ---[[doc-- - - Also {\bfseries EXPERIMENTAL}: custom file resolvers via callback. - ---doc]]-- -create_callback("luaotfload.resolve_font", "simple", dummy_function) - -request_resolvers.my = function (specification) - call_callback("luaotfload.resolve_font", specification) +if not config.actions.reconfigure () then + logreport ("log", 0, "load", "Post-configuration hooks failed.") end --[[doc-- 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), +-- 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 + -- cgit v1.2.3