diff options
-rw-r--r-- | Makefile | 20 | ||||
-rw-r--r-- | NEWS | 3 | ||||
-rw-r--r-- | doc/filegraph.dot | 3 | ||||
-rwxr-xr-x[-rw-r--r--] | scripts/mkimport | 152 | ||||
-rwxr-xr-x | scripts/mkstatus | 62 | ||||
-rw-r--r-- | src/fontloader/luaotfload-package.lua | 6 | ||||
-rw-r--r-- | src/fontloader/runtime/fontloader-reference.lua (renamed from src/fontloader/runtime/fontloader-fontloader.lua) | 0 | ||||
-rw-r--r-- | src/luaotfload-colors.lua | 17 | ||||
-rw-r--r-- | src/luaotfload-configuration.lua | 6 | ||||
-rw-r--r-- | src/luaotfload-database.lua | 110 | ||||
-rw-r--r-- | src/luaotfload-init.lua | 140 | ||||
-rw-r--r-- | src/luaotfload-letterspace.lua | 9 | ||||
-rw-r--r-- | src/luaotfload-log.lua | 49 | ||||
-rw-r--r-- | src/luaotfload-main.lua | 246 | ||||
-rw-r--r-- | src/luaotfload-override.lua | 52 | ||||
-rw-r--r-- | src/luaotfload-resolvers.lua | 256 |
16 files changed, 666 insertions, 465 deletions
@@ -6,6 +6,7 @@ DOCSRCDIR = ./doc SCRIPTSRCDIR = ./scripts SRCSRCDIR = ./src FONTLOADERDIR = $(SRCSRCDIR)/fontloader/runtime +PACKAGEDIR = $(SRCSRCDIR)/fontloader BUILDDIR = ./build MISCDIR = ./misc @@ -48,7 +49,8 @@ DOCS = $(DOCPDF) $(DOTPDF) $(MANPAGES) GLYPHS = $(BUILDDIR)/$(NAME)-glyphlist.lua CHARS = $(BUILDDIR)/$(NAME)-characters.lua STATUS = $(BUILDDIR)/$(NAME)-status.lua -RESOURCES = $(GLYPHS) $(CHARS) $(STATUS) +LOADER = $(BUILDDIR)/fontloader-$(shell date +%F).lua +RESOURCES = $(GLYPHS) $(CHARS) $(LOADER) $(STATUS) SOURCE = $(DOCSRC) $(MANSRC) $(SRC) README COPYING Makefile NEWS $(RESOURCESCRIPTS) # Files grouped by installation location @@ -88,8 +90,10 @@ LUA = texlua ## variables. DO_GLYPHS = $(LUA) $(GLYPHSCRIPT) > /dev/null DO_CHARS = $(LUA) $(CHARSCRIPT) > /dev/null -DO_STATUS = $(LUA) $(STATUSSCRIPT) > /dev/null -DO_IMPORT = $(LUA) $(IMPORTSCRIPT) > /dev/null +DO_STATUS = $(LUA) $(STATUSSCRIPT) --fontloader=$(LOADER) >/dev/null +DO_IMPORT = $(LUA) $(IMPORTSCRIPT) import >/dev/null +DO_PACKAGE = $(LUA) $(IMPORTSCRIPT) package \ + $(PACKAGEDIR)/luaotfload-package.lua $(LOADER) >/dev/null define check-lua-files @echo validating syntax @@ -113,8 +117,12 @@ builddir: $(BUILDDIR) resources: $(RESOURCES) chars: $(CHARS) status: $(STATUS) +package: loader +loader: $(LOADER) ctan: $(CTAN_ZIP) tds: $(TDS_ZIP) +import: + $(DO_IMPORT) graph: $(DOTPDF) doc: $(DOCS) @@ -136,9 +144,12 @@ $(GLYPHS): builddir $(CHARS): builddir $(DO_CHARS) -$(STATUS): builddir +$(STATUS): builddir loader $(DO_STATUS) +$(LOADER): builddir + $(DO_PACKAGE) + $(BUILDDIR): /dev/null mkdir -p $(BUILDDIR) @@ -222,6 +233,7 @@ showtargets: @echo " luaotfload.conf(5) (requires Docutils)" @echo " graph generate file graph (requires GraphViz)" @echo + @echo " loader merge fontloader" @echo " chars import char-def.lua as luaotfload-characters.lua" @echo " status create repository info (luaotfload-status.lua)" @echo @@ -11,6 +11,9 @@ Change History * Revised letterspacing, now utilizing the ``node.direct`` interface * Revized colorization of fonts, utilizing ``node.direct`` (Dohyun Kim) * Colorization was moved to the ``post_linebreak_filter`` stage + * Move remaining functionality from ``luaotfload-override`` into + initialization + * Write names index if fonts were removed 2014/07/13, luaotfload v2.5 * Remove legacy code. diff --git a/doc/filegraph.dot b/doc/filegraph.dot index 47db9ea..e1a9937 100644 --- a/doc/filegraph.dot +++ b/doc/filegraph.dot @@ -199,10 +199,9 @@ strict digraph luaotfload_files { //looks weird with circo ... <table cellborder="0" bgcolor="#FFFFFFAA"> <th> <td colspan="2"> <font point-size="12" face="Iwona Italic">Luaotfload Libraries</font> </td> </th> <tr> <td>luaotfload-auxiliary.lua</td> <td>luaotfload-features.lua</td> </tr> - <tr> <td>luaotfload-override.lua</td> <td>luaotfload-loaders.lua</td> </tr> + <tr> <td>luaotfload-loaders.lua</td> <td>luaotfload-color.lua</td> </tr> <tr> <td>luaotfload-log.lua</td> <td>luaotfload-letterspace.lua</td> </tr> <tr> <td>luaotfload-parsers.lua</td> <td>luaotfload-database.lua</td> </tr> - <tr> <td>luaotfload-color.lua</td> </tr> </table> >, ] diff --git a/scripts/mkimport b/scripts/mkimport index a430587..0833ccb 100644..100755 --- a/scripts/mkimport +++ b/scripts/mkimport @@ -1,7 +1,7 @@ #!/usr/bin/env texlua ------------------------------------------------------------------------------- -- FILE: mkimport.lua --- USAGE: ./mkimport.lua +-- USAGE: texlua ./mkimport.lua -- DESCRIPTION: check luaotfload imports against Context -- REQUIREMENTS: luatex, the lualibs package, Context MkIV -- AUTHOR: Philipp Gesang (Phg), <phg@phi-gamma.net> @@ -12,12 +12,15 @@ ------------------------------------------------------------------------------- --- PURPOSE ---- +--- --- - Facilitate detecting changes in the fontloader source. --- - Assist in updating source code and (partially) automate importing. +--- --- - Account for files in the plain fontloader distribution, alert in case of --- additions or deletions. ---- +--- +--- - Fontloader packaging. +--- ------------------------------------------------------------------------------- local debug = false @@ -26,18 +29,23 @@ kpse.set_program_name "luatex" local lfs = require "lfs" local md5 = require "md5" +local os = require "os" require "lualibs" +local filedirname = file.dirname local fileiswritable = file.is_writable local ioloaddata = io.loaddata local iopopen = io.popen local iowrite = io.write local lfschdir = lfs.chdir +local lfscurrentdir = lfs.currentdir local lfsisdir = lfs.isdir local lfsisfile = lfs.isfile local md5sumhexa = md5.sumhexa +local osdate = os.date local osgettimeofday = os.gettimeofday +local osrename = os.rename local stringformat = string.format local tableconcat = table.concat @@ -71,6 +79,26 @@ local prefixes = { fontloader = "luatex", } +--[[doc-- + + The output name is fixed so we have to deal with it but maybe we + can get a patch to mtx-package upstreamed in the future. In any + case, we are content with renaming the result for the time being. + + The target name is constructed on the fly from the current date. + TODO It should be possible to supply a name and possibly + destination path on the command line. + + Paths are relative to the base directory (``$PWD``). + +--doc]]-- + +local loader_merge_name = "luaotfload-package.lua" +local loader_output_name = "luaotfload-package-merged.lua" +local loader_target_name = "fontloader-%s.lua" +local loader_orig_dir = "/src/fontloader/" +local loader_target_dir = "/build/" + ------------------------------------------------------------------------------- -- helpers ------------------------------------------------------------------------------- @@ -169,7 +197,7 @@ local imports = { { name = "fonts-ext" , ours = nil , kind = kind_merged }, { name = "fonts-inj" , ours = nil , kind = kind_merged }, { name = "fonts-lua" , ours = nil , kind = kind_merged }, - { name = "fonts-merged" , ours = "fontloader" , kind = kind_essential }, + { name = "fonts-merged" , ours = "reference" , kind = kind_essential }, { name = "fonts-ota" , ours = nil , kind = kind_merged }, { name = "fonts-otn" , ours = nil , kind = kind_merged }, { name = "fonts" , ours = nil , kind = kind_merged }, @@ -641,6 +669,49 @@ local tell = function (arg) return describe (target, location) end +local build_paths = function (argv) + if not argv or type (argv) ~= "table" then die "build_paths" end + + local orig_dir = lfscurrentdir () + local base_dir = orig_dir .. loader_orig_dir + local target_name = orig_dir .. loader_target_dir + .. stringformat (loader_target_name, os.date ("%F")) + local merge_name = base_dir .. loader_merge_name + local output_name = base_dir .. loader_output_name + + if #argv >= 2 then + local fname = argv[2] + local dir = filedirname (fname) .. "/" + if not lfsisdir (dir) then + die ("second argument must be point into existing directory, not “%s”", + argv[2]) + end + base_dir = dir + merge_name = fname + output_name = dir .. loader_output_name + end + + if #argv == 3 then + --- also set the target name + local fname = argv[3] + local dir = filedirname (fname) + if not lfsisdir (dir) then + die ("third argument must be point into writable directory, not “%s”", + argv[3]) + end + target_name = fname + end + + local ret = { + orig_dir = orig_dir, + base_dir = base_dir, + merge_name = merge_name, + target_name = target_name, + output_name = output_name, + } + return ret +end + --[[doc-- Packaging works as follows: @@ -659,43 +730,40 @@ end --doc]]-- -local package = function (args) - local t0 = osgettimeofday () - local orig_dir = lfs.currentdir () - local base_dir = orig_dir .. "/src/fontloader/" - local merge_name = base_dir .. "luaotfload-package.lua" - --- output name is fixed so we have to deal with it but maybe we can - --- get a patch to mtx-package upstreamed in the future - local output_name = base_dir .. "luaotfload-package-merged.lua" - local target_name = stringformat ("fontloader-%s.lua", - os.date ("%F")) - status ("assuming fontloader source in %s", base_dir) - status ("reading merge instructions from %s", merge_name) - status ("writing output to %s", target_name) +local package = function (argv) + local t0 = osgettimeofday () + local paths = build_paths (argv) + + status ("assuming fontloader source in %s", paths.base_dir) + status ("reading merge instructions from %s", paths.merge_name) + status ("mtx-package result at %s", paths.output_name) + status ("writing output to %s", paths.target_name) --- check preconditions - if not lfsisdir (base_dir) then die ("directory %s does not exist", emphasis (base_dir )) end - if not lfsisfile (merge_name) then die ("missing merge file at %s", emphasis (merge_name )) end - if not fileiswritable (output_name) then die ("cannot write to %s", emphasis (output_name)) end - if not fileiswritable (target_name) then die ("cannot write to %s", emphasis (target_name)) end - if not lfschdir (base_dir) then die ("failed to cd into %s", emphasis (base_dir )) end + if not lfsisdir (paths.base_dir) then die ("directory %s does not exist", emphasis (paths.base_dir )) end + if not lfsisfile (paths.merge_name) then die ("missing merge file at %s", emphasis (paths.merge_name )) end + if not fileiswritable (paths.output_name) then die ("cannot write to %s", emphasis (paths.output_name)) end + if not fileiswritable (paths.target_name) then die ("cannot write to %s", emphasis (paths.target_name)) end +---- not lfschdir (paths.base_dir) then die ("failed to cd into %s", emphasis (paths.base_dir )) end - if lfsisfile (output_name) then - status ("output file already exists at “%s”, unlinking", output_name) - local ret, err = os.remove (output_name) + if lfsisfile (paths.output_name) then + status ("output file already exists at “%s”, unlinking", + paths.output_name) + local ret, err = os.remove (paths.output_name) if ret == nil then - if not lfschdir (orig_dir) then - status ("warning: failed to cd retour into %s", emphasis (orig_dir)) + if not lfschdir (paths.orig_dir) then + status ("warning: failed to cd retour into %s", + emphasis (paths.orig_dir)) end die ("failed to remove existing merge package") end end - --die ("missing merge file at %s", emphasis (merge_name )) end + --die ("missing merge file at %s", emphasis (paths.merge_name )) end --- perform merge - local cmd = { "mtxrun", "--script", "package", "--merge", merge_name } + local cmd = { "mtxrun", "--script", "package", "--merge", paths.merge_name } local shl = tableconcat (cmd, " ") status ("invoking %s as “%s”", emphasis "mtx-package", shl) @@ -703,8 +771,9 @@ local package = function (args) local fh = iopopen (shl, "r") if not fh then - if not lfschdir (orig_dir) then - status ("warning: failed to cd retour into %s", emphasis (orig_dir)) + if not lfschdir (paths.orig_dir) then + status ("warning: failed to cd retour into %s", + emphasis (paths.orig_dir)) end die ("merge failed; failed to invoke mtxrun") end @@ -720,19 +789,34 @@ local package = function (args) --- clean up - if not lfschdir (orig_dir) then - status ("warning: failed to cd retour into %s", emphasis (orig_dir)) + if not lfschdir (paths.orig_dir) then + status ("warning: failed to cd retour into %s", + emphasis (paths.orig_dir)) end --- check postconditions - if not lfsisfile (output_name) then die ("merge failed; package not found at " .. output_name) end + if not lfsisfile (paths.output_name) then + die ("merge failed; package not found at " .. paths.output_name) + end --- at this point we know that mtxrun was invoked correctly and the --- result file has been created + if lfsisfile (paths.target_name) then + status ("target file %s exists, overwriting", emphasis (paths.target_name)) + end + + local res, err = osrename (paths.output_name, paths.target_name) + + if res == nil then + die ("merge failed; failed to move package from %s to %s", + paths.output_name, paths.target_name) + end + status ("merge complete; operation finished in %.0f ms", (osgettimeofday() - t0) * 1000) + status ("a fresh fontloader at %s is ready to roll", paths.target_name) end local help = function () diff --git a/scripts/mkstatus b/scripts/mkstatus index e18abb7..809d4af 100755 --- a/scripts/mkstatus +++ b/scripts/mkstatus @@ -26,6 +26,7 @@ local iosavedata = io.savedata local iopopen = io.popen local iowrite = io.write local lfsisdir = lfs.isdir +local stringmatch = string.match ----------------------------------------------------------------------- -- settings @@ -55,8 +56,8 @@ local names = { { "src", "luaotfload-loaders.lua", }, { "src", "luaotfload-log.lua", }, { "src", "luaotfload-main.lua", }, - { "src/fontloader/runtime", "fontloader-fontloader.lua", }, - { "src", "luaotfload-override.lua", }, + { "src/fontloader/runtime", "fontloader-reference.lua", }, + --{ "src", "luaotfload-override.lua", }, --> part of init now { "src", "luaotfload-parsers.lua", }, { "src", "luaotfload-tool.lua", }, { "scripts", "mkcharacters", }, @@ -121,8 +122,9 @@ end local hash_all hash_all = function (list, acc) - if list == nil then - return hash_all (table.fastcopy (names), { }) + if acc == nil then + local base = table.fastcopy (names) + return hash_all (table.append (base, list), { }) end local finfo = list[#list] @@ -156,10 +158,58 @@ hash_all = function (list, acc) return acc end +local handle_argv = function (argv) + local ret = { files = { }, loader = nil } + local argc = #argv + if argc < 1 then return ret end + local argoff = 1 + if argv [1] == "-v" then + verbose = true + if argc == 1 then return ret end + argoff = 2 + end + local aux aux = function (acc, i) + if i > argc then return acc else + local cur = argv[i] + if type (cur) == "string" then + local loader = stringmatch (cur, "--fontloader=(.+)$") + if loader then + cur = loader + acc.loader = file.basename (cur) + end + if lfs.isfile (cur) then + local files = acc.files + files[#files + 1] = cur + end + else + die ("file not found: %s", tostring (cur)) + end + return aux (acc, i + 1) + end + end + return aux (ret, argoff) +end + +local add_files +add_files = function (lst, acc) + if lst == nil then return end + if acc == nil then return add_files (lst, { }) end + local len = #lst + if len == 0 then return acc end + local cur = lst[len] + local fname = file.basename (cur) + local path = file.dirname (cur) + acc[#acc + 1] = { path, fname } + lst[len] = nil + return add_files (lst, acc) +end + local main = function () - if arg [1] == "-v" then verbose = true end - local hashes = hash_all () + local raw_extra = handle_argv (arg) + local cuit_extra = add_files (raw_extra.files) + local hashes = hash_all (cuit_extra) local notes = git_info () + notes.loader = raw_extra.loader local serialized = table.serialize ({ notes = notes, hashes = hashes }, true) local success = io.savedata (filelist, serialized) diff --git a/src/fontloader/luaotfload-package.lua b/src/fontloader/luaotfload-package.lua index b60ae17..725c498 100644 --- a/src/fontloader/luaotfload-package.lua +++ b/src/fontloader/luaotfload-package.lua @@ -63,12 +63,16 @@ loadmodule "l-boolean.lua" loadmodule "l-math.lua" loadmodule "util-str.lua" +--- Another file containing auxiliary definitions must be present +--- prior to initialization of the configuration. + +loadmodule "luatex-basics-gen.lua" + --- The files below constitute the “fontloader proper”. Some of the --- functionality like file resolvers is overloaded later by --- Luaotfload. Consequently, the resulting package is pretty --- bare-bones and not usable independently. -loadmodule("luatex-basics-gen.lua") loadmodule("data-con.lua") loadmodule("luatex-basics-nod.lua") loadmodule("font-ini.lua") diff --git a/src/fontloader/runtime/fontloader-fontloader.lua b/src/fontloader/runtime/fontloader-reference.lua index d8095a2..d8095a2 100644 --- a/src/fontloader/runtime/fontloader-fontloader.lua +++ b/src/fontloader/runtime/fontloader-reference.lua diff --git a/src/luaotfload-colors.lua b/src/luaotfload-colors.lua index 8035210..19903d8 100644 --- a/src/luaotfload-colors.lua +++ b/src/luaotfload-colors.lua @@ -40,6 +40,8 @@ local setattribute = nodedirect.set_attribute local texset = tex.set local texget = tex.get +local texsettoks = tex.settoks +local texgettoks = tex.gettoks local stringformat = string.format local concat = table.concat @@ -310,9 +312,6 @@ node_colorize = function (head, current_color) return head, current_color end -local pgf_extgs = { } -luaotfload.pgf_extgs = pgf_extgs - --- node -> node local color_handler = function (head) head = todirect(head) @@ -326,7 +325,7 @@ local color_handler = function (head) local no_extgs = not tpr:find("/ExtGState<<.*>>") local pgf_loaded = no_extgs and luaotfload.pgf_loaded if pgf_loaded then - tpr = concat(pgf_extgs) + tpr = texgettoks(pgf_loaded) end local t = "" @@ -338,7 +337,7 @@ local color_handler = function (head) end if t ~= "" then if pgf_loaded then - pgf_extgs[#pgf_extgs+1] = t + texsettoks("global", pgf_loaded, tpr..t) else if no_extgs then tpr = tpr .. "/ExtGState<<>>" @@ -379,13 +378,5 @@ add_color_callback = function ( ) end end -tex.sprint("\\count255=\\catcode`@ \\catcode`@=11 ", - "\\ifdefined\\AtBeginDocument\\else\\def\\AtBeginDocument#1{#1}\\fi", - "\\AtBeginDocument{\\ifdefined\\pgfutil@everybye", - "\\directlua{luaotfload.pgf_loaded=true}\\begingroup", - "\\toks@{\\pgf@sys@addpdfresource@extgs@plain{\\directlua{tex.sprint(luaotfload.pgf_extgs)}}}", - "\\edef\\x{\\endgroup\\noexpand\\pgfutil@everybye{\\the\\toks@\\the\\pgfutil@everybye}}\\x", - "\\fi}\\catcode`@=\\count255 ") - -- vim:tw=71:sw=4:ts=4:expandtab diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index e9393c5..e2cfbd8 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -140,9 +140,9 @@ local feature_presets = { --doc]]-- local registered_loaders = { - default = "fontloader", - fontloader = "fontloader", - tl2013 = "tl2013", + default = luaotfloadstatus and luaotfloadstatus.notes.loader or "reference", + reference = "reference", + tl2014 = "tl2014", } --[[doc-- diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index 1831ca3..f4aab16 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 @@ -2241,6 +2241,28 @@ end --[[doc-- + count_removed -- Count paths that do not exist in the file system. + +--doc]]-- + +--- string list -> size_t +local count_removed = function (old) + report("log", 4, "db", "Checking removed files.") + local nrem = 0 + local nold = #old + for i = 1, nold do + local f = old[i] + if not kpsereadable_file (f) then + report("log", 2, "db", + "File %s does not exist in file system.") + nrem = nrem + 1 + end + end + return nrem +end + +--[[doc-- + retrieve_namedata -- Scan the list of collected fonts and populate the list of namedata. @@ -2253,7 +2275,7 @@ end --doc]]-- ---- string * string list -> dbobj -> dbobj -> bool? -> int +--- string * string list -> dbobj -> dbobj -> bool? -> int * int local retrieve_namedata = function (files, currentnames, targetnames, dry_run) local nfiles = #files @@ -2348,10 +2370,7 @@ local collect_font_filenames_local = function () return files end ---- dbobj -> dbobj -> int * int - --- fontentry list -> filemap - generate_filedata = function (mappings) report ("both", 2, "db", "Creating filename map.") @@ -2383,7 +2402,6 @@ generate_filedata = function (mappings) for index = 1, nmappings do local entry = mappings [index] - local filedata = entry.file local format local location @@ -2473,7 +2491,7 @@ generate_filedata = function (mappings) --- 3) add to fullpath map full [index] = fullpath - end + end --- mapping traversal return files end @@ -2849,7 +2867,7 @@ end --doc]]-- ---- unit -> string * bool list +--- unit -> string * string list local collect_font_filenames = function () report ("info", 4, "db", "Scanning the filesystem for font files.") @@ -3098,6 +3116,8 @@ end --- dbobj? -> bool? -> bool? -> dbobj update_names = function (currentnames, force, dry_run) local targetnames + local n_new = 0 + local n_rem = 0 local conf = config.luaotfload if conf.run.live ~= false and conf.db.update_live == false then @@ -3149,13 +3169,16 @@ update_names = function (currentnames, force, dry_run) --- pass 2: read font files (normal case) or reuse information --- present in index + n_rem = count_removed (currentnames.files.full) + n_new = retrieve_namedata (font_filenames, currentnames, targetnames, dry_run) + report ("info", 3, "db", - "Found %d font files; %d new entries.", - #font_filenames, n_new) + "Found %d font files; %d new, %d stale entries.", + #font_filenames, n_new, n_rem) end --- pass 3 (optional): collect some stats about the raw font info @@ -3181,7 +3204,6 @@ update_names = function (currentnames, force, dry_run) --- pass 7: order design size tables targetnames.families = order_design_sizes (targetnames.families) - report ("info", 3, "db", "Rebuilt in %0.f ms.", 1000 * (osgettimeofday () - starttime)) @@ -3189,8 +3211,9 @@ update_names = function (currentnames, force, dry_run) if dry_run ~= true then - if n_new == 0 then - report ("info", 2, "db", "No new fonts found, skip saving to disk.") + if n_new + n_rem == 0 then + report ("info", 2, "db", + "No new or removed fonts, skip saving to disk.") else local success, reason = save_names () if not success then @@ -3449,17 +3472,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 feff4cc..a493cc1 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -9,6 +9,8 @@ ----------------------------------------------------------------------- -- +local setmetatable = setmetatable + --[[doc-- Initialization phases: @@ -65,7 +67,7 @@ local logreport --- filled in after loading the log module --doc]]-- -local init_pre = function () +local init_early = function () local store = { } config = config or { } --- global @@ -74,6 +76,7 @@ local init_pre = function () config.lualibs.verbose = false config.lualibs.prefer_merged = true config.lualibs.load_extended = true + fonts = fonts or { } require "lualibs" @@ -131,8 +134,10 @@ local init_pre = function () return number end + luaotfload.loaders.fontloader "basics-gen" + return store -end --- [init_pre] +end --- [init_early] --[[doc-- @@ -180,11 +185,8 @@ end local init_adapt = function () - luaotfload.context_environment = { } - luaotfload.push_namespaces = push_namespaces - luaotfload.pop_namespaces = pop_namespaces - - local our_environment = push_namespaces () + local context_environment = { } + local our_environment = push_namespaces () --[[doc-- @@ -196,7 +198,7 @@ local init_adapt = function () tex.attribute[0] = 0 - return our_environment + return our_environment, context_environment end --- [init_adapt] @@ -277,9 +279,9 @@ local init_cleanup = function (store) --doc]]-- - luaotfload.pop_namespaces (store.our_environment, - false, - luaotfload.context_environment) + pop_namespaces (store.our_environment, + false, + store.context_environment) --[[doc-- @@ -294,10 +296,7 @@ local init_cleanup = function (store) callback.register = store.trapped_register end --- [init_cleanup] -local init_post = function () - --- hook for actions that need to take place after the fontloader is - --- installed - +local init_post_install_callbacks = function () --[[doc-- we do our own callback handling with the means provided by @@ -316,19 +315,122 @@ local init_post = function () nodes.simple_font_handler, "luaotfload.node_processor", 1) +end + +local init_post_load_agl = function () + + --[[doc-- + + Adobe Glyph List. + ----------------------------------------------------------------- + + Context provides a somewhat different font-age.lua from an + unclear origin. Unfortunately, the file name it reads from is + hard-coded in font-enc.lua, so we have to replace the entire + table. + + This shouldn’t cause any complications. Due to its implementation + the glyph list will be loaded upon loading a OTF or TTF for the + first time during a TeX run. (If one sticks to TFM/OFM then it is + never read at all.) For this reason we can install a metatable + that looks up the file of our choosing and only falls back to the + Context one in case it cannot be found. + + --doc]]-- + + local findfile = resolvers.findfile + local encodings = fonts.encodings + + if not findfile or not encodings then + --- Might happen during refactoring; we continue graciously but in + --- a somewhat defect state. + logreport ("log", 0, "init", + "preconditions unmet, skipping the Adobe Glyph List; " + .. "this is a Luaotfload bug.") + return + end + + if next (fonts.encodings.agl) then + --- unnecessary because the file shouldn’t be loaded at this time + --- but we’re just making sure + fonts.encodings.agl = nil + collectgarbage"collect" + end + + local agl_init = { } --- start out empty, fill on demand + encodings.agl = agl_init --- ugh, replaced again later + + setmetatable (agl_init, { __index = function (t, k) + + if k ~= "unicodes" then + return nil + end + + local glyphlist = findfile "luaotfload-glyphlist.lua" + if glyphlist then + logreport ("log", 1, "init", "loading the Adobe glyph list") + else + glyphlist = findfile "font-age.lua" + logreport ("both", 0, "init", + "loading the extended glyph list from ConTeXt") + end + + if not glyphlist then + logreport ("both", 4, "init", + "Adobe glyph list not found, please check your installation.") + return nil + end + logreport ("both", 4, "init", + "found Adobe glyph list file at ``%s``, using that.", + glyphlist) + + local unicodes = dofile(glyphlist) + encodings.agl = { unicodes = unicodes } + return unicodes + end }) + +end + +--- (unit -> unit) list +local init_post_actions = { + init_post_install_callbacks, + init_post_load_agl, +} + +--- unit -> size_t +local init_post = function () + --- hook for actions that need to take place after the fontloader is + --- installed + + local n = #init_post_actions + for i = 1, n do + local action = init_post_actions[i] + local taction = type (action) + if not action or taction ~= "function" then + logreport ("both", 1, "init", + "post hook WARNING: action %d not a function but %s/%s; ignoring.", + i, action, taction) + else + --- call closure + action () + end + end + + return n end --- [init_post] return { - init = function () + early = init_early, + main = function (store) local starttime = os.gettimeofday () - local store = init_pre () - store.our_environment = init_adapt () + store.our_environment, store.context_environment = init_adapt () init_main () init_cleanup (store) logreport ("both", 1, "init", "fontloader loaded in %0.3f seconds", os.gettimeofday() - starttime) - init_post () + local n = init_post () + logreport ("both", 5, "init", "post hook terminated, %d actions performed", n) end } diff --git a/src/luaotfload-letterspace.lua b/src/luaotfload-letterspace.lua index 8956f82..9a0646b 100644 --- a/src/luaotfload-letterspace.lua +++ b/src/luaotfload-letterspace.lua @@ -471,12 +471,15 @@ local enablefontkerning = function ( ) local handler = function (hd) local direct_hd = todirect (hd) - local hd, _done = kerncharacters (hd) - if not hd then --- bad + logreport ("term", 5, "letterspace", + "kerncharacters() invoked with node.direct interface \z + (``%s`` -> ``%s``)", tostring (hd), tostring (direct_hd)) + local direct_hd, _done = kerncharacters (direct_hd) + if not direct_hd then --- bad logreport ("both", 0, "letterspace", "kerncharacters() failed to return a valid new head") end - return tonode (hd) + return tonode (direct_hd) end return add_processor( handler diff --git a/src/luaotfload-log.lua b/src/luaotfload-log.lua index a0e78bd..7c012f4 100644 --- a/src/luaotfload-log.lua +++ b/src/luaotfload-log.lua @@ -355,52 +355,3 @@ end texio.reporter = texioreporter ---[[doc-- - - Adobe Glyph List. - ------------------------------------------------------------------- - - Context provides a somewhat different font-age.lua from an unclear - origin. Unfortunately, the file name it reads from is hard-coded - in font-enc.lua, so we have to replace the entire table. - - This shouldn’t cause any complications. Due to its implementation - the glyph list will be loaded upon loading a OTF or TTF for the - first time during a TeX run. (If one sticks to TFM/OFM then it is - never read at all.) For this reason we can install a metatable that - looks up the file of our choosing and only falls back to the - Context one in case it cannot be found. - ---doc]]-- - -if fonts then --- need to be running TeX - if next(fonts.encodings.agl) then - --- unnecessary because the file shouldn’t be loaded at this time - --- but we’re just making sure - fonts.encodings.agl = nil - collectgarbage"collect" - end - - - fonts.encodings.agl = { } - - setmetatable(fonts.encodings.agl, { __index = function (t, k) - if k == "unicodes" then - local glyphlist = resolvers.findfile"luaotfload-glyphlist.lua" - if glyphlist then - report ("log", 1, "load", "loading the Adobe glyph list") - else - glyphlist = resolvers.findfile"font-age.lua" - report ("both", 0, "load", - "loading the extended glyph list from ConTeXt") - end - local unicodes = dofile(glyphlist) - fonts.encodings.agl = { unicodes = unicodes } - return unicodes - else - return nil - end - end }) -end - --- vim:tw=71:sw=4:ts=4:expandtab diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index e8f05d6..b633ed7 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -1,6 +1,6 @@ ----------------------------------------------------------------------- -- FILE: luaotfload-main.lua --- DESCRIPTION: Luaotfload initialization +-- DESCRIPTION: Luaotfload entry point -- REQUIREMENTS: luatex v.0.80 or later; packages lualibs, luatexbase -- AUTHOR: Élie Roux, Khaled Hosny, Philipp Gesang -- VERSION: same as Luaotfload @@ -20,9 +20,7 @@ luaotfload.log = luaotfload.log or { } luaotfload.version = "2.6" luaotfload.loaders = { } luaotfload.min_luatex_version = 79 --- i. e. 0.79 -luaotfload.fontloader_package = "fontloader" --- default: from current Context -----------.fontloader_package = "slim" - +luaotfload.fontloader_package = "reference" --- default: from current Context local authors = "\z Hans Hagen,\z @@ -67,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 @@ -155,13 +145,11 @@ luaotfload.loaders.luaotfload = load_luaotfload_module luaotfload.loaders.fontloader = load_fontloader_module luaotfload.init = load_luaotfload_module "init" --- fontloader initialization -luaotfload.init.init () +local store = luaotfload.init.early () local log = luaotfload.log local logreport = log.report -load_luaotfload_module "override" --- load glyphlist on demand - --[[doc-- Now we load the modules written for \identifier{luaotfload}. @@ -175,232 +163,18 @@ if not config.actions.apply_defaults () then logreport ("log", 0, "load", "Configuration unsuccessful.") end +luaotfload.init.main (store) + 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-- - - \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 - ---[[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. +luaotfload.resolvers = load_luaotfload_module "resolvers" --- Font lookup -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-- +luaotfload.resolvers.install () - 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-override.lua b/src/luaotfload-override.lua deleted file mode 100644 index b75530b..0000000 --- a/src/luaotfload-override.lua +++ /dev/null @@ -1,52 +0,0 @@ -if not modules then modules = { } end modules ["luaotfload-override"] = { - version = "2.5", - comment = "companion to Luaotfload", - author = "Khaled Hosny, Elie Roux, Philipp Gesang", - copyright = "Luaotfload Development Team", - license = "GNU GPL v2.0" -} - -local findfile = resolvers.findfile -local encodings = fonts.encodings - -local log = luaotfload.log -local report = log.report - ---[[doc-- - - Adobe Glyph List. - ------------------------------------------------------------------- - - Context provides a somewhat different font-age.lua from an unclear - origin. Unfortunately, the file name it reads from is hard-coded - in font-enc.lua, so we have to replace the entire table. - - This shouldn’t cause any complications. Due to its implementation - the glyph list will be loaded upon loading a OTF or TTF for the - first time during a TeX run. (If one sticks to TFM/OFM then it is - never read at all.) For this reason we can install a metatable that - looks up the file of our choosing and only falls back to the - Context one in case it cannot be found. - ---doc]]-- - -encodings.agl = { } - -setmetatable(fonts.encodings.agl, { __index = function (t, k) - if k ~= "unicodes" then - return nil - end - local glyphlist = findfile "luaotfload-glyphlist.lua" - if glyphlist then - report ("log", 1, "load", "loading the Adobe glyph list") - else - glyphlist = findfile "font-age.lua" - report ("both", 0, "load", - "loading the extended glyph list from ConTeXt") - end - local unicodes = dofile(glyphlist) - encodings.agl = { unicodes = unicodes } - return unicodes -end }) - --- vim:tw=71:sw=4:ts=4:expandtab 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 + |