From d26a285e185facdfdbbf7aa52a485663f3036c21 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Thu, 16 May 2013 14:17:12 +0200
Subject: add functions for retrieving information about loaded fonts

---
 luaotfload-auxiliary.lua | 72 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 72 insertions(+)

diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
index dde5686..c8f1299 100644
--- a/luaotfload-auxiliary.lua
+++ b/luaotfload-auxiliary.lua
@@ -484,6 +484,8 @@ aux.sprint_math_dimension = sprint_math_dimension
 local namesresolve      = fonts.names.resolve
 local namesscan_dir     = fonts.names.scan_dir
 
+--- local directories -------------------------------------------------
+
 --- migrated from luaotfload-database.lua
 --- https://github.com/lualatex/luaotfload/pull/61#issuecomment-17776975
 
@@ -506,6 +508,8 @@ end
 
 aux.scan_external_dir = scan_external_dir
 
+--- db queries --------------------------------------------------------
+
 --- https://github.com/lualatex/luaotfload/issues/74
 --- string -> (string * int)
 local resolve_fontname = function (name)
@@ -542,4 +546,72 @@ end
 
 aux.resolve_fontlist = resolve_fontlist
 
+--- loaded fonts ------------------------------------------------------
+
+--- just a proof of concept
+
+--- fontobj -> string list -> (string list) list
+local get_font_data get_font_data = function (tfmdata, keys, acc, n)
+  if not acc then
+    return get_font_data(tfmdata, keys, {}, 1)
+  end
+  local key = keys[n]
+  if key then
+    local val = tfmdata[key]
+    if val then
+      acc[#acc+1] = val
+    else
+      acc[#acc+1] = false
+    end
+    return get_font_data(tfmdata, keys, acc, n+1)
+  end
+  return acc
+end
+
+--[[doc--
+
+    The next one operates on the fonts.hashes.identifiers table.
+    It returns a list containing tuples of font ids and the
+    contents of the fields specified in the first argument.
+    Font table entries that were created indirectly -- e.g. by
+    \letterspacefont or during font expansion -- will not be
+    listed.
+
+--doc]]--
+
+local default_keys = { "fullname" }
+
+--- string list -> (int * string list) list
+local get_loaded_fonts get_loaded_fonts = function (keys, acc, lastid)
+  if not acc then
+    if not keys then
+      keys = default_keys
+    end
+    return get_loaded_fonts(keys, {}, lastid)
+  end
+  local id, tfmdata = next(identifiers, lastid)
+  if id then
+    local data = get_font_data(tfmdata, keys)
+    acc[#acc+1] = { id, data }
+    return get_loaded_fonts (keys, acc, id)
+  end
+  return acc
+end
+
+aux.get_loaded_fonts = get_loaded_fonts
+
+--- Raw access to the font.* namespace is unsafe so no documentation on
+--- this one.
+local get_raw_fonts = function ( )
+  local res = { }
+  for i, v in font.each() do
+    if v.filename then
+      res[#res+1] = { i, v }
+    end
+  end
+  return res
+end
+
+aux.get_raw_fonts = get_raw_fonts
+
 -- vim:tw=71:sw=2:ts=2:expandtab
-- 
cgit v1.2.3


From 52711d3284f2d0de886fc3ab2d693a2ad69589d7 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Thu, 16 May 2013 15:56:00 +0200
Subject: add unsafe glyph checker

---
 luaotfload-auxiliary.lua | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
index c8f1299..f0d5a04 100644
--- a/luaotfload-auxiliary.lua
+++ b/luaotfload-auxiliary.lua
@@ -230,6 +230,8 @@ luatexbase.add_to_callback(
 ---                             glyphs
 -----------------------------------------------------------------------
 
+local agl = fonts.encodings.agl
+
 --- int -> int -> bool
 local font_has_glyph = function (font_id, codepoint)
   local fontdata = fonts.hashes.identifiers[font_id]
@@ -241,6 +243,20 @@ end
 
 aux.font_has_glyph = font_has_glyph
 
+--- undocumented
+
+local raw_slot_of_name = function (font_id, glyphname)
+  local fontdata = font.fonts[font_id]
+  if fontdata.type == "virtual" then --- get base font for glyph idx
+    local codepoint  = agl.unicodes[glyphname]
+    local glyph      = fontdata.characters[codepoint]
+    if fontdata.characters[codepoint] then
+      return codepoint
+    end
+  end
+  return false
+end
+
 --[[doc--
 
   This one is approximately “name_to_slot” from the microtype package;
@@ -249,10 +265,14 @@ aux.font_has_glyph = font_has_glyph
 
   http://www.adobe.com/devnet/opentype/archives/glyph.html
 
+  The “unsafe” switch triggers a fallback lookup in the raw fonts
+  table. As some of the information is stored as references, this may
+  have unpredictable side-effects.
+
 --doc]]--
 
---- int -> string -> (int | false)
-local slot_of_name = function (font_id, glyphname)
+--- int -> string -> bool -> (int | false)
+local slot_of_name = function (font_id, glyphname, unsafe)
   local fontdata = identifiers[font_id]
   if fontdata then
     local unicode = fontdata.resources.unicodes[glyphname]
@@ -261,6 +281,8 @@ local slot_of_name = function (font_id, glyphname)
     else
       return unicode[1] --- for multiple components
     end
+  elseif unsafe == true then -- for Robert
+    return raw_slot_of_name(font_id, glyphname)
   end
   return false
 end
@@ -283,7 +305,7 @@ local indices
 --- int -> (string | false)
 local name_of_slot = function (codepoint)
   if not indices then --- this will load the glyph list
-    local unicodes = fonts.encodings.agl.unicodes
+    local unicodes = agl.unicodes
     indices = table.swapped(unicodes)
   end
   local glyphname = indices[codepoint]
-- 
cgit v1.2.3


From ee4c3dd630ae4228b5e222f7099055e327785f97 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Thu, 16 May 2013 20:32:10 +0200
Subject: fix behavior of ``aux.slot_of_name()`` for missing glyphs

spotted by Robert
---
 luaotfload-auxiliary.lua | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
index f0d5a04..64fac90 100644
--- a/luaotfload-auxiliary.lua
+++ b/luaotfload-auxiliary.lua
@@ -276,10 +276,14 @@ local slot_of_name = function (font_id, glyphname, unsafe)
   local fontdata = identifiers[font_id]
   if fontdata then
     local unicode = fontdata.resources.unicodes[glyphname]
-    if unicode and type(unicode) == "number" then
-      return unicode
-    else
-      return unicode[1] --- for multiple components
+    if unicode then
+      if type(unicode) == "number" then
+        return unicode
+      else
+        return unicode[1] --- for multiple components
+      end
+--  else
+--    --- missing
     end
   elseif unsafe == true then -- for Robert
     return raw_slot_of_name(font_id, glyphname)
-- 
cgit v1.2.3


From 3554232ccc8e1f7a121eb25c31867bab2de85b64 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Fri, 17 May 2013 13:34:36 +0200
Subject: add script to extract parts of ``char-def.lua``

---
 mkcharacters | 120 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 120 insertions(+)
 create mode 100755 mkcharacters

diff --git a/mkcharacters b/mkcharacters
new file mode 100755
index 0000000..0ec871e
--- /dev/null
+++ b/mkcharacters
@@ -0,0 +1,120 @@
+#!/usr/bin/env texlua
+-----------------------------------------------------------------------
+--         FILE:  mkcharacters.lua
+--        USAGE:  ./mkcharacters.lua 
+--  DESCRIPTION:  import parts of char-def.lua
+-- REQUIREMENTS:  lua, lpeg, ConTeXt, the lualibs package
+--       AUTHOR:  Philipp Gesang (Phg), <phg42.2a@gmail.com>
+--      VERSION:  1.0
+--      CREATED:  2013-05-17 12:41:39+0200
+-----------------------------------------------------------------------
+-- we create a stripped-down version of char-def.lua
+-----------------------------------------------------------------------
+
+
+-----------------------------------------------------------------------
+--                              config
+-----------------------------------------------------------------------
+local charfile      = "./luaotfload-characters.lua"
+local chardef       = "~phg/base/char-def.lua"
+local import        = { "direction", "mirror", } --> πολυγλωσσία/uax9
+
+-----------------------------------------------------------------------
+--                             includes
+-----------------------------------------------------------------------
+
+kpse.set_program_name"luatex"
+
+for _, lib in next, { "lualibs-lua.lua",
+                      "lualibs-lpeg.lua",
+                      "lualibs-table.lua", } do
+  local found = assert(kpse.find_file(lib, "lua"),
+                       "Could not locate " .. lib .. ".\n"
+                       .. "Please install the lualibs package.")
+  require(found)
+end
+
+if not (chardef and lfs.isfile(chardef)) then
+  --- we could grab the file from contextgarden but as Context is part
+  --- of TL it’s not worth bothering 
+  chardef = assert(kpse.find_file("char-def.lua", "lua"),
+                   "Could not find ConTeXt.")
+end
+
+-----------------------------------------------------------------------
+--                           functionality
+-----------------------------------------------------------------------
+
+local get_characters = function ( )
+  local data
+  local inchan = io.open(chardef, "r")
+  if not inchan then
+    io.write("Could not open file for reading: "..chardef.."\n.")
+    goto fail
+  end
+  data = inchan:read "*all"
+  inchan:close()
+  data = loadstring(data)
+  if data then
+    data() --> characters.data
+    data = nil
+    collectgarbage "collect"
+    if characters.data and next(characters.data) then
+      return characters.data
+    end
+    io.write "Character table empty.\n"
+    goto fail
+  end
+  io.write(chardef .. " is not a valid Lua file.\n")
+  ::fail::
+  io.write "Emergency exit.\n"
+  os.exit(1)
+end
+
+local extract_fields_indeed
+extract_fields_indeed = function (data, acc, lastidx)
+  local idx, char = next(data, lastidx)
+  if idx then
+    local imported = { }
+    for i=1, #import do
+      local field = import[i]
+      imported[field] = char[field]
+    end
+    acc[idx] = imported
+    return extract_fields_indeed(data, acc, idx)
+  end
+  return acc
+end
+
+local extract_fields = function (data)
+  return extract_fields_indeed(data, {}, nil)
+end
+
+local writedata = function (data)
+  local outchan = io.open(charfile, "w")
+  if not outchan then
+    io.write("Could not open "..charfile.." for writing.\n")
+    return false
+  end
+  outchan:write(data)
+  outchan:close()
+  return true
+end
+
+do
+  local chardata    = get_characters()
+  local stripped    = extract_fields(chardata)
+  local serialized  = table.serialize(stripped)
+  if writedata(serialized) then
+    goto done
+  end
+  goto fail
+end
+
+::done::
+  os.exit(0)
+
+::fail::
+  io.write "Emergency exit.\n"
+  os.exit(1)
+
-- 
cgit v1.2.3


From 7c91bc4d366e6d0e4e04234441015f009d46d06a Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Fri, 17 May 2013 13:40:48 +0200
Subject: add serialization spec

---
 mkcharacters | 6 +++++-
 1 file changed, 5 insertions(+), 1 deletion(-)

diff --git a/mkcharacters b/mkcharacters
index 0ec871e..9b2f0c1 100755
--- a/mkcharacters
+++ b/mkcharacters
@@ -104,7 +104,11 @@ end
 do
   local chardata    = get_characters()
   local stripped    = extract_fields(chardata)
-  local serialized  = table.serialize(stripped)
+  local serialized  = table.serialize(stripped, true, {
+    compact   = true,
+    noquotes  = true,
+    hexify    = true, --- for consistency with char-def
+  })
   if writedata(serialized) then
     goto done
   end
-- 
cgit v1.2.3


From 8f0e083cfb980c95706f447cc117d9399518a9d7 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Fri, 17 May 2013 14:14:24 +0200
Subject: create make rule combining glyphlist and character list generation

---
 Makefile     | 23 +++++++++++++++++------
 mkcharacters |  3 +--
 2 files changed, 18 insertions(+), 8 deletions(-)

diff --git a/Makefile b/Makefile
index fce2e70..10b93ad 100644
--- a/Makefile
+++ b/Makefile
@@ -7,6 +7,9 @@ OTFL         = $(wildcard luaotfload-*.lua) luaotfload-blacklist.cnf
 
 GLYPHSCRIPT  = mkglyphlist
 GLYPHSOURCE  = glyphlist.txt
+CHARSCRIPT   = mkcharacters
+
+RESOURCESCRIPTS = $(GLYPHSCRIPT) $(CHARSCRIPT)
 
 SCRIPTNAME   = luaotfload-tool
 SCRIPT       = $(SCRIPTNAME).lua
@@ -20,12 +23,13 @@ DOT    		 = $(GRAPH).dot
 
 # Files grouped by generation mode
 GLYPHS      = luaotfload-glyphlist.lua
+CHARS       = luaotfload-characters.lua
 GRAPHED     = $(DOTPDF)
 MAN			= $(MANPAGE)
 COMPILED    = $(DOC)
 UNPACKED    = luaotfload.sty luaotfload.lua
-GENERATED   = $(GRAPHED) $(UNPACKED) $(COMPILED) $(GLYPHS) $(MAN)
-SOURCE 		= $(DTX) $(MANSOURCE) $(OTFL) README Makefile NEWS $(GLYPHSCRIPT)
+GENERATED   = $(GRAPHED) $(UNPACKED) $(COMPILED) $(GLYPHS) $(CHARS) $(MAN)
+SOURCE 		= $(DTX) $(MANSOURCE) $(OTFL) README Makefile NEWS $(RESOURCESCRIPTS)
 
 # test files
 TESTDIR 		= tests
@@ -34,7 +38,7 @@ TESTFILES_SYS 	= $(TESTDIR)/systemfonts.tex $(TESTDIR)/fontconfig_conf_reading.t
 TESTFILES_TL 	= $(filter-out $(TESTFILES_SYS), $(TESTFILES))
 
 # Files grouped by installation location
-SCRIPTFILES = $(SCRIPT) $(OLDSCRIPT) $(GLYPHSCRIPT)
+SCRIPTFILES = $(SCRIPT) $(OLDSCRIPT) $(RESOURCESCRIPTS)
 RUNFILES    = $(UNPACKED) $(filter-out $(SCRIPTFILES),$(OTFL))
 DOCFILES    = $(DOC) $(DOTPDF) README NEWS
 MANFILES	= $(MANPAGE)
@@ -57,11 +61,14 @@ CTAN_ZIP = $(NAME).zip
 TDS_ZIP  = $(NAME).tds.zip
 ZIPS 	 = $(CTAN_ZIP) $(TDS_ZIP)
 
+LUA	= texlua
+
 DO_TEX 		  	= luatex --interaction=batchmode $< >/dev/null
 # (with the next version of latexmk: -pdf -pdflatex=lualatex)
 DO_LATEX 	  	= latexmk -pdf -e '$$pdflatex = q(lualatex %O %S)' -silent $< >/dev/null
 DO_GRAPHVIZ 	= dot -Tpdf -o $@ $< > /dev/null
-DO_GLYPHLIST 	= texlua ./mkglyphlist > /dev/null
+DO_GLYPHS 		= $(LUA) $(GLYPHSCRIPT) > /dev/null
+DO_CHARS 		= $(LUA) $(CHARSCRIPT)  > /dev/null
 DO_DOCUTILS 	= rst2man $< >$@ 2>/dev/null
 
 all: $(GENERATED)
@@ -69,13 +76,17 @@ graph: $(GRAPHED)
 doc: $(GRAPHED) $(COMPILED) $(MAN)
 manual: $(MAN)
 unpack: $(UNPACKED)
-glyphs: $(GLYPHS)
+resources: $(GLYPHS) $(CHARS)
+chars: $(CHARS)
 ctan: $(CTAN_ZIP)
 tds: $(TDS_ZIP)
 world: all ctan
 
 $(GLYPHS): /dev/null
-	$(DO_GLYPHLIST)
+	$(DO_GLYPHS)
+
+$(CHARS): /dev/null
+	$(DO_CHARS)
 
 $(GRAPHED): $(DOT)
 	$(DO_GRAPHVIZ)
diff --git a/mkcharacters b/mkcharacters
index 9b2f0c1..a627ea9 100755
--- a/mkcharacters
+++ b/mkcharacters
@@ -3,7 +3,7 @@
 --         FILE:  mkcharacters.lua
 --        USAGE:  ./mkcharacters.lua 
 --  DESCRIPTION:  import parts of char-def.lua
--- REQUIREMENTS:  lua, lpeg, ConTeXt, the lualibs package
+-- REQUIREMENTS:  lua, ConTeXt, the lualibs package
 --       AUTHOR:  Philipp Gesang (Phg), <phg42.2a@gmail.com>
 --      VERSION:  1.0
 --      CREATED:  2013-05-17 12:41:39+0200
@@ -11,7 +11,6 @@
 -- we create a stripped-down version of char-def.lua
 -----------------------------------------------------------------------
 
-
 -----------------------------------------------------------------------
 --                              config
 -----------------------------------------------------------------------
-- 
cgit v1.2.3


From 1184d5032b4a812f8185d9d54a7a101c2c77bc35 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Fri, 17 May 2013 14:16:50 +0200
Subject: update NEWS

---
 NEWS | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index 2b7d4a0..9cb5ad9 100644
--- a/NEWS
+++ b/NEWS
@@ -1,7 +1,7 @@
 Change History
 --------------
 
-2013/05/11, luaotfload v2.2:
+2013/05/17, luaotfload v2.2:
     * There is now a central, non-personal dev repo on github:
       https://github.com/lualatex/luaotfload
     * Synchronisation with ConTeXt from TeXLive 2013, inducing
@@ -30,6 +30,7 @@ Change History
     * Unsupported v1.3 codebase is included in the luaotfload-*lua files. Crude,
       but effective way to support older Luatex binaries
     * implemented basic cache control/stats option for luaotfload-tool
+    * Character list is generated from char-def.lua (mkcharacters)
 
 2013/04/27, luaotfload v1.3:
     *  blacklisting lingoes.ttf (segfaults)
-- 
cgit v1.2.3


From ad95948e09bde3357faf57b6b13e63ae74fe60bb Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Fri, 17 May 2013 14:56:59 +0200
Subject: load character data on demand

---
 luaotfload-auxiliary.lua | 42 +++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 41 insertions(+), 1 deletion(-)

diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
index 64fac90..1a48914 100644
--- a/luaotfload-auxiliary.lua
+++ b/luaotfload-auxiliary.lua
@@ -26,6 +26,9 @@ local identifiers   = fonts.hashes.identifiers
 local fontid        = font.id
 local texsprint     = tex.sprint
 
+local dofile        = dofile
+local getmetatable  = getmetatable
+local setmetatable  = setmetatable
 local utf8          = unicode.utf8
 local stringlower   = string.lower
 local stringformat  = string.format
@@ -227,7 +230,7 @@ luatexbase.add_to_callback(
   "luaotfload.aux.set_capheight")
 
 -----------------------------------------------------------------------
----                             glyphs
+---                      glyphs and characters
 -----------------------------------------------------------------------
 
 local agl = fonts.encodings.agl
@@ -321,6 +324,43 @@ end
 
 aux.name_of_slot      = name_of_slot
 
+--[[doc--
+
+  In Context, characters.data is where the data from char-def.lua
+  resides. The file is huge (>3.7 MB as of 2013) and not part of the
+  isolated font loader. Nevertheless, we include a partial version
+  generated by the mkcharacters script that contains only the
+  “direction” and “mirror” fields of each character defined.
+
+--doc]]--
+
+characters      = characters or { } --- should be created in basics-gen
+characters.data = { }
+local chardef   = "luaotfload-characters"
+
+do
+  local chardata
+  local index = function (t, k)
+    if chardata == nil then
+      log("Loading character metadata from %s.", chardef)
+      chardata = dofile(kpse.find_file("luaotfload-characters.lua"))
+      if chardata == nil then
+        warning("Could not load %s; continuing with empty character table.",
+                chardef)
+        chardata = { }
+      end
+    end
+    return chardata[k]
+  end
+
+  local mt = getmetatable(characters.data)
+  if mt then
+    mt.__index = index
+  else
+    setmetatable(characters.data, { __index = index })
+  end
+end
+
 -----------------------------------------------------------------------
 ---                 features / scripts / languages
 -----------------------------------------------------------------------
-- 
cgit v1.2.3


From aceb8a22bd3e7c53de492d3e806ae265942ccfa6 Mon Sep 17 00:00:00 2001
From: Philipp Gesang <phg42.2a@gmail.com>
Date: Fri, 17 May 2013 15:39:51 +0200
Subject: add ``get_quad()``

---
 luaotfload-auxiliary.lua | 52 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 51 insertions(+), 1 deletion(-)

diff --git a/luaotfload-auxiliary.lua b/luaotfload-auxiliary.lua
index 1a48914..2bfcbf0 100644
--- a/luaotfload-auxiliary.lua
+++ b/luaotfload-auxiliary.lua
@@ -21,7 +21,8 @@ config.luaotfload           = config.luaotfload or { }
 local aux           = luaotfload.aux
 local log           = luaotfload.log
 local warning       = luaotfload.log
-local identifiers   = fonts.hashes.identifiers
+local fonthashes    = fonts.hashes
+local identifiers   = fonthashes.identifiers
 
 local fontid        = font.id
 local texsprint     = tex.sprint
@@ -680,4 +681,53 @@ end
 
 aux.get_raw_fonts = get_raw_fonts
 
+-----------------------------------------------------------------------
+---                         font parameters
+-----------------------------------------------------------------------
+--- analogy of font-hsh
+
+fonthashes.parameters    = fonthashes.parameters or { }
+fonthashes.quads         = fonthashes.quads or { }
+
+local parameters         = fonthashes.parameters or { }
+local quads              = fonthashes.quads or { }
+
+setmetatable(parameters, { __index = function (t, font_id)
+  local tfmdata = identifiers[font_id]
+  if not tfmdata then --- unsafe; avoid
+    tfmdata = font.fonts[font_id]
+  end
+  if tfmdata and type(tfmdata) == "table" then
+    local fontparameters = tfmdata.parameters
+    t[font_id] = fontparameters
+    return fontparameters
+  end
+  return nil
+end})
+
+--[[doc--
+
+  Note that the reason as to why we prefer functions over table indices
+  is that functions are much safer against unintended manipulation.
+  This justifies the overhead they cost.
+
+--doc]]--
+
+--- int -> (number | false)
+local get_quad = function (font_id)
+  local quad = quads[font_id]
+  if quad then
+    return quad
+  end
+  local fontparameters = parameters[font_id]
+  if fontparameters then
+    local quad     = fontparameters.quad or 0
+    quads[font_id] = quad
+    return quad
+  end
+  return false
+end
+
+aux.get_quad = get_quad
+
 -- vim:tw=71:sw=2:ts=2:expandtab
-- 
cgit v1.2.3