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 +  | 
