From d8dcfd9af18a15af70ec86d8e01e6d7a0f43c35c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 30 Jul 2015 07:53:30 +0200 Subject: [aux] do not rely on the AGL being loaded at initialization time --- src/luaotfload-auxiliary.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index 1ef581e..dce0d60 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -19,6 +19,7 @@ local aux = luaotfload.aux local log = luaotfload.log local report = log.report local fonthashes = fonts.hashes +local encodings = fonts.encodings local identifiers = fonthashes.identifiers local fontnames = fonts.names @@ -214,8 +215,6 @@ luatexbase.add_to_callback( --- glyphs and characters ----------------------------------------------------------------------- -local agl = fonts.encodings.agl - --- int -> int -> bool local font_has_glyph = function (font_id, codepoint) local fontdata = fonts.hashes.identifiers[font_id] @@ -232,7 +231,7 @@ aux.font_has_glyph = font_has_glyph 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 codepoint = encodings.agl.unicodes[glyphname] local glyph = fontdata.characters[codepoint] if fontdata.characters[codepoint] then return codepoint @@ -293,7 +292,7 @@ local indices --- int -> (string | false) local name_of_slot = function (codepoint) if not indices then --- this will load the glyph list - local unicodes = agl.unicodes + local unicodes = encodings.agl.unicodes indices = table.swapped(unicodes) end local glyphname = indices[codepoint] -- cgit v1.2.3 From e05c2e2c2f72788e63da7334e054fd887bd22e70 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 27 Aug 2015 23:08:11 +0200 Subject: [main] install stub for main initialization hook --- src/luaotfload-main.lua | 8 ++++++++ src/luaotfload.sty | 1 + 2 files changed, 9 insertions(+) diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index b633ed7..36db2c3 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -266,4 +266,12 @@ load_luaotfload_module "auxiliary" --- additional high-level functionality luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec +luaotfload.main = function () + local starttime = os.gettimeofday () + --- XXX stub + logreport ("both", 0, "main", + "initialization completed in %0.3f seconds", + os.gettimeofday() - starttime) +end + -- vim:tw=79:sw=4:ts=4:et diff --git a/src/luaotfload.sty b/src/luaotfload.sty index c9c9864..ec62dad 100644 --- a/src/luaotfload.sty +++ b/src/luaotfload.sty @@ -45,4 +45,5 @@ \RequirePackage{luatexbase} \fi \RequireLuaModule{luaotfload-main} +\directlua{local _void = luaotfload.main ()} -- cgit v1.2.3 From 7cd218b920814322d002f915ed5c8bb0132cf40a Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 27 Aug 2015 23:28:32 +0200 Subject: [main,loaders] regroup callback handling code with loaders MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ... changing the meaning of the file’s designation instead of adding yet another file. All the callback manipulation is now contained inside that module which will inject most of its functionality only when its main ``.install()`` method is called. --- src/luaotfload-loaders.lua | 147 ++++++++++++++++++++++++++++++++++++--------- src/luaotfload-main.lua | 116 +++++------------------------------ 2 files changed, 134 insertions(+), 129 deletions(-) diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index 901d4d8..061789c 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -1,34 +1,127 @@ -if not modules then modules = { } end modules ["loaders"] = { - version = "2.5", - comment = "companion to luaotfload-main.lua", - author = "Hans Hagen, Khaled Hosny, Elie Roux, Philipp Gesang", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} +#!/usr/bin/env texlua +----------------------------------------------------------------------- +-- FILE: luaotfload-loaders.lua +-- DESCRIPTION: Luaotfload callback handling +-- REQUIREMENTS: luatex v.0.80 or later; packages lualibs, luatexbase +-- AUTHOR: Philipp Gesang (Phg), , Hans Hagen, Khaled Hosny, Elie Roux +-- VERSION: just consult Git, okay? +----------------------------------------------------------------------- +-- +--- Contains parts of the earlier main script. + +if not lualibs then error "this module requires Luaotfload" end +if not luaotfload then error "this module requires Luaotfload" end + +local logreport = luaotfload.log and luaotfload.log.report or print +local add_to_callback = luatexbase.add_to_callback +local create_callback = luatexbase.create_callback +local reset_callback = luatexbase.reset_callback +local call_callback = luatexbase.call_callback +local dummy_function = function () end + +local install_formats = function () + local fonts = fonts + if not fonts then return false end + + local readers = fonts.readers + local handlers = fonts.handlers + local formats = fonts.formats + if not readers or not handlers or not formats then return false end + + local aux = function (which, reader) + if not which or type (which) ~= "string" then return false end + formats [which] = "type1" + readers [which] = reader + handlers [which] = { } + return true + end + + return aux ("pfa", function (spec) return readers.opentype (spec, "pfa", "type1") end) + and aux ("pfb", function (spec) return readers.opentype (spec, "pfb", "type1") end) + and aux ("ofm", readers.tfm) +end + +--[[doc-- -local fonts = fonts -local readers = fonts.readers -local handlers = fonts.handlers -local formats = fonts.formats - -local pfb_reader = function (specification) - return readers.opentype (specification, "pfb", "type1") -end - -local pfa_reader = function (specification) - return readers.opentype (specification, "pfa", "type1") + \subsection{\CONTEXT override} + \label{define-font} + We provide a simplified version of the original font definition + callback. + +--doc]]-- + + +local definers = { } --- (string, spec -> size -> id -> tmfdata) hash_t +do + local read = fonts.definers.read + + local patch = function (specification, size, id) + local fontdata = read (specification, size, id) + if type (fontdata) == "table" and fontdata.shared then + --- We need to test for the “shared” field here + --- or else the fontspec capheight callback will + --- operate on tfm fonts. + call_callback ("luaotfload.patch_font", fontdata, specification) + else + call_callback ("luaotfload.patch_font_unsafe", fontdata, specification) + end + return fontdata + end + + local mk_info = function (name) + local definer = name == "patch" and patch or read + return function (specification, size, id) + logreport ("both", 0, "main", "defining font no. %d", id) + logreport ("both", 0, "main", " > active font definer: %q", name) + logreport ("both", 0, "main", " > spec %q", specification) + logreport ("both", 0, "main", " > at size %.2f pt", size / 2^16) + local result = definer (specification, size, id) + if not result then + logreport ("both", 0, "main", " > font definition failed") + return + elseif type (result) == "number" then + logreport ("both", 0, "main", " > font definition yielded id %d", result) + return result + end + logreport ("both", 0, "main", " > font definition successful") + logreport ("both", 0, "main", " > name %q", result.name or "") + logreport ("both", 0, "main", " > fontname %q", result.fontname or "") + logreport ("both", 0, "main", " > fullname %q", result.fullname or "") + return result + end + end + + definers.patch = patch + definers.generic = read + definers.info_patch = mk_info "patch" + definers.info_generic = mk_info "generic" end -formats.pfa = "type1" -readers.pfa = pfa_reader -handlers.pfa = { } +--[[doc-- + + We create callbacks for patching fonts on the fly, to be used by + other packages. In addition to the regular \identifier{patch_font} + callback there is an unsafe variant \identifier{patch_font_unsafe} + that will be invoked even if the target font lacks certain essential + tfmdata tables. -formats.pfb = "type1" -readers.pfb = pfb_reader -handlers.pfb = { } + The callbacks initially contain the empty function that we are going + to override below. -formats.ofm = "type1" -readers.ofm = readers.tfm -handlers.ofm = { } +--doc]]-- +return { + install = function () + if not install_formats () then + logreport ("both", 0, "main", "error initializing OFM/PF{A,B} loaders") + end + create_callback("luaotfload.patch_font", "simple", dummy_function) + create_callback("luaotfload.patch_font_unsafe", "simple", dummy_function) + + reset_callback "define_font" + local definer = config.luaotfload.run.definer + add_to_callback ("define_font", definers[definer or "patch"], + "luaotfload.define_font", 1) + end +} -- vim:tw=71:sw=2:ts=2:expandtab diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 36db2c3..fe27215 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -67,12 +67,6 @@ luaotfload.module = { local luatexbase = luatexbase local require = require local type = type -local add_to_callback = luatexbase.add_to_callback -local create_callback = luatexbase.create_callback -local reset_callback = luatexbase.reset_callback -local call_callback = luatexbase.call_callback - -local dummy_function = function () end --- XXX this will be moved to the luaotfload namespace when we have the init module local error, warning, info, log = luatexbase.provides_module(luaotfload.module) @@ -165,110 +159,28 @@ 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. - -luaotfload.resolvers = load_luaotfload_module "resolvers" --- Font lookup - -luaotfload.resolvers.install () - -if not config.actions.reconfigure () then - logreport ("log", 0, "load", "Post-configuration hooks failed.") -end - ---[[doc-- - - We create callbacks for patching fonts on the fly, to be used by - other packages. In addition to the regular \identifier{patch_font} - callback there is an unsafe variant \identifier{patch_font_unsafe} - that will be invoked even if the target font lacks certain essential - tfmdata tables. - - The callbacks initially contain the empty function that we are going to - override below. - ---doc]]-- - -create_callback("luaotfload.patch_font", "simple", dummy_function) -create_callback("luaotfload.patch_font_unsafe", "simple", dummy_function) - ---[[doc-- - - \subsection{\CONTEXT override} - \label{define-font} - We provide a simplified version of the original font definition - callback. +luaotfload.main = function () + local starttime = os.gettimeofday () ---doc]]-- + luaotfload.loaders = load_luaotfload_module "loaders" --- Font loading; callbacks + luaotfload.loaders.install () + load_luaotfload_module "database" --- Font management. + load_luaotfload_module "colors" --- Per-font colors. -local definers = { } --- (string, spec -> size -> id -> tmfdata) hash_t -do - local read = fonts.definers.read - - local patch = function (specification, size, id) - local fontdata = read (specification, size, id) - if type (fontdata) == "table" and fontdata.shared then - --- We need to test for the “shared” field here - --- or else the fontspec capheight callback will - --- operate on tfm fonts. - call_callback ("luaotfload.patch_font", fontdata, specification) - else - call_callback ("luaotfload.patch_font_unsafe", fontdata, specification) - end - return fontdata - end + luaotfload.resolvers = load_luaotfload_module "resolvers" --- Font lookup + luaotfload.resolvers.install () - local mk_info = function (name) - local definer = name == "patch" and patch or read - return function (specification, size, id) - logreport ("both", 0, "main", "defining font no. %d", id) - logreport ("both", 0, "main", " > active font definer: %q", name) - logreport ("both", 0, "main", " > spec %q", specification) - logreport ("both", 0, "main", " > at size %.2f pt", size / 2^16) - local result = definer (specification, size, id) - if not result then - logreport ("both", 0, "main", " > font definition failed") - return - elseif type (result) == "number" then - logreport ("both", 0, "main", " > font definition yielded id %d", result) - return result - end - logreport ("both", 0, "main", " > font definition successful") - logreport ("both", 0, "main", " > name %q", result.name or "") - logreport ("both", 0, "main", " > fontname %q", result.fontname or "") - logreport ("both", 0, "main", " > fullname %q", result.fullname or "") - return result - end + if not config.actions.reconfigure () then + logreport ("log", 0, "load", "Post-configuration hooks failed.") end - definers.patch = patch - definers.generic = read - definers.info_patch = mk_info "patch" - definers.info_generic = mk_info "generic" -end - -reset_callback "define_font" - ---[[doc-- + load_luaotfload_module "features" --- font request and feature handling + load_luaotfload_module "letterspace" --- extra character kerning + load_luaotfload_module "auxiliary" --- additional high-level functionality - Finally we register the callbacks. + luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec ---doc]]-- - -local definer = config.luaotfload.run.definer -add_to_callback ("define_font", definers[definer], "luaotfload.define_font", 1) - -load_luaotfload_module "features" --- font request and feature handling -load_luaotfload_module "letterspace" --- extra character kerning -load_luaotfload_module "auxiliary" --- additional high-level functionality - -luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec - -luaotfload.main = function () - local starttime = os.gettimeofday () - --- XXX stub logreport ("both", 0, "main", "initialization completed in %0.3f seconds", os.gettimeofday() - starttime) -- cgit v1.2.3 From c6fdf62a060ad9e77c461d5eb7a55699fa6c7249 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 27 Aug 2015 23:39:46 +0200 Subject: [loaders] {re,un}-scope locals for economy --- src/luaotfload-loaders.lua | 57 +++++++++++++++++++++++++++++----------------- 1 file changed, 36 insertions(+), 21 deletions(-) diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index 061789c..f722d85 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -12,12 +12,7 @@ if not lualibs then error "this module requires Luaotfload" end if not luaotfload then error "this module requires Luaotfload" end -local logreport = luaotfload.log and luaotfload.log.report or print -local add_to_callback = luatexbase.add_to_callback -local create_callback = luatexbase.create_callback -local reset_callback = luatexbase.reset_callback -local call_callback = luatexbase.call_callback -local dummy_function = function () end +local logreport = luaotfload.log and luaotfload.log.report or print local install_formats = function () local fonts = fonts @@ -29,7 +24,11 @@ local install_formats = function () if not readers or not handlers or not formats then return false end local aux = function (which, reader) - if not which or type (which) ~= "string" then return false end + if not which or type (which) ~= "string" + or not reader or type (reader) ~= "function" then + logreport ("both", 2, "main", "error installing reader for “%s”", which) + return false + end formats [which] = "type1" readers [which] = reader handlers [which] = { } @@ -51,7 +50,7 @@ end --doc]]-- -local definers = { } --- (string, spec -> size -> id -> tmfdata) hash_t +local definers --- (string, spec -> size -> id -> tmfdata) hash_t do local read = fonts.definers.read @@ -61,7 +60,7 @@ do --- We need to test for the “shared” field here --- or else the fontspec capheight callback will --- operate on tfm fonts. - call_callback ("luaotfload.patch_font", fontdata, specification) + luatexbase.call_callback ("luaotfload.patch_font", fontdata, specification) else call_callback ("luaotfload.patch_font_unsafe", fontdata, specification) end @@ -91,10 +90,12 @@ do end end - definers.patch = patch - definers.generic = read - definers.info_patch = mk_info "patch" - definers.info_generic = mk_info "generic" + definers = { + patch = patch, + generic = read, + info_patch = mk_info "patch", + info_generic = mk_info "generic", + } end --[[doc-- @@ -110,18 +111,32 @@ end --doc]]-- +local install_callbacks = function () + local create_callback = luatexbase.create_callback + local dummy_function = function () end + create_callback ("luaotfload.patch_font", "simple", dummy_function) + create_callback ("luaotfload.patch_font_unsafe", "simple", dummy_function) + luatexbase.reset_callback "define_font" + local definer = config.luaotfload.run.definer + luatexbase.add_to_callback ("define_font", + definers[definer or "patch"], + "luaotfload.define_font", + 1) + return true +end + return { install = function () + local ret = true if not install_formats () then logreport ("both", 0, "main", "error initializing OFM/PF{A,B} loaders") + ret = false end - create_callback("luaotfload.patch_font", "simple", dummy_function) - create_callback("luaotfload.patch_font_unsafe", "simple", dummy_function) - - reset_callback "define_font" - local definer = config.luaotfload.run.definer - add_to_callback ("define_font", definers[definer or "patch"], - "luaotfload.define_font", 1) + if not install_callbacks () then + logreport ("both", 0, "main", "error installing font loader callbacks") + ret = false + end + return ret end } --- vim:tw=71:sw=2:ts=2:expandtab +-- vim:tw=79:sw=2:ts=2:expandtab -- cgit v1.2.3 From c3db46b819beebb892698513bd51341b9a691786 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 27 Aug 2015 23:42:44 +0200 Subject: [main,loaders] adjust noise and check status of loader init --- src/luaotfload-loaders.lua | 26 +++++++++++++------------- src/luaotfload-main.lua | 4 +++- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index f722d85..44216d7 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -26,7 +26,7 @@ local install_formats = function () local aux = function (which, reader) if not which or type (which) ~= "string" or not reader or type (reader) ~= "function" then - logreport ("both", 2, "main", "error installing reader for “%s”", which) + logreport ("both", 2, "loaders", "Error installing reader for “%s”.", which) return false end formats [which] = "type1" @@ -70,22 +70,22 @@ do local mk_info = function (name) local definer = name == "patch" and patch or read return function (specification, size, id) - logreport ("both", 0, "main", "defining font no. %d", id) - logreport ("both", 0, "main", " > active font definer: %q", name) - logreport ("both", 0, "main", " > spec %q", specification) - logreport ("both", 0, "main", " > at size %.2f pt", size / 2^16) + logreport ("both", 0, "loaders", "defining font no. %d", id) + logreport ("both", 0, "loaders", " > active font definer: %q", name) + logreport ("both", 0, "loaders", " > spec %q", specification) + logreport ("both", 0, "loaders", " > at size %.2f pt", size / 2^16) local result = definer (specification, size, id) if not result then - logreport ("both", 0, "main", " > font definition failed") + logreport ("both", 0, "loaders", " > font definition failed") return elseif type (result) == "number" then - logreport ("both", 0, "main", " > font definition yielded id %d", result) + logreport ("both", 0, "loaders", " > font definition yielded id %d", result) return result end - logreport ("both", 0, "main", " > font definition successful") - logreport ("both", 0, "main", " > name %q", result.name or "") - logreport ("both", 0, "main", " > fontname %q", result.fontname or "") - logreport ("both", 0, "main", " > fullname %q", result.fullname or "") + logreport ("both", 0, "loaders", " > font definition successful") + logreport ("both", 0, "loaders", " > name %q", result.name or "") + logreport ("both", 0, "loaders", " > fontname %q", result.fontname or "") + logreport ("both", 0, "loaders", " > fullname %q", result.fullname or "") return result end end @@ -129,11 +129,11 @@ return { install = function () local ret = true if not install_formats () then - logreport ("both", 0, "main", "error initializing OFM/PF{A,B} loaders") + logreport ("log", 0, "loaders", "Error initializing OFM/PF{A,B} loaders.") ret = false end if not install_callbacks () then - logreport ("both", 0, "main", "error installing font loader callbacks") + logreport ("log", 0, "loaders", "Error installing font loader callbacks.") ret = false end return ret diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index fe27215..32eb04d 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -163,7 +163,9 @@ luaotfload.main = function () local starttime = os.gettimeofday () luaotfload.loaders = load_luaotfload_module "loaders" --- Font loading; callbacks - luaotfload.loaders.install () + if not luaotfload.loaders.install () then + logreport ("log", 0, "load", "Callback and loader initialization failed.") + end load_luaotfload_module "database" --- Font management. load_luaotfload_module "colors" --- Per-font colors. -- cgit v1.2.3 From c7967b7a69bc5cf4e0c2e38b4e552c2587a7502d Mon Sep 17 00:00:00 2001 From: Dohyun Kim Date: Fri, 25 Sep 2015 14:01:40 +0900 Subject: [colors] support displayed math --- src/luaotfload-colors.lua | 52 ++++++++++++++++++++++++++++------------------- 1 file changed, 31 insertions(+), 21 deletions(-) diff --git a/src/luaotfload-colors.lua b/src/luaotfload-colors.lua index 89884b6..2171a68 100644 --- a/src/luaotfload-colors.lua +++ b/src/luaotfload-colors.lua @@ -192,6 +192,7 @@ local whatsit_t = nodetype("whatsit") local disc_t = nodetype("disc") local pdfliteral_t = node.subtype("pdf_literal") local colorstack_t = node.subtype("pdf_colorstack") +local mlist_to_hlist = node.mlist_to_hlist local color_callback local color_attr = luatexbase.new_attribute("luaotfload_color_attribute") @@ -230,8 +231,6 @@ local get_font_color = function (font_id) return font_color end -local cnt = 0 - --[[doc-- While the second argument and second returned value are apparently always nil when the function is called, they temporarily take string @@ -240,26 +239,24 @@ values during the node list traversal. --- (node * (string | nil)) -> (node * (string | nil)) local node_colorize -node_colorize = function (head, current_color) +node_colorize = function (head, toplevel, current_color) local n = head while n do local n_id = getid(n) if n_id == hlist_t or n_id == vlist_t then - cnt = cnt + 1 local n_list = getlist(n) if getattribute(n_list, color_attr) then if current_color then head, n, current_color = color_whatsit(head, n, current_color, false) end else - n_list, current_color = node_colorize(n_list, current_color) + n_list, current_color = node_colorize(n_list, false, current_color) if current_color and getsubtype(n) == 1 then -- created by linebreak n_list, _, current_color = color_whatsit(n_list, nodetail(n_list), current_color, false, true) end setfield(n, "head", n_list) end - cnt = cnt - 1 elseif n_id == glyph_t then --- colorization is restricted to those fonts @@ -303,7 +300,7 @@ node_colorize = function (head, current_color) n = getnext(n) end - if cnt == 0 and current_color then + if toplevel and current_color then head, _, current_color = color_whatsit(head, nodetail(head), current_color, false, true) end @@ -314,7 +311,7 @@ end --- node -> node local color_handler = function (head) head = todirect(head) - head = node_colorize(head) + head = node_colorize(head, true) head = tonode(head) -- now append our page resources @@ -351,6 +348,8 @@ local color_handler = function (head) end local color_callback_activated = 0 +local add_to_callback = luatexbase.add_to_callback +local priority_in_callback = luatexbase.priority_in_callback --- unit -> unit add_color_callback = function ( ) @@ -360,19 +359,30 @@ add_color_callback = function ( ) end if color_callback_activated == 0 then - luatexbase.add_to_callback(color_callback, - color_handler, - "luaotfload.color_handler") - luatexbase.add_to_callback("hpack_filter", - function (head, groupcode) - if groupcode == "hbox" or - groupcode == "adjusted_hbox" or - groupcode == "align_set" then - head = color_handler(head) - end - return head - end, - "luaotfload.color_handler") + add_to_callback(color_callback, + color_handler, + "luaotfload.color_handler") + add_to_callback("hpack_filter", + function (head, groupcode) + if groupcode == "hbox" or + groupcode == "adjusted_hbox" or + groupcode == "align_set" then + head = color_handler(head) + end + return head + end, + "luaotfload.color_handler") + add_to_callback("mlist_to_hlist", + function (head, display_type, need_penalties) + if priority_in_callback("mlist_to_hlist","luaotfload.color_handler") == 1 then + head = mlist_to_hlist(head, display_type, need_penalties) + end + if display_type == "text" then + return head + end + return color_handler(head) + end, + "luaotfload.color_handler") color_callback_activated = 1 end end -- cgit v1.2.3 From 4a76c3abcdf750cbf1e825d0fce637e35f63b10a Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 27 Sep 2015 18:28:14 +0200 Subject: [main, parsers] prepare for deferred initialization --- src/luaotfload-init.lua | 4 ++-- src/luaotfload-main.lua | 6 +++++- src/luaotfload-parsers.lua | 49 +++++++++++++++++++++------------------------- 3 files changed, 29 insertions(+), 30 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index a493cc1..a5e5bec 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -38,8 +38,8 @@ local logreport --- filled in after loading the log module --[[doc-- \subsection{Preparing the Font Loader} - We treat the fontloader as a black box so behavior is consistent - between formats. + We treat the fontloader as a semi-black box so behavior is + consistent between formats. We load the fontloader code directly in the same fashion as the Plain format \identifier{luatex-fonts} that is part of Context. How this is executed depends on the presence on the diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 32eb04d..3005f5a 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -150,7 +150,11 @@ local logreport = log.report --doc]]-- -load_luaotfload_module "parsers" --- fonts.conf and syntax +local tmp = load_luaotfload_module "parsers" --- fonts.conf and syntax +if not tmp.init () then + logreport ("log", 0, "load", "Failed to install the parsers.") +end + load_luaotfload_module "configuration" --- configuration options if not config.actions.apply_defaults () then diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua index a52b5d4..151cb9e 100644 --- a/src/luaotfload-parsers.lua +++ b/src/luaotfload-parsers.lua @@ -2,26 +2,14 @@ ------------------------------------------------------------------------------- -- FILE: luaotfload-parsers.lua -- DESCRIPTION: various lpeg-based parsers used in Luaotfload --- REQUIREMENTS: Luaotfload > 2.4 --- AUTHOR: Philipp Gesang (Phg), +-- REQUIREMENTS: Luaotfload > 2.6 +-- AUTHOR: Philipp Gesang (Phg), -- VERSION: same as Luaotfload -- CREATED: 2014-01-14 10:15:20+0100 ------------------------------------------------------------------------------- -- -if not modules then modules = { } end modules ['luaotfload-parsers'] = { - version = "2.5", - comment = "companion to luaotfload-main.lua", - author = "Philipp Gesang", - copyright = "Luaotfload Development Team", - license = "GNU GPL v2.0" -} - -luaotfload = luaotfload or { } -luaotfload.parsers = luaotfload.parsers or { } -local parsers = luaotfload.parsers -parsers.traversal_maxdepth = 42 --- prevent stack overflows -local traversal_maxdepth = parsers.traversal_maxdepth --- TODO could be an option +local traversal_maxdepth = 42 --- prevent stack overflows local rawset = rawset @@ -42,8 +30,7 @@ local filedirname = file.dirname local io = io local ioopen = io.open -local log = luaotfload.log -local logreport = log.report +local logreport = print local string = string local stringsub = string.sub @@ -399,10 +386,6 @@ local read_fonts_conf = function (path_list, find_files) return acc end -luaotfload.parsers.read_fonts_conf = read_fonts_conf - - - ------------------------------------------------------------------------------- --- MISC PARSERS ------------------------------------------------------------------------------- @@ -410,10 +393,8 @@ luaotfload.parsers.read_fonts_conf = read_fonts_conf local trailingslashes = slash^1 * P(-1) local stripslashes = C((1 - trailingslashes)^0) -parsers.stripslashes = stripslashes local splitcomma = Ct((C(noncomma^1) + comma)^1) -parsers.splitcomma = splitcomma @@ -653,8 +634,6 @@ local font_request = Ct(path_lookup * (colon^-1 * features)^-1 --- v2.5 parser: 1065 rules --- v1.2 parser: 230 rules -luaotfload.parsers.font_request = font_request - ------------------------------------------------------------------------------- --- INI FILES ------------------------------------------------------------------------------- @@ -731,7 +710,7 @@ local ini_variables = Cg (Cf (Ct "" * ini_variable^0, rawset), "variables") local ini_section = Ct (ini_heading * ini_variables) local ini_sections = skip_line^0 * ini_section^0 -local config = Ct (ini_sections) +local parse_config = Ct (ini_sections) --[=[doc-- @@ -763,6 +742,22 @@ local config = Ct (ini_sections) --doc]=]-- -luaotfload.parsers.config = config +return { + init = function () + logreport = luaotfload.log.report + luaotfload.parsers = { + --- parameters + traversal_maxdepth = traversal_maxdepth, + --- main parsers + read_fonts_conf = read_fonts_conf, + font_request = font_request, + config = parse_config, + --- common patterns + stripslashes = stripslashes, + splitcomma = splitcomma, + } + return true + end +} -- vim:ft=lua:tw=71:et:sw=2:sts=4:ts=8 -- cgit v1.2.3 From 974d9c6a280e42d01eb4a7c810900f9b4855e919 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 27 Sep 2015 18:43:41 +0200 Subject: [main, conf] prepare for deferred loading --- src/luaotfload-configuration.lua | 57 ++++++++++++++++++++-------------------- src/luaotfload-main.lua | 22 ++++++++-------- 2 files changed, 40 insertions(+), 39 deletions(-) diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index e2cfbd8..263c8ad 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -6,7 +6,6 @@ -- AUTHOR: Philipp Gesang (Phg), -- AUTHOR: Dohyun Kim -- VERSION: same as Luaotfload --- MODIFIED: 2015-05-05 ------------------------------------------------------------------------------- -- @@ -18,17 +17,12 @@ if not modules then modules = { } end modules ["luaotfload-configuration"] = { license = "GNU GPL v2.0" } -luaotfload = luaotfload or { } -config = config or { } -config.luaotfload = { } - local status_file = "luaotfload-status" local luaotfloadstatus = require (status_file) -local stringexplode = string.explode +local string = string local stringfind = string.find local stringformat = string.format -local string = string local stringstrip = string.strip local stringsub = string.sub @@ -55,9 +49,7 @@ local lpegmatch = lpeg.match local commasplitter = lpeg.splitat "," local equalssplitter = lpeg.splitat "=" -local kpse = kpse local kpseexpand_path = kpse.expand_path -local kpselookup = kpse.lookup local lfs = lfs local lfsisfile = lfs.isfile @@ -67,16 +59,12 @@ local file = file local filejoin = file.join local filereplacesuffix = file.replacesuffix +local logreport = print -- overloaded later +local getwritablepath = caches.getwritablepath -local parsers = luaotfload.parsers - -local log = luaotfload.log -local logreport = log.report - -local config_parser = parsers.config -local stripslashes = parsers.stripslashes -local getwritablepath = caches.getwritablepath +local config_parser -- set later during init +local stripslashes -- set later during init ------------------------------------------------------------------------------- --- SETTINGS @@ -301,8 +289,11 @@ local set_name_resolver = function () end local set_loglevel = function () - log.set_loglevel (config.luaotfload.run.log_level) - return true + if luaotfload then + luaotfload.log.set_loglevel (config.luaotfload.run.log_level) + return true + end + return false end local build_cache_paths = function () @@ -846,7 +837,7 @@ local read = function (extra) return false end - local parsed = lpegmatch (parsers.config, raw) + local parsed = lpegmatch (config_parser, raw) if not parsed then logreport ("both", 2, "conf", "Error parsing configuration file %q.", readme) return false @@ -912,13 +903,23 @@ end --- EXPORTS ------------------------------------------------------------------------------- -luaotfload.default_config = default_config - -config.actions = { - read = read, - apply = apply, - apply_defaults = apply_defaults, - reconfigure = reconfigure, - dump = dump, +return { + init = function () + config.luaotfload = { } + logreport = luaotfload.log.report + local parsers = luaotfload.parsers + config_parser = parsers.config + stripslashes = parsers.stripslashes + + luaotfload.default_config = default_config + config.actions = { + read = read, + apply = apply, + apply_defaults = apply_defaults, + reconfigure = reconfigure, + dump = dump, + } + return true + end } diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 3005f5a..73f9a75 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -15,6 +15,7 @@ local initial_log_level = 0 luaotfload = luaotfload or { } +config = config or { } local luaotfload = luaotfload luaotfload.log = luaotfload.log or { } luaotfload.version = "2.6" @@ -150,22 +151,21 @@ local logreport = log.report --doc]]-- -local tmp = load_luaotfload_module "parsers" --- fonts.conf and syntax -if not tmp.init () then - logreport ("log", 0, "load", "Failed to install the parsers.") -end - -load_luaotfload_module "configuration" --- configuration options - -if not config.actions.apply_defaults () then - logreport ("log", 0, "load", "Configuration unsuccessful.") -end - luaotfload.init.main (store) luaotfload.main = function () local starttime = os.gettimeofday () + local tmp = load_luaotfload_module "parsers" --- fonts.conf and syntax + if not tmp.init () then + logreport ("log", 0, "load", "Failed to install the parsers.") + end + + local tmp = load_luaotfload_module "configuration" --- configuration options + if not tmp.init() or not config.actions.apply_defaults () then + logreport ("log", 0, "load", "Configuration unsuccessful.") + end + luaotfload.loaders = load_luaotfload_module "loaders" --- Font loading; callbacks if not luaotfload.loaders.install () then logreport ("log", 0, "load", "Callback and loader initialization failed.") -- cgit v1.2.3 From 145203842d83591fc9e67322472994c481d5aadc Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 27 Sep 2015 18:50:22 +0200 Subject: [main] move toplevel statements into init routine --- src/luaotfload-main.lua | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 73f9a75..9e57dbf 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -139,26 +139,21 @@ local load_fontloader_module = make_loader "fontloader" luaotfload.loaders.luaotfload = load_luaotfload_module luaotfload.loaders.fontloader = load_fontloader_module -luaotfload.init = load_luaotfload_module "init" --- fontloader initialization - -local store = luaotfload.init.early () -local log = luaotfload.log -local logreport = log.report - --[[doc-- Now we load the modules written for \identifier{luaotfload}. --doc]]-- -luaotfload.init.main (store) - luaotfload.main = function () local starttime = os.gettimeofday () + local init = load_luaotfload_module "init" --- fontloader initialization + local store = init.early () --- injects the log module too + local logreport = luaotfload.log.report local tmp = load_luaotfload_module "parsers" --- fonts.conf and syntax if not tmp.init () then - logreport ("log", 0, "load", "Failed to install the parsers.") + logreport ("log", 0, "load", "Failed to install the parsers module.") end local tmp = load_luaotfload_module "configuration" --- configuration options @@ -166,6 +161,10 @@ luaotfload.main = function () logreport ("log", 0, "load", "Configuration unsuccessful.") end + if not init.main (store) then + logreport ("log", 0, "load", "Main fontloader initialization failed.") + end + luaotfload.loaders = load_luaotfload_module "loaders" --- Font loading; callbacks if not luaotfload.loaders.install () then logreport ("log", 0, "load", "Callback and loader initialization failed.") -- cgit v1.2.3 From 1497cfdbee7193ab84f87daa6229b54be3209cd4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 27 Sep 2015 19:18:06 +0200 Subject: [main, db] convert for deferred initialization Also clean up the local name of the logger for consistency with the rest of the code base. --- src/luaotfload-database.lua | 440 +++++++++++++++++++++++--------------------- 1 file changed, 226 insertions(+), 214 deletions(-) diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index f4aab16..d9d7594 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -45,7 +45,7 @@ local stripslashes = parsers.stripslashes local splitcomma = parsers.splitcomma local log = luaotfload.log -local report = log.report +local logreport = log and log.report or print -- overriden later on local report_status = log.names_status local report_status_start = log.names_status_start local report_status_stop = log.names_status_stop @@ -119,19 +119,10 @@ local tablefastcopy = table.fastcopy local tabletofile = table.tofile local tabletohash = table.tohash local tableserialize = table.serialize ---- the font loader namespace is “fonts”, same as in Context ---- we need to put some fallbacks into place for when running ---- as a script -fonts = fonts or { } -fonts.names = fonts.names or { } -fonts.definers = fonts.definers or { } - -local names = fonts.names +local names = fonts and fonts.names or { } + local name_index = nil --> upvalue for names.data local lookup_cache = nil --> for names.lookups -names.version = 2.51 -names.data = nil --- contains the loaded database -names.lookups = nil --- contains the lookup cache --- string -> (string * string) local make_luanames = function (path) @@ -485,12 +476,12 @@ load_names = function (dry_run, no_rebuild) local foundname, data = load_lua_file (config.luaotfload.paths.index_path_lua) if data then - report ("log", 0, "db", - "Font names database loaded from %s", foundname) - report ("term", 3, "db", - "Font names database loaded from %s", foundname) - report ("info", 3, "db", "Loading took %0.f ms.", - 1000 * (osgettimeofday () - starttime)) + logreport ("log", 0, "db", + "Font names database loaded from %s", foundname) + logreport ("term", 3, "db", + "Font names database loaded from %s", foundname) + logreport ("info", 3, "db", "Loading took %0.f ms.", + 1000 * (osgettimeofday () - starttime)) local db_version, names_version if data.meta then @@ -503,32 +494,32 @@ load_names = function (dry_run, no_rebuild) end names_version = names.version if db_version ~= names_version then - report ("both", 0, "db", - [[Version mismatch; expected %4.3f, got %4.3f.]], - names_version, db_version) + logreport ("both", 0, "db", + [[Version mismatch; expected %4.3f, got %4.3f.]], + names_version, db_version) if not fonts_reloaded then - report ("both", 0, "db", [[Force rebuild.]]) + logreport ("both", 0, "db", [[Force rebuild.]]) data = update_names ({ }, true, false) if not data then - report ("both", 0, "db", - "Database creation unsuccessful.") + logreport ("both", 0, "db", + "Database creation unsuccessful.") end end end else if no_rebuild == true then - report ("both", 2, "db", - [[Database does not exist, skipping rebuild though.]]) + logreport ("both", 2, "db", + [[Database does not exist, skipping rebuild though.]]) return false end - report ("both", 0, "db", - [[Font names database not found, generating new one.]]) - report ("both", 0, "db", - [[This can take several minutes; please be patient.]]) + logreport ("both", 0, "db", + [[Font names database not found, generating new one.]]) + logreport ("both", 0, "db", + [[This can take several minutes; please be patient.]]) data = update_names (initialize_namedata (get_font_filter ()), nil, dry_run) if not data then - report ("both", 0, "db", "Database creation unsuccessful.") + logreport ("both", 0, "db", "Database creation unsuccessful.") end end return data @@ -559,12 +550,12 @@ local load_lookups load_lookups = function ( ) local foundname, data = load_lua_file(config.luaotfload.paths.lookup_path_lua) if data then - report("log", 0, "cache", "Lookup cache loaded from %s.", foundname) - report("term", 3, "cache", - "Lookup cache loaded from %s.", foundname) + logreport ("log", 0, "cache", "Lookup cache loaded from %s.", foundname) + logreport ("term", 3, "cache", + "Lookup cache loaded from %s.", foundname) else - report("both", 1, "cache", - "No lookup cache, creating empty.") + logreport ("both", 1, "cache", + "No lookup cache, creating empty.") data = { } end lookup_cache = data @@ -780,23 +771,24 @@ 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 ...", - request) + logreport ("both", 4, "cache", "Looking for %q in cache ...", + request) local found = lookup_cache [request] --- case 1) cache positive ---------------------------------------- if found then --- replay fields from cache hit - report("info", 4, "cache", "Found!") + logreport ("info", 4, "cache", "Found!") local basename = found[1] --- check the presence of the file in case it’s been removed local success = verify_font_file (basename) if success == true then return basename, found[2], true end - report("both", 4, "cache", "Cached file not found; resolving again.") + logreport ("both", 4, "cache", + "Cached file not found; resolving again.") else - report("both", 4, "cache", "Not cached; resolving.") + logreport ("both", 4, "cache", "Not cached; resolving.") end --- case 2) cache negative ---------------------------------------- @@ -807,16 +799,16 @@ lookup_font_name_cached = function (specification) end --- ... then we add the fields to the cache ... ... local entry = { filename, subfont } - report("both", 4, "cache", "New entry: %s.", request) + logreport ("both", 4, "cache", "New entry: %s.", request) lookup_cache [request] = entry --- obviously, the updated cache needs to be stored. --- TODO this should trigger a save only once the --- document is compiled (finish_pdffile callback?) - report("both", 5, "cache", "Saving updated cache.") + logreport ("both", 5, "cache", "Saving updated cache.") local success = save_lookups () if not success then --- sad, but not critical - report("both", 0, "cache", "Error writing cache.") + logreport ("both", 0, "cache", "Error writing cache.") end return filename, subfont end @@ -973,8 +965,8 @@ local lookup_familyname = function (specification, name, style, askedsize) if not success then return nil, nil end - report ("info", 2, "db", "Match found: %s(%d).", - resolved, subfont or 0) + logreport ("info", 2, "db", "Match found: %s(%d).", + resolved, subfont or 0) return resolved, subfont end @@ -1140,9 +1132,9 @@ reload_db = function (why, caller, ...) local namedata = name_index local formats = tableconcat (namedata.meta.formats, ",") - report ("both", 0, "db", - "Reload initiated (formats: %s); reason: %q.", - formats, why) + logreport ("both", 0, "db", + "Reload initiated (formats: %s); reason: %q.", + formats, why) set_font_filter (formats) namedata = update_names (namedata, false, false) @@ -1153,7 +1145,7 @@ reload_db = function (why, caller, ...) return caller (...) end - report ("both", 0, "db", "Database update unsuccessful.") + logreport ("both", 0, "db", "Database update unsuccessful.") end --- string -> string -> int @@ -1237,15 +1229,15 @@ find_closest = function (name, limit) if n_distances > 0 then --- got some data tablesort(distances) limit = mathmin(n_distances, limit) - report(false, 1, "query", - "Displaying %d distance levels.", limit) + logreport (false, 1, "query", + "Displaying %d distance levels.", limit) for i = 1, limit do local dist = distances[i] local namelst = by_distance[dist] - report(false, 0, "query", - "Distance from \"%s\": %s\n " - .. tableconcat (namelst, "\n "), + logreport (false, 0, "query", + "Distance from \"%s\": %s\n " + .. tableconcat (namelst, "\n "), name, dist) end @@ -1273,7 +1265,7 @@ local load_font_file = function (filename, subfont) local rawfont, _msg = fontloaderopen (filename, subfont) --local rawfont, _msg = fontloaderinfo (filename, subfont) if not rawfont then - report ("log", 1, "db", "ERROR: failed to open %s.", filename) + logreport ("log", 1, "db", "ERROR: failed to open %s.", filename) return end return rawfont @@ -1316,8 +1308,8 @@ local get_english_names = function (metadata) end -- no (English) names table, probably a broken font - report("both", 3, "db", - "%s: missing or broken English names table.", basename) + logreport ("both", 3, "db", + "%s: missing or broken English names table.", basename) return { fontname = metadata.fontname, fullname = metadata.fullname, } end @@ -1343,9 +1335,9 @@ local get_raw_info = function (metadata, basename) --- Broken names table, e.g. avkv.ttf with UTF-16 strings; --- we put some dummies in place like the fontloader --- (font-otf.lua) does. - report("both", 3, "db", - "%s has invalid postscript font names, using dummies.", - basename) + logreport ("both", 3, "db", + "%s has invalid postscript font names, using dummies.", + basename) fontname = "bad-fontname-" .. basename fullname = "bad-fullname-" .. basename end @@ -1619,7 +1611,7 @@ local compare_timestamps = function (fullname, if targetentrystatus ~= nil and targetentrystatus.timestamp == targettimestamp then - report ("log", 3, "db", "Font %q already read.", fullname) + logreport ("log", 3, "db", "Font %q already read.", fullname) return false end @@ -1641,7 +1633,7 @@ local compare_timestamps = function (fullname, targetentrystatus.index [targetindex + 1] = location end - report ("log", 3, "db", "Font %q already indexed.", fullname) + logreport ("log", 3, "db", "Font %q already indexed.", fullname) return false end @@ -1721,8 +1713,8 @@ local read_font_names = function (fullname, --- 1) skip if blacklisted if names.blacklist[fullname] or names.blacklist[basename] then - report("log", 2, "db", - "Ignoring blacklisted font %q.", fullname) + logreport ("log", 2, "db", + "Ignoring blacklisted font %q.", fullname) return false end @@ -1745,8 +1737,8 @@ local read_font_names = function (fullname, local loader = loaders [format] --- ot_fullinfo, t1_fullinfo if not loader then - report ("both", 0, "db", - "Unknown format: %q, skipping.", format) + logreport ("both", 0, "db", + "Unknown format: %q, skipping.", format) return false end @@ -1755,8 +1747,8 @@ local read_font_names = function (fullname, local info = fontloaderinfo (fullname) if not info then - report ("log", 1, "db", - "Failed to read basic information from %q", basename) + logreport ("log", 1, "db", + "Failed to read basic information from %q", basename) return false end @@ -1830,9 +1822,7 @@ end fonts.path_normalize = path_normalize -names.blacklist = { } - -local blacklist = names.blacklist +local blacklist = { } local p_blacklist --- prefixes of dirs --- string list -> string list @@ -1861,8 +1851,8 @@ local create_blacklist = function (blacklist, whitelist) local result = { } local dirs = { } - report("info", 2, "db", "Blacklisting %d files and directories.", - #blacklist) + logreport ("info", 2, "db", "Blacklisting %d files and directories.", + #blacklist) for i=1, #blacklist do local entry = blacklist[i] if lfsisdir(entry) then @@ -1872,7 +1862,7 @@ local create_blacklist = function (blacklist, whitelist) end end - report("info", 2, "db", "Whitelisting %d files.", #whitelist) + logreport ("info", 2, "db", "Whitelisting %d files.", #whitelist) for i=1, #whitelist do result[whitelist[i]] = nil end @@ -1914,9 +1904,9 @@ read_blacklist = function () if first_chr == "%" or stringis_empty(line) then -- comment or empty line elseif first_chr == "-" then - report ("both", 3, "db", - "Whitelisted file %q via %q.", - line, path) + logreport ("both", 3, "db", + "Whitelisted file %q via %q.", + line, path) whitelist[#whitelist+1] = stringsub(line, 2, -1) else local cmt = stringfind(line, "%%") @@ -1924,9 +1914,9 @@ read_blacklist = function () line = stringsub(line, 1, cmt - 1) end line = stringstrip(line) - report ("both", 3, "db", - "Blacklisted file %q via %q.", - line, path) + logreport ("both", 3, "db", + "Blacklisted file %q via %q.", + line, path) blacklist[#blacklist+1] = line end end @@ -2123,24 +2113,24 @@ end --- string -> string -> string * string list local collect_font_filenames_dir = function (dirname, location) if lpegmatch (p_blacklist, dirname) then - report ("both", 4, "db", - "Skipping blacklisted directory %s.", dirname) + logreport ("both", 4, "db", + "Skipping blacklisted directory %s.", dirname) --- ignore return { } end local found = find_font_files (dirname, location ~= "texmf" and location ~= "local") if not found then - report ("both", 4, "db", - "No such directory: %q; skipping.", dirname) + logreport ("both", 4, "db", + "No such directory: %q; skipping.", dirname) return { } end local nfound = #found local files = { } - report ("both", 4, "db", - "%d font files detected in %s.", - nfound, dirname) + logreport ("both", 4, "db", + "%d font files detected in %s.", + nfound, dirname) for j = 1, nfound do local fullname = found[j] files[#files + 1] = { path_normalize (fullname), location } @@ -2184,14 +2174,14 @@ local collect_font_filenames_texmf = function () local osfontdir = kpseexpand_path "$OSFONTDIR" if stringis_empty (osfontdir) then - report ("info", 1, "db", "Scanning TEXMF for fonts...") + logreport ("info", 1, "db", "Scanning TEXMF for fonts...") else - report ("info", 1, "db", "Scanning TEXMF and $OSFONTDIR for fonts...") + logreport ("info", 1, "db", "Scanning TEXMF and $OSFONTDIR for fonts...") if log.get_loglevel () > 3 then local osdirs = filesplitpath (osfontdir) - report ("info", 0, "db", "$OSFONTDIR has %d entries:", #osdirs) + logreport ("info", 0, "db", "$OSFONTDIR has %d entries:", #osdirs) for i = 1, #osdirs do - report ("info", 0, "db", "[%d] %s", i, osdirs[i]) + logreport ("info", 0, "db", "[%d] %s", i, osdirs[i]) end end end @@ -2205,14 +2195,14 @@ local collect_font_filenames_texmf = function () end local tasks = filter_out_pwd (filesplitpath (fontdirs)) - report ("info", 3, "db", - "Initiating scan of %d directories.", #tasks) + logreport ("info", 3, "db", + "Initiating scan of %d directories.", #tasks) local files = { } for _, dir in next, tasks do files = tableappend (files, collect_font_filenames_dir (dir, "texmf")) end - report ("term", 3, "db", "Collected %d files.", #files) + logreport ("term", 3, "db", "Collected %d files.", #files) return files end @@ -2247,14 +2237,14 @@ end --- string list -> size_t local count_removed = function (old) - report("log", 4, "db", "Checking removed files.") + logreport ("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.") + logreport ("log", 2, "db", + "File %s does not exist in file system.") nrem = nrem + 1 end end @@ -2281,7 +2271,7 @@ local retrieve_namedata = function (files, currentnames, targetnames, dry_run) local nfiles = #files local nnew = 0 - report ("info", 1, "db", "Scanning %d collected font files ...", nfiles) + logreport ("info", 1, "db", "Scanning %d collected font files ...", nfiles) local bylocation = { texmf = { 0, 0 } , ["local"] = { 0, 0 } @@ -2294,12 +2284,12 @@ local retrieve_namedata = function (files, currentnames, targetnames, dry_run) count[1] = count[1] + 1 if dry_run == true then local truncated = truncate_string (fullname, 43) - report ("log", 2, "db", "Would have been loading %s.", fullname) + logreport ("log", 2, "db", "Would have been loading %s.", fullname) report_status ("term", "db", "Would have been loading %s", truncated) --- skip the read_font_names part else local truncated = truncate_string (fullname, 32) - report ("log", 2, "db", "Loading font %s.", fullname) + logreport ("log", 2, "db", "Loading font %s.", fullname) report_status ("term", "db", "Loading font %s", truncated) local new = read_font_names (fullname, currentnames, targetnames, location) @@ -2311,8 +2301,8 @@ local retrieve_namedata = function (files, currentnames, targetnames, dry_run) end report_status_stop ("term", "db", "Scanned %d files, %d new.", nfiles, nnew) for location, count in next, bylocation do - report ("term", 4, "db", " * %s: %d files, %d new", - location, count[1], count[2]) + logreport ("term", 4, "db", " * %s: %d files, %d new", + location, count[1], count[2]) end return nnew end @@ -2321,15 +2311,15 @@ end local collect_font_filenames_system = function () local n_scanned, n_new = 0, 0 - report ("info", 1, "db", "Scanning system fonts...") - report ("info", 2, "db", - "Searching in static system directories...") + logreport ("info", 1, "db", "Scanning system fonts...") + logreport ("info", 2, "db", + "Searching in static system directories...") local files = { } for _, dir in next, get_os_dirs () do tableappend (files, collect_font_filenames_dir (dir, "system")) end - report ("term", 3, "db", "Collected %d files.", #files) + logreport ("term", 3, "db", "Collected %d files.", #files) return files end @@ -2355,25 +2345,25 @@ end --- unit -> string * string list local collect_font_filenames_local = function () local pwd = lfscurrentdir () - report ("both", 1, "db", "Scanning for fonts in $PWD (%q) ...", pwd) + logreport ("both", 1, "db", "Scanning for fonts in $PWD (%q) ...", pwd) local files = collect_font_filenames_dir (pwd, "local") local nfiles = #files if nfiles > 0 then targetnames.meta["local"] = true --- prevent saving to disk - report ("term", 1, "db", "Found %d files.", pwd) + logreport ("term", 1, "db", "Found %d files.", pwd) else - report ("term", 1, "db", - "Couldn’t find a thing here. What a waste.", pwd) + logreport ("term", 1, "db", + "Couldn’t find a thing here. What a waste.", pwd) end - report ("term", 3, "db", "Collected %d files.", #files) + logreport ("term", 3, "db", "Collected %d files.", #files) return files end --- fontentry list -> filemap generate_filedata = function (mappings) - report ("both", 2, "db", "Creating filename map.") + logreport ("both", 2, "db", "Creating filename map.") local nmappings = #mappings @@ -2435,10 +2425,10 @@ generate_filedata = function (mappings) if inbase then local present = inbase [basename] if present then - report ("both", 4, "db", - "Conflicting basename: %q already indexed \z - in category %s, ignoring.", - barename, location) + logreport ("both", 4, "db", + "Conflicting basename: %q already indexed \z + in category %s, ignoring.", + barename, location) conflicts.basenames = conflicts.basenames + 1 --- track conflicts per font @@ -2465,10 +2455,10 @@ generate_filedata = function (mappings) if inbare then local present = inbare [barename] if present then - report ("both", 4, "db", - "Conflicting barename: %q already indexed \z - in category %s/%s, ignoring.", - barename, location, format) + logreport ("both", 4, "db", + "Conflicting barename: %q already indexed \z + in category %s/%s, ignoring.", + barename, location, format) conflicts.barenames = conflicts.barenames + 1 --- track conflicts per font @@ -2650,7 +2640,7 @@ end collect_families = function (mappings) - report ("info", 2, "db", "Analyzing families.") + logreport ("info", 2, "db", "Analyzing families.") local families = { ["local"] = { }, @@ -2746,7 +2736,7 @@ local style_categories = { "r", "b", "i", "bi" } local bold_categories = { "b", "bi" } group_modifiers = function (mappings, families) - report ("info", 2, "db", "Analyzing shapes, weights, and styles.") + logreport ("info", 2, "db", "Analyzing shapes, weights, and styles.") for location, location_data in next, families do for format, format_data in next, location_data do for familyname, collected in next, format_data do @@ -2845,7 +2835,7 @@ end order_design_sizes = function (families) - report ("info", 2, "db", "Ordering design sizes.") + logreport ("info", 2, "db", "Ordering design sizes.") for location, data in next, families do for format, data in next, data do @@ -2870,7 +2860,7 @@ end --- unit -> string * string list local collect_font_filenames = function () - report ("info", 4, "db", "Scanning the filesystem for font files.") + logreport ("info", 4, "db", "Scanning the filesystem for font files.") local filenames = { } local bisect = config.luaotfload.misc.bisect @@ -2900,7 +2890,7 @@ end --- int -> string local nth_font_filename = function (n) - report ("info", 4, "db", "Picking font file no. %d.", n) + logreport ("info", 4, "db", "Picking font file no. %d.", n) if not p_blacklist then read_blacklist () end @@ -2915,7 +2905,7 @@ end --doc]]-- local font_slice = function (lo, hi) - report ("info", 4, "db", "Retrieving font files nos. %d--%d.", lo, hi) + logreport ("info", 4, "db", "Retrieving font files nos. %d--%d.", lo, hi) if not p_blacklist then read_blacklist () end @@ -2937,7 +2927,7 @@ end --- unit -> int local count_font_files = function () - report ("info", 4, "db", "Counting font files.") + logreport ("info", 4, "db", "Counting font files.") if not p_blacklist then read_blacklist () end @@ -3063,31 +3053,31 @@ local collect_statistics = function (mappings) itemlist = tableconcat (itemlist, ", ") end - report ("both", 0, "db", - " · %4d × %s.", - freq, itemlist) + logreport ("both", 0, "db", + " · %4d × %s.", + freq, itemlist) end end - report ("both", 0, "", "~~~~ font index statistics ~~~~") - report ("both", 0, "db", - " · Collected %d fonts (%d names) in %d families.", - #mappings, n_fullname, n_family) + logreport ("both", 0, "", "~~~~ font index statistics ~~~~") + logreport ("both", 0, "db", + " · Collected %d fonts (%d names) in %d families.", + #mappings, n_fullname, n_family) pprint_top (families, 4, true) - report ("both", 0, "db", - " · %d different “subfamily” kinds.", - setsize (subfamily)) + logreport ("both", 0, "db", + " · %d different “subfamily” kinds.", + setsize (subfamily)) pprint_top (subfamily, 4) - report ("both", 0, "db", - " · %d different “prefmodifiers” kinds.", - setsize (prefmodifiers)) + logreport ("both", 0, "db", + " · %d different “prefmodifiers” kinds.", + setsize (prefmodifiers)) pprint_top (prefmodifiers, 4) - report ("both", 0, "db", - " · %d different “fontstyle_name” kinds.", - setsize (fontstyle_name)) + logreport ("both", 0, "db", + " · %d different “fontstyle_name” kinds.", + setsize (fontstyle_name)) pprint_top (fontstyle_name, 4) end @@ -3121,7 +3111,7 @@ update_names = function (currentnames, force, dry_run) local conf = config.luaotfload if conf.run.live ~= false and conf.db.update_live == false then - report ("info", 2, "db", "Skipping database update.") + logreport ("info", 2, "db", "Skipping database update.") --- skip all db updates return currentnames or name_index end @@ -3133,15 +3123,16 @@ update_names = function (currentnames, force, dry_run) - “targetnames” is the final table to return - force is whether we rebuild it from scratch or not ]] - report("both", 1, "db", "Updating the font names database" - .. (force and " forcefully." or ".")) + logreport ("both", 1, "db", + "Updating the font names database" + .. (force and " forcefully." or ".")) if config.luaotfload.db.skip_read == true then --- the difference to a “dry run” is that we don’t search --- for font files entirely. we also ignore the “force” --- parameter since it concerns only the font files. - report ("info", 2, "db", - "Ignoring font files, reusing old data.") + logreport ("info", 2, "db", + "Ignoring font files, reusing old data.") currentnames = load_names (false) targetnames = currentnames else @@ -3152,8 +3143,9 @@ update_names = function (currentnames, force, dry_run) currentnames = load_names (dry_run) end if currentnames.meta.version ~= names.version then - report ("both", 1, "db", "No font names database or old " - .. "one found; generating new one.") + logreport ("both", 1, "db", + "No font names database or old \z + one found; generating new one.") currentnames = initialize_namedata (get_font_filter ()) end end @@ -3176,9 +3168,9 @@ update_names = function (currentnames, force, dry_run) targetnames, dry_run) - report ("info", 3, "db", - "Found %d font files; %d new, %d stale entries.", - #font_filenames, n_new, n_rem) + logreport ("info", 3, "db", + "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 @@ -3204,27 +3196,27 @@ 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)) + logreport ("info", 3, "db", + "Rebuilt in %0.f ms.", + 1000 * (osgettimeofday () - starttime)) name_index = targetnames if dry_run ~= true then if n_new + n_rem == 0 then - report ("info", 2, "db", - "No new or removed fonts, skip saving to disk.") + logreport ("info", 2, "db", + "No new or removed fonts, skip saving to disk.") else local success, reason = save_names () if not success then - report ("both", 0, "db", - "Failed to save database to disk: %s", - reason) + logreport ("both", 0, "db", + "Failed to save database to disk: %s", + reason) end end if flush_lookup_cache () and save_lookups () then - report ("both", 2, "cache", "Lookup cache emptied.") + logreport ("both", 2, "cache", "Lookup cache emptied.") return targetnames end end @@ -3241,18 +3233,18 @@ save_lookups = function ( ) caches.compile (lookup_cache, luaname, lucname) --- double check ... if lfsisfile (luaname) and lfsisfile (lucname) then - report ("both", 3, "cache", "Lookup cache saved.") + logreport ("both", 3, "cache", "Lookup cache saved.") return true end - report ("info", 0, "cache", "Could not compile lookup cache.") + logreport ("info", 0, "cache", "Could not compile lookup cache.") return false end - report ("info", 0, "cache", "Lookup cache file not writable.") + logreport ("info", 0, "cache", "Lookup cache file not writable.") if not fileiswritable (luaname) then - report ("info", 0, "cache", "Failed to write %s.", luaname) + logreport ("info", 0, "cache", "Failed to write %s.", luaname) end if not fileiswritable (lucname) then - report ("info", 0, "cache", "Failed to write %s.", lucname) + logreport ("info", 0, "cache", "Failed to write %s.", lucname) end return false end @@ -3281,33 +3273,33 @@ save_names = function (currentnames) tabletofile (luaname, currentnames, true) caches.compile (currentnames, luaname, lucname) end - report ("info", 2, "db", "Font index saved at ...") + logreport ("info", 2, "db", "Font index saved at ...") local success = false if lfsisfile (luaname) then - report ("info", 2, "db", "Text: " .. luaname) + logreport ("info", 2, "db", "Text: " .. luaname) success = true end if lfsisfile (gzname) then - report ("info", 2, "db", "Gzip: " .. gzname) + logreport ("info", 2, "db", "Gzip: " .. gzname) success = true end if lfsisfile (lucname) then - report ("info", 2, "db", "Byte: " .. lucname) + logreport ("info", 2, "db", "Byte: " .. lucname) success = true end if success then return true else - report ("info", 0, "db", "Could not compile font index.") + logreport ("info", 0, "db", "Could not compile font index.") return false end end - report ("info", 0, "db", "Index file not writable") + logreport ("info", 0, "db", "Index file not writable") if not fileiswritable (luaname) then - report ("info", 0, "db", "Failed to write %s.", luaname) + logreport ("info", 0, "db", "Failed to write %s.", luaname) end if not fileiswritable (lucname) then - report ("info", 0, "db", "Failed to write %s.", lucname) + logreport ("info", 0, "db", "Failed to write %s.", lucname) end return false end @@ -3321,7 +3313,7 @@ end --- string -> string -> string list -> string list -> string list -> unit local print_cache = function (category, path, luanames, lucnames, rest) local report_indeed = function (...) - report("info", 0, "cache", ...) + logreport ("info", 0, "cache", ...) end report_indeed("Luaotfload cache: %s", category) report_indeed("location: %s", path) @@ -3333,15 +3325,15 @@ end --- string -> string -> string list -> bool -> bool local purge_from_cache = function (category, path, list, all) - report("info", 1, "cache", "Luaotfload cache: %s %s", - (all and "erase" or "purge"), category) - report("info", 1, "cache", "location: %s",path) + logreport ("info", 1, "cache", "Luaotfload cache: %s %s", + (all and "erase" or "purge"), category) + logreport ("info", 1, "cache", "location: %s", path) local n = 0 for i=1,#list do local filename = list[i] if stringfind(filename,"luatex%-cache") then -- safeguard if all then - report("info", 5, "cache", "Removing %s.", filename) + logreport ("info", 5, "cache", "Removing %s.", filename) osremove(filename) n = n + 1 else @@ -3350,7 +3342,7 @@ local purge_from_cache = function (category, path, list, all) local checkname = file.replacesuffix( filename, "lua", "luc") if lfsisfile(checkname) then - report("info", 5, "cache", "Removing %s.", filename) + logreport ("info", 5, "cache", "Removing %s.", filename) osremove(filename) n = n + 1 end @@ -3358,7 +3350,7 @@ local purge_from_cache = function (category, path, list, all) end end end - report("info", 1, "cache", "Removed lua files : %i", n) + logreport ("info", 1, "cache", "Removed lua files : %i", n) return true end @@ -3435,7 +3427,7 @@ local erase_cache = function ( ) end local separator = function ( ) - report("info", 0, string.rep("-", 67)) + logreport ("info", 0, string.rep("-", 67)) end --- unit -> unit @@ -3464,35 +3456,55 @@ end --- export functionality to the namespace “fonts.names” ----------------------------------------------------------------------- -names.set_font_filter = set_font_filter -names.flush_lookup_cache = flush_lookup_cache -names.save_lookups = save_lookups -names.load = load_names -names.access_font_index = access_font_index -names.data = function () return name_index end -names.save = save_names -names.update = update_names -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.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 - ---- font cache -names.purge_cache = purge_cache -names.erase_cache = erase_cache -names.show_cache = show_cache - -names.find_closest = find_closest - --- for testing purpose -names.read_fonts_conf = read_fonts_conf +local export = { + set_font_filter = set_font_filter, + flush_lookup_cache = flush_lookup_cache, + save_lookups = save_lookups, + load = load_names, + access_font_index = access_font_index, + data = function () return name_index end, + save = save_names, + update = update_names, + lookup_font_file = lookup_font_file, + lookup_font_name = lookup_font_name, + lookup_font_name_cached = lookup_font_name_cached, + getfilename = lookup_fullpath, + lookup_fullpath = lookup_fullpath, + read_blacklist = read_blacklist, + sanitize_fontname = sanitize_fontname, + getmetadata = getmetadata, + set_location_precedence = set_location_precedence, + count_font_files = count_font_files, + nth_font_filename = nth_font_filename, + font_slice = font_slice, + --- font cache + purge_cache = purge_cache, + erase_cache = erase_cache, + show_cache = show_cache, + find_closest = find_closest, + -- for testing purpose + read_fonts_conf = read_fonts_conf, +} + +return { + init = function () + --- the font loader namespace is “fonts”, same as in Context + --- we need to put some fallbacks into place for when running + --- as a script + log = luaotfload.log + logreport = log.report + fonts = fonts or { } + local fonts = fonts + fonts.names = fonts.names or names + fonts.definers = fonts.definers or { } + + names.blacklist = blacklist + names.version = 2.51 + names.data = nil --- contains the loaded database + names.lookups = nil --- contains the lookup cache + + for sym, ref in next, export do names[sym] = ref end + end +} -- vim:tw=71:sw=4:ts=4:expandtab -- cgit v1.2.3 From 780113609ffbb146c1b5a825cb25025246cdba2a Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 27 Sep 2015 20:17:02 +0200 Subject: [main, *] convert for centralized initialization routine --- src/luaotfload-colors.lua | 78 +++++++++++++++++--------------- src/luaotfload-configuration.lua | 4 ++ src/luaotfload-database.lua | 6 +-- src/luaotfload-features.lua | 81 +++++++++++++++++---------------- src/luaotfload-init.lua | 2 + src/luaotfload-loaders.lua | 2 +- src/luaotfload-main.lua | 96 ++++++++++++++++++++++++++-------------- 7 files changed, 157 insertions(+), 112 deletions(-) diff --git a/src/luaotfload-colors.lua b/src/luaotfload-colors.lua index 89884b6..a0b80bd 100644 --- a/src/luaotfload-colors.lua +++ b/src/luaotfload-colors.lua @@ -19,8 +19,7 @@ explanation: http://tug.org/pipermail/luatex/2013-May/004305.html --doc]]-- -local log = luaotfload.log -local logreport = log.report +local logreport = luaotfload and luaotfload.log.report or print local nodedirect = node.direct local newnode = nodedirect.new @@ -44,10 +43,7 @@ local texsettoks = tex.settoks local texgettoks = tex.gettoks local stringformat = string.format - -local otffeatures = fonts.constructors.newfeatures("otf") local identifiers = fonts.hashes.identifiers -local registerotffeature = otffeatures.register local add_color_callback --[[ this used to be a global‽ ]] @@ -101,36 +97,6 @@ local sanitize_color_expression = function (digits) return sanitized end ---[[doc-- -``setcolor`` modifies tfmdata.properties.color in place ---doc]]-- - ---- fontobj -> string -> unit ---- ---- (where “string” is a rgb value as three octet ---- hexadecimal, with an optional fourth transparency ---- value) ---- -local setcolor = function (tfmdata, value) - local sanitized = sanitize_color_expression(value) - local properties = tfmdata.properties - - if sanitized then - properties.color = sanitized - add_color_callback() - end -end - -registerotffeature { - name = "color", - description = "color", - initializers = { - base = setcolor, - node = setcolor, - } -} - - --- something is carried around in ``res`` --- for later use by color_handler() --- but what? @@ -377,5 +343,47 @@ add_color_callback = function ( ) end end +--[[doc-- +``setcolor`` modifies tfmdata.properties.color in place +--doc]]-- + +--- fontobj -> string -> unit +--- +--- (where “string” is a rgb value as three octet +--- hexadecimal, with an optional fourth transparency +--- value) +--- +local setcolor = function (tfmdata, value) + local sanitized = sanitize_color_expression(value) + local properties = tfmdata.properties + + if sanitized then + properties.color = sanitized + add_color_callback() + end +end + +return { + init = function () + logreport = luaotfload.log.report + if not fonts then + logreport ("log", 0, "color", + "OTF mechanisms missing -- did you forget to \z + load a font loader?") + return false + end + fonts.handlers.otf.features.register { + name = "color", + description = "color", + initializers = { + base = setcolor, + node = setcolor, + } + } + return true + end +} + + -- vim:tw=71:sw=4:ts=4:expandtab diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index 263c8ad..86a302e 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -919,6 +919,10 @@ return { reconfigure = reconfigure, dump = dump, } + if not apply_defaults () then + logreport ("log", 0, "load", + "Configuration unsuccessful: error loading default settings.") + end return true end } diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index d9d7594..4af2451 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -3491,9 +3491,8 @@ return { --- the font loader namespace is “fonts”, same as in Context --- we need to put some fallbacks into place for when running --- as a script - log = luaotfload.log - logreport = log.report - fonts = fonts or { } + if not fonts then return false end + logreport = luaotfload.log.report local fonts = fonts fonts.names = fonts.names or names fonts.definers = fonts.definers or { } @@ -3504,6 +3503,7 @@ return { names.lookups = nil --- contains the lookup cache for sym, ref in next, export do names[sym] = ref end + return true end } diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 9b895ce..6fb2114 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -921,24 +921,13 @@ end ---[[ end included font-ltx.lua ]] ---[[doc-- -This uses the code from luatex-fonts-merged (<- font-otc.lua) instead -of the removed luaotfload-font-otc.lua. - -TODO find out how far we get setting features without these lines, -relying on luatex-fonts only (it *does* handle features somehow, after -all). ---doc]]-- - --- we assume that the other otf stuff is loaded already +-- We assume that the other otf stuff is loaded already; though there’s +-- another check below during the initialization phase. ---[[ begin snippet from font-otc.lua ]] local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end) local report_otf = logs.reporter("fonts","otf loading") -local otf = fonts.handlers.otf -local registerotffeature = otf.features.register - --[[HH-- In the userdata interface we can not longer tweak the loaded font as @@ -960,7 +949,7 @@ setmetatableindex(types, function(t,k) t[k] = k return k end) -- "key" local everywhere = { ["*"] = { ["*"] = true } } -- or: { ["*"] = { "*" } } local noflags = { } -local function addfeature(data,feature,specifications) +local function addfeature (data, feature, specifications) local descriptions = data.descriptions local resources = data.resources local lookups = resources.lookups @@ -1100,26 +1089,9 @@ local function addfeature(data,feature,specifications) end end - -otf.enhancers.addfeature = addfeature - -local extrafeatures = { } - -function otf.addfeature(name,specification) - extrafeatures[name] = specification -end - -local function enhance(data,filename,raw) - for feature, specification in next, extrafeatures do - addfeature(data,feature,specification) - end -end - -otf.enhancers.register("check extra features",enhance) - ---[[ end snippet from font-otc.lua ]] -local tlig = { +local tlig_specification = { { type = "substitution", features = everywhere, @@ -1167,9 +1139,6 @@ local tlig = { }, } -otf.addfeature ("tlig", tlig) -otf.addfeature ("trep", { }) - local anum_arabic = { --- these are the same as in font-otc [0x0030] = 0x0660, [0x0031] = 0x0661, @@ -1228,11 +1197,45 @@ local anum_specification = { }, } -otf.addfeature ("anum", anum_specification) +return { + init = function () + + if not fonts and fonts.handlers then + logreport ("log", 0, "color", + "OTF mechanisms missing -- did you forget to \z + load a font loader?") + return false + end + + local otf = fonts.handlers.otf -registerotffeature { - name = "anum", - description = "arabic digits", + local extrafeatures = { + tlig = tlig_specification, + trep = { }, + anum = anum_specification, + } + + otf.enhancers.register ("check extra features", + function (data,filename, raw) + for feature, specification in next, extrafeatures do + addfeature (data, feature, specification) + end + end) + + logreport = luaotfload.log.report + if not fonts then + logreport ("log", 0, "color", + "OTF mechanisms missing -- did you forget to \z + load a font loader?") + return false + end + + otf.features.register { + name = "anum", + description = "arabic digits", + } + return true + end } -- vim:tw=71:sw=4:ts=4:expandtab diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index a5e5bec..af71cb2 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -431,6 +431,8 @@ return { os.gettimeofday() - starttime) local n = init_post () logreport ("both", 5, "init", "post hook terminated, %d actions performed", n) + return true end } +-- vim:tw=79:sw=2:ts=2:expandtab diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index 44216d7..89a9fff 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -126,7 +126,7 @@ local install_callbacks = function () end return { - install = function () + init = function () local ret = true if not install_formats () then logreport ("log", 0, "loaders", "Error initializing OFM/PF{A,B} loaders.") diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 9e57dbf..815a2f0 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -13,6 +13,9 @@ --- version 2.4 to 2.5. Thus, the comments are still in TeX (Latex) --- markup. +local os = os +local osgettimeofday = os.gettimeofday + local initial_log_level = 0 luaotfload = luaotfload or { } config = config or { } @@ -125,70 +128,95 @@ local make_loader_name = function (prefix, name) return name end +local timing_info = { + t_load = { }, + t_init = { }, +} + local make_loader = function (prefix) return function (name) + local t_0 = osgettimeofday () local modname = make_loader_name (prefix, name) - return require (modname) + local data = require (modname) + local t_end = osgettimeofday () + timing_info.t_load [name] = t_end - t_0 + return data end end -local load_luaotfload_module = make_loader "luaotfload" ------ load_luaotfload_module = make_loader "luatex" --=> for Luatex-Plain -local load_fontloader_module = make_loader "fontloader" +local install_loaders = function () + local loaders = { } + local loadmodule = make_loader "luaotfload" + loaders.luaotfload = loadmodule + loaders.fontloader = make_loader "fontloader" +----loaders.plaintex = make_loader "luatex" --=> for Luatex-Plain + + loaders.initialize = function (name) + local tmp = loadmodule (name) + local logreport = luaotfload.log.report + if type (tmp) == "table" then + local init = tmp.init + if init and type (init) == "function" then + local t_0 = osgettimeofday () + if not init () then + logreport ("log", 0, "load", + "Failed to load module “%s”.", name) + return + end + local t_end = osgettimeofday () + local d_t = t_end - t_0 + logreport ("log", 4, "load", + "Module “%s” loaded in %d ms.", + d_t) + timing_info.t_init [name] = d_t + end + end + end -luaotfload.loaders.luaotfload = load_luaotfload_module -luaotfload.loaders.fontloader = load_fontloader_module + return loaders +end ---[[doc-- - Now we load the modules written for \identifier{luaotfload}. +luaotfload.main = function () ---doc]]-- + luaotfload.loaders = install_loaders () + local loaders = luaotfload.loaders + local loadmodule = loaders.luaotfload + local initialize = loaders.initialize -luaotfload.main = function () - local starttime = os.gettimeofday () - local init = load_luaotfload_module "init" --- fontloader initialization - local store = init.early () --- injects the log module too + local starttime = osgettimeofday () + local init = loadmodule "init" --- fontloader initialization + local store = init.early () --- injects the log module too local logreport = luaotfload.log.report - local tmp = load_luaotfload_module "parsers" --- fonts.conf and syntax - if not tmp.init () then - logreport ("log", 0, "load", "Failed to install the parsers module.") - end - - local tmp = load_luaotfload_module "configuration" --- configuration options - if not tmp.init() or not config.actions.apply_defaults () then - logreport ("log", 0, "load", "Configuration unsuccessful.") - end + initialize "parsers" --- fonts.conf and syntax + initialize "configuration" --- configuration options if not init.main (store) then logreport ("log", 0, "load", "Main fontloader initialization failed.") end - luaotfload.loaders = load_luaotfload_module "loaders" --- Font loading; callbacks - if not luaotfload.loaders.install () then - logreport ("log", 0, "load", "Callback and loader initialization failed.") - end - - load_luaotfload_module "database" --- Font management. - load_luaotfload_module "colors" --- Per-font colors. + initialize "loaders" --- Font loading; callbacks + initialize "database" --- Font management. + initialize "colors" --- Per-font colors. - luaotfload.resolvers = load_luaotfload_module "resolvers" --- Font lookup + luaotfload.resolvers = loadmodule "resolvers" --- Font lookup luaotfload.resolvers.install () if not config.actions.reconfigure () then logreport ("log", 0, "load", "Post-configuration hooks failed.") end - load_luaotfload_module "features" --- font request and feature handling - load_luaotfload_module "letterspace" --- extra character kerning - load_luaotfload_module "auxiliary" --- additional high-level functionality + initialize "features" --- font request and feature handling + loadmodule "letterspace" --- extra character kerning + loadmodule "auxiliary" --- additional high-level functionality luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec logreport ("both", 0, "main", "initialization completed in %0.3f seconds", - os.gettimeofday() - starttime) + osgettimeofday() - starttime) +----inspect (timing_info) end -- vim:tw=79:sw=4:ts=4:et -- cgit v1.2.3 From 120c852ccd7a1579310ed855a4d8b1322a1f9d09 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 06:48:50 +0100 Subject: main: fix module insertion and throw away luatexbase-provided resources --- src/luaotfload-main.lua | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 815a2f0..3d68a17 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -72,16 +72,9 @@ local luatexbase = luatexbase local require = require local type = type -local error, warning, info, log = +local _error, _warning, _info, _log = luatexbase.provides_module(luaotfload.module) -luaotfload.log.tex = { - error = error, - warning = warning, - info = info, - log = log, -} - --[[doc-- We set the minimum version requirement for \LUATEX to v0.76, @@ -167,7 +160,7 @@ local install_loaders = function () local d_t = t_end - t_0 logreport ("log", 4, "load", "Module “%s” loaded in %d ms.", - d_t) + name, d_t) timing_info.t_init [name] = d_t end end -- cgit v1.2.3 From d2e389383564c7f7faf9dd93976e5d548924e1e4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 06:54:43 +0100 Subject: [db] fix behavior when starting with no data --- src/luaotfload-database.lua | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index 4af2451..1845643 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -354,7 +354,7 @@ local initialize_namedata = function (formats, created) status = { }, -- was: status; map abspath -> mapping mappings = { }, -- TODO: check if still necessary after rewrite names = { }, --- files = { }, -- created later + files = { }, -- created later meta = { created = created or now, formats = formats, @@ -2236,7 +2236,12 @@ end --doc]]-- --- string list -> size_t -local count_removed = function (old) +local count_removed = function (files) + if not files or not files.full then + logreport ("log", 4, "db", "Empty file store; no data to work with.") + return 0 + end + local old = files.full logreport ("log", 4, "db", "Checking removed files.") local nrem = 0 local nold = #old @@ -3161,7 +3166,7 @@ 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_rem = count_removed (currentnames.files) n_new = retrieve_namedata (font_filenames, currentnames, -- cgit v1.2.3 From 811d385a2c903f001ceb719ae1a29ce4586b16b4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 06:56:07 +0100 Subject: [loaders] fix call to missing local --- src/luaotfload-loaders.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index 89a9fff..b644266 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -62,7 +62,7 @@ do --- operate on tfm fonts. luatexbase.call_callback ("luaotfload.patch_font", fontdata, specification) else - call_callback ("luaotfload.patch_font_unsafe", fontdata, specification) + luatexbase.call_callback ("luaotfload.patch_font_unsafe", fontdata, specification) end return fontdata end -- cgit v1.2.3 From 5907d3909cdc508f7804434d4a88d3977530ed64 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 07:03:11 +0100 Subject: [db] fix access to restructured globals --- src/luaotfload-database.lua | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index 1845643..b871954 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -39,11 +39,6 @@ if not modules then modules = { } end modules ['luaotfload-database'] = { local lpeg = require "lpeg" local P, Cc, lpegmatch = lpeg.P, lpeg.Cc, lpeg.match -local parsers = luaotfload.parsers -local read_fonts_conf = parsers.read_fonts_conf -local stripslashes = parsers.stripslashes -local splitcomma = parsers.splitcomma - local log = luaotfload.log local logreport = log and log.report or print -- overriden later on local report_status = log.names_status @@ -1820,8 +1815,6 @@ do end end -fonts.path_normalize = path_normalize - local blacklist = { } local p_blacklist --- prefixes of dirs @@ -1953,6 +1946,9 @@ do return end + if splitcomma == nil then + splitcomma = luaotfload.parsers and luaotfload.parsers.splitcomma + end if stringsub (formats, 1, 1) == "+" then -- add formats = lpegmatch (splitcomma, stringsub (formats, 2)) if formats then @@ -2138,10 +2134,12 @@ local collect_font_filenames_dir = function (dirname, location) return files end - --- string list -> string list local filter_out_pwd = function (dirs) local result = { } + if stripslashes == nil then + stripslashes = luaotfload.parsers and luaotfload.parsers.stripslashes + end local pwd = path_normalize (lpegmatch (stripslashes, lfscurrentdir ())) for i = 1, #dirs do @@ -2223,7 +2221,10 @@ local function get_os_dirs () "/usr/local/etc/fonts/fonts.conf", "/etc/fonts/fonts.conf", } - local os_dirs = read_fonts_conf(fonts_conves, find_files) + if not luaotfload.parsers then + logreport ("log", 0, "db", "Fatal: no fonts.conf parser.") + end + local os_dirs = luaotfload.parsers.read_fonts_conf(fonts_conves, find_files) return os_dirs end return {} @@ -3488,7 +3489,6 @@ local export = { show_cache = show_cache, find_closest = find_closest, -- for testing purpose - read_fonts_conf = read_fonts_conf, } return { -- cgit v1.2.3 From a29b5562c526a9079f09ea022db5fa4951c18c58 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 07:09:22 +0100 Subject: [tool] fix interfacing with database --- src/luaotfload-tool.lua | 53 ++++++++++++++++++++++++------------------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index e240e4c..fdc6c62 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -143,15 +143,14 @@ require"luaotfload-basics-gen.lua" texio.write, texio.write_nl = backup.write, backup.write_nl utilities = backup.utilities +fonts = { names = { } } -- for db; normally provided by the fontloaders + require "luaotfload-log.lua" --- this populates the luaotfload.log.* namespace require "luaotfload-parsers" --- fonts.conf, configuration, and request syntax require "luaotfload-configuration" --- configuration file handling require "luaotfload-database" require "alt_getopt" -local names = fonts.names -local sanitize_fontname = names.sanitize_fontname - local log = luaotfload.log local report = log.report @@ -272,7 +271,7 @@ local about = [[ local version_msg = function ( ) local out = function (...) texiowrite_nl (stringformat (...)) end local uname = os.uname () - local meta = names.getmetadata () + local meta = fonts.names.getmetadata () out (about, luaotfload.self) out ("%s version: %q", luaotfload.self, version) out ("Revision: %q", config.luaotfload.status.notes.revision) @@ -673,7 +672,7 @@ subfont_by_name = function (lst, askedname, n) local font = lst[n] if font then - if sanitize_fontname (font.fullname) == askedname then + if fonts.names.sanitize_fontname (font.fullname) == askedname then return font end return subfont_by_name (lst, askedname, n+1) @@ -690,10 +689,10 @@ The font info knows two levels of detail: --doc]]-- local show_font_info = function (basename, askedname, detail, warnings) - local filenames = names.data().files + local filenames = fonts.names.data().files local index = filenames.base[basename] local fullname = filenames.full[index] - askedname = sanitize_fontname (askedname) + askedname = fonts.names.sanitize_fontname (askedname) if not fullname then -- texmf fullname = resolvers.findfile(basename) end @@ -797,17 +796,17 @@ actions.help = function (job) end actions.blacklist = function (job) - names.read_blacklist() + fonts.names.read_blacklist() local n = 0 - for n, entry in next, tablesortedkeys(names.blacklist) do + for n, entry in next, tablesortedkeys(fonts.names.blacklist) do iowrite (stringformat("(%d %s)\n", n, entry)) end return true, false end actions.generate = function (job) - local _ = names.update (fontnames, job.force_reload, job.dry_run) - local namedata = names.data () + local _ = fonts.names.update (fontnames, job.force_reload, job.dry_run) + local namedata = fonts.names.data () if namedata then report ("info", 2, "db", "Fonts in the database: %i", #namedata.mappings) return true, true @@ -895,7 +894,7 @@ local bisect_start = function () end report ("info", 2, "bisect", "Starting bisection of font database %q.", bisect_status_file) - local n = names.count_font_files () + local n = fonts.names.count_font_files () local pivot = mathfloor (n / 2) local data = { { 1, n, pivot } } report ("info", 0, "bisect", "Initializing pivot to %d.", pivot) @@ -946,7 +945,7 @@ local bisect_terminate = function (nsteps, culprit) report ("info", 1, "bisect", "Bisection completed after %d steps.", nsteps) report ("info", 0, "bisect", - "Bad file: %s.", names.nth_font_filename (culprit)) + "Bad file: %s.", fonts.names.nth_font_filename (culprit)) report ("info", 0, "bisect", "Run with --bisect=stop to finish bisection.") return true, false @@ -959,7 +958,7 @@ end --doc]]-- local list_remainder = function (lo, hi) - local fonts = names.font_slice (lo, hi) + local fonts = fonts.names.font_slice (lo, hi) report ("info", 0, "bisect", "%d fonts left.", hi - lo + 1) for i = 1, #fonts do report ("info", 1, "bisect", " · %2d: %s", lo, fonts[i]) @@ -1110,9 +1109,9 @@ actions.bisect = function (job) end actions.flush = function (job) - local success = names.flush_lookup_cache() + local success = fonts.names.flush_lookup_cache() if success then - local success = names.save_lookups() + local success = fonts.names.save_lookups() if success then report ("info", 2, "cache", "Lookup cache emptied") return true, true @@ -1122,9 +1121,9 @@ actions.flush = function (job) end local cache_directives = { - ["purge"] = names.purge_cache, - ["erase"] = names.erase_cache, - ["show"] = names.show_cache, + ["purge"] = fonts.names.purge_cache, + ["erase"] = fonts.names.erase_cache, + ["show"] = fonts.names.show_cache, } actions.cache = function (job) @@ -1154,7 +1153,7 @@ actions.query = function (job) features = { }, } - tmpspec = names.handle_request (tmpspec) + tmpspec = fonts.names.handle_request (tmpspec) if not tmpspec.size then tmpspec.size = 655360 --- assume 10pt @@ -1165,13 +1164,13 @@ actions.query = function (job) if tmpspec.lookup == "name" or tmpspec.lookup == "anon" --- not *exactly* as resolvers.anon then - foundname, subfont = names.resolve_name (tmpspec) + foundname, subfont = fonts.names.resolve_name (tmpspec) if foundname then - foundname, _, success = names.font_file_lookup (foundname) + foundname, _, success = fonts.names.font_file_lookup (foundname) end elseif tmpspec.lookup == "file" then foundname, _, success = - names.font_file_lookup (tmpspec.name) + fonts.names.font_file_lookup (tmpspec.name) end if success then @@ -1196,7 +1195,7 @@ actions.query = function (job) if job.fuzzy == true then report (false, 0, "resolve", "Looking for close matches, this may take a while ...") - local _success = names.find_closest(query, job.fuzzy_limit) + local _success = fonts.names.find_closest(query, job.fuzzy_limit) end end return true, true @@ -1274,7 +1273,7 @@ local splitcomma = luaotfload.parsers.splitcomma actions.list = function (job) local criterion = job.criterion local asked_fields = job.asked_fields - local name_index = names.data () + local name_index = fonts.names.data () if asked_fields then asked_fields = lpegmatch(splitcomma, asked_fields) @@ -1286,7 +1285,7 @@ actions.list = function (job) end if not name_index then - name_index = names.load() + name_index = fonts.names.load() end local mappings = name_index.mappings @@ -1528,7 +1527,7 @@ local process_cmdline = function ( ) -- unit -> jobspec elseif v == "D" then result.dry_run = true elseif v == "p" then - names.set_location_precedence { + fonts.names.set_location_precedence { "local", "texmf", "system" } elseif v == "b" then -- cgit v1.2.3 From 3b2349244c00df1393f3aedb910e7e458a52a7ea Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 07:17:04 +0100 Subject: [tool] defer import of logger --- src/luaotfload-tool.lua | 207 ++++++++++++++++++++++++++---------------------- 1 file changed, 114 insertions(+), 93 deletions(-) diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index fdc6c62..6b84a6d 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -151,8 +151,12 @@ require "luaotfload-configuration" --- configuration file handling require "luaotfload-database" require "alt_getopt" -local log = luaotfload.log -local report = log.report +local logreport + +local init_modules = function () + logreport = luaotfload.log.report +end + local help_messages = { ["luaotfload-tool"] = [[ @@ -702,9 +706,9 @@ local show_font_info = function (basename, askedname, detail, warnings) if nfonts > 0 then -- true type collection local subfont if askedname then - report (true, 1, "resolve", - [[%s is part of the font collection %s]], - askedname, basename) + logreport (true, 1, "resolve", + [[%s is part of the font collection %s]], + askedname, basename) subfont = subfont_by_name(shortinfo, askedname) end if subfont then @@ -713,11 +717,11 @@ local show_font_info = function (basename, askedname, detail, warnings) show_full_info(fullname, subfont, warnings) end else -- list all subfonts - report (true, 1, "resolve", - [[%s is a font collection]], basename) + logreport (true, 1, "resolve", + [[%s is a font collection]], basename) for subfont = 1, nfonts do - report (true, 1, "resolve", - [[Showing info for font no. %d]], n) + logreport (true, 1, "resolve", + [[Showing info for font no. %d]], n) show_info_items(shortinfo[subfont]) if detail == true then show_full_info(fullname, subfont, warnings) @@ -731,7 +735,7 @@ local show_font_info = function (basename, askedname, detail, warnings) end end else - report (true, 1, "resolve", "Font %s not found", filename) + logreport (true, 1, "resolve", "Font %s not found", filename) end end @@ -759,9 +763,9 @@ local actions = { } --- (jobspec -> (bool * bool)) list actions.loglevel = function (job) local lvl = job.log_level if lvl then - log.set_loglevel(lvl) - report ("info", 3, "util", "Setting the log level to %d.", lvl) - report ("log", 2, "util", "Lua=%q", _VERSION) + luaotfload.log.set_loglevel(lvl) + logreport ("info", 3, "util", "Setting the log level to %d.", lvl) + logreport ("log", 2, "util", "Lua=%q", _VERSION) end return true, true end @@ -808,7 +812,9 @@ actions.generate = function (job) local _ = fonts.names.update (fontnames, job.force_reload, job.dry_run) local namedata = fonts.names.data () if namedata then - report ("info", 2, "db", "Fonts in the database: %i", #namedata.mappings) + logreport ("info", 2, "db", + "Fonts in the database: %i", + #namedata.mappings) return true, true end return false, false @@ -844,12 +850,14 @@ local write_bisect_status = function (data) osdate ("%Y-%m-d %H:%M:%S", os.time ()), payload) if status and iosavedata (bisect_status_file, status) then - report ("info", 4, "bisect", - "Bisection state written to %s.", bisect_status_file) + logreport ("info", 4, "bisect", + "Bisection state written to %s.", + bisect_status_file) return true end - report ("info", 0, "bisect", - "Failed to write bisection state to %s.", bisect_status_file) + logreport ("info", 0, "bisect", + "Failed to write bisection state to %s.", + bisect_status_file) return false end @@ -861,16 +869,22 @@ end --- unit -> state list local read_bisect_status = function () - report ("info", 4, "bisect", "Testing for status file: %q.", bisect_status_file) + logreport ("info", 4, "bisect", + "Testing for status file: %q.", + bisect_status_file) if not lfsisfile (bisect_status_file) then - report ("info", 2, "bisect", "No such file: %q.", bisect_status_file) - report ("info", 0, "bisect", "Not in bisect mode.") + logreport ("info", 2, "bisect", + "No such file: %q.", bisect_status_file) + logreport ("info", 0, "bisect", + "Not in bisect mode.") return false end - report ("info", 4, "bisect", "Reading status file: %q.", bisect_status_file) + logreport ("info", 4, "bisect", + "Reading status file: %q.", bisect_status_file) local success, status = pcall (dofile, bisect_status_file) if not success then - report ("info", 0, "bisect", "Could not read status file.") + logreport ("info", 0, "bisect", + "Could not read status file.") return false end return status @@ -885,19 +899,21 @@ end local bisect_start = function () if lfsisfile (bisect_status_file) then - report ("info", 0, "bisect", - "Bisect session in progress.", - bisect_status_file) - report ("info", 0, "bisect", - "Use --bisect=stop to erase it before starting over.") + logreport ("info", 0, "bisect", + "Bisect session in progress.", + bisect_status_file) + logreport ("info", 0, "bisect", + "Use --bisect=stop to erase it before starting over.") return false, false end - report ("info", 2, "bisect", - "Starting bisection of font database %q.", bisect_status_file) + logreport ("info", 2, "bisect", + "Starting bisection of font database %q.", + bisect_status_file) local n = fonts.names.count_font_files () local pivot = mathfloor (n / 2) local data = { { 1, n, pivot } } - report ("info", 0, "bisect", "Initializing pivot to %d.", pivot) + logreport ("info", 0, "bisect", + "Initializing pivot to %d.", pivot) if write_bisect_status (data) then return true, false end @@ -911,21 +927,23 @@ end --doc]]-- local bisect_stop = function () - report ("info", 3, "bisect", "Erasing bisection state at %s.", bisect_status_file) + logreport ("info", 3, "bisect", + "Erasing bisection state at %s.", + bisect_status_file) if lfsisfile (bisect_status_file) then local success, msg = os.remove (bisect_status_file) if not success then - report ("info", 2, "bisect", - "Failed to erase file %s (%s).", - bisect_status_file, msg) + logreport ("info", 2, "bisect", + "Failed to erase file %s (%s).", + bisect_status_file, msg) end end if lfsisdir (bisect_status_path) then local success, msg = os.remove (bisect_status_path) if not success then - report ("info", 2, "bisect", - "Failed to erase directory %s (%s).", - bisect_status_path, msg) + logreport ("info", 2, "bisect", + "Failed to erase directory %s (%s).", + bisect_status_path, msg) end end if lfsisfile (bisect_status_file) then @@ -942,12 +960,12 @@ end --doc]]-- local bisect_terminate = function (nsteps, culprit) - report ("info", 1, "bisect", - "Bisection completed after %d steps.", nsteps) - report ("info", 0, "bisect", - "Bad file: %s.", fonts.names.nth_font_filename (culprit)) - report ("info", 0, "bisect", - "Run with --bisect=stop to finish bisection.") + logreport ("info", 1, "bisect", + "Bisection completed after %d steps.", nsteps) + logreport ("info", 0, "bisect", + "Bad file: %s.", fonts.names.nth_font_filename (culprit)) + logreport ("info", 0, "bisect", + "Run with --bisect=stop to finish bisection.") return true, false end @@ -959,9 +977,9 @@ end local list_remainder = function (lo, hi) local fonts = fonts.names.font_slice (lo, hi) - report ("info", 0, "bisect", "%d fonts left.", hi - lo + 1) + logreport ("info", 0, "bisect", "%d fonts left.", hi - lo + 1) for i = 1, #fonts do - report ("info", 1, "bisect", " · %2d: %s", lo, fonts[i]) + logreport ("info", 1, "bisect", " · %2d: %s", lo, fonts[i]) lo = lo + 1 end end @@ -994,8 +1012,9 @@ local bisect_set = function (outcome) local lo, hi, pivot = unpack (previous) - report ("info", 3, "bisect", "Previous step %d: lo=%d, hi=%d, pivot=%d.", - nsteps, lo, hi, pivot) + logreport ("info", 3, "bisect", + "Previous step %d: lo=%d, hi=%d, pivot=%d.", + nsteps, lo, hi, pivot) if outcome == "bad" then hi = pivot @@ -1006,9 +1025,9 @@ local bisect_set = function (outcome) return bisect_terminate (nsteps, lo) end pivot = mathfloor ((lo + hi) / 2) - report ("info", 0, "bisect", - "Continuing with the lower segment: lo=%d, hi=%d, pivot=%d.", - lo, hi, pivot) + logreport ("info", 0, "bisect", + "Continuing with the lower segment: lo=%d, hi=%d, pivot=%d.", + lo, hi, pivot) elseif outcome == "good" then lo = pivot + 1 if lo >= hi then --- complete @@ -1018,11 +1037,12 @@ local bisect_set = function (outcome) return bisect_terminate (nsteps, lo) end pivot = mathfloor ((lo + hi) / 2) - report ("info", 0, "bisect", - "Continuing with the upper segment: lo=%d, hi=%d, pivot=%d.", - lo, hi, pivot) + logreport ("info", 0, "bisect", + "Continuing with the upper segment: lo=%d, hi=%d, pivot=%d.", + lo, hi, pivot) else -- can’t happen - report ("info", 0, "bisect", "What the hell?", lo, hi, pivot) + logreport ("info", 0, "bisect", + "What the hell?", lo, hi, pivot) return false, false end @@ -1049,13 +1069,13 @@ local bisect_status = function () if nsteps > 1 then for i = nsteps - 1, 1, -1 do local step = status[i] - report ("info", 2, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", - i, unpack (step)) + logreport ("info", 2, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", + i, unpack (step)) end end local current = status[nsteps] - report ("info", 0, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", - nsteps, unpack (current)) + logreport ("info", 0, "bisect", "Step %d: lo=%d, hi=%d, pivot=%d.", + nsteps, unpack (current)) return true, false end @@ -1081,10 +1101,10 @@ local bisect_run = function () current = status[nsteps - 1] end local lo, hi, pivot = unpack (current) - report ("info", 3, "bisect", "Previous step %d: lo=%d, hi=%d, pivot=%d.", - nsteps, lo, hi, pivot) - report ("info", 1, "bisect", "Step %d: Testing fonts from %d to %d.", - currentstep, lo, pivot) + logreport ("info", 3, "bisect", "Previous step %d: lo=%d, hi=%d, pivot=%d.", + nsteps, lo, hi, pivot) + logreport ("info", 1, "bisect", "Step %d: Testing fonts from %d to %d.", + currentstep, lo, pivot) config.luaotfload.misc.bisect = { lo, pivot } return true, true end @@ -1102,7 +1122,7 @@ actions.bisect = function (job) local mode = job.bisect local runner = bisect_modes[mode] if not runner then - report ("info", 0, "bisect", "Unknown directive %q.", mode) + logreport ("info", 0, "bisect", "Unknown directive %q.", mode) return false, false end return runner (job) @@ -1113,7 +1133,7 @@ actions.flush = function (job) if success then local success = fonts.names.save_lookups() if success then - report ("info", 2, "cache", "Lookup cache emptied") + logreport ("info", 2, "cache", "Lookup cache emptied") return true, true end end @@ -1129,8 +1149,8 @@ local cache_directives = { actions.cache = function (job) local directive = cache_directives[job.cache] if not directive or type(directive) ~= "function" then - report ("info", 2, "cache", - "Invalid font cache directive %s.", job.cache) + logreport ("info", 2, "cache", + "Invalid font cache directive %s.", job.cache) return false, false end if directive() then @@ -1174,27 +1194,27 @@ actions.query = function (job) end if success then - report (false, 0, "resolve", "Font %q found!", query) + logreport (false, 0, "resolve", "Font %q found!", query) if subfont then - report (false, 0, "resolve", - "Resolved file name %q, subfont nr. %q", - foundname, subfont) + logreport (false, 0, "resolve", + "Resolved file name %q, subfont nr. %q", + foundname, subfont) else - report (false, 0, "resolve", - "Resolved file name %q", foundname) + logreport (false, 0, "resolve", + "Resolved file name %q", foundname) end if job.show_info then show_font_info (foundname, query, job.full_info, job.warnings) iowrite "\n" end else - report (false, 0, "resolve", "Cannot find %q in index.", query) - report (false, 0, "resolve", - "Hint: use the --fuzzy option to display suggestions.", - query) + logreport (false, 0, "resolve", "Cannot find %q in index.", query) + logreport (false, 0, "resolve", + "Hint: use the --fuzzy option to display suggestions.", + query) if job.fuzzy == true then - report (false, 0, "resolve", - "Looking for close matches, this may take a while ...") + logreport (false, 0, "resolve", + "Looking for close matches, this may take a while ...") local _success = fonts.names.find_closest(query, job.fuzzy_limit) end end @@ -1268,14 +1288,13 @@ set_primary_field = function (fields, addme, acc, n) return acc end -local splitcomma = luaotfload.parsers.splitcomma - actions.list = function (job) local criterion = job.criterion local asked_fields = job.asked_fields local name_index = fonts.names.data () if asked_fields then + local splitcomma = luaotfload.parsers.splitcomma asked_fields = lpegmatch(splitcomma, asked_fields) end @@ -1292,7 +1311,7 @@ actions.list = function (job) local nmappings = #mappings if criterion == "*" then - report (false, 1, "list", "All %d entries", nmappings) + logreport (false, 1, "list", "All %d entries", nmappings) for i=1, nmappings do local entry = mappings[i] local fields = get_fields(entry, asked_fields) @@ -1307,12 +1326,12 @@ actions.list = function (job) criterion = criterion[1] asked_fields = set_primary_field(asked_fields, criterion) - report (false, 1, "list", "By %s", criterion) + logreport (false, 1, "list", "By %s", criterion) --- firstly, build a list of fonts to operate on local targets = { } if asked_value then --- only those whose value matches - report (false, 2, "list", "Restricting to value %s", asked_value) + logreport (false, 2, "list", "Restricting to value %s", asked_value) for i=1, nmappings do local entry = mappings[i] if entry[criterion] @@ -1357,7 +1376,7 @@ actions.list = function (job) end end local ntargets = #targets - report (false, 2, "list", "%d entries", ntargets) + logreport (false, 2, "list", "%d entries", ntargets) --- now, output the collection for i=1, ntargets do @@ -1494,7 +1513,7 @@ local process_cmdline = function ( ) -- unit -> jobspec elseif v == "log" then local str = optarg[n] if str then - finalizers = log.set_logout(str, finalizers) + finalizers = luaotfload.log.set_logout(str, finalizers) end elseif v == "find" then action_pending["query"] = true @@ -1588,6 +1607,8 @@ local process_cmdline = function ( ) -- unit -> jobspec end local main = function ( ) -- unit -> int + if init_modules () == false then return -42 end + local retval = 0 local job = process_cmdline() @@ -1598,23 +1619,23 @@ local main = function ( ) -- unit -> int local actionname = action_sequence[i] local exit = false if action_pending[actionname] then - report ("log", 3, "util", "Preparing for task", "%s", actionname) + logreport ("log", 3, "util", "Preparing for task", "%s", actionname) local action = actions[actionname] local success, continue = action(job) if not success then - report (false, 0, "util", - "Failed to execute task.", "%s", actionname) + logreport (false, 0, "util", + "Failed to execute task.", "%s", actionname) retval = -1 exit = true elseif not continue then - report (false, 3, "util", - "Task completed, exiting.", "%s", actionname) + logreport (false, 3, "util", + "Task completed, exiting.", "%s", actionname) exit = true else - report (false, 3, "util", - "Task completed successfully.", "%s", actionname) + logreport (false, 3, "util", + "Task completed successfully.", "%s", actionname) end end if exit then break end -- cgit v1.2.3 From c810fcae82effa6c73b7da19e0b94d735be9f767 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 07:31:42 +0100 Subject: [tool] adapt to current initialization --- src/luaotfload-tool.lua | 51 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 47 insertions(+), 4 deletions(-) diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index 6b84a6d..181bd5c 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -145,16 +145,59 @@ utilities = backup.utilities fonts = { names = { } } -- for db; normally provided by the fontloaders -require "luaotfload-log.lua" --- this populates the luaotfload.log.* namespace -require "luaotfload-parsers" --- fonts.conf, configuration, and request syntax -require "luaotfload-configuration" --- configuration file handling -require "luaotfload-database" +local require_init = { } + +local loadmodule = function (name) + local v = require ("luaotfload-" .. name) + if v then + local mod = { } + local tv = type (v) + if tv == "table" then + mod.name = name + mod.init = v.init + require_init [#require_init + 1] = mod + elseif tv == "function" then + mod.name = name + mod.init = v + require_init [#require_init + 1] = mod + end + end +end + require "alt_getopt" +loadmodule "log.lua" --- this populates the luaotfload.log.* namespace +loadmodule "parsers" --- fonts.conf, configuration, and request syntax +loadmodule "configuration" --- configuration file handling +loadmodule "database" + local logreport local init_modules = function () + --- NB we don’t command the logger at this point. + local todo = #require_init + local ret = true + for i = 1, todo do + local mod = require_init[i] + local name = mod.name + local init = mod.init + if type (init) ~= "function" then + error ("luaotfload broken; module " + .. name .. " missing initializers!") + end + local v = mod.init () + if v == true then + --- evaluated well + elseif type (v) == "table" then + luaotfload[name] = v + else + error ("luaotfload broken; initialization of module " + .. name .. " returned " .. tostring (v) .. ".") + return false + end + end logreport = luaotfload.log.report + return ret end -- cgit v1.2.3 From d7a36a33d8d57a5aec9232364cf0bd307523281c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 28 Oct 2015 07:52:00 +0100 Subject: [*] update news --- NEWS | 1 + 1 file changed, 1 insertion(+) diff --git a/NEWS b/NEWS index a1ffb1e..bf2441d 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,7 @@ Change History * Move remaining functionality from ``luaotfload-override`` into initialization * Write names index if fonts were removed + * Separate module loading from initialization 2014/07/13, luaotfload v2.5 * Remove legacy code. -- cgit v1.2.3 From 4f053696e1813fde4bd6cebbb77ff2a1e1f6800b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 07:14:40 +0100 Subject: [fontloader] sync with Context as of 2015-10-29 --- src/fontloader/misc/fontloader-basics-nod.lua | 3 + src/fontloader/misc/fontloader-font-afm.lua | 18 +- src/fontloader/misc/fontloader-font-con.lua | 114 +- src/fontloader/misc/fontloader-font-def.lua | 6 +- src/fontloader/misc/fontloader-font-map.lua | 473 ++-- src/fontloader/misc/fontloader-font-otb.lua | 10 +- src/fontloader/misc/fontloader-font-otf.lua | 583 ++++- src/fontloader/misc/fontloader-font-otp.lua | 5 +- src/fontloader/misc/fontloader-font-tfm.lua | 1 + src/fontloader/misc/fontloader-fonts-cbk.lua | 33 +- src/fontloader/misc/fontloader-fonts-inj.lua | 375 +-- src/fontloader/misc/fontloader-fonts-otn.lua | 2125 +++++++++++----- src/fontloader/misc/fontloader-fonts.lua | 18 +- src/fontloader/misc/fontloader-l-lpeg.lua | 2 +- src/fontloader/misc/fontloader-l-lua.lua | 34 +- src/fontloader/misc/fontloader-l-string.lua | 7 +- src/fontloader/misc/fontloader-l-table.lua | 2 +- src/fontloader/misc/fontloader-mplib.lua | 114 +- src/fontloader/misc/fontloader-mplib.tex | 21 +- src/fontloader/misc/fontloader-plain.tex | 25 +- src/fontloader/misc/fontloader-test.tex | 26 +- src/fontloader/misc/fontloader-util-str.lua | 13 +- src/fontloader/runtime/fontloader-reference.lua | 2947 ++++++++++++++++------- 23 files changed, 4803 insertions(+), 2152 deletions(-) diff --git a/src/fontloader/misc/fontloader-basics-nod.lua b/src/fontloader/misc/fontloader-basics-nod.lua index 1ec2895..39400a3 100644 --- a/src/fontloader/misc/fontloader-basics-nod.lua +++ b/src/fontloader/misc/fontloader-basics-nod.lua @@ -56,6 +56,9 @@ local whatcodes = { } for k,v in next, node.whatsits() do whatcodes[string.gs local glyphcodes = { [0] = "character", "glyph", "ligature", "ghost", "left", "right" } local disccodes = { [0] = "discretionary", "explicit", "automatic", "regular", "first", "second" } +for i=0,#glyphcodes do glyphcodes[glyphcodes[i]] = i end +for i=0,#disccodes do disccodes [disccodes [i]] = i end + nodes.nodecodes = nodecodes nodes.whatcodes = whatcodes nodes.whatsitcodes = whatcodes diff --git a/src/fontloader/misc/fontloader-font-afm.lua b/src/fontloader/misc/fontloader-font-afm.lua index a96c668..329639b 100644 --- a/src/fontloader/misc/fontloader-font-afm.lua +++ b/src/fontloader/misc/fontloader-font-afm.lua @@ -152,14 +152,14 @@ end local keys = { } -function keys.FontName (data,line) data.metadata.fontname = strip (line) -- get rid of spaces - data.metadata.fullname = strip (line) end -function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end -function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch = toboolean(line,true) end -function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end -function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end -function keys.Descender (data,line) data.metadata.descender = tonumber (line) end -function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end +function keys.FontName (data,line) data.metadata.fontname = strip (line) -- get rid of spaces + data.metadata.fullname = strip (line) end +function keys.ItalicAngle (data,line) data.metadata.italicangle = tonumber (line) end +function keys.IsFixedPitch(data,line) data.metadata.monospaced = toboolean(line,true) end +function keys.CharWidth (data,line) data.metadata.charwidth = tonumber (line) end +function keys.XHeight (data,line) data.metadata.xheight = tonumber (line) end +function keys.Descender (data,line) data.metadata.descender = tonumber (line) end +function keys.Ascender (data,line) data.metadata.ascender = tonumber (line) end function keys.Comment (data,line) -- Comment DesignSize 12 (pts) -- Comment TFM designsize: 12 (in points) @@ -640,7 +640,7 @@ local function copytotfm(data) local spacer = "space" local spaceunits = 500 -- - local monospaced = metadata.isfixedpitch + local monospaced = metadata.monospaced local charwidth = metadata.charwidth local italicangle = metadata.italicangle local charxheight = metadata.xheight and metadata.xheight > 0 and metadata.xheight diff --git a/src/fontloader/misc/fontloader-font-con.lua b/src/fontloader/misc/fontloader-font-con.lua index 72fbb5c..383a403 100644 --- a/src/fontloader/misc/fontloader-font-con.lua +++ b/src/fontloader/misc/fontloader-font-con.lua @@ -191,10 +191,9 @@ in the process; numbers are of course copies. Here 65536 equals 1pt. (Due to excessive memory usage in CJK fonts, we no longer pass the boundingbox.)

--ldx]]-- --- The scaler is only used for otf and afm and virtual fonts. If --- a virtual font has italic correction make sure to set the --- hasitalics flag. Some more flags will be added in --- the future. +-- The scaler is only used for otf and afm and virtual fonts. If a virtual font has italic +-- correction make sure to set the hasitalics flag. Some more flags will be added in the +-- future. --[[ldx--

The reason why the scaler was originally split, is that for a while we experimented @@ -426,6 +425,7 @@ function constructors.scale(tfmdata,specification) local vdelta = delta -- target.designsize = parameters.designsize -- not really needed so it might become obsolete + target.units = units target.units_per_em = units -- just a trigger for the backend -- local direction = properties.direction or tfmdata.direction or 0 -- pointless, as we don't use omf fonts at all @@ -562,26 +562,27 @@ function constructors.scale(tfmdata,specification) target.mathparameters = nil -- nop end -- - local italickey = "italic" - local useitalics = true -- something context - -- - -- some context specific trickery (this will move to a plugin) + -- Here we support some context specific trickery (this might move to a plugin). During the + -- transition to opentype the engine had troubles with italics so we had some additional code + -- for fixing that. In node mode (text) we don't care much if italics gets passed because + -- the engine does nothign with them then. -- if hasmath then - -- the latest luatex can deal with it itself so we now disable this - -- mechanism here - -- - -- if properties.mathitalics then - -- italickey = "italic_correction" - -- if trace_defining then - -- report_defining("math italics disabled for font %a, fullname %a, filename %a",name,fullname,filename) - -- end - -- end - autoitalicamount = false -- new - elseif properties.textitalics then - italickey = "italic_correction" - useitalics = false - if properties.delaytextitalics then + local mathitalics = properties.mathitalics + if mathitalics == false then + if trace_defining then + report_defining("%s italics %s for font %a, fullname %a, filename %a","math",hasitalics and "ignored" or "disabled",name,fullname,filename) + end + hasitalics = false + autoitalicamount = false + end + else + local textitalics = properties.textitalics + if textitalics == false then + if trace_defining then + report_defining("%s italics %s for font %a, fullname %a, filename %a","text",hasitalics and "ignored" or "disabled",name,fullname,filename) + end + hasitalics = false autoitalicamount = false end end @@ -590,8 +591,7 @@ function constructors.scale(tfmdata,specification) -- if trace_defining then report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a", - name,fullname,filename,hdelta,vdelta, - hasmath and "enabled" or "disabled",useitalics and "enabled" or "disabled") + name,fullname,filename,hdelta,vdelta,hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled") end -- constructors.beforecopyingcharacters(target,tfmdata) @@ -606,15 +606,15 @@ function constructors.scale(tfmdata,specification) local c = changed[unicode] if c then description = descriptions[c] or descriptions[unicode] or character - character = characters[c] or character - index = description.index or c + character = characters[c] or character + index = description.index or c else description = descriptions[unicode] or character - index = description.index or unicode + index = description.index or unicode end else description = descriptions[unicode] or character - index = description.index or unicode + index = description.index or unicode end local width = description.width local height = description.height @@ -699,23 +699,6 @@ function constructors.scale(tfmdata,specification) end end -- - if autoitalicamount then - local vi = description.italic - if not vi then - local vi = description.boundingbox[3] - description.width + autoitalicamount - if vi > 0 then -- < 0 indicates no overshoot or a very small auto italic - chr[italickey] = vi*hdelta - end - elseif vi ~= 0 then - chr[italickey] = vi*hdelta - end - elseif hasitalics then - local vi = description.italic - if vi and vi ~= 0 then - chr[italickey] = vi*hdelta - end - end - -- to be tested if hasmath then -- todo, just operate on descriptions.math local vn = character.next @@ -754,7 +737,7 @@ function constructors.scale(tfmdata,specification) end end end - local va = character.top_accent + local va = character.accent if va then chr.top_accent = vdelta*va end @@ -777,6 +760,27 @@ function constructors.scale(tfmdata,specification) chr.mathkern = kerns -- singular -> should be patched in luatex ! end end + if hasitalics then + local vi = character.italic + if vi and vi ~= 0 then + chr.italic = vi*hdelta + end + end + elseif autoitalicamount then -- itlc feature + local vi = description.italic + if not vi then + local vi = description.boundingbox[3] - description.width + autoitalicamount + if vi > 0 then -- < 0 indicates no overshoot or a very small auto italic + chr.italic = vi*hdelta + end + elseif vi ~= 0 then + chr.italic = vi*hdelta + end + elseif hasitalics then -- unlikely + local vi = character.italic + if vi and vi ~= 0 then + chr.italic = vi*hdelta + end end if haskerns then local vk = character.kerns @@ -843,6 +847,8 @@ function constructors.scale(tfmdata,specification) targetcharacters[unicode] = chr end -- + properties.setitalics = hasitalics -- for postprocessing + -- constructors.aftercopyingcharacters(target,tfmdata) -- constructors.trytosharefont(target,tfmdata) @@ -895,12 +901,21 @@ function constructors.finalize(tfmdata) parameters.slantfactor = tfmdata.slant or 0 end -- - if not parameters.designsize then - parameters.designsize = tfmdata.designsize or (factors.pt * 10) + local designsize = parameters.designsize + if designsize then + parameters.minsize = tfmdata.minsize or designsize + parameters.maxsize = tfmdata.maxsize or designsize + else + designsize = factors.pt * 10 + parameters.designsize = designsize + parameters.minsize = designsize + parameters.maxsize = designsize end + parameters.minsize = tfmdata.minsize or parameters.designsize + parameters.maxsize = tfmdata.maxsize or parameters.designsize -- if not parameters.units then - parameters.units = tfmdata.units_per_em or 1000 + parameters.units = tfmdata.units or tfmdata.units_per_em or 1000 end -- if not tfmdata.descriptions then @@ -976,6 +991,7 @@ function constructors.finalize(tfmdata) tfmdata.auto_protrude = nil tfmdata.extend = nil tfmdata.slant = nil + tfmdata.units = nil tfmdata.units_per_em = nil -- tfmdata.cache = nil diff --git a/src/fontloader/misc/fontloader-font-def.lua b/src/fontloader/misc/fontloader-font-def.lua index fdded3c..add42ee 100644 --- a/src/fontloader/misc/fontloader-font-def.lua +++ b/src/fontloader/misc/fontloader-font-def.lua @@ -183,10 +183,11 @@ end function resolvers.name(specification) local resolve = fonts.names.resolve if resolve then - local resolved, sub = resolve(specification.name,specification.sub,specification) -- we pass specification for overloaded versions + local resolved, sub, subindex = resolve(specification.name,specification.sub,specification) -- we pass specification for overloaded versions if resolved then specification.resolved = resolved specification.sub = sub + specification.subindex = subindex local suffix = lower(suffixonly(resolved)) if fonts.formats[suffix] then specification.forced = suffix @@ -204,10 +205,11 @@ end function resolvers.spec(specification) local resolvespec = fonts.names.resolvespec if resolvespec then - local resolved, sub = resolvespec(specification.name,specification.sub,specification) -- we pass specification for overloaded versions + local resolved, sub, subindex = resolvespec(specification.name,specification.sub,specification) -- we pass specification for overloaded versions if resolved then specification.resolved = resolved specification.sub = sub + specification.subindex = subindex specification.forced = lower(suffixonly(resolved)) specification.forcedname = resolved specification.name = removesuffix(resolved) diff --git a/src/fontloader/misc/fontloader-font-map.lua b/src/fontloader/misc/fontloader-font-map.lua index 69474ba..b645d9a 100644 --- a/src/fontloader/misc/fontloader-font-map.lua +++ b/src/fontloader/misc/fontloader-font-map.lua @@ -31,25 +31,27 @@ of obsolete. Some code may move to runtime or auxiliary modules.

The name to unciode related code will stay of course.

--ldx]]-- -local function loadlumtable(filename) -- will move to font goodies - local lumname = file.replacesuffix(file.basename(filename),"lum") - local lumfile = resolvers.findfile(lumname,"map") or "" - if lumfile ~= "" and lfs.isfile(lumfile) then - if trace_loading or trace_mapping then - report_fonts("loading map table %a",lumfile) - end - lumunic = dofile(lumfile) - return lumunic, lumfile - end -end +-- local function loadlumtable(filename) -- will move to font goodies +-- local lumname = file.replacesuffix(file.basename(filename),"lum") +-- local lumfile = resolvers.findfile(lumname,"map") or "" +-- if lumfile ~= "" and lfs.isfile(lumfile) then +-- if trace_loading or trace_mapping then +-- report_fonts("loading map table %a",lumfile) +-- end +-- lumunic = dofile(lumfile) +-- return lumunic, lumfile +-- end +-- end local hex = R("AF","09") -local hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end -local hexsix = (hex*hex*hex*hex*hex*hex) / function(s) return tonumber(s,16) end +----- hexfour = (hex*hex*hex*hex) / function(s) return tonumber(s,16) end +----- hexsix = (hex*hex*hex*hex*hex*hex) / function(s) return tonumber(s,16) end +local hexfour = (hex*hex*hex^-2) / function(s) return tonumber(s,16) end +local hexsix = (hex*hex*hex^-4) / function(s) return tonumber(s,16) end local dec = (R("09")^1) / tonumber local period = P(".") -local unicode = P("uni") * (hexfour * (period + P(-1)) * Cc(false) + Ct(hexfour^1) * Cc(true)) -local ucode = P("u") * (hexsix * (period + P(-1)) * Cc(false) + Ct(hexsix ^1) * Cc(true)) +local unicode = (P("uni") + P("UNI")) * (hexfour * (period + P(-1)) * Cc(false) + Ct(hexfour^1) * Cc(true)) -- base planes +local ucode = (P("u") + P("U") ) * (hexsix * (period + P(-1)) * Cc(false) + Ct(hexsix ^1) * Cc(true)) -- extended local index = P("index") * dec * Cc(false) local parser = unicode + ucode + index @@ -168,7 +170,6 @@ end -- return s -- end -mappings.loadlumtable = loadlumtable mappings.makenameparser = makenameparser mappings.tounicode = tounicode mappings.tounicode16 = tounicode16 @@ -179,13 +180,13 @@ local ligseparator = P("_") local varseparator = P(".") local namesplitter = Ct(C((1 - ligseparator - varseparator)^1) * (ligseparator * C((1 - ligseparator - varseparator)^1))^0) +-- maybe: ff fi fl ffi ffl => f_f f_i f_l f_f_i f_f_l + -- local function test(name) -- local split = lpegmatch(namesplitter,name) -- print(string.formatters["%s: [% t]"](name,split)) -- end --- maybe: ff fi fl ffi ffl => f_f f_i f_l f_f_i f_f_l - -- test("i.f_") -- test("this") -- test("this.that") @@ -221,332 +222,184 @@ end mappings.overloads = overloads -function mappings.addtounicode(data,filename) - local resources = data.resources - local properties = data.properties - local descriptions = data.descriptions - local unicodes = resources.unicodes - local lookuptypes = resources.lookuptypes +function mappings.addtounicode(data,filename,checklookups) + local resources = data.resources + local unicodes = resources.unicodes if not unicodes then return end + local properties = data.properties + local descriptions = data.descriptions -- we need to move this code unicodes['space'] = unicodes['space'] or 32 unicodes['hyphen'] = unicodes['hyphen'] or 45 unicodes['zwj'] = unicodes['zwj'] or 0x200D unicodes['zwnj'] = unicodes['zwnj'] or 0x200C - local private = fonts.constructors.privateoffset - local unicodevector = fonts.encodings.agl.unicodes -- loaded runtime in context - ----- namevector = fonts.encodings.agl.names -- loaded runtime in context - local missing = { } - local lumunic, uparser, oparser - local cidinfo, cidnames, cidcodes, usedmap - -- - cidinfo = properties.cidinfo - usedmap = cidinfo and fonts.cid.getmap(cidinfo) -- + local private = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF + local unicodevector = fonts.encodings.agl.unicodes or { } -- loaded runtime in context + local contextvector = fonts.encodings.agl.ctxcodes or { } -- loaded runtime in context + local missing = { } + local nofmissing = 0 + local oparser = nil + local cidnames = nil + local cidcodes = nil + local cidinfo = properties.cidinfo + local usedmap = cidinfo and fonts.cid.getmap(cidinfo) + local uparser = makenameparser() -- hm, every time? if usedmap then - oparser = usedmap and makenameparser(cidinfo.ordering) - cidnames = usedmap.names - cidcodes = usedmap.unicodes + oparser = usedmap and makenameparser(cidinfo.ordering) + cidnames = usedmap.names + cidcodes = usedmap.unicodes end - uparser = makenameparser() - local ns, nl = 0, 0 + local ns = 0 + local nl = 0 + -- for unic, glyph in next, descriptions do - local index = glyph.index - local name = glyph.name - local r = overloads[name] - if r then - -- get rid of weird ligatures - -- glyph.name = r.name - glyph.unicode = r.unicode - elseif unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then - local unicode = lumunic and lumunic[name] or unicodevector[name] - if unicode then - glyph.unicode = unicode - ns = ns + 1 - end - -- cidmap heuristics, beware, there is no guarantee for a match unless - -- the chain resolves - if (not unicode) and usedmap then - local foundindex = lpegmatch(oparser,name) - if foundindex then - unicode = cidcodes[foundindex] -- name to number - if unicode then - glyph.unicode = unicode - ns = ns + 1 - else - local reference = cidnames[foundindex] -- number to name - if reference then - local foundindex = lpegmatch(oparser,reference) - if foundindex then - unicode = cidcodes[foundindex] - if unicode then - glyph.unicode = unicode - ns = ns + 1 + local name = glyph.name + if name then + local index = glyph.index + local r = overloads[name] + if r then + -- get rid of weird ligatures + -- glyph.name = r.name + glyph.unicode = r.unicode + elseif not unic or unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then + local unicode = unicodevector[name] or contextvector[name] + if unicode then + glyph.unicode = unicode + ns = ns + 1 + end + -- cidmap heuristics, beware, there is no guarantee for a match unless + -- the chain resolves + if (not unicode) and usedmap then + local foundindex = lpegmatch(oparser,name) + if foundindex then + unicode = cidcodes[foundindex] -- name to number + if unicode then + glyph.unicode = unicode + ns = ns + 1 + else + local reference = cidnames[foundindex] -- number to name + if reference then + local foundindex = lpegmatch(oparser,reference) + if foundindex then + unicode = cidcodes[foundindex] + if unicode then + glyph.unicode = unicode + ns = ns + 1 + end end - end - if not unicode or unicode == "" then - local foundcodes, multiple = lpegmatch(uparser,reference) - if foundcodes then - glyph.unicode = foundcodes - if multiple then - nl = nl + 1 - unicode = true - else - ns = ns + 1 - unicode = foundcodes + if not unicode or unicode == "" then + local foundcodes, multiple = lpegmatch(uparser,reference) + if foundcodes then + glyph.unicode = foundcodes + if multiple then + nl = nl + 1 + unicode = true + else + ns = ns + 1 + unicode = foundcodes + end end end end end end end - end - -- a.whatever or a_b_c.whatever or a_b_c (no numbers) a.b_ - -- - -- It is not trivial to find a solution that suits all fonts. We tried several alternatives - -- and this one seems to work reasonable also with fonts that use less standardized naming - -- schemes. The extra private test is tested by KE and seems to work okay with non-typical - -- fonts as well. - -- - -- The next time I look into this, I'll add an extra analysis step to the otf loader (we can - -- resolve some tounicodes by looking into the gsub data tables that are bound to glyphs. - -- --- a real tricky last resort: --- --- local lookups = glyph.lookups --- if lookups then --- for _, lookup in next, lookups do -- assume consistency else we need to sort --- for i=1,#lookup do --- local l = lookup[i] --- if l.type == "ligature" then --- local s = l.specification --- if s.char == glyph.name then --- local components = s.components --- if components then --- local t, n = { }, 0 --- unicode = true --- for l=1,#components do --- local base = components[l] --- local u = unicodes[base] or unicodevector[base] --- if not u then --- break --- elseif type(u) == "table" then --- if u[1] >= private then --- unicode = false --- break --- end --- n = n + 1 --- t[n] = u[1] --- else --- if u >= private then --- unicode = false --- break --- end --- n = n + 1 --- t[n] = u --- end --- end --- if n == 0 then -- done then --- -- nothing --- elseif n == 1 then --- glyph.unicode = t[1] --- else --- glyph.unicode = t --- end --- nl = nl + 1 --- break --- end --- end --- end --- end --- if unicode then --- break --- end --- end --- end - if not unicode or unicode == "" then - local split = lpegmatch(namesplitter,name) - local nsplit = split and #split or 0 - local t, n = { }, 0 - unicode = true - for l=1,nsplit do - local base = split[l] - local u = unicodes[base] or unicodevector[base] - if not u then - break - elseif type(u) == "table" then - if u[1] >= private then - unicode = false - break + -- a.whatever or a_b_c.whatever or a_b_c (no numbers) a.b_ + -- + -- It is not trivial to find a solution that suits all fonts. We tried several alternatives + -- and this one seems to work reasonable also with fonts that use less standardized naming + -- schemes. The extra private test is tested by KE and seems to work okay with non-typical + -- fonts as well. + -- + if not unicode or unicode == "" then + local split = lpegmatch(namesplitter,name) + local nsplit = split and #split or 0 -- add if + if nsplit == 0 then + -- skip + elseif nsplit == 1 then + local base = split[1] + local u = unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + -- skip + elseif type(u) == "table" then + -- unlikely + if u[1] < private then + unicode = u + glyph.unicode = unicode + end + elseif u < private then + unicode = u + glyph.unicode = unicode end - n = n + 1 - t[n] = u[1] else - if u >= private then - unicode = false - break - end - n = n + 1 - t[n] = u - end - end - if n == 0 then -- done then - -- nothing - elseif n == 1 then - glyph.unicode = t[1] - else - glyph.unicode = t - end - nl = nl + 1 - end - -- last resort (we might need to catch private here as well) - if not unicode or unicode == "" then - local foundcodes, multiple = lpegmatch(uparser,name) - if foundcodes then - glyph.unicode = foundcodes - if multiple then - nl = nl + 1 - unicode = true - else - ns = ns + 1 - unicode = foundcodes - end - end - end - -- check using substitutes and alternates - local r = overloads[unicode] - if r then - unicode = r.unicode - glyph.unicode = unicode - end - -- - if not unicode then - missing[name] = true - end - end - end - if next(missing) then - local guess = { } - -- helper - local function check(gname,code,unicode) - local description = descriptions[code] - -- no need to add a self reference - local variant = description.name - if variant == gname then - return - end - -- the variant already has a unicode (normally that resultrs in a default tounicode to self) - local unic = unicodes[variant] - if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then - -- no default mapping and therefore maybe no tounicode yet - else - return - end - -- the variant already has a tounicode - if descriptions[code].unicode then - return - end - -- add to the list - local g = guess[variant] - -- local r = overloads[unicode] - -- if r then - -- unicode = r.unicode - -- end - if g then - g[gname] = unicode - else - guess[variant] = { [gname] = unicode } - end - end - -- - for unicode, description in next, descriptions do - local slookups = description.slookups - if slookups then - local gname = description.name - for tag, data in next, slookups do - local lookuptype = lookuptypes[tag] - if lookuptype == "alternate" then - for i=1,#data do - check(gname,data[i],unicode) - end - elseif lookuptype == "substitution" then - check(gname,data,unicode) - end - end - end - local mlookups = description.mlookups - if mlookups then - local gname = description.name - for tag, list in next, mlookups do - local lookuptype = lookuptypes[tag] - if lookuptype == "alternate" then - for i=1,#list do - local data = list[i] - for i=1,#data do - check(gname,data[i],unicode) + local t, n = { }, 0 + for l=1,nsplit do + local base = split[l] + local u = unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + break + elseif type(u) == "table" then + if u[1] >= private then + break + end + n = n + 1 + t[n] = u[1] + else + if u >= private then + break + end + n = n + 1 + t[n] = u end end - elseif lookuptype == "substitution" then - for i=1,#list do - check(gname,list[i],unicode) + if n > 0 then + if n == 1 then + unicode = t[1] + else + unicode = t + end + glyph.unicode = unicode end end + nl = nl + 1 end - end - end - -- resolve references - local done = true - while done do - done = false - for k, v in next, guess do - if type(v) ~= "number" then - for kk, vv in next, v do - if vv == -1 or vv >= private or (vv >= 0xE000 and vv <= 0xF8FF) or vv == 0xFFFE or vv == 0xFFFF then - local uu = guess[kk] - if type(uu) == "number" then - guess[k] = uu - done = true - end + -- last resort (we might need to catch private here as well) + if not unicode or unicode == "" then + local foundcodes, multiple = lpegmatch(uparser,name) + if foundcodes then + glyph.unicode = foundcodes + if multiple then + nl = nl + 1 + unicode = true else - guess[k] = vv - done = true + ns = ns + 1 + unicode = foundcodes end end end - end - end - -- wrap up - local orphans = 0 - local guessed = 0 - for k, v in next, guess do - if type(v) == "number" then - descriptions[unicodes[k]].unicode = descriptions[v].unicode or v -- can also be a table - guessed = guessed + 1 - else - local t = nil - local l = lower(k) - local u = unicodes[l] - if not u then - orphans = orphans + 1 - elseif u == -1 or u >= private or (u >= 0xE000 and u <= 0xF8FF) or u == 0xFFFE or u == 0xFFFF then - local unicode = descriptions[u].unicode - if unicode then - descriptions[unicodes[k]].unicode = unicode - guessed = guessed + 1 - else - orphans = orphans + 1 - end - else - orphans = orphans + 1 + -- check using substitutes and alternates + local r = overloads[unicode] + if r then + unicode = r.unicode + glyph.unicode = unicode + end + -- + if not unicode then + missing[unic] = true + nofmissing = nofmissing + 1 end end + else + -- no name end - if trace_loading and orphans > 0 or guessed > 0 then - report_fonts("%s glyphs with no related unicode, %s guessed, %s orphans",guessed+orphans,guessed,orphans) - end end + if type(checklookups) == "function" then + checklookups(data,missing,nofmissing) + end + -- todo: go lowercase if trace_mapping then for unic, glyph in table.sortedhash(descriptions) do local name = glyph.name diff --git a/src/fontloader/misc/fontloader-font-otb.lua b/src/fontloader/misc/fontloader-font-otb.lua index 4e955a1..c9f5d4a 100644 --- a/src/fontloader/misc/fontloader-font-otb.lua +++ b/src/fontloader/misc/fontloader-font-otb.lua @@ -321,14 +321,14 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis for unicode, character in next, characters do local description = descriptions[unicode] - local lookups = description.slookups + local lookups = description.slookups if lookups then for l=1,#lookuplist do local lookupname = lookuplist[l] local lookupdata = lookups[lookupname] if lookupdata then local lookuptype = lookuptypes[lookupname] - local action = actions[lookuptype] + local action = actions[lookuptype] if action then action(lookupdata,lookuptags,lookupname,description,unicode) end @@ -342,7 +342,7 @@ local function preparesubstitutions(tfmdata,feature,value,validlookups,lookuplis local lookuplist = lookups[lookupname] if lookuplist then local lookuptype = lookuptypes[lookupname] - local action = actions[lookuptype] + local action = actions[lookuptype] if action then for i=1,#lookuplist do action(lookuplist[i],lookuptags,lookupname,description,unicode) @@ -614,8 +614,8 @@ local function featuresinitializer(tfmdata,value) local collectlookups = otf.collectlookups local rawdata = tfmdata.shared.rawdata local properties = tfmdata.properties - local script = properties.script - local language = properties.language + local script = properties.script -- or "dflt" -- can be nil + local language = properties.language -- or "dflt" -- can be nil local basesubstitutions = rawdata.resources.features.gsub local basepositionings = rawdata.resources.features.gpos -- diff --git a/src/fontloader/misc/fontloader-font-otf.lua b/src/fontloader/misc/fontloader-font-otf.lua index e7a97c6..0ca1e98 100644 --- a/src/fontloader/misc/fontloader-font-otf.lua +++ b/src/fontloader/misc/fontloader-font-otf.lua @@ -12,15 +12,19 @@ if not modules then modules = { } end modules ['font-otf'] = { -- to_table -> totable -- ascent descent +-- to be checked: combinations like: +-- +-- current="ABCD" with [A]=nothing, [BC]=ligature, [D]=single (applied to result of BC so funny index) +-- +-- unlikely but possible + -- more checking against low level calls of functions local utfbyte = utf.byte -local format, gmatch, gsub, find, match, lower, strip = string.format, string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip +local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip local type, next, tonumber, tostring = type, next, tonumber, tostring local abs = math.abs -local insert = table.insert -local lpegmatch = lpeg.match -local reversed, concat, remove, sortedkeys = table.reversed, table.concat, table.remove, table.sortedkeys +local reversed, concat, insert, remove, sortedkeys = table.reversed, table.concat, table.insert, table.remove, table.sortedkeys local ioflush = io.flush local fastcopy, tohash, derivetable = table.fastcopy, table.tohash, table.derive local formatters = string.formatters @@ -54,7 +58,7 @@ local otf = fonts.handlers.otf otf.glists = { "gsub", "gpos" } -otf.version = 2.812 -- beware: also sync font-mis.lua +otf.version = 2.819 -- beware: also sync font-mis.lua and in mtx-fonts otf.cache = containers.define("fonts", "otf", otf.version, true) local hashes = fonts.hashes @@ -283,13 +287,17 @@ local ordered_enhancers = { "check glyphs", "check metadata", - "check extra features", -- after metadata +-- "check extra features", -- after metadata "prepare tounicode", "check encoding", -- moved "add duplicates", + "expand lookups", -- a temp hack awaiting the lua loader + +-- "check extra features", -- after metadata and duplicates + "cleanup tables", "compact lookups", @@ -386,6 +394,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone if featurefile then name = name .. "@" .. file.removesuffix(file.basename(featurefile)) end + -- or: sub = tonumber(sub) if sub == "" then sub = false end @@ -442,6 +451,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone end end if reload then + starttiming("fontloader") report_otf("loading %a, hash %a",filename,hash) local fontdata, messages if sub then @@ -476,6 +486,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone data = { size = size, time = time, + subfont = sub, format = otf_format(filename), featuredata = featurefiles, resources = { @@ -512,7 +523,6 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone tounicodetable = Ct(splitter), }, } - starttiming(data) report_otf("file size: %s", size) enhancers.apply(data,filename,fontdata) local packtime = { } @@ -529,10 +539,10 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone if cleanup > 1 then collectgarbage("collect") end - stoptiming(data) + stoptiming("fontloader") if elapsedtime then -- not in generic - report_otf("preprocessing and caching time %s, packtime %s", - elapsedtime(data),packdata and elapsedtime(packtime) or 0) + report_otf("loading, optimizing, packing and caching time %s, pack time %s", + elapsedtime("fontloader"),packdata and elapsedtime(packtime) or 0) end close_font(fontdata) -- free memory if cleanup > 3 then @@ -543,6 +553,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone collectgarbage("collect") end else + stoptiming("fontloader") data = nil report_otf("loading failed due to read error") end @@ -589,6 +600,7 @@ function otf.load(filename,sub,featurefile) -- second argument (format) is gone applyruntimefixes(filename,data) end enhance("add dimensions",data,filename,nil,false) +enhance("check extra features",data,filename) if trace_sequences then showfeatureorder(data,filename) end @@ -697,7 +709,7 @@ local function somecopy(old) -- fast one end end --- not setting hasitalics and class (when nil) during table cronstruction can save some mem +-- not setting hasitalics and class (when nil) during table construction can save some mem actions["prepare glyphs"] = function(data,filename,raw) local tableversion = tonumber(raw.table_version) or 0 @@ -780,7 +792,7 @@ actions["prepare glyphs"] = function(data,filename,raw) end if not unicode or unicode == -1 then -- or unicode >= criterium then if not name then - name = format("u%06X.ctx",private) + name = formatters["u%06X.ctx"](private) end unicode = private unicodes[name] = private @@ -803,7 +815,7 @@ actions["prepare glyphs"] = function(data,filename,raw) -- end -- end if not name then - name = format("u%06X.ctx",unicode) + name = formatters["u%06X.ctx"](unicode) end unicodes[name] = unicode nofunicodes = nofunicodes + 1 @@ -819,35 +831,35 @@ actions["prepare glyphs"] = function(data,filename,raw) glyph = glyph, } descriptions[unicode] = description -local altuni = glyph.altuni -if altuni then - -- local d - for i=1,#altuni do - local a = altuni[i] - local u = a.unicode - if u ~= unicode then - local v = a.variant - if v then - -- tricky: no addition to d? needs checking but in practice such dups are either very simple - -- shapes or e.g cjk with not that many features - local vv = variants[v] - if vv then - vv[u] = unicode - else -- xits-math has some: - vv = { [u] = unicode } - variants[v] = vv - end - -- elseif d then - -- d[#d+1] = u - -- else - -- d = { u } - end - end - end - -- if d then - -- duplicates[unicode] = d -- is this needed ? - -- end -end + local altuni = glyph.altuni + if altuni then + -- local d + for i=1,#altuni do + local a = altuni[i] + local u = a.unicode + if u ~= unicode then + local v = a.variant + if v then + -- tricky: no addition to d? needs checking but in practice such dups are either very simple + -- shapes or e.g cjk with not that many features + local vv = variants[v] + if vv then + vv[u] = unicode + else -- xits-math has some: + vv = { [u] = unicode } + variants[v] = vv + end + -- elseif d then + -- d[#d+1] = u + -- else + -- d = { u } + end + end + end + -- if d then + -- duplicates[unicode] = d -- is this needed ? + -- end + end end end else @@ -916,7 +928,7 @@ end end indices[index] = unicode -- if not name then - -- name = format("u%06X",unicode) -- u%06X.ctx + -- name = formatters["u%06X"](unicode) -- u%06X.ctx -- end descriptions[unicode] = { -- width = glyph.width, @@ -1089,7 +1101,7 @@ actions["add duplicates"] = function(data,filename,raw) end if u > 0 then -- and local duplicate = table.copy(description) -- else packing problem - duplicate.comment = format("copy of U+%05X", unicode) + duplicate.comment = formatters["copy of %U"](unicode) descriptions[u] = duplicate -- validduplicates[#validduplicates+1] = u if trace_loading then @@ -1107,16 +1119,16 @@ end -- boundingbox: split into ht/dp takes more memory (larger tables and less sharing) actions["analyze glyphs"] = function(data,filename,raw) -- maybe integrate this in the previous - local descriptions = data.descriptions - local resources = data.resources - local metadata = data.metadata - local properties = data.properties - local hasitalics = false - local widths = { } - local marks = { } -- always present (saves checking) + local descriptions = data.descriptions + local resources = data.resources + local metadata = data.metadata + local properties = data.properties + local hasitalics = false + local widths = { } + local marks = { } -- always present (saves checking) for unicode, description in next, descriptions do - local glyph = description.glyph - local italic = glyph.italic_correction + local glyph = description.glyph + local italic = glyph.italic_correction -- only in a math font (we also have vert/horiz) if not italic then -- skip elseif italic == 0 then @@ -1185,7 +1197,8 @@ end actions["reorganize features"] = function(data,filename,raw) -- combine with other local features = { } data.resources.features = features - for k, what in next, otf.glists do + for k=1,#otf.glists do + local what = otf.glists[k] local dw = raw[what] if dw then local f = { } @@ -1254,6 +1267,140 @@ actions["reorganize anchor classes"] = function(data,filename,raw) end end +-- local function checklookups(data,missing,nofmissing) +-- local resources = data.resources +-- local unicodes = resources.unicodes +-- local lookuptypes = resources.lookuptypes +-- if not unicodes or not lookuptypes then +-- return +-- elseif nofmissing <= 0 then +-- return +-- end +-- local descriptions = data.descriptions +-- local private = fonts.constructors and fonts.constructors.privateoffset or 0xF0000 -- 0x10FFFF +-- -- +-- local ns, nl = 0, 0 + +-- local guess = { } +-- -- helper +-- local function check(gname,code,unicode) +-- local description = descriptions[code] +-- -- no need to add a self reference +-- local variant = description.name +-- if variant == gname then +-- return +-- end +-- -- the variant already has a unicode (normally that results in a default tounicode to self) +-- local unic = unicodes[variant] +-- if unic == -1 or unic >= private or (unic >= 0xE000 and unic <= 0xF8FF) or unic == 0xFFFE or unic == 0xFFFF then +-- -- no default mapping and therefore maybe no tounicode yet +-- else +-- return +-- end +-- -- the variant already has a tounicode +-- if descriptions[code].unicode then +-- return +-- end +-- -- add to the list +-- local g = guess[variant] +-- -- local r = overloads[unicode] +-- -- if r then +-- -- unicode = r.unicode +-- -- end +-- if g then +-- g[gname] = unicode +-- else +-- guess[variant] = { [gname] = unicode } +-- end +-- end +-- -- +-- for unicode, description in next, descriptions do +-- local slookups = description.slookups +-- if slookups then +-- local gname = description.name +-- for tag, data in next, slookups do +-- local lookuptype = lookuptypes[tag] +-- if lookuptype == "alternate" then +-- for i=1,#data do +-- check(gname,data[i],unicode) +-- end +-- elseif lookuptype == "substitution" then +-- check(gname,data,unicode) +-- end +-- end +-- end +-- local mlookups = description.mlookups +-- if mlookups then +-- local gname = description.name +-- for tag, list in next, mlookups do +-- local lookuptype = lookuptypes[tag] +-- if lookuptype == "alternate" then +-- for i=1,#list do +-- local data = list[i] +-- for i=1,#data do +-- check(gname,data[i],unicode) +-- end +-- end +-- elseif lookuptype == "substitution" then +-- for i=1,#list do +-- check(gname,list[i],unicode) +-- end +-- end +-- end +-- end +-- end +-- -- resolve references +-- local done = true +-- while done do +-- done = false +-- for k, v in next, guess do +-- if type(v) ~= "number" then +-- for kk, vv in next, v do +-- if vv == -1 or vv >= private or (vv >= 0xE000 and vv <= 0xF8FF) or vv == 0xFFFE or vv == 0xFFFF then +-- local uu = guess[kk] +-- if type(uu) == "number" then +-- guess[k] = uu +-- done = true +-- end +-- else +-- guess[k] = vv +-- done = true +-- end +-- end +-- end +-- end +-- end +-- -- wrap up +-- local orphans = 0 +-- local guessed = 0 +-- for k, v in next, guess do +-- if type(v) == "number" then +-- descriptions[unicodes[k]].unicode = descriptions[v].unicode or v -- can also be a table +-- guessed = guessed + 1 +-- else +-- local t = nil +-- local l = lower(k) +-- local u = unicodes[l] +-- if not u then +-- orphans = orphans + 1 +-- elseif u == -1 or u >= private or (u >= 0xE000 and u <= 0xF8FF) or u == 0xFFFE or u == 0xFFFF then +-- local unicode = descriptions[u].unicode +-- if unicode then +-- descriptions[unicodes[k]].unicode = unicode +-- guessed = guessed + 1 +-- else +-- orphans = orphans + 1 +-- end +-- else +-- orphans = orphans + 1 +-- end +-- end +-- end +-- if trace_loading and orphans > 0 or guessed > 0 then +-- report_otf("%s glyphs with no related unicode, %s guessed, %s orphans",guessed+orphans,guessed,orphans) +-- end +-- end + actions["prepare tounicode"] = function(data,filename,raw) fonts.mappings.addtounicode(data,filename) end @@ -1288,8 +1435,9 @@ actions["reorganize subtables"] = function(data,filename,raw) local lookups = { } local chainedfeatures = { } resources.sequences = sequences - resources.lookups = lookups - for _, what in next, otf.glists do + resources.lookups = lookups -- we also have lookups in data itself + for k=1,#otf.glists do + local what = otf.glists[k] local dw = raw[what] if dw then for k=1,#dw do @@ -1375,12 +1523,6 @@ actions["reorganize subtables"] = function(data,filename,raw) end end --- test this: --- --- for _, what in next, otf.glists do --- raw[what] = nil --- end - actions["prepare lookups"] = function(data,filename,raw) local lookups = raw.lookups if lookups then @@ -1494,12 +1636,16 @@ end actions["reorganize lookups"] = function(data,filename,raw) -- we could check for "" and n == 0 -- we prefer the before lookups in a normal order if data.lookups then - local splitter = data.helpers.tounicodetable - local t_u_cache = { } - local s_u_cache = t_u_cache -- string keys - local t_h_cache = { } - local s_h_cache = t_h_cache -- table keys (so we could use one cache) - local r_u_cache = { } -- maybe shared + local helpers = data.helpers + local duplicates = data.resources.duplicates + local splitter = helpers.tounicodetable + local t_u_cache = { } + local s_u_cache = t_u_cache -- string keys + local t_h_cache = { } + local s_h_cache = t_h_cache -- table keys (so we could use one cache) + local r_u_cache = { } -- maybe shared + helpers.matchcache = t_h_cache -- so that we can add duplicates + -- for _, lookup in next, data.lookups do local rules = lookup.rules if rules then @@ -1653,6 +1799,50 @@ actions["reorganize lookups"] = function(data,filename,raw) -- we could check fo end end +actions["expand lookups"] = function(data,filename,raw) -- we could check for "" and n == 0 + if data.lookups then + local cache = data.helpers.matchcache + if cache then + local duplicates = data.resources.duplicates + for key, hash in next, cache do + local done = nil + for key in next, hash do + local unicode = duplicates[key] + if not unicode then + -- no duplicate + elseif type(unicode) == "table" then + -- multiple duplicates + for i=1,#unicode do + local u = unicode[i] + if hash[u] then + -- already in set + elseif done then + done[u] = key + else + done = { [u] = key } + end + end + else + -- one duplicate + if hash[unicode] then + -- already in set + elseif done then + done[unicode] = key + else + done = { [unicode] = key } + end + end + end + if done then + for u in next, done do + hash[u] = true + end + end + end + end + end +end + local function check_variants(unicode,the_variants,splitter,unicodes) local variants = the_variants.variants if variants then -- use splitter @@ -1693,11 +1883,11 @@ local function check_variants(unicode,the_variants,splitter,unicodes) parts = nil end end - local italic_correction = the_variants.italic_correction - if italic_correction and italic_correction == 0 then - italic_correction = nil + local italic = the_variants.italic + if italic and italic == 0 then + italic = nil end - return variants, parts, italic_correction + return variants, parts, italic end actions["analyze math"] = function(data,filename,raw) @@ -1706,15 +1896,16 @@ actions["analyze math"] = function(data,filename,raw) local unicodes = data.resources.unicodes local splitter = data.helpers.tounicodetable for unicode, description in next, data.descriptions do - local glyph = description.glyph - local mathkerns = glyph.mathkern -- singular - local horiz_variants = glyph.horiz_variants - local vert_variants = glyph.vert_variants - local top_accent = glyph.top_accent - if mathkerns or horiz_variants or vert_variants or top_accent then + local glyph = description.glyph + local mathkerns = glyph.mathkern -- singular + local hvariants = glyph.horiz_variants + local vvariants = glyph.vert_variants + local accent = glyph.top_accent + local italic = glyph.italic_correction + if mathkerns or hvariants or vvariants or accent or italic then local math = { } - if top_accent then - math.top_accent = top_accent + if accent then + math.accent = accent end if mathkerns then for k, v in next, mathkerns do @@ -1730,15 +1921,14 @@ actions["analyze math"] = function(data,filename,raw) end math.kerns = mathkerns end - if horiz_variants then - math.horiz_variants, math.horiz_parts, math.horiz_italic_correction = check_variants(unicode,horiz_variants,splitter,unicodes) + if hvariants then + math.hvariants, math.hparts, math.hitalic = check_variants(unicode,hvariants,splitter,unicodes) end - if vert_variants then - math.vert_variants, math.vert_parts, math.vert_italic_correction = check_variants(unicode,vert_variants,splitter,unicodes) + if vvariants then + math.vvariants, math.vparts, math.vitalic = check_variants(unicode,vvariants,splitter,unicodes) end - local italic_correction = description.italic - if italic_correction and italic_correction ~= 0 then - math.italic_correction = italic_correction + if italic and italic ~= 0 then + math.italic = italic end description.math = math end @@ -1903,7 +2093,7 @@ actions["merge kern classes"] = function(data,filename,raw) report_otf("%s kern overloads ignored",ignored) end if blocked > 0 then - report_otf("%s succesive kerns blocked",blocked) + report_otf("%s successive kerns blocked",blocked) end end end @@ -1940,18 +2130,21 @@ actions["check metadata"] = function(data,filename,raw) end end -- + local names = raw.names + -- if metadata.validation_state and table.contains(metadata.validation_state,"bad_ps_fontname") then -- the ff library does a bit too much (and wrong) checking ... so we need to catch this -- at least for now local function valid(what) - local names = raw.names - for i=1,#names do - local list = names[i] - local names = list.names - if names then - local name = names[what] - if name and valid_ps_name(name) then - return name + if names then + for i=1,#names do + local list = names[i] + local names = list.names + if names then + local name = names[what] + if name and valid_ps_name(name) then + return name + end end end end @@ -1975,6 +2168,33 @@ actions["check metadata"] = function(data,filename,raw) check("fullname") end -- + if names then + local psname = metadata.psname + if not psname or psname == "" then + for i=1,#names do + local name = names[i] + -- Currently we use the same restricted search as in the new context (specific) font loader + -- but we might add more lang checks (it worked ok in the new loaded so now we're in sync) + -- This check here is also because there are (esp) cjk fonts out there with psnames different + -- from fontnames (gives a bad lookup in backend). + if lower(name.lang) == "english (us)" then + local specification = name.names + if specification then + local postscriptname = specification.postscriptname + if postscriptname then + psname = postscriptname + end + end + end + break + end + end + if psname ~= metadata.fontname then + report_otf("fontname %a, fullname %a, psname %a",metadata.fontname,metadata.fullname,psname) + end + metadata.psname = psname + end + -- end actions["cleanup tables"] = function(data,filename,raw) @@ -2000,7 +2220,9 @@ end -- we can share { } as it is never set ---- ligatures have an extra specification.char entry that we don't use +-- ligatures have an extra specification.char entry that we don't use + +-- mlookups only with pairs and ligatures actions["reorganize glyph lookups"] = function(data,filename,raw) local resources = data.resources @@ -2081,14 +2303,14 @@ actions["reorganize glyph lookups"] = function(data,filename,raw) if mlookups then description.mlookups = mlookups end + -- description.lookups = nil end end - end local zero = { 0, 0 } -actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we replace inplace we safe entries +actions["reorganize glyph anchors"] = function(data,filename,raw) local descriptions = data.descriptions for unicode, description in next, descriptions do local anchors = description.glyph.anchors @@ -2311,7 +2533,7 @@ end -- we cannot share descriptions as virtual fonts might extend them (ok, -- we could use a cache with a hash -- --- we already assing an empty tabel to characters as we can add for +-- we already assign an empty tabel to characters as we can add for -- instance protruding info and loop over characters; one is not supposed -- to change descriptions and if one does so one should make a copy! @@ -2334,10 +2556,14 @@ local function copytotfm(data,cache_id) local spaceunits = 500 local spacer = "space" local designsize = metadata.designsize or metadata.design_size or 100 + local minsize = metadata.minsize or metadata.design_range_bottom or designsize + local maxsize = metadata.maxsize or metadata.design_range_top or designsize local mathspecs = metadata.math -- if designsize == 0 then designsize = 100 + minsize = 100 + maxsize = 100 end if mathspecs then for name, value in next, mathspecs do @@ -2355,8 +2581,11 @@ local function copytotfm(data,cache_id) local m = d.math if m then -- watch out: luatex uses horiz_variants for the parts - local variants = m.horiz_variants - local parts = m.horiz_parts + -- + local italic = m.italic + -- + local variants = m.hvariants + local parts = m.hparts -- local done = { [unicode] = true } if variants then local c = character @@ -2373,9 +2602,11 @@ local function copytotfm(data,cache_id) c.horiz_variants = parts elseif parts then character.horiz_variants = parts + italic = m.hitalic end - local variants = m.vert_variants - local parts = m.vert_parts + -- + local variants = m.vvariants + local parts = m.vparts -- local done = { [unicode] = true } if variants then local c = character @@ -2392,15 +2623,18 @@ local function copytotfm(data,cache_id) c.vert_variants = parts elseif parts then character.vert_variants = parts + italic = m.vitalic end - local italic_correction = m.vert_italic_correction - if italic_correction then - character.vert_italic_correction = italic_correction -- was c. + -- + if italic and italic ~= 0 then + character.italic = italic -- overload end - local top_accent = m.top_accent - if top_accent then - character.top_accent = top_accent + -- + local accent = m.accent + if accent then + character.accent = accent end + -- local kerns = m.kerns if kerns then character.mathkerns = kerns @@ -2413,16 +2647,16 @@ local function copytotfm(data,cache_id) local filename = constructors.checkedfilename(resources) local fontname = metadata.fontname local fullname = metadata.fullname or fontname - local psname = fontname or fullname - local units = metadata.units_per_em or 1000 + local psname = metadata.psname or fontname or fullname + local units = metadata.units or metadata.units_per_em or 1000 -- if units == 0 then -- catch bugs in fonts units = 1000 -- maybe 2000 when ttf - metadata.units_per_em = 1000 + metadata.units = 1000 report_otf("changing %a units to %a",0,units) end -- - local monospaced = metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion == "Monospaced") + local monospaced = metadata.monospaced or metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion == "Monospaced") local charwidth = pfminfo.avgwidth -- or unset local charxheight = pfminfo.os2_xheight and pfminfo.os2_xheight > 0 and pfminfo.os2_xheight -- charwidth = charwidth * units/1000 @@ -2492,17 +2726,16 @@ local function copytotfm(data,cache_id) end end -- - parameters.designsize = (designsize/10)*65536 - parameters.ascender = abs(metadata.ascent or 0) - parameters.descender = abs(metadata.descent or 0) - parameters.units = units + parameters.designsize = (designsize/10)*65536 + parameters.minsize = (minsize /10)*65536 + parameters.maxsize = (maxsize /10)*65536 + parameters.ascender = abs(metadata.ascender or metadata.ascent or 0) + parameters.descender = abs(metadata.descender or metadata.descent or 0) + parameters.units = units -- properties.space = spacer properties.encodingbytes = 2 properties.format = data.format or otf_format(filename) or formats.otf --- if units ~= 1000 and format ~= "truetype" then --- properties.format = "truetype" --- end properties.noglyphnames = true properties.filename = filename properties.fontname = fontname @@ -2703,3 +2936,111 @@ function otf.scriptandlanguage(tfmdata,attr) local properties = tfmdata.properties return properties.script or "dflt", properties.language or "dflt" end + +-- a little bit of abstraction + +local function justset(coverage,unicode,replacement) + coverage[unicode] = replacement +end + +otf.coverup = { + stepkey = "subtables", + actions = { + substitution = justset, + alternate = justset, + multiple = justset, + ligature = justset, + kern = justset, + }, + register = function(coverage,lookuptype,format,feature,n,descriptions,resources) + local name = formatters["ctx_%s_%s"](feature,n) + if lookuptype == "kern" then + resources.lookuptypes[name] = "position" + else + resources.lookuptypes[name] = lookuptype + end + for u, c in next, coverage do + local description = descriptions[u] + local slookups = description.slookups + if slookups then + slookups[name] = c + else + description.slookups = { [name] = c } + end +-- inspect(feature,description) + end + return name + end +} + +-- moved from font-oth.lua + +local function getgsub(tfmdata,k,kind) + local description = tfmdata.descriptions[k] + if description then + local slookups = description.slookups -- we assume only slookups (we can always extend) + if slookups then + local shared = tfmdata.shared + local rawdata = shared and shared.rawdata + if rawdata then + local lookuptypes = rawdata.resources.lookuptypes + if lookuptypes then + local properties = tfmdata.properties + -- we could cache these + local validlookups, lookuplist = otf.collectlookups(rawdata,kind,properties.script,properties.language) + if validlookups then + for l=1,#lookuplist do + local lookup = lookuplist[l] + local found = slookups[lookup] + if found then + return found, lookuptypes[lookup] + end + end + end + end + end + end + end +end + +otf.getgsub = getgsub -- returns value, gsub_kind + +function otf.getsubstitution(tfmdata,k,kind,value) + local found, kind = getgsub(tfmdata,k,kind) + if not found then + -- + elseif kind == "substitution" then + return found + elseif kind == "alternate" then + local choice = tonumber(value) or 1 -- no random here (yet) + return found[choice] or found[1] or k + end + return k +end + +otf.getalternate = otf.getsubstitution + +function otf.getmultiple(tfmdata,k,kind) + local found, kind = getgsub(tfmdata,k,kind) + if found and kind == "multiple" then + return found + end + return { k } +end + +function otf.getkern(tfmdata,left,right,kind) + local kerns = getgsub(tfmdata,left,kind or "kern",true) -- for now we use getsub + if kerns then + local found = kerns[right] + local kind = type(found) + if kind == "table" then + found = found[1][3] -- can be more clever + elseif kind ~= "number" then + found = false + end + if found then + return found * tfmdata.parameters.factor + end + end + return 0 +end diff --git a/src/fontloader/misc/fontloader-font-otp.lua b/src/fontloader/misc/fontloader-font-otp.lua index ebf36ed..91bd05b 100644 --- a/src/fontloader/misc/fontloader-font-otp.lua +++ b/src/fontloader/misc/fontloader-font-otp.lua @@ -12,9 +12,8 @@ if not modules then modules = { } end modules ['font-otp'] = { -- -- unless we sort all hashes we can get a different pack order (no big deal but size can differ) -local next, type = next, type +local next, type, tostring = next, type, tostring local sort, concat = table.sort, table.concat -local sortedhash = table.sortedhash local trace_packing = false trackers.register("otf.packing", function(v) trace_packing = v end) local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end) @@ -148,6 +147,7 @@ end -- we then need to sort more thanks to random hashing local function packdata(data) + if data then -- stripdata(data) local h, t, c = { }, { }, { } @@ -537,6 +537,7 @@ local unpacked_mt = { } local function unpackdata(data) + if data then local tables = data.tables if tables then diff --git a/src/fontloader/misc/fontloader-font-tfm.lua b/src/fontloader/misc/fontloader-font-tfm.lua index ab03788..401dc83 100644 --- a/src/fontloader/misc/fontloader-font-tfm.lua +++ b/src/fontloader/misc/fontloader-font-tfm.lua @@ -24,6 +24,7 @@ local constructors = fonts.constructors local encodings = fonts.encodings local tfm = constructors.newhandler("tfm") +tfm.version = 1.000 local tfmfeatures = constructors.newfeatures("tfm") local registertfmfeature = tfmfeatures.register diff --git a/src/fontloader/misc/fontloader-fonts-cbk.lua b/src/fontloader/misc/fontloader-fonts-cbk.lua index 81b5b6e..9da8151 100644 --- a/src/fontloader/misc/fontloader-fonts-cbk.lua +++ b/src/fontloader/misc/fontloader-fonts-cbk.lua @@ -160,12 +160,31 @@ function nodes.handlers.nodepass(head) local range = basefonts[i] local start = range[1] local stop = range[2] - if stop then - start, stop = ligaturing(start,stop) - start, stop = kerning(start,stop) - elseif start then - start = ligaturing(start) - start = kerning(start) + -- maybe even: if start and start ~= stop then + if start or stop then + local prev = nil + local next = nil + local front = start == head + if stop then + next = stop.next + start, stop = ligaturing(start,stop) + start, stop = kerning(start,stop) + elseif start then + prev = start.prev + start = ligaturing(start) + start = kerning(start) + end + if prev then + start.prev = prev + prev.next = start + end + if next then + stop.next = next + next.prev = stop + end + if front then + head = start + end end end end @@ -176,7 +195,7 @@ function nodes.handlers.nodepass(head) end function nodes.handlers.basepass(head) - if not basepass then + if basepass then head = ligaturing(head) head = kerning(head) end diff --git a/src/fontloader/misc/fontloader-fonts-inj.lua b/src/fontloader/misc/fontloader-fonts-inj.lua index 332e920..36781f7 100644 --- a/src/fontloader/misc/fontloader-fonts-inj.lua +++ b/src/fontloader/misc/fontloader-fonts-inj.lua @@ -8,7 +8,16 @@ if not modules then modules = { } end modules ['font-inj'] = { -- This property based variant is not faster but looks nicer than the attribute one. We -- need to use rawget (which is apbout 4 times slower than a direct access but we cannot --- get/set that one for our purpose! +-- get/set that one for our purpose! This version does a bit more with discretionaries +-- (and Kai has tested it with his collection of weird fonts.) + +-- There is some duplicate code here (especially in the the pre/post/replace branches) but +-- we go for speed. We could store a list of glyph and mark nodes when registering but it's +-- cleaner to have an identification pass here. Also, I need to keep tracing in mind so +-- being too clever here is dangerous. + +-- The subtype test is not needed as there will be no (new) properties set, given that we +-- reset the properties. if not nodes.properties then return end @@ -80,8 +89,7 @@ function injections.resetcounts() keepregisteredcounts = false end --- We need to make sure that a possible metatable will not kick in --- unexpectedly. +-- We need to make sure that a possible metatable will not kick in unexpectedly. function injections.reset(n) local p = rawget(properties,n) @@ -146,7 +154,8 @@ end function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) -- hm: nuts or nodes local dx = factor*(exit[1]-entry[1]) local dy = -factor*(exit[2]-entry[2]) - local ws, wn = tfmstart.width, tfmnext.width + local ws = tfmstart.width + local wn = tfmnext.width nofregisteredcursives = nofregisteredcursives + 1 if rlmode < 0 then dx = -(dx + wn) @@ -195,7 +204,10 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne end function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2lflag & tfmchr not used - local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4] + local x = factor*spec[1] + local y = factor*spec[2] + local w = factor*spec[3] + local h = factor*spec[4] if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay? local yoffset = y - h local leftkern = x -- both kerns are set in a pair kern compared @@ -205,9 +217,12 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l if rlmode and rlmode < 0 then leftkern, rightkern = rightkern, leftkern end + if not injection then + injection = "injections" + end local p = rawget(properties,current) if p then - local i = rawget(p,"injections") + local i = rawget(p,injection) if i then if leftkern ~= 0 then i.leftkern = (i.leftkern or 0) + leftkern @@ -219,19 +234,19 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l i.yoffset = (i.yoffset or 0) + yoffset end elseif leftkern ~= 0 or rightkern ~= 0 then - p.injections = { + p[injection] = { leftkern = leftkern, rightkern = rightkern, yoffset = yoffset, } else - p.injections = { + p[injection] = { yoffset = yoffset, } end elseif leftkern ~= 0 or rightkern ~= 0 then properties[current] = { - injections = { + [injection] = { leftkern = leftkern, rightkern = rightkern, yoffset = yoffset, @@ -239,7 +254,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l } else properties[current] = { - injections = { + [injection] = { yoffset = yoffset, }, } @@ -250,10 +265,9 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l return x, y, w, h -- no bound end --- this needs checking for rl < 0 but it is unlikely that a r2l script --- uses kernclasses between glyphs so we're probably safe (KE has a --- problematic font where marks interfere with rl < 0 in the previous --- case) +-- This needs checking for rl < 0 but it is unlikely that a r2l script uses kernclasses between +-- glyphs so we're probably safe (KE has a problematic font where marks interfere with rl < 0 in +-- the previous case) function injections.setkern(current,factor,rlmode,x,injection) local dx = factor * x @@ -285,7 +299,7 @@ function injections.setkern(current,factor,rlmode,x,injection) end end -function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=baseanchor, ma=markanchor +function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) -- ba=baseanchor, ma=markanchor local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2]) nofregisteredmarks = nofregisteredmarks + 1 -- markanchors[nofregisteredmarks] = base @@ -293,14 +307,20 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean dx = tfmbase.width - dx -- see later commented ox end local p = rawget(properties,start) + -- hm, dejavu serif does a sloppy mark2mark before mark2base if p then local i = rawget(p,"injections") if i then - i.markx = dx - i.marky = dy - i.markdir = rlmode or 0 - i.markbase = nofregisteredmarks - i.markbasenode = base + if i.markmark then + -- out of order mkmk: yes or no or option + else + i.markx = dx + i.marky = dy + i.markdir = rlmode or 0 + i.markbase = nofregisteredmarks + i.markbasenode = base + i.markmark = mkmk + end else p.injections = { markx = dx, @@ -308,6 +328,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean markdir = rlmode or 0, markbase = nofregisteredmarks, markbasenode = base, + markmark = mkmk, } end else @@ -318,6 +339,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean markdir = rlmode or 0, markbase = nofregisteredmarks, markbasenode = base, + markmark = mkmk, }, } end @@ -430,30 +452,36 @@ local function show_result(head) end end --- we could also check for marks here but maybe not all are registered (needs checking) - -local function collect_glyphs_1(head) - local glyphs, nofglyphs = { }, 0 - local marks, nofmarks = { }, 0 +local function collect_glyphs(head,offsets) + local glyphs, glyphi, nofglyphs = { }, { }, 0 + local marks, marki, nofmarks = { }, { }, 0 local nf, tm = nil, nil - for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts - if getsubtype(n) < 256 then - local f = getfont(n) - if f ~= nf then - nf = f - tm = fontdata[nf].resources.marks -- other hash in ctx - end - if tm and tm[getchar(n)] then - nofmarks = nofmarks + 1 - marks[nofmarks] = n - else - nofglyphs = nofglyphs + 1 - glyphs[nofglyphs] = n + local n = head + + local function identify(n,what) + local f = getfont(n) + if f ~= nf then + nf = f + -- other hash in ctx: + tm = fontdata[nf].resources + if tm then + tm = tm.marks end + end + if tm and tm[getchar(n)] then + nofmarks = nofmarks + 1 + marks[nofmarks] = n + marki[nofmarks] = "injections" + else + nofglyphs = nofglyphs + 1 + glyphs[nofglyphs] = n + glyphi[nofglyphs] = what + end + if offsets then -- yoffsets can influence curs steps local p = rawget(properties,n) if p then - local i = rawget(p,"injections") + local i = rawget(p,what) if i then local yoffset = i.yoffset if yoffset and yoffset ~= 0 then @@ -463,38 +491,50 @@ local function collect_glyphs_1(head) end end end - return glyphs, nofglyphs, marks, nofmarks -end -local function collect_glyphs_2(head) - local glyphs, nofglyphs = { }, 0 - local marks, nofmarks = { }, 0 - local nf, tm = nil, nil - for n in traverse_id(glyph_code,head) do - if getsubtype(n) < 256 then - local f = getfont(n) - if f ~= nf then - nf = f - tm = fontdata[nf].resources.marks -- other hash in ctx - end - if tm and tm[getchar(n)] then - nofmarks = nofmarks + 1 - marks[nofmarks] = n - else - nofglyphs = nofglyphs + 1 - glyphs[nofglyphs] = n - end + while n do -- only needed for relevant fonts + local id = getid(n) + if id == glyph_code then + identify(n,"injections") + elseif id == disc_code then + local d = getfield(n,"pre") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + identify(n,"preinjections") + end + end + end + local d = getfield(n,"post") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + identify(n,"postinjections") + end + end + end + local d = getfield(n,"replace") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n) < 256 then + identify(n,"replaceinjections") + end + end + end end + n = getnext(n) end - return glyphs, nofglyphs, marks, nofmarks + + return glyphs, glyphi, nofglyphs, marks, marki, nofmarks end -local function inject_marks(marks,nofmarks) +local function inject_marks(marks,marki,nofmarks) for i=1,nofmarks do - local n = marks[i] + local n = marks[i] local pn = rawget(properties,n) if pn then - pn = rawget(pn,"injections") + local ni = marki[i] + local pn = rawget(pn,ni) if pn then local p = pn.markbasenode if p then @@ -503,7 +543,7 @@ local function inject_marks(marks,nofmarks) local rightkern = nil local pp = rawget(properties,p) if pp then - pp = rawget(pp,"injections") + pp = rawget(pp,ni) if pp then rightkern = pp.rightkern end @@ -516,13 +556,22 @@ local function inject_marks(marks,nofmarks) else -- kern(x) glyph(p) kern(w-x) mark(n) -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern - local leftkern = pp.leftkern - if leftkern then - ox = px - pn.markx + -- + -- According to Kai we don't need to handle leftkern here but I'm + -- pretty sure I've run into a case where it was needed so maybe + -- some day we need something more clever here. + -- + if false then + -- a mark with kerning + local leftkern = pp.leftkern + if leftkern then + ox = px - pn.markx - leftkern + else + ox = px - pn.markx + end else - ox = px - pn.markx - leftkern + ox = px - pn.markx end --- report_injections("l2r case 1: %p",ox) end else -- we need to deal with fonts that have marks with width @@ -548,12 +597,13 @@ local function inject_marks(marks,nofmarks) setfield(n,"xoffset",ox) -- local py = getfield(p,"yoffset") - local oy = 0 - if marks[p] then - oy = py + pn.marky - else - oy = getfield(n,"yoffset") + py + pn.marky - end +-- local oy = 0 +-- if marks[p] then +-- oy = py + pn.marky +-- else +-- oy = getfield(n,"yoffset") + py + pn.marky +-- end + local oy = getfield(n,"yoffset") + py + pn.marky setfield(n,"yoffset",oy) else -- normally this can't happen (only when in trace mode which is a special case anyway) @@ -564,14 +614,14 @@ local function inject_marks(marks,nofmarks) end end -local function inject_cursives(glyphs,nofglyphs) +local function inject_cursives(glyphs,glyphi,nofglyphs) local cursiveanchor, lastanchor = nil, nil local minc, maxc, last = 0, 0, nil for i=1,nofglyphs do - local n = glyphs[i] + local n = glyphs[i] local pn = rawget(properties,n) if pn then - pn = rawget(pn,"injections") + pn = rawget(pn,glyphi[i]) end if pn then local cursivex = pn.cursivex @@ -630,7 +680,7 @@ local function inject_cursives(glyphs,nofglyphs) -- if maxc > 0 and not cursiveanchor then -- local ny = getfield(n,"yoffset") -- for i=maxc,minc,-1 do - -- local ti = glyphs[i] + -- local ti = glyphs[i][1] -- ny = ny + properties[ti].cursivedy -- setfield(ti,"yoffset",ny) -- why not add ? -- end @@ -647,23 +697,67 @@ local function inject_cursives(glyphs,nofglyphs) end end -local function inject_kerns(head,list,length) - -- todo: pre/post/replace +-- G +D-pre G +-- D-post+ +-- +D-replace+ +-- +-- G +D-pre +D-pre +-- D-post +D-post +-- +D-replace +D-replace + +local function inject_kerns(head,glist,ilist,length) -- not complete ! compare with inject_kerns_only (but unlikely disc here) for i=1,length do - local n = list[i] + local n = glist[i] local pn = rawget(properties,n) if pn then - local i = rawget(pn,"injections") - if i then - local leftkern = i.leftkern - if leftkern and leftkern ~= 0 then - insert_node_before(head,n,newkern(leftkern)) -- type 0/2 - end - local rightkern = i.rightkern - if rightkern and rightkern ~= 0 then - insert_node_after(head,n,newkern(rightkern)) -- type 0/2 - end - end + local dp = nil + local dr = nil + local ni = ilist[i] + local p = nil + if ni == "injections" then + p = getprev(n) + if p then + local id = getid(p) + if id == disc_code then + dp = getfield(p,"post") + dr = getfield(p,"replace") + end + end + end + if dp then + local i = rawget(pn,"postinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local t = find_tail(dp) + insert_node_after(dp,t,newkern(leftkern)) + setfield(p,"post",dp) -- currently we need to force a tail refresh + end + end + end + if dr then + local i = rawget(pn,"replaceinjections") + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + local t = find_tail(dr) + insert_node_after(dr,t,newkern(leftkern)) + setfield(p,"replace",dr) -- currently we need to force a tail refresh + end + end + else + local i = rawget(pn,ni) + if i then + local leftkern = i.leftkern + if leftkern and leftkern ~= 0 then + insert_node_before(head,n,newkern(leftkern)) -- type 0/2 + end + local rightkern = i.rightkern + if rightkern and rightkern ~= 0 then + insert_node_after(head,n,newkern(rightkern)) -- type 0/2 + end + end + end end end end @@ -673,23 +767,18 @@ local function inject_everything(head,where) if trace_injections then trace(head,"everything") end - local glyphs, nofglyphs, marks, nofmarks - if nofregisteredpairs > 0 then - glyphs, nofglyphs, marks, nofmarks = collect_glyphs_1(head) - else - glyphs, nofglyphs, marks, nofmarks = collect_glyphs_2(head) - end + local glyphs, glyphi, nofglyphs, marks, marki, nofmarks = collect_glyphs(head,nofregisteredpairs > 0) if nofglyphs > 0 then if nofregisteredcursives > 0 then - inject_cursives(glyphs,nofglyphs) + inject_cursives(glyphs,glyphi,nofglyphs) end if nofregisteredmarks > 0 then -- and nofmarks > 0 - inject_marks(marks,nofmarks) + inject_marks(marks,marki,nofmarks) end - inject_kerns(head,glyphs,nofglyphs) + inject_kerns(head,glyphs,glyphi,nofglyphs) end if nofmarks > 0 then - inject_kerns(head,marks,nofmarks) + inject_kerns(head,marks,marki,nofmarks) end if keepregisteredcounts then keepregisteredcounts = false @@ -702,13 +791,21 @@ local function inject_everything(head,where) return tonode(head), true end +-- G +D-pre G +-- D-post+ +-- +D-replace+ +-- +-- G +D-pre +D-pre +-- D-post +D-post +-- +D-replace +D-replace + local function inject_kerns_only(head,where) head = tonut(head) if trace_injections then trace(head,"kerns") end local n = head - local p = nil + local p = nil -- disc node when non-nil while n do local id = getid(n) if id == glyph_code then @@ -724,6 +821,7 @@ local function inject_kerns_only(head,where) if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"post",d) -- currently we need to force a tail refresh end end end @@ -735,6 +833,7 @@ local function inject_kerns_only(head,where) if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"replace",d) -- currently we need to force a tail refresh end end else @@ -747,6 +846,7 @@ local function inject_kerns_only(head,where) end end else + -- this is the most common case local i = rawget(pn,"injections") if i then local leftkern = i.leftkern @@ -756,8 +856,6 @@ local function inject_kerns_only(head,where) end end end - else - break end p = nil elseif id == disc_code then @@ -812,7 +910,7 @@ local function inject_kerns_only(head,where) local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local pn = rawget(properties,n) -- why can it be empty { } + local pn = rawget(properties,n) if pn then local i = rawget(pn,"replaceinjections") if i then @@ -850,9 +948,8 @@ local function inject_pairs_only(head,where) if trace_injections then trace(head,"pairs") end - -- local n = head - local p = nil + local p = nil -- disc node when non-nil while n do local id = getid(n) if id == glyph_code then @@ -868,6 +965,7 @@ local function inject_pairs_only(head,where) if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"post",d) -- currently we need to force a tail refresh end -- local rightkern = i.rightkern -- if rightkern and rightkern ~= 0 then @@ -884,6 +982,7 @@ local function inject_pairs_only(head,where) if leftkern and leftkern ~= 0 then local t = find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"replace",d) -- currently we need to force a tail refresh end -- local rightkern = i.rightkern -- if rightkern and rightkern ~= 0 then @@ -909,24 +1008,22 @@ local function inject_pairs_only(head,where) -- this is the most common case local i = rawget(pn,"injections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then - insert_node_before(head,n,newkern(leftkern)) + head = insert_node_before(head,n,newkern(leftkern)) end local rightkern = i.rightkern if rightkern and rightkern ~= 0 then insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end end - else - break end p = nil elseif id == disc_code then @@ -935,16 +1032,12 @@ local function inject_pairs_only(head,where) local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local p = rawget(properties,n) - if p then - local i = rawget(p,"preinjections") + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"preinjections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern - if leftkern ~= 0 then + if leftkern and leftkern ~= 0 then h = insert_node_before(h,n,newkern(leftkern)) end local rightkern = i.rightkern @@ -952,6 +1045,10 @@ local function inject_pairs_only(head,where) insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -967,14 +1064,10 @@ local function inject_pairs_only(head,where) local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local p = rawget(properties,n) - if p then - local i = rawget(p,"postinjections") + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"postinjections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then h = insert_node_before(h,n,newkern(leftkern)) @@ -984,6 +1077,10 @@ local function inject_pairs_only(head,where) insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -999,14 +1096,10 @@ local function inject_pairs_only(head,where) local h = d for n in traverse_id(glyph_code,d) do if getsubtype(n) < 256 then - local p = rawget(properties,n) - if p then - local i = rawget(p,"replaceinjections") + local pn = rawget(properties,n) + if pn then + local i = rawget(pn,"replaceinjections") if i then - local yoffset = i.yoffset - if yoffset and yoffset ~= 0 then - setfield(n,"yoffset",yoffset) - end local leftkern = i.leftkern if leftkern and leftkern ~= 0 then h = insert_node_before(h,n,newkern(leftkern)) @@ -1016,6 +1109,10 @@ local function inject_pairs_only(head,where) insert_node_after(head,n,newkern(rightkern)) n = getnext(n) -- to be checked end + local yoffset = i.yoffset + if yoffset and yoffset ~= 0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -1042,7 +1139,7 @@ local function inject_pairs_only(head,where) return tonode(head), true end -function injections.handler(head,where) -- optimize for n=1 ? +function injections.handler(head,where) if nofregisteredmarks > 0 or nofregisteredcursives > 0 then return inject_everything(head,where) elseif nofregisteredpairs > 0 then diff --git a/src/fontloader/misc/fontloader-fonts-otn.lua b/src/fontloader/misc/fontloader-fonts-otn.lua index dd3aa61..1b99c56 100644 --- a/src/fontloader/misc/fontloader-fonts-otn.lua +++ b/src/fontloader/misc/fontloader-fonts-otn.lua @@ -6,12 +6,16 @@ if not modules then modules = { } end modules ['font-otn'] = { license = "see context related readme files", } --- todo: looks like we have a leak somewhere (probably in ligatures) --- todo: copy attributes to disc - -- this is a context version which can contain experimental code, but when we -- have serious patches we also need to change the other two font-otn files +-- at some point i might decide to convert the whole list into a table and then +-- run over that instead (but it has some drawbacks as we also need to deal with +-- attributes and such so we need to keep a lot of track - which is why i rejected +-- that method - although it has become a bit easier in the meantime so it might +-- become an alternative (by that time i probably have gone completely lua) .. the +-- usual chicken-egg issues ... maybe mkix as it's no real tex any more then + -- preprocessors = { "nodes" } -- anchor class : mark, mkmk, curs, mklg (todo) @@ -40,7 +44,18 @@ if not modules then modules = { } end modules ['font-otn'] = { -- mark (to mark) code is still not what it should be (too messy but we need some more extreem husayni tests) -- remove some optimizations (when I have a faster machine) -- --- maybe redo the lot some way (more context specific) +-- beware: +-- +-- we do some disc jugling where we need to keep in mind that the +-- pre, post and replace fields can have prev pointers to a nesting +-- node ... i wonder if that is still needed +-- +-- not possible: +-- +-- \discretionary {alpha-} {betagammadelta} +-- {\discretionary {alphabeta-} {gammadelta} +-- {\discretionary {alphabetagamma-} {delta} +-- {alphabetagammadelta}}} --[[ldx--

This module is a bit more split up that I'd like but since we also want to test @@ -65,9 +80,12 @@ is currently acceptable. Not all functions are implemented yet, often because I lack the fonts for testing. Many scripts are not yet supported either, but I will look into them as soon as users ask for it.

-

Because there are different interpretations possible, I will extend the code -with more (configureable) variants. I can also add hooks for users so that they can -write their own extensions.

+

The specification leaves room for interpretation. In case of doubt the microsoft +implementation is the reference as it is the most complete one. As they deal with +lots of scripts and fonts, Kai and Ivo did a lot of testing of the generic code and +their suggestions help improve the code. I'm aware that not all border cases can be +taken care of, unless we accept excessive runtime, and even then the interference +with other mechanisms (like hyphenation) are not trivial.

Glyphs are indexed not by unicode but in their own way. This is because there is no relationship with unicode at all, apart from the fact that a font might cover certain @@ -94,12 +112,12 @@ when there's a fix in the library or code that results in different tables.

--ldx]]-- --- action handler chainproc chainmore comment +-- action handler chainproc -- --- gsub_single ok ok ok --- gsub_multiple ok ok not implemented yet --- gsub_alternate ok ok not implemented yet --- gsub_ligature ok ok ok +-- gsub_single ok ok +-- gsub_multiple ok ok +-- gsub_alternate ok ok +-- gsub_ligature ok ok -- gsub_context ok -- -- gsub_contextchain ok -- -- gsub_reversecontextchain ok -- @@ -123,7 +141,6 @@ results in different tables.

-- chainmore : multiple substitutions triggered by contextual lookup (e.g. fij -> f + ij) -- -- remark: the 'not implemented yet' variants will be done when we have fonts that use them --- remark: we need to check what to do with discretionaries -- We used to have independent hashes for lookups but as the tags are unique -- we now use only one hash. If needed we can have multiple again but in that @@ -131,16 +148,14 @@ results in different tables.

-- Todo: make plugin feature that operates on char/glyphnode arrays -local concat, insert, remove = table.concat, table.insert, table.remove -local gmatch, gsub, find, match, lower, strip = string.gmatch, string.gsub, string.find, string.match, string.lower, string.strip -local type, next, tonumber, tostring = type, next, tonumber, tostring -local lpegmatch = lpeg.match +local type, next, tonumber = type, next, tonumber local random = math.random local formatters = string.formatters local logs, trackers, nodes, attributes = logs, trackers, nodes, attributes -local registertracker = trackers.register +local registertracker = trackers.register +local registerdirective = directives.register local fonts = fonts local otf = fonts.handlers.otf @@ -162,6 +177,16 @@ local trace_steps = false registertracker("otf.steps", function(v local trace_skips = false registertracker("otf.skips", function(v) trace_skips = v end) local trace_directions = false registertracker("otf.directions", function(v) trace_directions = v end) +local trace_kernruns = false registertracker("otf.kernruns", function(v) trace_kernruns = v end) +local trace_discruns = false registertracker("otf.discruns", function(v) trace_discruns = v end) +local trace_compruns = false registertracker("otf.compruns", function(v) trace_compruns = v end) + +local quit_on_no_replacement = true -- maybe per font +local zwnjruns = true + +registerdirective("otf.zwnjruns", function(v) zwnjruns = v end) +registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end) + local report_direct = logs.reporter("fonts","otf direct") local report_subchain = logs.reporter("fonts","otf subchain") local report_chain = logs.reporter("fonts","otf chain") @@ -230,11 +255,7 @@ local math_code = nodecodes.math local dir_code = whatcodes.dir local localpar_code = whatcodes.localpar - local discretionary_code = disccodes.discretionary -local regular_code = disccodes.regular -local automatic_code = disccodes.automatic - local ligature_code = glyphcodes.ligature local privateattribute = attributes.private @@ -286,6 +307,15 @@ local handlers = { } local rlmode = 0 local featurevalue = false +local sweephead = { } +local sweepnode = nil +local sweepprev = nil +local sweepnext = nil + +local notmatchpre = { } +local notmatchpost = { } +local notmatchreplace = { } + -- head is always a whatsit so we can safely assume that head is not changed -- we use this for special testing and documentation @@ -376,8 +406,66 @@ local function copy_glyph(g) -- next and prev are untouched ! end end --- +local function flattendisk(head,disc) + local replace = getfield(disc,"replace") + setfield(disc,"replace",nil) + free_node(disc) + if head == disc then + local next = getnext(disc) + if replace then + if next then + local tail = find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + end + return replace, replace + elseif next then + return next, next + else + return -- maybe warning + end + else + local next = getnext(disc) + local prev = getprev(disc) + if replace then + local tail = find_node_tail(replace) + if next then + setfield(tail,"next",next) + setfield(next,"prev",tail) + end + setfield(prev,"next",replace) + setfield(replace,"prev",prev) + return head, replace + else + if next then + setfield(next,"prev",prev) + end + setfield(prev,"next",next) + return head, next + end + end +end +local function appenddisc(disc,list) + local post = getfield(disc,"post") + local replace = getfield(disc,"replace") + local phead = list + local rhead = copy_node_list(list) + local ptail = find_node_tail(post) + local rtail = find_node_tail(replace) + if post then + setfield(ptail,"next",phead) + setfield(phead,"prev",ptail) + else + setfield(disc,"post",phead) + end + if replace then + setfield(rtail,"next",rhead) + setfield(rhead,"prev",rtail) + else + setfield(disc,"replace",rhead) + end +end -- start is a mark and we need to keep that one @@ -416,8 +504,8 @@ end -- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the -- third component. -local function getcomponentindex(start) - if getid(start) ~= glyph_code then +local function getcomponentindex(start) -- we could store this offset in the glyph (nofcomponents) + if getid(start) ~= glyph_code then -- and then get rid of all components return 0 elseif getsubtype(start) == ligature_code then local i = 0 @@ -434,16 +522,28 @@ local function getcomponentindex(start) end end --- eventually we will do positioning in an other way (needs addional w/h/d fields) +local a_noligature = attributes.private("noligature") local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head + if getattr(start,a_noligature) == 1 then + -- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first) + return head, start + end if start == stop and getchar(start) == char then resetinjection(start) setfield(start,"char",char) return head, start end + -- needs testing (side effects): + local components = getfield(start,"components") + if components then + -- we get a double free .. needs checking + -- flush_node_list(components) + end + -- local prev = getprev(start) local next = getnext(stop) + local comp = start setfield(start,"prev",nil) setfield(stop,"next",nil) local base = copy_glyph(start) @@ -453,15 +553,15 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun resetinjection(base) setfield(base,"char",char) setfield(base,"subtype",ligature_code) - setfield(base,"components",start) -- start can have components + setfield(base,"components",comp) -- start can have components ... do we need to flush? if prev then setfield(prev,"next",base) end if next then setfield(next,"prev",base) end - setfield(base,"next",next) setfield(base,"prev",prev) + setfield(base,"next",next) if not discfound then local deletemarks = markflag ~= "mark" local components = start @@ -480,7 +580,9 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun if trace_marks then logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getligaindex(start)) end - head, current = insert_node_after(head,current,copy_node(start)) -- unlikely that mark has components + local n = copy_node(start) + copyinjection(n,start) + head, current = insert_node_after(head,current,n) -- unlikely that mark has components elseif trace_marks then logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char)) end @@ -501,17 +603,85 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun end start = getnext(start) end + else + -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks + local discprev = getfield(discfound,"prev") + local discnext = getfield(discfound,"next") + if discprev and discnext then + -- we assume normalization in context, and don't care about generic ... especially + -- \- can give problems as there we can have a negative char but that won't match + -- anyway + local pre = getfield(discfound,"pre") + local post = getfield(discfound,"post") + local replace = getfield(discfound,"replace") + if not replace then -- todo: signal simple hyphen + local prev = getfield(base,"prev") + local copied = copy_node_list(comp) + setfield(discnext,"prev",nil) -- also blocks funny assignments + setfield(discprev,"next",nil) -- also blocks funny assignments + if pre then + setfield(discprev,"next",pre) + setfield(pre,"prev",discprev) + end + pre = comp + if post then + local tail = find_node_tail(post) + setfield(tail,"next",discnext) + setfield(discnext,"prev",tail) + setfield(post,"prev",nil) + else + post = discnext + end + setfield(prev,"next",discfound) + setfield(discfound,"prev",prev) + setfield(discfound,"next",next) + setfield(next,"prev",discfound) + setfield(base,"next",nil) + setfield(base,"prev",nil) + setfield(base,"components",copied) + setfield(discfound,"pre",pre) + setfield(discfound,"post",post) + setfield(discfound,"replace",base) + setfield(discfound,"subtype",discretionary_code) + base = prev -- restart + end + end end return head, base end -function handlers.gsub_single(head,start,kind,lookupname,replacement) - if trace_singles then - logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) +local function multiple_glyphs(head,start,multiple,ignoremarks) + local nofmultiples = #multiple + if nofmultiples > 0 then + resetinjection(start) + setfield(start,"char",multiple[1]) + if nofmultiples > 1 then + local sn = getnext(start) + for k=2,nofmultiples do -- todo: use insert_node +-- untested: +-- +-- while ignoremarks and marks[getchar(sn)] then +-- local sn = getnext(sn) +-- end + local n = copy_node(start) -- ignore components + resetinjection(n) + setfield(n,"char",multiple[k]) + setfield(n,"prev",start) + setfield(n,"next",sn) + if sn then + setfield(sn,"prev",n) + end + setfield(start,"next",n) + start = n + end + end + return head, start, true + else + if trace_multiples then + logprocess("no multiple for %s",gref(getchar(start))) + end + return head, start, false end - resetinjection(start) - setfield(start,"char",replacement) - return head, start, true end local function get_alternative_glyph(start,alternatives,value,trace_alternatives) @@ -546,38 +716,15 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives end end -local function multiple_glyphs(head,start,multiple,ignoremarks) - local nofmultiples = #multiple - if nofmultiples > 0 then - resetinjection(start) - setfield(start,"char",multiple[1]) - if nofmultiples > 1 then - local sn = getnext(start) - for k=2,nofmultiples do -- todo: use insert_node --- untested: --- --- while ignoremarks and marks[getchar(sn)] then --- local sn = getnext(sn) --- end - local n = copy_node(start) -- ignore components - resetinjection(n) - setfield(n,"char",multiple[k]) - setfield(n,"next",sn) - setfield(n,"prev",start) - if sn then - setfield(sn,"prev",n) - end - setfield(start,"next",n) - start = n - end - end - return head, start, true - else - if trace_multiples then - logprocess("no multiple for %s",gref(getchar(start))) - end - return head, start, false +-- handlers + +function handlers.gsub_single(head,start,kind,lookupname,replacement) + if trace_singles then + logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) end + resetinjection(start) + setfield(start,"char",replacement) + return head, start, true end function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence) @@ -605,7 +752,7 @@ function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence) end function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) - local s, stop, discfound = getnext(start), nil, false + local s, stop = getnext(start), nil local startchar = getchar(start) if marks[startchar] then while s do @@ -633,24 +780,30 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) else head, start = markstoligature(kind,lookupname,head,start,stop,lig) end - return head, start, true + return head, start, true, false else -- ok, goto next lookup end end else - local skipmark = sequence.flags[1] + local skipmark = sequence.flags[1] + local discfound = false + local lastdisc = nil while s do local id = getid(s) - if id == glyph_code and getsubtype(s)<256 then - if getfont(s) == currentfont then + if id == glyph_code and getsubtype(s)<256 then -- not needed + if getfont(s) == currentfont then -- also not needed only when mark local char = getchar(s) if skipmark and marks[char] then s = getnext(s) - else - local lg = ligature[char] + else -- ligature is a tree + local lg = ligature[char] -- can there be multiple in a row? maybe in a bad font if lg then - stop = s + if not discfound and lastdisc then + discfound = lastdisc + lastdisc = nil + end + stop = s -- needed for fake so outside then ligature = lg s = getnext(s) else @@ -661,13 +814,13 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) break end elseif id == disc_code then - discfound = true + lastdisc = s s = getnext(s) else break end end - local lig = ligature.ligature + local lig = ligature.ligature -- can't we get rid of this .ligature? if lig then if stop then if trace_ligatures then @@ -685,14 +838,88 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) end end - return head, start, true + return head, start, true, discfound else - -- weird but happens + -- weird but happens, pseudo ligatures ... just the components end end + return head, start, false, discfound +end + +function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection) + local startchar = getchar(start) + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection) -- ,characters[startchar]) + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) + end return head, start, false end +function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection) + -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too + -- todo: kerns in components of ligatures + local snext = getnext(start) + if not snext then + return head, start, false + else + local prev = start + local done = false + local factor = tfmdata.parameters.factor + local lookuptype = lookuptypes[lookupname] + while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do + local nextchar = getchar(snext) + local krn = kerns[nextchar] + if not krn and marks[nextchar] then + prev = snext + snext = getnext(snext) + else + if not krn then + -- skip + elseif type(krn) == "table" then + if lookuptype == "pair" then -- probably not needed + local a, b = krn[2], krn[3] + if a and #a > 0 then + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar]) + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b and #b > 0 then + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar]) + if trace_kerns then + local startchar = getchar(start) + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + else -- wrong ... position has different entries + report_process("%s: check this out (old kern stuff)",pref(kind,lookupname)) + -- local a, b = krn[2], krn[6] + -- if a and a ~= 0 then + -- local k = setkern(snext,factor,rlmode,a) + -- if trace_kerns then + -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) + -- end + -- end + -- if b and b ~= 0 then + -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor) + -- end + end + done = true + elseif krn ~= 0 then + local k = setkern(snext,factor,rlmode,krn,injection) + if trace_kerns then + logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) -- prev? + end + done = true + end + break + end + end + return head, start, done + end +end + --[[ldx--

We get hits on a mark, but we're not sure if the it has to be applied so we need to explicitly test for basechar, baselig and basemark entries.

@@ -855,7 +1082,7 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence if al[anchor] then local ma = markanchors[anchor] if ma then - local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar]) + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true) if trace_marks then logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) @@ -938,85 +1165,11 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) end end -function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence) - local startchar = getchar(start) - local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) - end - return head, start, false -end - -function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) - -- todo: kerns in disc nodes: pre, post, replace -> loop over disc too - -- todo: kerns in components of ligatures - local snext = getnext(start) - if not snext then - return head, start, false - else - local prev, done = start, false - local factor = tfmdata.parameters.factor - local lookuptype = lookuptypes[lookupname] - while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do - local nextchar = getchar(snext) - local krn = kerns[nextchar] - if not krn and marks[nextchar] then - prev = snext - snext = getnext(snext) - else - if not krn then - -- skip - elseif type(krn) == "table" then - if lookuptype == "pair" then -- probably not needed - local a, b = krn[2], krn[3] - if a and #a > 0 then - local startchar = getchar(start) - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - if b and #b > 0 then - local startchar = getchar(start) - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) - if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - else -- wrong ... position has different entries - report_process("%s: check this out (old kern stuff)",pref(kind,lookupname)) - -- local a, b = krn[2], krn[6] - -- if a and a ~= 0 then - -- local k = setkern(snext,factor,rlmode,a) - -- if trace_kerns then - -- logprocess("%s: inserting first kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) - -- end - -- end - -- if b and b ~= 0 then - -- logwarning("%s: ignoring second kern xoff %s",pref(kind,lookupname),b*factor) - -- end - end - done = true - elseif krn ~= 0 then - local k = setkern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) - end - done = true - end - break - end - end - return head, start, done - end -end - --[[ldx--

I will implement multiple chain replacements once I run into a font that uses it. It's not that complex to handle.

--ldx]]-- -local chainmores = { } local chainprocs = { } local function logprocess(...) @@ -1045,11 +1198,6 @@ function chainprocs.chainsub(head,start,stop,kind,chainname,currentcontext,looku return head, start, false end -function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n) - logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname)) - return head, start, false -end - -- The reversesub is a special case, which is why we need to store the replacements -- in a bit weird way. There is no lookup and the replacement comes from the lookup -- itself. It is meant mostly for dealing with Urdu. @@ -1116,8 +1264,7 @@ as less as needed but that would also make the code even more messy.

-- end --[[ldx-- -

Here we replace start by a single variant, First we delete the rest of the -match.

+

Here we replace start by a single variant.

--ldx]]-- function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex) @@ -1125,7 +1272,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo local current = start local subtables = currentlookup.subtables if #subtables > 1 then - logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," ")) + logwarning("todo: check if we need to loop over the replacements: % t",subtables) end while current do if getid(current) == glyph_code then @@ -1160,11 +1307,8 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo return head, start, false end -chainmores.gsub_single = chainprocs.gsub_single - --[[ldx-- -

Here we replace start by a sequence of new glyphs. First we delete the rest of -the match.

+

Here we replace start by a sequence of new glyphs.

--ldx]]-- function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) @@ -1193,8 +1337,6 @@ function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext, return head, start, false end -chainmores.gsub_multiple = chainprocs.gsub_multiple - --[[ldx--

Here we replace start by new glyph. First we delete the rest of the match.

--ldx]]-- @@ -1249,8 +1391,6 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext return head, start, false end -chainmores.gsub_alternate = chainprocs.gsub_alternate - --[[ldx--

When we replace ligatures we use a helper that handles the marks. I might change this function (move code inline and handle the marks by a separate function). We @@ -1276,13 +1416,19 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, local s = getnext(start) local discfound = false local last = stop - local nofreplacements = 0 + local nofreplacements = 1 local skipmark = currentlookup.flags[1] while s do local id = getid(s) if id == disc_code then - s = getnext(s) - discfound = true + if not discfound then + discfound = s + end + if s == stop then + break -- okay? or before the disc + else + s = getnext(s) + end else local schar = getchar(s) if skipmark and marks[schar] then -- marks @@ -1315,7 +1461,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end head, start = toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound) - return head, start, true, nofreplacements + return head, start, true, nofreplacements, discfound elseif trace_bugs then if start == stop then logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) @@ -1325,11 +1471,97 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end end - return head, start, false, 0 + return head, start, false, 0, false +end + +function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) + -- untested .. needs checking for the new model + local startchar = getchar(start) + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local kerns = lookuphash[lookupname] + if kerns then + kerns = kerns[startchar] -- needed ? + if kerns then + local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns) -- ,characters[startchar]) + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) + end + end + end + return head, start, false +end + +function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) + local snext = getnext(start) + if snext then + local startchar = getchar(start) + local subtables = currentlookup.subtables + local lookupname = subtables[1] + local kerns = lookuphash[lookupname] + if kerns then + kerns = kerns[startchar] + if kerns then + local lookuptype = lookuptypes[lookupname] + local prev, done = start, false + local factor = tfmdata.parameters.factor + while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do + local nextchar = getchar(snext) + local krn = kerns[nextchar] + if not krn and marks[nextchar] then + prev = snext + snext = getnext(snext) + else + if not krn then + -- skip + elseif type(krn) == "table" then + if lookuptype == "pair" then + local a, b = krn[2], krn[3] + if a and #a > 0 then + local startchar = getchar(start) + local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a) -- ,characters[startchar]) + if trace_kerns then + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b and #b > 0 then + local startchar = getchar(start) + local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b) -- ,characters[nextchar]) + if trace_kerns then + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + else + report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname)) + -- local a, b = krn[2], krn[6] + -- if a and a ~= 0 then + -- local k = setkern(snext,factor,rlmode,a) + -- if trace_kerns then + -- logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) + -- end + -- end + -- if b and b ~= 0 then + -- logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor) + -- end + end + done = true + elseif krn ~= 0 then + local k = setkern(snext,factor,rlmode,krn) + if trace_kerns then + logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) + end + done = true + end + break + end + end + return head, start, done + end + end + end + return head, start, false end -chainmores.gsub_ligature = chainprocs.gsub_ligature - function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) local markchar = getchar(start) if marks[markchar] then @@ -1497,7 +1729,7 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext if al[anchor] then local ma = markanchors[anchor] if ma then - local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar]) + local dx, dy, bound = setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true) if trace_marks then logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) @@ -1588,133 +1820,346 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l return head, start, false end -function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) - -- untested .. needs checking for the new model - local startchar = getchar(start) - local subtables = currentlookup.subtables - local lookupname = subtables[1] - local kerns = lookuphash[lookupname] - if kerns then - kerns = kerns[startchar] -- needed ? - if kerns then - local dx, dy, w, h = setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) +-- what pointer to return, spec says stop +-- to be discussed ... is bidi changer a space? +-- elseif char == zwnj and sequence[n][32] then -- brrr + +-- somehow l or f is global +-- we don't need to pass the currentcontext, saves a bit +-- make a slow variant then can be activated but with more tracing + +local function show_skip(kind,chainname,char,ck,class) + if ck[9] then + logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10]) + else + logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2]) + end +end + +-- A previous version had disc collapsing code in the (single sub) handler plus some +-- checking in the main loop, but that left the pre/post sequences undone. The best +-- solution is to add some checking there and backtrack when a replace/post matches +-- but it takes a bit of work to figure out an efficient way (this is what the sweep* +-- names refer to). I might look into that variant one day again as it can replace +-- some other code too. In that approach we can have a special version for gub and pos +-- which gains some speed. This method does the test and passes info to the handlers +-- (sweepnode, sweepmode, sweepprev, sweepnext, etc). Here collapsing is handled in the +-- main loop which also makes code elsewhere simpler (i.e. no need for the other special +-- runners and disc code in ligature building). I also experimented with pushing preceding +-- glyphs sequences in the replace/pre fields beforehand which saves checking afterwards +-- but at the cost of duplicate glyphs (memory) but it's too much overhead (runtime). +-- +-- In the meantime Kai had moved the code from the single chain into a more general handler +-- and this one (renamed to chaindisk) is used now. I optimized the code a bit and brought +-- it in sycn with the other code. Hopefully I didn't introduce errors. Note: this somewhat +-- complex approach is meant for fonts that implement (for instance) ligatures by character +-- replacement which to some extend is not that suitable for hyphenation. I also use some +-- helpers. This method passes some states but reparses the list. There is room for a bit of +-- speed up but that will be done in the context version. (In fact a partial rewrite of all +-- code can bring some more efficientry.) +-- +-- I didn't test it with extremes but successive disc nodes still can give issues but in +-- order to handle that we need more complex code which also slows down even more. The main +-- loop variant could deal with that: test, collapse, backtrack. + +local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,chainindex,sequence,chainproc) + + if not start then + return head, start, false + end + + local startishead = start == head + local seq = ck[3] + local f = ck[4] + local l = ck[5] + local s = #seq + local done = false + local sweepnode = sweepnode + local sweeptype = sweeptype + local sweepoverflow = false + local checkdisc = getprev(head) -- hm bad name head + local keepdisc = not sweepnode + local lookaheaddisc = nil + local backtrackdisc = nil + local current = start + local last = start + local prev = getprev(start) + + -- fishy: so we can overflow and then go on in the sweep? + + local i = f + while i <= l do + local id = getid(current) + if id == glyph_code then + i = i + 1 + last = current + current = getnext(current) + elseif id == disc_code then + if keepdisc then + keepdisc = false + if notmatchpre[current] ~= notmatchreplace[current] then + lookaheaddisc = current + end + local replace = getfield(current,"replace") + while replace and i <= l do + if getid(replace) == glyph_code then + i = i + 1 + end + replace = getnext(replace) + end + last = current + current = getnext(c) + else + head, current = flattendisk(head,current) + end + else + last = current + current = getnext(current) + end + if current then + -- go on + elseif sweepoverflow then + -- we already are folling up on sweepnode + break + elseif sweeptype == "post" or sweeptype == "replace" then + current = getnext(sweepnode) + if current then + sweeptype = nil + sweepoverflow = true + else + break end end end - return head, start, false -end -chainmores.gpos_single = chainprocs.gpos_single -- okay? + if sweepoverflow then + local prev = current and getprev(current) + if not current or prev ~= sweepnode then + local head = getnext(sweepnode) + local tail = nil + if prev then + tail = prev + setfield(current,"prev",sweepnode) + else + tail = find_node_tail(head) + end + setfield(sweepnode,"next",current) + setfield(head,"prev",nil) + setfield(tail,"next",nil) + appenddisc(sweepnode,head) + end + end --- when machines become faster i will make a shared function + if l < s then + local i = l + local t = sweeptype == "post" or sweeptype == "replace" + while current and i < s do + local id = getid(current) + if id == glyph_code then + i = i + 1 + current = getnext(current) + elseif id == disc_code then + if keepdisc then + keepdisc = false + if notmatchpre[current] ~= notmatchreplace[current] then + lookaheaddisc = current + end + local replace = getfield(c,"replace") + while replace and i < s do + if getid(replace) == glyph_code then + i = i + 1 + end + replace = getnext(replace) + end + current = getnext(current) + elseif notmatchpre[current] ~= notmatchreplace[current] then + head, current = flattendisk(head,current) + else + current = getnext(current) -- HH + end + else + current = getnext(current) + end + if not current and t then + current = getnext(sweepnode) + if current then + sweeptype = nil + end + end + end + end -function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) - local snext = getnext(start) - if snext then - local startchar = getchar(start) - local subtables = currentlookup.subtables - local lookupname = subtables[1] - local kerns = lookuphash[lookupname] - if kerns then - kerns = kerns[startchar] - if kerns then - local lookuptype = lookuptypes[lookupname] - local prev, done = start, false - local factor = tfmdata.parameters.factor - while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do - local nextchar = getchar(snext) - local krn = kerns[nextchar] - if not krn and marks[nextchar] then - prev = snext - snext = getnext(snext) - else - if not krn then - -- skip - elseif type(krn) == "table" then - if lookuptype == "pair" then - local a, b = krn[2], krn[3] - if a and #a > 0 then - local startchar = getchar(start) - local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - if b and #b > 0 then - local startchar = getchar(start) - local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) - if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - else - report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname)) - local a, b = krn[2], krn[6] - if a and a ~= 0 then - local k = setkern(snext,factor,rlmode,a) - if trace_kerns then - logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) - end - end - if b and b ~= 0 then - logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor) - end - end - done = true - elseif krn ~= 0 then - local k = setkern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) - end - done = true + if f > 1 then + local current = prev + local i = f + local t = sweeptype == "pre" or sweeptype == "replace" + if not current and t and current == checkdisk then + current = getprev(sweepnode) + end + while current and i > 1 do -- missing getprev added / moved outside + local id = getid(current) + if id == glyph_code then + i = i - 1 + elseif id == disc_code then + if keepdisc then + keepdisc = false + if notmatchpost[current] ~= notmatchreplace[current] then + backtrackdisc = current + end + local replace = getfield(current,"replace") + while replace and i > 1 do + if getid(replace) == glyph_code then + i = i - 1 end - break + replace = getnext(replace) end + elseif notmatchpost[current] ~= notmatchreplace[current] then + head, current = flattendisk(head,current) end - return head, start, done + end + current = getprev(current) + if t and current == checkdisk then + current = getprev(sweepnode) end end end - return head, start, false -end -chainmores.gpos_pair = chainprocs.gpos_pair -- okay? + local ok = false + if lookaheaddisc then --- what pointer to return, spec says stop --- to be discussed ... is bidi changer a space? --- elseif char == zwnj and sequence[n][32] then -- brrr + local cf = start + local cl = getprev(lookaheaddisc) + local cprev = getprev(start) + local insertedmarks = 0 --- somehow l or f is global --- we don't need to pass the currentcontext, saves a bit --- make a slow variant then can be activated but with more tracing + while cprev and getid(cf) == glyph_code and getfont(cf) == currentfont and getsubtype(cf) < 256 and marks[getchar(cf)] do + insertedmarks = insertedmarks + 1 + cf = cprev + startishead = cf == head + cprev = getprev(cprev) + end + + setfield(lookaheaddisc,"prev",cprev) + if cprev then + setfield(cprev,"next",lookaheaddisc) + end + setfield(cf,"prev",nil) + setfield(cl,"next",nil) + if startishead then + head = lookaheaddisc + end + + local replace = getfield(lookaheaddisc,"replace") + local pre = getfield(lookaheaddisc,"pre") + local new = copy_node_list(cf) + local cnew = new + for i=1,insertedmarks do + cnew = getnext(cnew) + end + local clast = cnew + for i=f,l do + clast = getnext(clast) + end + if not notmatchpre[lookaheaddisc] then + cf, start, ok = chainproc(cf,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if not notmatchreplace[lookaheaddisc] then + new, cnew, ok = chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if pre then + setfield(cl,"next",pre) + setfield(pre,"prev",cl) + end + if replace then + local tail = find_node_tail(new) + setfield(tail,"next",replace) + setfield(replace,"prev",tail) + end + setfield(lookaheaddisc,"pre",cf) -- also updates tail + setfield(lookaheaddisc,"replace",new) -- also updates tail + + start = getprev(lookaheaddisc) + sweephead[cf] = getnext(clast) + sweephead[new] = getnext(last) + + elseif backtrackdisc then + + local cf = getnext(backtrackdisc) + local cl = start + local cnext = getnext(start) + local insertedmarks = 0 + + while cnext and getid(cnext) == glyph_code and getfont(cnext) == currentfont and getsubtype(cnext) < 256 and marks[getchar(cnext)] do + insertedmarks = insertedmarks + 1 + cl = cnext + cnext = getnext(cnext) + end + if cnext then + setfield(cnext,"prev",backtrackdisc) + end + setfield(backtrackdisc,"next",cnext) + setfield(cf,"prev",nil) + setfield(cl,"next",nil) + local replace = getfield(backtrackdisc,"replace") + local post = getfield(backtrackdisc,"post") + local new = copy_node_list(cf) + local cnew = find_node_tail(new) + for i=1,insertedmarks do + cnew = getprev(cnew) + end + local clast = cnew + for i=f,l do + clast = getnext(clast) + end + if not notmatchpost[backtrackdisc] then + cf, start, ok = chainproc(cf,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if not notmatchreplace[backtrackdisc] then + new, cnew, ok = chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if post then + local tail = find_node_tail(post) + setfield(tail,"next",cf) + setfield(cf,"prev",tail) + else + post = cf + end + if replace then + local tail = find_node_tail(replace) + setfield(tail,"next",new) + setfield(new,"prev",tail) + else + replace = new + end + setfield(backtrackdisc,"post",post) -- also updates tail + setfield(backtrackdisc,"replace",replace) -- also updates tail + start = getprev(backtrackdisc) + sweephead[post] = getnext(clast) + sweephead[replace] = getnext(last) -local function show_skip(kind,chainname,char,ck,class) - if ck[9] then - logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10]) else - logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2]) - end -end -local quit_on_no_replacement = true + head, start, ok = chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) -directives.register("otf.chain.quitonnoreplacement",function(value) -- maybe per font - quit_on_no_replacement = value -end) + end + + return head, start, ok +end local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash) - -- local rule, lookuptype, sequence, f, l, lookups = ck[1], ck[2] ,ck[3], ck[4], ck[5], ck[6] + local sweepnode = sweepnode + local sweeptype = sweeptype + local diskseen = false + local checkdisc = getprev(head) local flags = sequence.flags local done = false local skipmark = flags[1] local skipligature = flags[2] local skipbase = flags[3] - local someskip = skipmark or skipligature or skipbase -- could be stored in flags for a fast test (hm, flags could be false !) - local markclass = sequence.markclass -- todo, first we need a proper test + local markclass = sequence.markclass local skipped = false - for k=1,#contexts do + + for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu) local match = true local current = start local last = start @@ -1728,7 +2173,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq else -- maybe we need a better space check (maybe check for glue or category or combination) -- we cannot optimize for n=2 because there can be disc nodes - local f, l = ck[4], ck[5] + local f = ck[4] + local l = ck[5] -- current match if f == 1 and f == l then -- current only -- already a hit @@ -1738,9 +2184,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if f == l then -- new, else last out of sync (f is > 1) -- match = true else + local discfound = nil local n = f + 1 last = getnext(last) while n <= l do + if not last and (sweeptype == "post" or sweeptype == "replace") then + last = getnext(sweepnode) + sweeptype = nil + end if last then local id = getid(last) if id == glyph_code then @@ -1748,7 +2199,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq local char = getchar(last) local ccd = descriptions[char] if ccd then - local class = ccd.class + local class = ccd.class or "base" if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then skipped = true if trace_skips then @@ -1761,18 +2212,77 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end n = n + 1 else - match = false + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpre[discfound] + else + match = false + end break end else - match = false + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpre[discfound] + else + match = false + end break end else - match = false + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpre[discfound] + else + match = false + end break end elseif id == disc_code then + diskseen = true + discfound = last + notmatchpre[last] = nil + notmatchpost[last] = true + notmatchreplace[last] = nil + local pre = getfield(last,"pre") + local replace = getfield(last,"replace") + if pre then + local n = n + while pre do + if seq[n][getchar(pre)] then + n = n + 1 + pre = getnext(pre) + if n > l then + break + end + else + notmatchpre[last] = true + break + end + end + if n <= l then + notmatchpre[last] = true + end + else + notmatchpre[last] = true + end + if replace then + -- so far we never entered this branch + while replace do + if seq[n][getchar(replace)] then + n = n + 1 + replace = getnext(replace) + if n > l then + break + end + else + notmatchreplace[last] = true + match = not notmatchpre[last] + break + end + end + match = not notmatchpre[last] + end last = getnext(last) else match = false @@ -1789,50 +2299,137 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if match and f > 1 then local prev = getprev(start) if prev then - local n = f-1 - while n >= 1 do - if prev then - local id = getid(prev) - if id == glyph_code then - if getfont(prev) == currentfont and getsubtype(prev)<256 then -- normal char - local char = getchar(prev) - local ccd = descriptions[char] - if ccd then - local class = ccd.class - if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then - skipped = true - if trace_skips then - show_skip(kind,chainname,char,ck,class) + if prev == checkdisc and (sweeptype == "pre" or sweeptype == "replace") then + prev = getprev(sweepnode) + -- sweeptype = nil + end + if prev then + local discfound = nil + local n = f - 1 + while n >= 1 do + if prev then + local id = getid(prev) + if id == glyph_code then + if getfont(prev) == currentfont and getsubtype(prev)<256 then -- normal char + local char = getchar(prev) + local ccd = descriptions[char] + if ccd then + local class = ccd.class + if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then + skipped = true + if trace_skips then + show_skip(kind,chainname,char,ck,class) + end + elseif seq[n][char] then + n = n -1 + else + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpost[discfound] + else + match = false + end + break end - elseif seq[n][char] then - n = n -1 else - match = false + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpost[discfound] + else + match = false + end break end else - match = false + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpost[discfound] + else + match = false + end break end + elseif id == disc_code then + -- the special case: f i where i becomes dottless i .. + diskseen = true + discfound = prev + notmatchpre[prev] = true + notmatchpost[prev] = nil + notmatchreplace[prev] = nil + local pre = getfield(prev,"pre") + local post = getfield(prev,"post") + local replace = getfield(prev,"replace") + if pre ~= start and post ~= start and replace ~= start then + if post then + local n = n + local posttail = find_node_tail(post) + while posttail do + if seq[n][getchar(posttail)] then + n = n - 1 + if posttail == post then + break + else + posttail = getprev(posttail) + if n < 1 then + break + end + end + else + notmatchpost[prev] = true + break + end + end + if n >= 1 then + notmatchpost[prev] = true + end + else + notmatchpost[prev] = true + end + if replace then + -- we seldom enter this branch (e.g. on brill efficient) + local replacetail = find_node_tail(replace) + while replacetail do + if seq[n][getchar(replacetail)] then + n = n - 1 + if replacetail == replace then + break + else + replacetail = getprev(replacetail) + if n < 1 then + break + end + end + else + notmatchreplace[prev] = true + match = not notmatchpost[prev] + break + end + end + if not match then + break + end + else + -- skip 'm + end + else + -- skip 'm + end + elseif seq[n][32] then + n = n -1 else match = false break end - elseif id == disc_code then - -- skip 'm - elseif seq[n][32] then - n = n -1 + prev = getprev(prev) + elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces + n = n - 1 else match = false break end - prev = getprev(prev) - elseif seq[n][32] then -- somewhat special, as zapfino can have many preceding spaces - n = n -1 - else - match = false - break end + else + match = false end else match = false @@ -1841,7 +2438,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq -- after if match and s > l then local current = last and getnext(last) + if not current then + if sweeptype == "post" or sweeptype == "replace" then + current = getnext(sweepnode) + -- sweeptype = nil + end + end if current then + local discfound = nil -- removed optimization for s-l == 1, we have to deal with marks anyway local n = l + 1 while n <= s do @@ -1861,19 +2465,81 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq elseif seq[n][char] then n = n + 1 else - match = false + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpre[discfound] + else + match = false + end break end + else + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpre[discfound] + else + match = false + end + break + end + else + if discfound then + notmatchreplace[discfound] = true + match = not notmatchpre[discfound] else match = false + end + break + end + elseif id == disc_code then + diskseen = true + discfound = current + notmatchpre[current] = nil + notmatchpost[current] = true + notmatchreplace[current] = nil + local pre = getfield(current,"pre") + local replace = getfield(current,"replace") + if pre then + local n = n + while pre do + if seq[n][getchar(pre)] then + n = n + 1 + pre = getnext(pre) + if n > s then + break + end + else + notmatchpre[current] = true + break + end + end + if n <= s then + notmatchpre[current] = true + end + else + notmatchpre[current] = true + end + if replace then + -- so far we never entered this branch + while replace do + if seq[n][getchar(replace)] then + n = n + 1 + replace = getnext(replace) + if n > s then + break + end + else + notmatchreplace[current] = true + match = notmatchpre[current] + break + end + end + if not match then break end else - match = false - break + -- skip 'm end - elseif id == disc_code then - -- skip 'm elseif seq[n][32] then -- brrr n = n + 1 else @@ -1894,7 +2560,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end if match then - -- ck == currentcontext + -- can lookups be of a different type ? + local diskchain = diskseen or sweepnode if trace_contexts then local rule, lookuptype, f, l = ck[1], ck[2], ck[4], ck[5] local char = getchar(start) @@ -1914,10 +2581,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq local chainlookupname = chainlookups[1] local chainlookup = lookuptable[chainlookupname] if chainlookup then - local cp = chainprocs[chainlookup.type] - if cp then + local chainproc = chainprocs[chainlookup.type] + if chainproc then local ok - head, start, ok = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + if diskchain then + head, start, ok = chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence,chainproc) + else + head, start, ok = chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end if ok then done = true end @@ -1929,13 +2600,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end else local i = 1 - while true do + while start and true do if skipped then - while true do + while true do -- todo: use properties local char = getchar(start) local ccd = descriptions[char] if ccd then - local class = ccd.class + local class = ccd.class or "base" if class == skipmark or class == skipligature or class == skipbase or (markclass and class == "mark" and not markclass[char]) then start = getnext(start) else @@ -1946,36 +2617,51 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end + -- see remark in ms standard under : LookupType 5: Contextual Substitution Subtable local chainlookupname = chainlookups[i] local chainlookup = lookuptable[chainlookupname] if not chainlookup then - -- okay, n matches, < n replacements + -- we just advance i = i + 1 else - local cp = chainmores[chainlookup.type] - if not cp then + local chainproc = chainprocs[chainlookup.type] + if not chainproc then -- actually an error logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) i = i + 1 else local ok, n - head, start, ok, n = cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) + if diskchain then + head, start, ok = chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence,chainproc) + else + head, start, ok, n = chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) + end -- messy since last can be changed ! if ok then done = true - -- skip next one(s) if ligature - i = i + (n or 1) - else - i = i + 1 + if n and n > 1 then + -- we have a ligature (cf the spec we advance one but we really need to test it + -- as there are fonts out there that are fuzzy and have too many lookups: + -- + -- U+1105 U+119E U+1105 U+119E : sourcehansansklight: script=hang ccmp=yes + -- + if i + n > nofchainlookups then + -- if trace_contexts then + -- logprocess("%s: quitting lookups",cref(kind,chainname)) + -- end + break + else + -- we need to carry one + end + end end + i = i + 1 end end - if i > nofchainlookups then + if i > nofchainlookups or not start then break elseif start then start = getnext(start) - else - -- weird end end end @@ -1990,8 +2676,16 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end + if done then + break -- out of contexts (new, needs checking) + end end end + if diskseen then -- maybe move up so that we can turn checking on/off + notmatchpre = { } + notmatchpost = { } + notmatchreplace = { } + end return head, start, done end @@ -2076,13 +2770,13 @@ local function initialize(sequence,script,language,enabled) local order = sequence.order if order then for i=1,#order do -- - local kind = order[i] -- + local kind = order[i] -- local valid = enabled[kind] if valid then local scripts = features[kind] -- local languages = scripts[script] or scripts[wildcard] if languages and (languages[language] or languages[wildcard]) then - return { valid, autofeatures[kind] or false, sequence.chain or 0, kind, sequence } + return { valid, autofeatures[kind] or false, sequence, kind } end end end @@ -2126,32 +2820,216 @@ function otf.dataset(tfmdata,font) -- generic variant, overloaded in context return rl end --- elseif id == glue_code then --- if p[5] then -- chain --- local pc = pp[32] --- if pc then --- start, ok = start, false -- p[1](start,kind,p[2],pc,p[3],p[4]) --- if ok then --- done = true --- end --- if start then start = getnext(start) end --- else --- start = getnext(start) --- end --- else --- start = getnext(start) --- end +-- assumptions: +-- +-- * languages that use complex disc nodes + +local function kernrun(disc,run) + -- + -- we catch + -- + if trace_kernruns then + report_run("kern") -- will be more detailed + end + -- + local prev = getprev(disc) -- todo, keep these in the main loop + local next = getnext(disc) -- todo, keep these in the main loop + -- + local pre = getfield(disc,"pre") + local post = getfield(disc,"post") + local replace = getfield(disc,"replace") + -- + local prevmarks = prev + -- + -- can be optional, because why on earth do we get a disc after a mark (okay, maybe when a ccmp + -- has happened but then it should be in the disc so basically this test indicates an error) + -- + while prevmarks and getid(prevmarks) == glyph_code and marks[getchar(prevmarks)] and getfont(prevmarks) == currentfont and getsubtype(prevmarks) < 256 do + prevmarks = getprev(prevmarks) + end + -- + if prev and (pre or replace) and not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then + prev = false + end + if next and (post or replace) and not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then + next = false + end + -- + if not pre then + -- go on + elseif prev then + local nest = getprev(pre) + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + run(prevmarks,"preinjections") + setfield(pre,"prev",nest) + setfield(prev,"next",disc) + else + run(pre,"preinjections") + end + -- + if not post then + -- go on + elseif next then + local tail = find_node_tail(post) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(post,"postinjections",next) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(post,"postinjections") + end + -- + if not replace and prev and next then + -- this should be already done by discfound + setfield(prev,"next",next) + setfield(next,"prev",prev) + run(prevmarks,"injections",next) + setfield(prev,"next",disc) + setfield(next,"prev",disc) + elseif prev and next then + local tail = find_node_tail(replace) + local nest = getprev(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(prevmarks,"replaceinjections",next) + setfield(replace,"prev",nest) + setfield(prev,"next",disc) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + elseif prev then + local nest = getprev(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + run(prevmarks,"replaceinjections") + setfield(replace,"prev",nest) + setfield(prev,"next",disc) + elseif next then + local tail = find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(replace,"replaceinjections",next) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(replace,"replaceinjections") + end +end --- there will be a new direction parser (pre-parsed etc) +-- the if new test might be dangerous as luatex will check / set some tail stuff +-- in a temp node --- less bytecode: 290 -> 254 --- --- attr = attr or false --- --- local a = getattr(start,0) --- if (a == attr and (not attribute or getprop(start,a_state) == attribute)) or (not attribute or getprop(start,a_state) == attribute) then --- -- the action --- end +local function comprun(disc,run) + if trace_compruns then + report_run("comp: %s",languages.serializediscretionary(disc)) + end + -- + local pre = getfield(disc,"pre") + if pre then + sweepnode = disc + sweeptype = "pre" -- in alternative code preinjections is used (also used then for proeprties, saves a variable) + local new, done = run(pre) + if done then + setfield(disc,"pre",new) + end + end + -- + local post = getfield(disc,"post") + if post then + sweepnode = disc + sweeptype = "post" + local new, done = run(post) + if done then + setfield(disc,"post",new) + end + end + -- + local replace = getfield(disc,"replace") + if replace then + sweepnode = disc + sweeptype = "replace" + local new, done = run(replace) + if done then + setfield(disc,"replace",new) + end + end + sweepnode = nil + sweeptype = nil +end + +local function testrun(disc,trun,crun) -- use helper + local next = getnext(disc) + if next then + local replace = getfield(disc,"replace") + if replace then + local prev = getprev(disc) + if prev then + -- only look ahead + local tail = find_node_tail(replace) + -- local nest = getprev(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + if trun(replace,next) then + setfield(disc,"replace",nil) -- beware, side effects of nest so first + setfield(prev,"next",replace) + setfield(replace,"prev",prev) + setfield(next,"prev",tail) + setfield(tail,"next",next) + setfield(disc,"prev",nil) + setfield(disc,"next",nil) + flush_node_list(disc) + return replace -- restart + else + setfield(tail,"next",nil) + setfield(next,"prev",disc) + end + else + -- weird case + end + else + -- no need + end + else + -- weird case + end + comprun(disc,crun) + return next +end + +local function discrun(disc,drun,krun) + local next = getnext(disc) + local prev = getprev(disc) + if trace_discruns then + report_run("disc") -- will be more detailed + end + if next and prev then + setfield(prev,"next",next) + -- setfield(next,"prev",prev) + drun(prev) + setfield(prev,"next",disc) + -- setfield(next,"prev",disc) + end + -- + local pre = getfield(disc,"pre") + if not pre then + -- go on + elseif prev then + local nest = getprev(pre) + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + krun(prev,"preinjections") + setfield(pre,"prev",nest) + setfield(prev,"next",disc) + else + krun(pre,"preinjections") + end + return next +end + +-- todo: maybe run lr and rl stretches local function featuresprocessor(head,font,attr) @@ -2180,6 +3058,7 @@ local function featuresprocessor(head,font,attr) currentfont = font rlmode = 0 + sweephead = { } local sequences = resources.sequences local done = false @@ -2195,23 +3074,27 @@ local function featuresprocessor(head,font,attr) -- Keeping track of the headnode is needed for devanagari (I generalized it a bit -- so that multiple cases are also covered.) - -- todo: retain prev + -- We don't goto the next node of a disc node is created so that we can then treat + -- the pre, post and replace. It's abit of a hack but works out ok for most cases. + + -- there can be less subtype and attr checking in the comprun etc helpers for s=1,#datasets do - local dataset = datasets[s] - featurevalue = dataset[1] -- todo: pass to function instead of using a global - - local sequence = dataset[5] -- sequences[s] -- also dataset[5] - local rlparmode = 0 - local topstack = 0 - local success = false - local attribute = dataset[2] - local chain = dataset[3] -- sequence.chain or 0 - local typ = sequence.type - local subtables = sequence.subtables - if chain < 0 then + local dataset = datasets[s] + featurevalue = dataset[1] -- todo: pass to function instead of using a global + local attribute = dataset[2] + local sequence = dataset[3] -- sequences[s] -- also dataset[5] + local kind = dataset[4] + ----- chain = dataset[5] -- sequence.chain or 0 + local rlparmode = 0 + local topstack = 0 + local success = false + local typ = sequence.type + local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- maybe all of them + local subtables = sequence.subtables + local handler = handlers[typ] + if typ == "gsub_reversecontextchain" then -- chain < 0 -- this is a limited case, no special treatments like 'init' etc - local handler = handlers[typ] -- we need to get rid of this slide! probably no longer needed in latest luatex local start = find_node_tail(head) -- slow (we can store tail because there's always a skip at the end): todo while start do @@ -2225,13 +3108,15 @@ local function featuresprocessor(head,font,attr) a = true end if a then + local char = getchar(start) for i=1,#subtables do local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - local lookupmatch = lookupcache[getchar(start)] + local lookupmatch = lookupcache[char] if lookupmatch then - head, start, success = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + -- todo: disc? + head, start, success = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if success then break end @@ -2252,24 +3137,30 @@ local function featuresprocessor(head,font,attr) end end else - local handler = handlers[typ] local ns = #subtables local start = head -- local ? rlmode = 0 -- to be checked ? if ns == 1 then -- happens often - local lookupname = subtables[1] + local lookupname = subtables[1] local lookupcache = lookuphash[lookupname] if not lookupcache then -- also check for empty cache report_missing_cache(typ,lookupname) else - local function subrun(start) - -- mostly for gsub, gpos would demand a more clever approach - local head = start - local done = false + local function c_run(head) -- no need to check for 256 and attr probably also the same + local done = false + local start = sweephead[head] + if start then + sweephead[head] = nil + else + start = head + end while start do local id = getid(start) - if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + if id ~= glyph_code then + -- very unlikely + start = getnext(start) + elseif getfont(start) == font and getsubtype(start) < 256 then local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -2281,7 +3172,7 @@ local function featuresprocessor(head,font,attr) if lookupmatch then -- sequence kan weg local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then done = true end @@ -2291,48 +3182,106 @@ local function featuresprocessor(head,font,attr) start = getnext(start) end else - start = getnext(start) + return head, false end end if done then - success = true - return head + success = true -- needed in this subrun? end + return head, done end - local function kerndisc(disc) -- we can assume that prev and next are glyphs - local prev = getprev(disc) - local next = getnext(disc) - if prev and next then - setfield(prev,"next",next) - -- setfield(next,"prev",prev) - local a = getattr(prev,0) - if a then - a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + local function t_run(start,stop) + while start ~= stop do + local id = getid(start) + if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + local a = getattr(start,0) + if a then + a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + else + a = not attribute or getprop(start,a_state) == attribute + end + if a then + local lookupmatch = lookupcache[getchar(start)] + if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check + -- if we need more than ligatures we can outline the code and use functions + local s = getnext(start) + local l = nil + while s do + local lg = lookupmatch[getchar(s)] + if lg then + l = lg + s = getnext(s) + else + break + end + end + if l and l.ligature then + return true + end + end + end + start = getnext(start) else - a = not attribute or getprop(prev,a_state) == attribute + break end - if a then - local lookupmatch = lookupcache[getchar(prev)] - if lookupmatch then - -- sequence kan weg - local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) - if ok then - done = true - success = true + end + end + + local function d_run(prev) -- we can assume that prev and next are glyphs + local a = getattr(prev,0) + if a then + a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + else + a = not attribute or getprop(prev,a_state) == attribute + end + if a then + local lookupmatch = lookupcache[getchar(prev)] + if lookupmatch then + -- sequence kan weg + local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1) + if ok then + done = true + success = true + end + end + end + end + + local function k_run(sub,injection,last) + local a = getattr(sub,0) + if a then + a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + else + a = not attribute or getprop(sub,a_state) == attribute + end + if a then + -- sequence kan weg + for n in traverse_nodes(sub) do -- only gpos + if n == last then + break + end + local id = getid(n) + if id == glyph_code then + local lookupmatch = lookupcache[getchar(n)] + if lookupmatch then + local h, d, ok = handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection) + if ok then + done = true + success = true + end end + else + -- message end end - setfield(prev,"next",disc) - -- setfield(next,"prev",disc) end - return next end while start do local id = getid(start) if id == glyph_code then - if getfont(start) == font and getsubtype(start) < 256 then + if getfont(start) == font and getsubtype(start) < 256 then -- why a 256 test ... local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -2340,59 +3289,52 @@ local function featuresprocessor(head,font,attr) a = not attribute or getprop(start,a_state) == attribute end if a then - local lookupmatch = lookupcache[getchar(start)] + local char = getchar(start) + local lookupmatch = lookupcache[char] if lookupmatch then -- sequence kan weg local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then success = true + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end if start then start = getnext(start) end else - start = getnext(start) + start = getnext(start) end else start = getnext(start) end elseif id == disc_code then - -- mostly for gsub - if getsubtype(start) == discretionary_code then - local pre = getfield(start,"pre") - if pre then - local new = subrun(pre) - if new then setfield(start,"pre",new) end - end - local post = getfield(start,"post") - if post then - local new = subrun(post) - if new then setfield(start,"post",new) end - end - local replace = getfield(start,"replace") - if replace then - local new = subrun(replace) - if new then setfield(start,"replace",new) end - end -elseif typ == "gpos_single" or typ == "gpos_pair" then - kerndisc(start) + if gpossing then + kernrun(start,k_run) + start = getnext(start) + elseif typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) + start = getnext(start) end - start = getnext(start) elseif id == whatsit_code then -- will be function local subtype = getsubtype(start) if subtype == dir_code then local dir = getfield(start,"dir") - if dir == "+TRT" or dir == "+TLT" then + if dir == "+TLT" then topstack = topstack + 1 dirstack[topstack] = dir - elseif dir == "-TRT" or dir == "-TLT" then - topstack = topstack - 1 - end - local newdir = dirstack[topstack] - if newdir == "+TRT" then - rlmode = -1 - elseif newdir == "+TLT" then rlmode = 1 + elseif dir == "+TRT" then + topstack = topstack + 1 + dirstack[topstack] = dir + rlmode = -1 + elseif dir == "-TLT" or dir == "-TRT" then + topstack = topstack - 1 + rlmode = dirstack[topstack] == "+TRT" and -1 or 1 else rlmode = rlparmode end @@ -2422,15 +3364,23 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then end end end + else - local function subrun(start) - -- mostly for gsub, gpos would demand a more clever approach - local head = start - local done = false + local function c_run(head) + local done = false + local start = sweephead[head] + if start then + sweephead[head] = nil + else + start = head + end while start do local id = getid(start) - if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + if id ~= glyph_code then + -- very unlikely + start = getnext(start) + elseif getfont(start) == font and getsubtype(start) < 256 then local a = getattr(start,0) if a then a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) @@ -2438,15 +3388,16 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then a = not attribute or getprop(start,a_state) == attribute end if a then + local char = getchar(start) for i=1,ns do local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - local lookupmatch = lookupcache[getchar(start)] + local lookupmatch = lookupcache[char] if lookupmatch then -- we could move all code inline but that makes things even more unreadable local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then done = true break @@ -2464,50 +3415,127 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then start = getnext(start) end else - start = getnext(start) + return head, false end end if done then success = true - return head end + return head, done end - local function kerndisc(disc) -- we can assume that prev and next are glyphs - local prev = getprev(disc) - local next = getnext(disc) - if prev and next then - setfield(prev,"next",next) - -- setfield(next,"prev",prev) - local a = getattr(prev,0) - if a then - a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) - else - a = not attribute or getprop(prev,a_state) == attribute + local function d_run(prev) + local a = getattr(prev,0) + if a then + a = (a == attr) and (not attribute or getprop(prev,a_state) == attribute) + else + a = not attribute or getprop(prev,a_state) == attribute + end + if a then + -- brr prev can be disc + local char = getchar(prev) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + -- we could move all code inline but that makes things even more unreadable + local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,i) + if ok then + done = true + break + end + end + else + report_missing_cache(typ,lookupname) + end end - if a then - for i=1,ns do - local lookupname = subtables[i] - local lookupcache = lookuphash[lookupname] - if lookupcache then - local lookupmatch = lookupcache[getchar(prev)] - if lookupmatch then - -- we could move all code inline but that makes things even more unreadable - local h, d, ok = handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) - if ok then - done = true - break + end + end + + local function k_run(sub,injection,last) + local a = getattr(sub,0) + if a then + a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute) + else + a = not attribute or getprop(sub,a_state) == attribute + end + if a then + for n in traverse_nodes(sub) do -- only gpos + if n == last then + break + end + local id = getid(n) + if id == glyph_code then + local char = getchar(n) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + local h, d, ok = handler(head,n,kind,lookupname,lookupmatch,sequence,lookuphash,i,injection) + if ok then + done = true + break + end end + else + report_missing_cache(typ,lookupname) + end + end + else + -- message + end + end + end + end + + local function t_run(start,stop) + while start ~= stop do + local id = getid(start) + if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then + local a = getattr(start,0) + if a then + a = (a == attr) and (not attribute or getprop(start,a_state) == attribute) + else + a = not attribute or getprop(start,a_state) == attribute + end + if a then + local char = getchar(start) + for i=1,ns do + local lookupname = subtables[i] + local lookupcache = lookuphash[lookupname] + if lookupcache then + local lookupmatch = lookupcache[char] + if lookupmatch then + -- if we need more than ligatures we can outline the code and use functions + local s = getnext(start) + local l = nil + while s do + local lg = lookupmatch[getchar(s)] + if lg then + l = lg + s = getnext(s) + else + break + end + end + if l and l.ligature then + return true + end + end + else + report_missing_cache(typ,lookupname) end - else - report_missing_cache(typ,lookupname) end end + start = getnext(start) + else + break end - setfield(prev,"next",disc) - -- setfield(next,"prev",disc) end - return next end while start do @@ -2522,21 +3550,26 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then end if a then for i=1,ns do - local lookupname = subtables[i] + local lookupname = subtables[i] local lookupcache = lookuphash[lookupname] if lookupcache then - local lookupmatch = lookupcache[getchar(start)] + local char = getchar(start) + local lookupmatch = lookupcache[char] if lookupmatch then -- we could move all code inline but that makes things even more unreadable local ok - head, start, ok = handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head, start, ok = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then success = true break elseif not start then -- don't ask why ... shouldn't happen break + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char == zwnj then + discrun(start,d_run) end else report_missing_cache(typ,lookupname) @@ -2550,42 +3583,30 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then start = getnext(start) end elseif id == disc_code then - -- mostly for gsub - if getsubtype(start) == discretionary_code then - local pre = getfield(start,"pre") - if pre then - local new = subrun(pre) - if new then setfield(start,"pre",new) end - end - local post = getfield(start,"post") - if post then - local new = subrun(post) - if new then setfield(start,"post",new) end - end - local replace = getfield(start,"replace") - if replace then - local new = subrun(replace) - if new then setfield(start,"replace",new) end - end -elseif typ == "gpos_single" or typ == "gpos_pair" then - kerndisc(start) + if gpossing then + kernrun(start,k_run) + start = getnext(start) + elseif typ == "gsub_ligature" then + start = testrun(start,t_run,c_run) + else + comprun(start,c_run) + start = getnext(start) end - start = getnext(start) elseif id == whatsit_code then local subtype = getsubtype(start) if subtype == dir_code then local dir = getfield(start,"dir") - if dir == "+TRT" or dir == "+TLT" then + if dir == "+TLT" then topstack = topstack + 1 dirstack[topstack] = dir - elseif dir == "-TRT" or dir == "-TLT" then - topstack = topstack - 1 - end - local newdir = dirstack[topstack] - if newdir == "+TRT" then - rlmode = -1 - elseif newdir == "+TLT" then rlmode = 1 + elseif dir == "+TRT" then + topstack = topstack + 1 + dirstack[topstack] = dir + rlmode = -1 + elseif dir == "-TLT" or dir == "-TRT" then + topstack = topstack - 1 + rlmode = dirstack[topstack] == "+TRT" and -1 or 1 else rlmode = rlparmode end @@ -2629,6 +3650,8 @@ elseif typ == "gpos_single" or typ == "gpos_pair" then return head, done end +-- this might move to the loader + local function generic(lookupdata,lookupname,unicode,lookuphash) local target = lookuphash[lookupname] if target then @@ -2638,47 +3661,48 @@ local function generic(lookupdata,lookupname,unicode,lookuphash) end end -local action = { +local function ligature(lookupdata,lookupname,unicode,lookuphash) + local target = lookuphash[lookupname] + if not target then + target = { } + lookuphash[lookupname] = target + end + for i=1,#lookupdata do + local li = lookupdata[i] + local tu = target[li] + if not tu then + tu = { } + target[li] = tu + end + target = tu + end + target.ligature = unicode +end + +local function pair(lookupdata,lookupname,unicode,lookuphash) + local target = lookuphash[lookupname] + if not target then + target = { } + lookuphash[lookupname] = target + end + local others = target[unicode] + local paired = lookupdata[1] + if others then + others[paired] = lookupdata + else + others = { [paired] = lookupdata } + target[unicode] = others + end +end +local action = { substitution = generic, multiple = generic, alternate = generic, position = generic, - - ligature = function(lookupdata,lookupname,unicode,lookuphash) - local target = lookuphash[lookupname] - if not target then - target = { } - lookuphash[lookupname] = target - end - for i=1,#lookupdata do - local li = lookupdata[i] - local tu = target[li] - if not tu then - tu = { } - target[li] = tu - end - target = tu - end - target.ligature = unicode - end, - - pair = function(lookupdata,lookupname,unicode,lookuphash) - local target = lookuphash[lookupname] - if not target then - target = { } - lookuphash[lookupname] = target - end - local others = target[unicode] - local paired = lookupdata[1] - if others then - others[paired] = lookupdata - else - others = { [paired] = lookupdata } - target[unicode] = others - end - end, - + ligature = ligature, + pair = pair, + kern = pair, } local function prepare_lookups(tfmdata) @@ -2691,12 +3715,17 @@ local function prepare_lookups(tfmdata) local lookuptypes = resources.lookuptypes local characters = tfmdata.characters local descriptions = tfmdata.descriptions + local duplicates = resources.duplicates -- we cannot free the entries in the descriptions as sometimes we access -- then directly (for instance anchors) ... selectively freeing does save -- much memory as it's only a reference to a table and the slot in the -- description hash is not freed anyway + -- we can delay this using metatables so that we don't make the hashes for + -- features we don't use but then we need to loop over the characters + -- many times so we gain nothing + for unicode, character in next, characters do -- we cannot loop over descriptions ! local description = descriptions[unicode] @@ -2706,7 +3735,7 @@ local function prepare_lookups(tfmdata) local lookups = description.slookups if lookups then for lookupname, lookupdata in next, lookups do - action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash) + action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash,duplicates) end end @@ -2716,7 +3745,7 @@ local function prepare_lookups(tfmdata) local lookuptype = lookuptypes[lookupname] for l=1,#lookuplist do local lookupdata = lookuplist[l] - action[lookuptype](lookupdata,lookupname,unicode,lookuphash) + action[lookuptype](lookupdata,lookupname,unicode,lookuphash,duplicates) end end end @@ -2740,7 +3769,7 @@ local function prepare_lookups(tfmdata) for name, anchor in next, anchors do local lookups = anchor_to_lookup[name] if lookups then - for lookup, _ in next, lookups do + for lookup in next, lookups do local target = lookuphash[lookup] if target then target[unicode] = anchors @@ -2760,6 +3789,8 @@ local function prepare_lookups(tfmdata) end +-- so far + local function split(replacement,original) local result = { } for i=1,#replacement do @@ -2835,7 +3866,7 @@ local function prepare_contextchains(tfmdata) -- use sequence[start] instead but it's somewhat ugly. nt = nt + 1 t[nt] = { nofrules, lookuptype, sequence, start, stop, rule.lookups, replacements } - for unic, _ in next, sequence[start] do + for unic in next, sequence[start] do local cu = contexts[unic] if not cu then contexts[unic] = t diff --git a/src/fontloader/misc/fontloader-fonts.lua b/src/fontloader/misc/fontloader-fonts.lua index c81e8cd..f18ba35 100644 --- a/src/fontloader/misc/fontloader-fonts.lua +++ b/src/fontloader/misc/fontloader-fonts.lua @@ -27,16 +27,10 @@ if not modules then modules = { } end modules ['luatex-fonts'] = { -- also add more helper code here, but that depends to what extend metatex (sidetrack of context) -- evolves into a low level layer (depends on time, as usual). -texio.write_nl("") -texio.write_nl("--------------------------------------------------------------------------------") -texio.write_nl("The font code has been brought in sync with the context version of 2014.12.21 so") -texio.write_nl("if things don't work out as expected the interfacing needs to be checked. When") -texio.write_nl("this works as expected a second upgrade will happen that gives a more complete") -texio.write_nl("support and another sync with the context code (that new code is currently being") -texio.write_nl("tested. The base pass is now integrated in the main pass. The results can differ") -texio.write_nl("from those in context because there we integrate some mechanisms differently.") -texio.write_nl("--------------------------------------------------------------------------------") -texio.write_nl("") +-- The code here is the same as in context version 2015.09.11 but the rendering in context can be +-- different from generic. This can be a side effect of additional callbacks, additional features +-- and interferences between mechanisms between macro packages. We use the rendering in context +-- and luatex-plain as reference for issues. utf = utf or unicode.utf8 @@ -221,9 +215,9 @@ if non_generic_context.luatex_fonts.skip_loading ~= true then loadmodule('font-oti.lua') loadmodule('font-otf.lua') loadmodule('font-otb.lua') - loadmodule('luatex-fonts-inj.lua') + loadmodule('luatex-fonts-inj.lua') -- normally the same as font-inj.lua loadmodule('luatex-fonts-ota.lua') - loadmodule('luatex-fonts-otn.lua') + loadmodule('luatex-fonts-otn.lua') -- normally the same as font-otn.lua loadmodule('font-otp.lua') loadmodule('luatex-fonts-lua.lua') loadmodule('font-def.lua') -- this code (stripped) might end up in luatex-fonts-def.lua diff --git a/src/fontloader/misc/fontloader-l-lpeg.lua b/src/fontloader/misc/fontloader-l-lpeg.lua index 55a0d89..5be1246 100644 --- a/src/fontloader/misc/fontloader-l-lpeg.lua +++ b/src/fontloader/misc/fontloader-l-lpeg.lua @@ -82,7 +82,7 @@ local lpegtype, lpegmatch, lpegprint = lpeg.type, lpeg.match, lpeg.print -- let's start with an inspector: if setinspector then - setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end) + setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) end -- Beware, we predefine a bunch of patterns here and one reason for doing so diff --git a/src/fontloader/misc/fontloader-l-lua.lua b/src/fontloader/misc/fontloader-l-lua.lua index 1a2a987..cb61829 100644 --- a/src/fontloader/misc/fontloader-l-lua.lua +++ b/src/fontloader/misc/fontloader-l-lua.lua @@ -129,22 +129,36 @@ local print, select, tostring = print, select, tostring local inspectors = { } -function setinspector(inspector) -- global function - inspectors[#inspectors+1] = inspector +function setinspector(kind,inspector) -- global function + inspectors[kind] = inspector end function inspect(...) -- global function for s=1,select("#",...) do local value = select(s,...) - local done = false - for i=1,#inspectors do - done = inspectors[i](value) - if done then - break + if value == nil then + print("nil") + else + local done = false + -- type driven (table) + local kind = type(value) + local inspector = inspectors[kind] + if inspector then + done = inspector(value) + if done then + break + end + end + -- whatever driven (token, node, ...) + for kind, inspector in next, inspectors do + done = inspector(value) + if done then + break + end + end + if not done then + print(tostring(value)) end - end - if not done then - print(tostring(value)) end end end diff --git a/src/fontloader/misc/fontloader-l-string.lua b/src/fontloader/misc/fontloader-l-string.lua index 70c66f6..e9dc2bb 100644 --- a/src/fontloader/misc/fontloader-l-string.lua +++ b/src/fontloader/misc/fontloader-l-string.lua @@ -192,10 +192,11 @@ string.itself = function(s) return s end -- also handy (see utf variant) -local pattern = Ct(C(1)^0) -- string and not utf ! +local pattern_c = Ct( C(1) ^0) -- string and not utf ! +local pattern_b = Ct((C(1)/byte)^0) -function string.totable(str) - return lpegmatch(pattern,str) +function string.totable(str,bytes) + return lpegmatch(bytes and pattern_b or pattern_c,str) end -- handy from within tex: diff --git a/src/fontloader/misc/fontloader-l-table.lua b/src/fontloader/misc/fontloader-l-table.lua index b02f210..552097e 100644 --- a/src/fontloader/misc/fontloader-l-table.lua +++ b/src/fontloader/misc/fontloader-l-table.lua @@ -1144,7 +1144,7 @@ function table.print(t,...) end if setinspector then - setinspector(function(v) if type(v) == "table" then serialize(print,v,"table") return true end end) + setinspector("table",function(v) if type(v) == "table" then serialize(print,v,"table") return true end end) end -- -- -- obsolete but we keep them for a while and might comment them later -- -- -- diff --git a/src/fontloader/misc/fontloader-mplib.lua b/src/fontloader/misc/fontloader-mplib.lua index c6628ac..fd6eb97 100644 --- a/src/fontloader/misc/fontloader-mplib.lua +++ b/src/fontloader/misc/fontloader-mplib.lua @@ -22,7 +22,9 @@ if metapost and metapost.version then else - local format, concat, abs, match = string.format, table.concat, math.abs, string.match + local format, match, gsub = string.format, string.match, string.gsub + local concat = table.concat + local abs = math.abs local mplib = require ('mplib') local kpse = require ('kpse') @@ -144,10 +146,101 @@ else metapost.make = metapost.make or function() end + local template = [[ + \pdfoutput=1 + \pdfpkresolution600 + \pdfcompresslevel=9 + %s\relax + \hsize=100in + \vsize=\hsize + \hoffset=-1in + \voffset=\hoffset + \topskip=0pt + \setbox0=\hbox{%s}\relax + \pageheight=\ht0 + \pagewidth=\wd0 + \box0 + \bye + ]] + + metapost.texrunner = "mtxrun --script plain" + + local texruns = 0 -- per document + local texhash = { } -- per document + + function metapost.maketext(mpd,str,what) + -- inefficient but one can always use metafun .. it's more a test + -- feature + local verbatimtex = mpd.verbatimtex + if not verbatimtex then + verbatimtex = { } + mpd.verbatimtex = verbatimtex + end + if what == 1 then + table.insert(verbatimtex,str) + else + local texcode = format(template,concat(verbatimtex,"\n"),str) + local texdone = texhash[texcode] + local jobname = tex.jobname + if not texdone then + texruns = texruns + 1 + texdone = texruns + texhash[texcode] = texdone + local texname = format("%s-mplib-%s.tmp",jobname,texdone) + local logname = format("%s-mplib-%s.log",jobname,texdone) + local pdfname = format("%s-mplib-%s.pdf",jobname,texdone) + io.savedata(texname,texcode) + os.execute(format("%s %s",metapost.texrunner,texname)) + os.remove(texname) + os.remove(logname) + end + return format('"image::%s-mplib-%s.pdf" infont defaultfont',jobname,texdone) + end + end + + local function mpprint(buffer,...) + for i=1,select("#",...) do + local value = select(i,...) + if value ~= nil then + local t = type(value) + if t == "number" then + buffer[#buffer+1] = format("%.16f",value) + elseif t == "string" then + buffer[#buffer+1] = value + elseif t == "table" then + buffer[#buffer+1] = "(" .. concat(value,",") .. ")" + else -- boolean or whatever + buffer[#buffer+1] = tostring(value) + end + end + end + end + + function metapost.runscript(mpd,code) + local code = loadstring(code) + if type(code) == "function" then + local buffer = { } + function metapost.print(...) + mpprint(buffer,...) + end + code() + -- mpd.buffer = buffer -- for tracing + return concat(buffer,"") + end + return "" + end + function metapost.load(name) + local mpd = { + buffer = { }, + verbatim = { } + } local mpx = mplib.new { ini_version = true, - find_file = metapost.finder, + find_file = metapost.finder, + make_text = function(...) return metapost.maketext (mpd,...) end, + run_script = function(...) return metapost.runscript(mpd,...) end, + extensions = 1, } local result if not mpx then @@ -217,8 +310,8 @@ else return figure:objects() end - function metapost.convert(result, flusher) - metapost.flush(result, flusher) + function metapost.convert(result,flusher) + metapost.flush(result,flusher) return true -- done end @@ -239,8 +332,13 @@ else end function pdf_textfigure(font,size,text,width,height,depth) - text = text:gsub(".","\\hbox{%1}") -- kerning happens in metapost - tex.sprint(format("\\MPLIBtextext{%s}{%s}{%s}{%s}{%s}",font,size,text,0,-( 7200/ 7227)/65536*depth)) + local how, what = match(text,"^(.-)::(.+)$") + if how == "image" then + tex.sprint(format("\\MPLIBpdftext{%s}{%s}",what,depth)) + else + text = gsub(text,".","\\hbox{%1}") -- kerning happens in metapost + tex.sprint(format("\\MPLIBtextext{%s}{%s}{%s}{%s}",font,size,text,depth)) + end end local bend_tolerance = 131/65536 @@ -375,8 +473,10 @@ else pdf_literalcode("Q") else local cs = object.color + local cr = false if cs and #cs > 0 then - pdf_literalcode(metapost.colorconverter(cs)) + cs, cr = metapost.colorconverter(cs) + pdf_literalcode(cs) end local ml = object.miterlimit if ml and ml ~= miterlimit then diff --git a/src/fontloader/misc/fontloader-mplib.tex b/src/fontloader/misc/fontloader-mplib.tex index 09dd179..f9de4b2 100644 --- a/src/fontloader/misc/fontloader-mplib.tex +++ b/src/fontloader/misc/fontloader-mplib.tex @@ -106,15 +106,14 @@ %D Text items have a special handler: -\def\MPLIBtextext#1#2#3#4#5% +\def\MPLIBtextext#1#2#3#4% {\begingroup \setbox\mplibscratchbox\hbox {\font\temp=#1 at #2bp% \temp #3}% \setbox\mplibscratchbox\hbox - {\hskip#4 bp% - \raise#5 bp% + {\raise#4sp% \box\mplibscratchbox}% \wd\mplibscratchbox0pt% \ht\mplibscratchbox0pt% @@ -122,4 +121,20 @@ \box\mplibscratchbox \endgroup} +\def\MPLIBpdftext#1#2% + {\ifcsname mplib::#1\endcsname + % already done, forgotten outside convert group + \message{}% + \else + \message{}% + \immediate\pdfximage{#1}% we cannot remove the file as it is included last + \expandafter\edef\csname mplib::#1\endcsname{\the\pdflastximage}% + \fi + \setbox\mplibscratchbox\hbox + {\raise#2sp\hbox{\pdfrefximage\csname mplib::#1\endcsname}}% + \wd\mplibscratchbox0pt% + \ht\mplibscratchbox0pt% + \dp\mplibscratchbox0pt% + \box\mplibscratchbox} + \endinput diff --git a/src/fontloader/misc/fontloader-plain.tex b/src/fontloader/misc/fontloader-plain.tex index c9a9e36..9902c49 100644 --- a/src/fontloader/misc/fontloader-plain.tex +++ b/src/fontloader/misc/fontloader-plain.tex @@ -11,7 +11,26 @@ \directlua {tex.enableprimitives('', tex.extraprimitives())} -\pdfoutput=1 +% We assume that pdf is used. + +\pdfoutput 1 + +% We set the page dimensions because otherwise the backend does weird things +% when we have for instance this on a line of its own: +% +% \hbox to 100cm {\hss wide indeed\hss} +% +% The page dimension calculation is a fuzzy one as there are some compensations +% for the \hoffset and \voffset and such. I remember long discussions and much +% trial and error in figuring this out during pdftex development times. Where +% a dvi driver will project on a papersize (and thereby clip) the pdf backend +% has to deal with the lack of a page concept on tex by some guessing. Normally +% a macro package will set the dimensions to something reasonable anyway. + +\pagewidth 8.5in +\pageheight 11.0in + +% We load some code at runtime: \everyjob \expandafter {% \the\everyjob @@ -20,9 +39,11 @@ \input {luatex-math}% \input {luatex-languages}% \input {luatex-mplib}% - % \input {luatex-gadgets}% + \input {luatex-gadgets}% } +% We also patch the version number: + \edef\fmtversion{\fmtversion+luatex} \dump diff --git a/src/fontloader/misc/fontloader-test.tex b/src/fontloader/misc/fontloader-test.tex index 6f48e0c..f851aab 100644 --- a/src/fontloader/misc/fontloader-test.tex +++ b/src/fontloader/misc/fontloader-test.tex @@ -1,3 +1,5 @@ +% texformat=luatex-plain + %D \module %D [ file=luatex-test, %D version=2009.12.01, @@ -33,12 +35,12 @@ \font\mathtest=cambria(math) {\mathtest 123} -\font\gothic=msgothic(ms-gothic) {\gothic whatever} +% \font\gothic=msgothic(ms-gothic) {\gothic whatever} % no longer in windows 10 \bgroup - \pdfprotrudechars2 - \pdfadjustspacing2 + \ifdefined\pdfprotrudechars \pdfprotrudechars \else \protrudechars \fi 2 \relax + \ifdefined\pdfadjustspacing \pdfadjustspacing \else \adjustspacing \fi 2 \relax \font\testb=file:lmroman12-regular:+liga;extend=1.5 at 12pt \testb \input tufte \par \font\testb=file:lmroman12-regular:+liga;slant=0.8 at 12pt \testb \input tufte \par @@ -48,12 +50,30 @@ \setmplibformat{plain} +\directlua { + function MpTest() + metapost.print("fullcircle scaled 3cm") + end +} + \mplibcode beginfig(1) ; draw fullcircle scaled 10cm withcolor red withpen pencircle xscaled 4mm yscaled 2mm rotated 30 ; + draw "test" infont defaultfont scaled 4 ; + verbatimtex \sl etex; + draw btex some more test etex scaled 2 ; + currentpicture := currentpicture shifted (0,1cm) ; + verbatimtex \bf etex; + draw btex another test etex scaled 2 ; + currentpicture := currentpicture shifted (0,1cm) ; + draw btex another test etex scaled 2 ; + draw + runscript("MpTest()") + withcolor green + withpen pencircle xscaled 2mm yscaled 1mm rotated 20 ; endfig ; \endmplibcode diff --git a/src/fontloader/misc/fontloader-util-str.lua b/src/fontloader/misc/fontloader-util-str.lua index c2139b1..95534c8 100644 --- a/src/fontloader/misc/fontloader-util-str.lua +++ b/src/fontloader/misc/fontloader-util-str.lua @@ -6,7 +6,7 @@ if not modules then modules = { } end modules ['util-str'] = { license = "see context related readme files" } -utilities = utilities or {} +utilities = utilities or { } utilities.strings = utilities.strings or { } local strings = utilities.strings @@ -354,7 +354,16 @@ function string.autosingle(s,sep) return ("'" .. tostring(s) .. "'") end -local tracedchars = { } +local tracedchars = { [0] = + -- the regular bunch + "[null]", "[soh]", "[stx]", "[etx]", "[eot]", "[enq]", "[ack]", "[bel]", + "[bs]", "[ht]", "[lf]", "[vt]", "[ff]", "[cr]", "[so]", "[si]", + "[dle]", "[dc1]", "[dc2]", "[dc3]", "[dc4]", "[nak]", "[syn]", "[etb]", + "[can]", "[em]", "[sub]", "[esc]", "[fs]", "[gs]", "[rs]", "[us]", + -- plus space + "[space]", -- 0x20 +} + string.tracedchars = tracedchars strings.tracers = tracedchars diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua index d8095a2..a2a598b 100644 --- a/src/fontloader/runtime/fontloader-reference.lua +++ b/src/fontloader/runtime/fontloader-reference.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 05/24/15 12:42:55 +-- merge date : 10/09/15 21:28:28 do -- begin closure to overcome local limits and interference @@ -57,21 +57,33 @@ if not package.loaders then end local print,select,tostring=print,select,tostring local inspectors={} -function setinspector(inspector) - inspectors[#inspectors+1]=inspector +function setinspector(kind,inspector) + inspectors[kind]=inspector end function inspect(...) for s=1,select("#",...) do local value=select(s,...) - local done=false - for i=1,#inspectors do - done=inspectors[i](value) - if done then - break + if value==nil then + print("nil") + else + local done=false + local kind=type(value) + local inspector=inspectors[kind] + if inspector then + done=inspector(value) + if done then + break + end + end + for kind,inspector in next,inspectors do + done=inspector(value) + if done then + break + end + end + if not done then + print(tostring(value)) end - end - if not done then - print(tostring(value)) end end end @@ -112,7 +124,7 @@ local floor=math.floor local P,R,S,V,Ct,C,Cs,Cc,Cp,Cmt=lpeg.P,lpeg.R,lpeg.S,lpeg.V,lpeg.Ct,lpeg.C,lpeg.Cs,lpeg.Cc,lpeg.Cp,lpeg.Cmt local lpegtype,lpegmatch,lpegprint=lpeg.type,lpeg.match,lpeg.print if setinspector then - setinspector(function(v) if lpegtype(v) then lpegprint(v) return true end end) + setinspector("lpeg",function(v) if lpegtype(v) then lpegprint(v) return true end end) end lpeg.patterns=lpeg.patterns or {} local patterns=lpeg.patterns @@ -995,9 +1007,10 @@ function string.valid(str,default) return (type(str)=="string" and str~="" and str) or default or nil end string.itself=function(s) return s end -local pattern=Ct(C(1)^0) -function string.totable(str) - return lpegmatch(pattern,str) +local pattern_c=Ct(C(1)^0) +local pattern_b=Ct((C(1)/byte)^0) +function string.totable(str,bytes) + return lpegmatch(bytes and pattern_b or pattern_c,str) end local replacer=lpeg.replacer("@","%%") function string.tformat(fmt,...) @@ -1884,7 +1897,7 @@ function table.print(t,...) end end if setinspector then - setinspector(function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) + setinspector("table",function(v) if type(v)=="table" then serialize(print,v,"table") return true end end) end function table.sub(t,i,j) return { unpack(t,i,j) } @@ -2937,7 +2950,13 @@ function string.autosingle(s,sep) end return ("'"..tostring(s).."'") end -local tracedchars={} +local tracedchars={ [0]= + "[null]","[soh]","[stx]","[etx]","[eot]","[enq]","[ack]","[bel]", + "[bs]","[ht]","[lf]","[vt]","[ff]","[cr]","[so]","[si]", + "[dle]","[dc1]","[dc2]","[dc3]","[dc4]","[nak]","[syn]","[etb]", + "[can]","[em]","[sub]","[esc]","[fs]","[gs]","[rs]","[us]", + "[space]", +} string.tracedchars=tracedchars strings.tracers=tracedchars function string.tracedchar(b) @@ -3886,6 +3905,8 @@ local nodecodes={} for k,v in next,node.types () do nodecodes[string.gsub(v,"_" local whatcodes={} for k,v in next,node.whatsits() do whatcodes[string.gsub(v,"_","")]=k end local glyphcodes={ [0]="character","glyph","ligature","ghost","left","right" } local disccodes={ [0]="discretionary","explicit","automatic","regular","first","second" } +for i=0,#glyphcodes do glyphcodes[glyphcodes[i]]=i end +for i=0,#disccodes do disccodes [disccodes [i]]=i end nodes.nodecodes=nodecodes nodes.whatcodes=whatcodes nodes.whatsitcodes=whatcodes @@ -4361,6 +4382,7 @@ function constructors.scale(tfmdata,specification) local hdelta=delta local vdelta=delta target.designsize=parameters.designsize + target.units=units target.units_per_em=units local direction=properties.direction or tfmdata.direction or 0 target.direction=direction @@ -4472,21 +4494,28 @@ function constructors.scale(tfmdata,specification) target.nomath=true target.mathparameters=nil end - local italickey="italic" - local useitalics=true if hasmath then - autoitalicamount=false - elseif properties.textitalics then - italickey="italic_correction" - useitalics=false - if properties.delaytextitalics then + local mathitalics=properties.mathitalics + if mathitalics==false then + if trace_defining then + report_defining("%s italics %s for font %a, fullname %a, filename %a","math",hasitalics and "ignored" or "disabled",name,fullname,filename) + end + hasitalics=false + autoitalicamount=false + end + else + local textitalics=properties.textitalics + if textitalics==false then + if trace_defining then + report_defining("%s italics %s for font %a, fullname %a, filename %a","text",hasitalics and "ignored" or "disabled",name,fullname,filename) + end + hasitalics=false autoitalicamount=false end end if trace_defining then report_defining("defining tfm, name %a, fullname %a, filename %a, hscale %a, vscale %a, math %a, italics %a", - name,fullname,filename,hdelta,vdelta, - hasmath and "enabled" or "disabled",useitalics and "enabled" or "disabled") + name,fullname,filename,hdelta,vdelta,hasmath and "enabled" or "disabled",hasitalics and "enabled" or "disabled") end constructors.beforecopyingcharacters(target,tfmdata) local sharedkerns={} @@ -4584,22 +4613,6 @@ function constructors.scale(tfmdata,specification) chr.right_protruding=protrusionfactor*width*vr end end - if autoitalicamount then - local vi=description.italic - if not vi then - local vi=description.boundingbox[3]-description.width+autoitalicamount - if vi>0 then - chr[italickey]=vi*hdelta - end - elseif vi~=0 then - chr[italickey]=vi*hdelta - end - elseif hasitalics then - local vi=description.italic - if vi and vi~=0 then - chr[italickey]=vi*hdelta - end - end if hasmath then local vn=character.next if vn then @@ -4637,7 +4650,7 @@ function constructors.scale(tfmdata,specification) end end end - local va=character.top_accent + local va=character.accent if va then chr.top_accent=vdelta*va end @@ -4660,6 +4673,27 @@ function constructors.scale(tfmdata,specification) chr.mathkern=kerns end end + if hasitalics then + local vi=character.italic + if vi and vi~=0 then + chr.italic=vi*hdelta + end + end + elseif autoitalicamount then + local vi=description.italic + if not vi then + local vi=description.boundingbox[3]-description.width+autoitalicamount + if vi>0 then + chr.italic=vi*hdelta + end + elseif vi~=0 then + chr.italic=vi*hdelta + end + elseif hasitalics then + local vi=character.italic + if vi and vi~=0 then + chr.italic=vi*hdelta + end end if haskerns then local vk=character.kerns @@ -4722,6 +4756,7 @@ function constructors.scale(tfmdata,specification) end targetcharacters[unicode]=chr end + properties.setitalics=hasitalics constructors.aftercopyingcharacters(target,tfmdata) constructors.trytosharefont(target,tfmdata) return target @@ -4762,11 +4797,20 @@ function constructors.finalize(tfmdata) if not parameters.slantfactor then parameters.slantfactor=tfmdata.slant or 0 end - if not parameters.designsize then - parameters.designsize=tfmdata.designsize or (factors.pt*10) + local designsize=parameters.designsize + if designsize then + parameters.minsize=tfmdata.minsize or designsize + parameters.maxsize=tfmdata.maxsize or designsize + else + designsize=factors.pt*10 + parameters.designsize=designsize + parameters.minsize=designsize + parameters.maxsize=designsize end + parameters.minsize=tfmdata.minsize or parameters.designsize + parameters.maxsize=tfmdata.maxsize or parameters.designsize if not parameters.units then - parameters.units=tfmdata.units_per_em or 1000 + parameters.units=tfmdata.units or tfmdata.units_per_em or 1000 end if not tfmdata.descriptions then local descriptions={} @@ -4829,6 +4873,7 @@ function constructors.finalize(tfmdata) tfmdata.auto_protrude=nil tfmdata.extend=nil tfmdata.slant=nil + tfmdata.units=nil tfmdata.units_per_em=nil tfmdata.cache=nil properties.finalized=true @@ -5393,24 +5438,13 @@ local fonts=fonts or {} local mappings=fonts.mappings or {} fonts.mappings=mappings local allocate=utilities.storage.allocate -local function loadlumtable(filename) - local lumname=file.replacesuffix(file.basename(filename),"lum") - local lumfile=resolvers.findfile(lumname,"map") or "" - if lumfile~="" and lfs.isfile(lumfile) then - if trace_loading or trace_mapping then - report_fonts("loading map table %a",lumfile) - end - lumunic=dofile(lumfile) - return lumunic,lumfile - end -end local hex=R("AF","09") -local hexfour=(hex*hex*hex*hex)/function(s) return tonumber(s,16) end -local hexsix=(hex*hex*hex*hex*hex*hex)/function(s) return tonumber(s,16) end +local hexfour=(hex*hex*hex^-2)/function(s) return tonumber(s,16) end +local hexsix=(hex*hex*hex^-4)/function(s) return tonumber(s,16) end local dec=(R("09")^1)/tonumber local period=P(".") -local unicode=P("uni")*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true)) -local ucode=P("u")*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true)) +local unicode=(P("uni")+P("UNI"))*(hexfour*(period+P(-1))*Cc(false)+Ct(hexfour^1)*Cc(true)) +local ucode=(P("u")+P("U") )*(hexsix*(period+P(-1))*Cc(false)+Ct(hexsix^1)*Cc(true)) local index=P("index")*dec*Cc(false) local parser=unicode+ucode+index local parsers={} @@ -5485,7 +5519,6 @@ local function fromunicode16(str) return (tonumber(l,16))*0x400+tonumber(r,16)-0xDC00 end end -mappings.loadlumtable=loadlumtable mappings.makenameparser=makenameparser mappings.tounicode=tounicode mappings.tounicode16=tounicode16 @@ -5516,244 +5549,162 @@ for k,v in next,overloads do end end mappings.overloads=overloads -function mappings.addtounicode(data,filename) +function mappings.addtounicode(data,filename,checklookups) local resources=data.resources - local properties=data.properties - local descriptions=data.descriptions local unicodes=resources.unicodes - local lookuptypes=resources.lookuptypes if not unicodes then return end + local properties=data.properties + local descriptions=data.descriptions unicodes['space']=unicodes['space'] or 32 unicodes['hyphen']=unicodes['hyphen'] or 45 unicodes['zwj']=unicodes['zwj'] or 0x200D unicodes['zwnj']=unicodes['zwnj'] or 0x200C - local private=fonts.constructors.privateoffset - local unicodevector=fonts.encodings.agl.unicodes + local private=fonts.constructors and fonts.constructors.privateoffset or 0xF0000 + local unicodevector=fonts.encodings.agl.unicodes or {} + local contextvector=fonts.encodings.agl.ctxcodes or {} local missing={} - local lumunic,uparser,oparser - local cidinfo,cidnames,cidcodes,usedmap - cidinfo=properties.cidinfo - usedmap=cidinfo and fonts.cid.getmap(cidinfo) + local nofmissing=0 + local oparser=nil + local cidnames=nil + local cidcodes=nil + local cidinfo=properties.cidinfo + local usedmap=cidinfo and fonts.cid.getmap(cidinfo) + local uparser=makenameparser() if usedmap then - oparser=usedmap and makenameparser(cidinfo.ordering) - cidnames=usedmap.names - cidcodes=usedmap.unicodes + oparser=usedmap and makenameparser(cidinfo.ordering) + cidnames=usedmap.names + cidcodes=usedmap.unicodes end - uparser=makenameparser() - local ns,nl=0,0 + local ns=0 + local nl=0 for unic,glyph in next,descriptions do - local index=glyph.index local name=glyph.name - local r=overloads[name] - if r then - glyph.unicode=r.unicode - elseif unic==-1 or unic>=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then - local unicode=lumunic and lumunic[name] or unicodevector[name] - if unicode then - glyph.unicode=unicode - ns=ns+1 - end - if (not unicode) and usedmap then - local foundindex=lpegmatch(oparser,name) - if foundindex then - unicode=cidcodes[foundindex] - if unicode then - glyph.unicode=unicode - ns=ns+1 - else - local reference=cidnames[foundindex] - if reference then - local foundindex=lpegmatch(oparser,reference) - if foundindex then - unicode=cidcodes[foundindex] - if unicode then - glyph.unicode=unicode - ns=ns+1 - end - end - if not unicode or unicode=="" then - local foundcodes,multiple=lpegmatch(uparser,reference) - if foundcodes then - glyph.unicode=foundcodes - if multiple then - nl=nl+1 - unicode=true - else + if name then + local index=glyph.index + local r=overloads[name] + if r then + glyph.unicode=r.unicode + elseif not unic or unic==-1 or unic>=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then + local unicode=unicodevector[name] or contextvector[name] + if unicode then + glyph.unicode=unicode + ns=ns+1 + end + if (not unicode) and usedmap then + local foundindex=lpegmatch(oparser,name) + if foundindex then + unicode=cidcodes[foundindex] + if unicode then + glyph.unicode=unicode + ns=ns+1 + else + local reference=cidnames[foundindex] + if reference then + local foundindex=lpegmatch(oparser,reference) + if foundindex then + unicode=cidcodes[foundindex] + if unicode then + glyph.unicode=unicode ns=ns+1 - unicode=foundcodes + end + end + if not unicode or unicode=="" then + local foundcodes,multiple=lpegmatch(uparser,reference) + if foundcodes then + glyph.unicode=foundcodes + if multiple then + nl=nl+1 + unicode=true + else + ns=ns+1 + unicode=foundcodes + end end end end end end end - end - if not unicode or unicode=="" then - local split=lpegmatch(namesplitter,name) - local nsplit=split and #split or 0 - local t,n={},0 - unicode=true - for l=1,nsplit do - local base=split[l] - local u=unicodes[base] or unicodevector[base] - if not u then - break - elseif type(u)=="table" then - if u[1]>=private then - unicode=false - break - end - n=n+1 - t[n]=u[1] - else - if u>=private then - unicode=false - break + if not unicode or unicode=="" then + local split=lpegmatch(namesplitter,name) + local nsplit=split and #split or 0 + if nsplit==0 then + elseif nsplit==1 then + local base=split[1] + local u=unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + elseif type(u)=="table" then + if u[1]=private or (unic>=0xE000 and unic<=0xF8FF) or unic==0xFFFE or unic==0xFFFF then - else - return - end - if descriptions[code].unicode then - return - end - local g=guess[variant] - if g then - g[gname]=unicode - else - guess[variant]={ [gname]=unicode } - end - end - for unicode,description in next,descriptions do - local slookups=description.slookups - if slookups then - local gname=description.name - for tag,data in next,slookups do - local lookuptype=lookuptypes[tag] - if lookuptype=="alternate" then - for i=1,#data do - check(gname,data[i],unicode) - end - elseif lookuptype=="substitution" then - check(gname,data,unicode) - end - end - end - local mlookups=description.mlookups - if mlookups then - local gname=description.name - for tag,list in next,mlookups do - local lookuptype=lookuptypes[tag] - if lookuptype=="alternate" then - for i=1,#list do - local data=list[i] - for i=1,#data do - check(gname,data[i],unicode) + local t,n={},0 + for l=1,nsplit do + local base=split[l] + local u=unicodes[base] or unicodevector[base] or contextvector[name] + if not u then + break + elseif type(u)=="table" then + if u[1]>=private then + break + end + n=n+1 + t[n]=u[1] + else + if u>=private then + break + end + n=n+1 + t[n]=u end end - elseif lookuptype=="substitution" then - for i=1,#list do - check(gname,list[i],unicode) + if n>0 then + if n==1 then + unicode=t[1] + else + unicode=t + end + glyph.unicode=unicode end end - end - end - end - local done=true - while done do - done=false - for k,v in next,guess do - if type(v)~="number" then - for kk,vv in next,v do - if vv==-1 or vv>=private or (vv>=0xE000 and vv<=0xF8FF) or vv==0xFFFE or vv==0xFFFF then - local uu=guess[kk] - if type(uu)=="number" then - guess[k]=uu - done=true - end + nl=nl+1 + end + if not unicode or unicode=="" then + local foundcodes,multiple=lpegmatch(uparser,name) + if foundcodes then + glyph.unicode=foundcodes + if multiple then + nl=nl+1 + unicode=true else - guess[k]=vv - done=true + ns=ns+1 + unicode=foundcodes end end end - end - end - local orphans=0 - local guessed=0 - for k,v in next,guess do - if type(v)=="number" then - descriptions[unicodes[k]].unicode=descriptions[v].unicode or v - guessed=guessed+1 - else - local t=nil - local l=lower(k) - local u=unicodes[l] - if not u then - orphans=orphans+1 - elseif u==-1 or u>=private or (u>=0xE000 and u<=0xF8FF) or u==0xFFFE or u==0xFFFF then - local unicode=descriptions[u].unicode - if unicode then - descriptions[unicodes[k]].unicode=unicode - guessed=guessed+1 - else - orphans=orphans+1 - end - else - orphans=orphans+1 + local r=overloads[unicode] + if r then + unicode=r.unicode + glyph.unicode=unicode + end + if not unicode then + missing[unic]=true + nofmissing=nofmissing+1 end end - end - if trace_loading and orphans>0 or guessed>0 then - report_fonts("%s glyphs with no related unicode, %s guessed, %s orphans",guessed+orphans,guessed,orphans) + else end end + if type(checklookups)=="function" then + checklookups(data,missing,nofmissing) + end if trace_mapping then for unic,glyph in table.sortedhash(descriptions) do local name=glyph.name @@ -5881,6 +5832,7 @@ local readers=fonts.readers local constructors=fonts.constructors local encodings=fonts.encodings local tfm=constructors.newhandler("tfm") +tfm.version=1.000 local tfmfeatures=constructors.newfeatures("tfm") local registertfmfeature=tfmfeatures.register constructors.resolvevirtualtoo=false @@ -6067,7 +6019,7 @@ local keys={} function keys.FontName (data,line) data.metadata.fontname=strip (line) data.metadata.fullname=strip (line) end function keys.ItalicAngle (data,line) data.metadata.italicangle=tonumber (line) end -function keys.IsFixedPitch(data,line) data.metadata.isfixedpitch=toboolean(line,true) end +function keys.IsFixedPitch(data,line) data.metadata.monospaced=toboolean(line,true) end function keys.CharWidth (data,line) data.metadata.charwidth=tonumber (line) end function keys.XHeight (data,line) data.metadata.xheight=tonumber (line) end function keys.Descender (data,line) data.metadata.descender=tonumber (line) end @@ -6489,7 +6441,7 @@ local function copytotfm(data) local emdash=0x2014 local spacer="space" local spaceunits=500 - local monospaced=metadata.isfixedpitch + local monospaced=metadata.monospaced local charwidth=metadata.charwidth local italicangle=metadata.italicangle local charxheight=metadata.xheight and metadata.xheight>0 and metadata.xheight @@ -7144,12 +7096,10 @@ if not modules then modules={} end modules ['font-otf']={ license="see context related readme files" } local utfbyte=utf.byte -local format,gmatch,gsub,find,match,lower,strip=string.format,string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip +local gmatch,gsub,find,match,lower,strip=string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip local type,next,tonumber,tostring=type,next,tonumber,tostring local abs=math.abs -local insert=table.insert -local lpegmatch=lpeg.match -local reversed,concat,remove,sortedkeys=table.reversed,table.concat,table.remove,table.sortedkeys +local reversed,concat,insert,remove,sortedkeys=table.reversed,table.concat,table.insert,table.remove,table.sortedkeys local ioflush=io.flush local fastcopy,tohash,derivetable=table.fastcopy,table.tohash,table.derive local formatters=string.formatters @@ -7176,7 +7126,7 @@ local report_otf=logs.reporter("fonts","otf loading") local fonts=fonts local otf=fonts.handlers.otf otf.glists={ "gsub","gpos" } -otf.version=2.812 +otf.version=2.819 otf.cache=containers.define("fonts","otf",otf.version,true) local hashes=fonts.hashes local definers=fonts.definers @@ -7353,10 +7303,10 @@ local ordered_enhancers={ "reorganize subtables", "check glyphs", "check metadata", - "check extra features", "prepare tounicode", "check encoding", "add duplicates", + "expand lookups", "cleanup tables", "compact lookups", "purge names", @@ -7493,6 +7443,7 @@ function otf.load(filename,sub,featurefile) end end if reload then + starttiming("fontloader") report_otf("loading %a, hash %a",filename,hash) local fontdata,messages if sub then @@ -7526,6 +7477,7 @@ function otf.load(filename,sub,featurefile) data={ size=size, time=time, + subfont=sub, format=otf_format(filename), featuredata=featurefiles, resources={ @@ -7553,7 +7505,6 @@ function otf.load(filename,sub,featurefile) tounicodetable=Ct(splitter), }, } - starttiming(data) report_otf("file size: %s",size) enhancers.apply(data,filename,fontdata) local packtime={} @@ -7570,10 +7521,10 @@ function otf.load(filename,sub,featurefile) if cleanup>1 then collectgarbage("collect") end - stoptiming(data) + stoptiming("fontloader") if elapsedtime then - report_otf("preprocessing and caching time %s, packtime %s", - elapsedtime(data),packdata and elapsedtime(packtime) or 0) + report_otf("loading, optimizing, packing and caching time %s, pack time %s", + elapsedtime("fontloader"),packdata and elapsedtime(packtime) or 0) end close_font(fontdata) if cleanup>3 then @@ -7584,6 +7535,7 @@ function otf.load(filename,sub,featurefile) collectgarbage("collect") end else + stoptiming("fontloader") data=nil report_otf("loading failed due to read error") end @@ -7625,6 +7577,7 @@ function otf.load(filename,sub,featurefile) applyruntimefixes(filename,data) end enhance("add dimensions",data,filename,nil,false) +enhance("check extra features",data,filename) if trace_sequences then showfeatureorder(data,filename) end @@ -7785,7 +7738,7 @@ actions["prepare glyphs"]=function(data,filename,raw) end if not unicode or unicode==-1 then if not name then - name=format("u%06X.ctx",private) + name=formatters["u%06X.ctx"](private) end unicode=private unicodes[name]=private @@ -7796,7 +7749,7 @@ actions["prepare glyphs"]=function(data,filename,raw) nofnames=nofnames+1 else if not name then - name=format("u%06X.ctx",unicode) + name=formatters["u%06X.ctx"](unicode) end unicodes[name]=unicode nofunicodes=nofunicodes+1 @@ -7810,25 +7763,25 @@ actions["prepare glyphs"]=function(data,filename,raw) glyph=glyph, } descriptions[unicode]=description -local altuni=glyph.altuni -if altuni then - for i=1,#altuni do - local a=altuni[i] - local u=a.unicode - if u~=unicode then - local v=a.variant - if v then - local vv=variants[v] - if vv then - vv[u]=unicode - else - vv={ [u]=unicode } - variants[v]=vv - end - end - end - end -end + local altuni=glyph.altuni + if altuni then + for i=1,#altuni do + local a=altuni[i] + local u=a.unicode + if u~=unicode then + local v=a.variant + if v then + local vv=variants[v] + if vv then + vv[u]=unicode + else + vv={ [u]=unicode } + variants[v]=vv + end + end + end + end + end end end else @@ -8014,7 +7967,7 @@ actions["add duplicates"]=function(data,filename,raw) end if u>0 then local duplicate=table.copy(description) - duplicate.comment=format("copy of U+%05X",unicode) + duplicate.comment=formatters["copy of %U"](unicode) descriptions[u]=duplicate if trace_loading then report_otf("duplicating %U to %U with index %H (%s kerns)",unicode,u,description.index,n) @@ -8035,7 +7988,7 @@ actions["analyze glyphs"]=function(data,filename,raw) local marks={} for unicode,description in next,descriptions do local glyph=description.glyph - local italic=glyph.italic_correction + local italic=glyph.italic_correction if not italic then elseif italic==0 then else @@ -8096,7 +8049,8 @@ end actions["reorganize features"]=function(data,filename,raw) local features={} data.resources.features=features - for k,what in next,otf.glists do + for k=1,#otf.glists do + local what=otf.glists[k] local dw=raw[what] if dw then local f={} @@ -8178,8 +8132,9 @@ actions["reorganize subtables"]=function(data,filename,raw) local lookups={} local chainedfeatures={} resources.sequences=sequences - resources.lookups=lookups - for _,what in next,otf.glists do + resources.lookups=lookups + for k=1,#otf.glists do + local what=otf.glists[k] local dw=raw[what] if dw then for k=1,#dw do @@ -8353,12 +8308,15 @@ local function r_uncover(splitter,cache,cover,replacements) end actions["reorganize lookups"]=function(data,filename,raw) if data.lookups then - local splitter=data.helpers.tounicodetable + local helpers=data.helpers + local duplicates=data.resources.duplicates + local splitter=helpers.tounicodetable local t_u_cache={} local s_u_cache=t_u_cache local t_h_cache={} local s_h_cache=t_h_cache local r_u_cache={} + helpers.matchcache=t_h_cache for _,lookup in next,data.lookups do local rules=lookup.rules if rules then @@ -8504,6 +8462,44 @@ actions["reorganize lookups"]=function(data,filename,raw) end end end +actions["expand lookups"]=function(data,filename,raw) + if data.lookups then + local cache=data.helpers.matchcache + if cache then + local duplicates=data.resources.duplicates + for key,hash in next,cache do + local done=nil + for key in next,hash do + local unicode=duplicates[key] + if not unicode then + elseif type(unicode)=="table" then + for i=1,#unicode do + local u=unicode[i] + if hash[u] then + elseif done then + done[u]=key + else + done={ [u]=key } + end + end + else + if hash[unicode] then + elseif done then + done[unicode]=key + else + done={ [unicode]=key } + end + end + end + if done then + for u in next,done do + hash[u]=true + end + end + end + end + end +end local function check_variants(unicode,the_variants,splitter,unicodes) local variants=the_variants.variants if variants then @@ -8544,11 +8540,11 @@ local function check_variants(unicode,the_variants,splitter,unicodes) parts=nil end end - local italic_correction=the_variants.italic_correction - if italic_correction and italic_correction==0 then - italic_correction=nil + local italic=the_variants.italic + if italic and italic==0 then + italic=nil end - return variants,parts,italic_correction + return variants,parts,italic end actions["analyze math"]=function(data,filename,raw) if raw.math then @@ -8558,13 +8554,14 @@ actions["analyze math"]=function(data,filename,raw) for unicode,description in next,data.descriptions do local glyph=description.glyph local mathkerns=glyph.mathkern - local horiz_variants=glyph.horiz_variants - local vert_variants=glyph.vert_variants - local top_accent=glyph.top_accent - if mathkerns or horiz_variants or vert_variants or top_accent then + local hvariants=glyph.horiz_variants + local vvariants=glyph.vert_variants + local accent=glyph.top_accent + local italic=glyph.italic_correction + if mathkerns or hvariants or vvariants or accent or italic then local math={} - if top_accent then - math.top_accent=top_accent + if accent then + math.accent=accent end if mathkerns then for k,v in next,mathkerns do @@ -8580,15 +8577,14 @@ actions["analyze math"]=function(data,filename,raw) end math.kerns=mathkerns end - if horiz_variants then - math.horiz_variants,math.horiz_parts,math.horiz_italic_correction=check_variants(unicode,horiz_variants,splitter,unicodes) + if hvariants then + math.hvariants,math.hparts,math.hitalic=check_variants(unicode,hvariants,splitter,unicodes) end - if vert_variants then - math.vert_variants,math.vert_parts,math.vert_italic_correction=check_variants(unicode,vert_variants,splitter,unicodes) + if vvariants then + math.vvariants,math.vparts,math.vitalic=check_variants(unicode,vvariants,splitter,unicodes) end - local italic_correction=description.italic - if italic_correction and italic_correction~=0 then - math.italic_correction=italic_correction + if italic and italic~=0 then + math.italic=italic end description.math=math end @@ -8745,7 +8741,7 @@ actions["merge kern classes"]=function(data,filename,raw) report_otf("%s kern overloads ignored",ignored) end if blocked>0 then - report_otf("%s succesive kerns blocked",blocked) + report_otf("%s successive kerns blocked",blocked) end end end @@ -8774,16 +8770,18 @@ actions["check metadata"]=function(data,filename,raw) ttftables[i].data="deleted" end end + local names=raw.names if metadata.validation_state and table.contains(metadata.validation_state,"bad_ps_fontname") then local function valid(what) - local names=raw.names - for i=1,#names do - local list=names[i] - local names=list.names - if names then - local name=names[what] - if name and valid_ps_name(name) then - return name + if names then + for i=1,#names do + local list=names[i] + local names=list.names + if names then + local name=names[what] + if name and valid_ps_name(name) then + return name + end end end end @@ -8806,6 +8804,28 @@ actions["check metadata"]=function(data,filename,raw) check("fontname") check("fullname") end + if names then + local psname=metadata.psname + if not psname or psname=="" then + for i=1,#names do + local name=names[i] + if lower(name.lang)=="english (us)" then + local specification=name.names + if specification then + local postscriptname=specification.postscriptname + if postscriptname then + psname=postscriptname + end + end + end + break + end + end + if psname~=metadata.fontname then + report_otf("fontname %a, fullname %a, psname %a",metadata.fontname,metadata.fullname,psname) + end + metadata.psname=psname + end end actions["cleanup tables"]=function(data,filename,raw) local duplicates=data.resources.duplicates @@ -8901,7 +8921,7 @@ actions["reorganize glyph lookups"]=function(data,filename,raw) end end local zero={ 0,0 } -actions["reorganize glyph anchors"]=function(data,filename,raw) +actions["reorganize glyph anchors"]=function(data,filename,raw) local descriptions=data.descriptions for unicode,description in next,descriptions do local anchors=description.glyph.anchors @@ -9103,9 +9123,13 @@ local function copytotfm(data,cache_id) local spaceunits=500 local spacer="space" local designsize=metadata.designsize or metadata.design_size or 100 + local minsize=metadata.minsize or metadata.design_range_bottom or designsize + local maxsize=metadata.maxsize or metadata.design_range_top or designsize local mathspecs=metadata.math if designsize==0 then designsize=100 + minsize=100 + maxsize=100 end if mathspecs then for name,value in next,mathspecs do @@ -9120,8 +9144,9 @@ local function copytotfm(data,cache_id) local d=descriptions[unicode] local m=d.math if m then - local variants=m.horiz_variants - local parts=m.horiz_parts + local italic=m.italic + local variants=m.hvariants + local parts=m.hparts if variants then local c=character for i=1,#variants do @@ -9132,9 +9157,10 @@ local function copytotfm(data,cache_id) c.horiz_variants=parts elseif parts then character.horiz_variants=parts + italic=m.hitalic end - local variants=m.vert_variants - local parts=m.vert_parts + local variants=m.vvariants + local parts=m.vparts if variants then local c=character for i=1,#variants do @@ -9145,14 +9171,14 @@ local function copytotfm(data,cache_id) c.vert_variants=parts elseif parts then character.vert_variants=parts + italic=m.vitalic end - local italic_correction=m.vert_italic_correction - if italic_correction then - character.vert_italic_correction=italic_correction + if italic and italic~=0 then + character.italic=italic end - local top_accent=m.top_accent - if top_accent then - character.top_accent=top_accent + local accent=m.accent + if accent then + character.accent=accent end local kerns=m.kerns if kerns then @@ -9164,14 +9190,14 @@ local function copytotfm(data,cache_id) local filename=constructors.checkedfilename(resources) local fontname=metadata.fontname local fullname=metadata.fullname or fontname - local psname=fontname or fullname - local units=metadata.units_per_em or 1000 + local psname=metadata.psname or fontname or fullname + local units=metadata.units or metadata.units_per_em or 1000 if units==0 then units=1000 - metadata.units_per_em=1000 + metadata.units=1000 report_otf("changing %a units to %a",0,units) end - local monospaced=metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion=="Monospaced") + local monospaced=metadata.monospaced or metadata.isfixedpitch or (pfminfo.panose and pfminfo.panose.proportion=="Monospaced") local charwidth=pfminfo.avgwidth local charxheight=pfminfo.os2_xheight and pfminfo.os2_xheight>0 and pfminfo.os2_xheight local italicangle=metadata.italicangle @@ -9236,8 +9262,10 @@ local function copytotfm(data,cache_id) end end parameters.designsize=(designsize/10)*65536 - parameters.ascender=abs(metadata.ascent or 0) - parameters.descender=abs(metadata.descent or 0) + parameters.minsize=(minsize/10)*65536 + parameters.maxsize=(maxsize/10)*65536 + parameters.ascender=abs(metadata.ascender or metadata.ascent or 0) + parameters.descender=abs(metadata.descender or metadata.descent or 0) parameters.units=units properties.space=spacer properties.encodingbytes=2 @@ -9416,6 +9444,99 @@ function otf.scriptandlanguage(tfmdata,attr) local properties=tfmdata.properties return properties.script or "dflt",properties.language or "dflt" end +local function justset(coverage,unicode,replacement) + coverage[unicode]=replacement +end +otf.coverup={ + stepkey="subtables", + actions={ + substitution=justset, + alternate=justset, + multiple=justset, + ligature=justset, + kern=justset, + }, + register=function(coverage,lookuptype,format,feature,n,descriptions,resources) + local name=formatters["ctx_%s_%s"](feature,n) + if lookuptype=="kern" then + resources.lookuptypes[name]="position" + else + resources.lookuptypes[name]=lookuptype + end + for u,c in next,coverage do + local description=descriptions[u] + local slookups=description.slookups + if slookups then + slookups[name]=c + else + description.slookups={ [name]=c } + end + end + return name + end +} +local function getgsub(tfmdata,k,kind) + local description=tfmdata.descriptions[k] + if description then + local slookups=description.slookups + if slookups then + local shared=tfmdata.shared + local rawdata=shared and shared.rawdata + if rawdata then + local lookuptypes=rawdata.resources.lookuptypes + if lookuptypes then + local properties=tfmdata.properties + local validlookups,lookuplist=otf.collectlookups(rawdata,kind,properties.script,properties.language) + if validlookups then + for l=1,#lookuplist do + local lookup=lookuplist[l] + local found=slookups[lookup] + if found then + return found,lookuptypes[lookup] + end + end + end + end + end + end + end +end +otf.getgsub=getgsub +function otf.getsubstitution(tfmdata,k,kind,value) + local found,kind=getgsub(tfmdata,k,kind) + if not found then + elseif kind=="substitution" then + return found + elseif kind=="alternate" then + local choice=tonumber(value) or 1 + return found[choice] or found[1] or k + end + return k +end +otf.getalternate=otf.getsubstitution +function otf.getmultiple(tfmdata,k,kind) + local found,kind=getgsub(tfmdata,k,kind) + if found and kind=="multiple" then + return found + end + return { k } +end +function otf.getkern(tfmdata,left,right,kind) + local kerns=getgsub(tfmdata,left,kind or "kern",true) + if kerns then + local found=kerns[right] + local kind=type(found) + if kind=="table" then + found=found[1][3] + elseif kind~="number" then + found=false + end + if found then + return found*tfmdata.parameters.factor + end + end + return 0 +end end -- closure @@ -9946,8 +10067,8 @@ local function featuresinitializer(tfmdata,value) local collectlookups=otf.collectlookups local rawdata=tfmdata.shared.rawdata local properties=tfmdata.properties - local script=properties.script - local language=properties.language + local script=properties.script + local language=properties.language local basesubstitutions=rawdata.resources.features.gsub local basepositionings=rawdata.resources.features.gpos if basesubstitutions or basepositionings then @@ -10125,7 +10246,8 @@ end function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) local dx=factor*(exit[1]-entry[1]) local dy=-factor*(exit[2]-entry[2]) - local ws,wn=tfmstart.width,tfmnext.width + local ws=tfmstart.width + local wn=tfmnext.width nofregisteredcursives=nofregisteredcursives+1 if rlmode<0 then dx=-(dx+wn) @@ -10172,7 +10294,10 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne return dx,dy,nofregisteredcursives end function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) - local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4] + local x=factor*spec[1] + local y=factor*spec[2] + local w=factor*spec[3] + local h=factor*spec[4] if x~=0 or w~=0 or y~=0 or h~=0 then local yoffset=y-h local leftkern=x @@ -10182,9 +10307,12 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) if rlmode and rlmode<0 then leftkern,rightkern=rightkern,leftkern end + if not injection then + injection="injections" + end local p=rawget(properties,current) if p then - local i=rawget(p,"injections") + local i=rawget(p,injection) if i then if leftkern~=0 then i.leftkern=(i.leftkern or 0)+leftkern @@ -10196,19 +10324,19 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) i.yoffset=(i.yoffset or 0)+yoffset end elseif leftkern~=0 or rightkern~=0 then - p.injections={ + p[injection]={ leftkern=leftkern, rightkern=rightkern, yoffset=yoffset, } else - p.injections={ + p[injection]={ yoffset=yoffset, } end elseif leftkern~=0 or rightkern~=0 then properties[current]={ - injections={ + [injection]={ leftkern=leftkern, rightkern=rightkern, yoffset=yoffset, @@ -10216,7 +10344,7 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) } else properties[current]={ - injections={ + [injection]={ yoffset=yoffset, }, } @@ -10255,7 +10383,7 @@ function injections.setkern(current,factor,rlmode,x,injection) return 0,0 end end -function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) +function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk) local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2]) nofregisteredmarks=nofregisteredmarks+1 if rlmode>=0 then @@ -10265,11 +10393,15 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) if p then local i=rawget(p,"injections") if i then - i.markx=dx - i.marky=dy - i.markdir=rlmode or 0 - i.markbase=nofregisteredmarks - i.markbasenode=base + if i.markmark then + else + i.markx=dx + i.marky=dy + i.markdir=rlmode or 0 + i.markbase=nofregisteredmarks + i.markbasenode=base + i.markmark=mkmk + end else p.injections={ markx=dx, @@ -10277,6 +10409,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) markdir=rlmode or 0, markbase=nofregisteredmarks, markbasenode=base, + markmark=mkmk, } end else @@ -10287,6 +10420,7 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) markdir=rlmode or 0, markbase=nofregisteredmarks, markbasenode=base, + markmark=mkmk, }, } end @@ -10391,27 +10525,33 @@ local function show_result(head) current=getnext(current) end end -local function collect_glyphs_1(head) - local glyphs,nofglyphs={},0 - local marks,nofmarks={},0 +local function collect_glyphs(head,offsets) + local glyphs,glyphi,nofglyphs={},{},0 + local marks,marki,nofmarks={},{},0 local nf,tm=nil,nil - for n in traverse_id(glyph_code,head) do - if getsubtype(n)<256 then - local f=getfont(n) - if f~=nf then - nf=f - tm=fontdata[nf].resources.marks - end - if tm and tm[getchar(n)] then - nofmarks=nofmarks+1 - marks[nofmarks]=n - else - nofglyphs=nofglyphs+1 - glyphs[nofglyphs]=n - end + local n=head + local function identify(n,what) + local f=getfont(n) + if f~=nf then + nf=f + tm=fontdata[nf].resources + if tm then + tm=tm.marks + end + end + if tm and tm[getchar(n)] then + nofmarks=nofmarks+1 + marks[nofmarks]=n + marki[nofmarks]="injections" + else + nofglyphs=nofglyphs+1 + glyphs[nofglyphs]=n + glyphi[nofglyphs]=what + end + if offsets then local p=rawget(properties,n) if p then - local i=rawget(p,"injections") + local i=rawget(p,what) if i then local yoffset=i.yoffset if yoffset and yoffset~=0 then @@ -10421,36 +10561,47 @@ local function collect_glyphs_1(head) end end end - return glyphs,nofglyphs,marks,nofmarks -end -local function collect_glyphs_2(head) - local glyphs,nofglyphs={},0 - local marks,nofmarks={},0 - local nf,tm=nil,nil - for n in traverse_id(glyph_code,head) do - if getsubtype(n)<256 then - local f=getfont(n) - if f~=nf then - nf=f - tm=fontdata[nf].resources.marks - end - if tm and tm[getchar(n)] then - nofmarks=nofmarks+1 - marks[nofmarks]=n - else - nofglyphs=nofglyphs+1 - glyphs[nofglyphs]=n - end + while n do + local id=getid(n) + if id==glyph_code then + identify(n,"injections") + elseif id==disc_code then + local d=getfield(n,"pre") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n)<256 then + identify(n,"preinjections") + end + end + end + local d=getfield(n,"post") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n)<256 then + identify(n,"postinjections") + end + end + end + local d=getfield(n,"replace") + if d then + for n in traverse_id(glyph_code,d) do + if getsubtype(n)<256 then + identify(n,"replaceinjections") + end + end + end end + n=getnext(n) end - return glyphs,nofglyphs,marks,nofmarks + return glyphs,glyphi,nofglyphs,marks,marki,nofmarks end -local function inject_marks(marks,nofmarks) +local function inject_marks(marks,marki,nofmarks) for i=1,nofmarks do local n=marks[i] local pn=rawget(properties,n) if pn then - pn=rawget(pn,"injections") + local ni=marki[i] + local pn=rawget(pn,ni) if pn then local p=pn.markbasenode if p then @@ -10459,7 +10610,7 @@ local function inject_marks(marks,nofmarks) local rightkern=nil local pp=rawget(properties,p) if pp then - pp=rawget(pp,"injections") + pp=rawget(pp,ni) if pp then rightkern=pp.rightkern end @@ -10468,11 +10619,17 @@ local function inject_marks(marks,nofmarks) if pn.markdir<0 then ox=px-pn.markx-rightkern else - local leftkern=pp.leftkern - if leftkern then - ox=px-pn.markx + + + if false then + local leftkern=pp.leftkern + if leftkern then + ox=px-pn.markx-leftkern + else + ox=px-pn.markx + end else - ox=px-pn.markx-leftkern + ox=px-pn.markx end end else @@ -10485,12 +10642,7 @@ local function inject_marks(marks,nofmarks) end setfield(n,"xoffset",ox) local py=getfield(p,"yoffset") - local oy=0 - if marks[p] then - oy=py+pn.marky - else - oy=getfield(n,"yoffset")+py+pn.marky - end + local oy=getfield(n,"yoffset")+py+pn.marky setfield(n,"yoffset",oy) else end @@ -10498,14 +10650,14 @@ local function inject_marks(marks,nofmarks) end end end -local function inject_cursives(glyphs,nofglyphs) +local function inject_cursives(glyphs,glyphi,nofglyphs) local cursiveanchor,lastanchor=nil,nil local minc,maxc,last=0,0,nil for i=1,nofglyphs do local n=glyphs[i] local pn=rawget(properties,n) if pn then - pn=rawget(pn,"injections") + pn=rawget(pn,glyphi[i]) end if pn then local cursivex=pn.cursivex @@ -10571,22 +10723,59 @@ local function inject_cursives(glyphs,nofglyphs) end end end -local function inject_kerns(head,list,length) +local function inject_kerns(head,glist,ilist,length) for i=1,length do - local n=list[i] + local n=glist[i] local pn=rawget(properties,n) if pn then - local i=rawget(pn,"injections") - if i then - local leftkern=i.leftkern - if leftkern and leftkern~=0 then - insert_node_before(head,n,newkern(leftkern)) - end - local rightkern=i.rightkern - if rightkern and rightkern~=0 then - insert_node_after(head,n,newkern(rightkern)) - end - end + local dp=nil + local dr=nil + local ni=ilist[i] + local p=nil + if ni=="injections" then + p=getprev(n) + if p then + local id=getid(p) + if id==disc_code then + dp=getfield(p,"post") + dr=getfield(p,"replace") + end + end + end + if dp then + local i=rawget(pn,"postinjections") + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + local t=find_tail(dp) + insert_node_after(dp,t,newkern(leftkern)) + setfield(p,"post",dp) + end + end + end + if dr then + local i=rawget(pn,"replaceinjections") + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + local t=find_tail(dr) + insert_node_after(dr,t,newkern(leftkern)) + setfield(p,"replace",dr) + end + end + else + local i=rawget(pn,ni) + if i then + local leftkern=i.leftkern + if leftkern and leftkern~=0 then + insert_node_before(head,n,newkern(leftkern)) + end + local rightkern=i.rightkern + if rightkern and rightkern~=0 then + insert_node_after(head,n,newkern(rightkern)) + end + end + end end end end @@ -10595,23 +10784,18 @@ local function inject_everything(head,where) if trace_injections then trace(head,"everything") end - local glyphs,nofglyphs,marks,nofmarks - if nofregisteredpairs>0 then - glyphs,nofglyphs,marks,nofmarks=collect_glyphs_1(head) - else - glyphs,nofglyphs,marks,nofmarks=collect_glyphs_2(head) - end + local glyphs,glyphi,nofglyphs,marks,marki,nofmarks=collect_glyphs(head,nofregisteredpairs>0) if nofglyphs>0 then if nofregisteredcursives>0 then - inject_cursives(glyphs,nofglyphs) + inject_cursives(glyphs,glyphi,nofglyphs) end if nofregisteredmarks>0 then - inject_marks(marks,nofmarks) + inject_marks(marks,marki,nofmarks) end - inject_kerns(head,glyphs,nofglyphs) + inject_kerns(head,glyphs,glyphi,nofglyphs) end if nofmarks>0 then - inject_kerns(head,marks,nofmarks) + inject_kerns(head,marks,marki,nofmarks) end if keepregisteredcounts then keepregisteredcounts=false @@ -10629,7 +10813,7 @@ local function inject_kerns_only(head,where) trace(head,"kerns") end local n=head - local p=nil + local p=nil while n do local id=getid(n) if id==glyph_code then @@ -10645,6 +10829,7 @@ local function inject_kerns_only(head,where) if leftkern and leftkern~=0 then local t=find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"post",d) end end end @@ -10656,6 +10841,7 @@ local function inject_kerns_only(head,where) if leftkern and leftkern~=0 then local t=find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"replace",d) end end else @@ -10677,8 +10863,6 @@ local function inject_kerns_only(head,where) end end end - else - break end p=nil elseif id==disc_code then @@ -10733,7 +10917,7 @@ local function inject_kerns_only(head,where) local h=d for n in traverse_id(glyph_code,d) do if getsubtype(n)<256 then - local pn=rawget(properties,n) + local pn=rawget(properties,n) if pn then local i=rawget(pn,"replaceinjections") if i then @@ -10770,7 +10954,7 @@ local function inject_pairs_only(head,where) trace(head,"pairs") end local n=head - local p=nil + local p=nil while n do local id=getid(n) if id==glyph_code then @@ -10786,6 +10970,7 @@ local function inject_pairs_only(head,where) if leftkern and leftkern~=0 then local t=find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"post",d) end end end @@ -10797,6 +10982,7 @@ local function inject_pairs_only(head,where) if leftkern and leftkern~=0 then local t=find_tail(d) insert_node_after(d,t,newkern(leftkern)) + setfield(p,"replace",d) end end else @@ -10811,24 +10997,22 @@ local function inject_pairs_only(head,where) else local i=rawget(pn,"injections") if i then - local yoffset=i.yoffset - if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) - end local leftkern=i.leftkern if leftkern and leftkern~=0 then - insert_node_before(head,n,newkern(leftkern)) + head=insert_node_before(head,n,newkern(leftkern)) end local rightkern=i.rightkern if rightkern and rightkern~=0 then insert_node_after(head,n,newkern(rightkern)) n=getnext(n) end + local yoffset=i.yoffset + if yoffset and yoffset~=0 then + setfield(n,"yoffset",yoffset) + end end end end - else - break end p=nil elseif id==disc_code then @@ -10837,16 +11021,12 @@ local function inject_pairs_only(head,where) local h=d for n in traverse_id(glyph_code,d) do if getsubtype(n)<256 then - local p=rawget(properties,n) - if p then - local i=rawget(p,"preinjections") + local pn=rawget(properties,n) + if pn then + local i=rawget(pn,"preinjections") if i then - local yoffset=i.yoffset - if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) - end local leftkern=i.leftkern - if leftkern~=0 then + if leftkern and leftkern~=0 then h=insert_node_before(h,n,newkern(leftkern)) end local rightkern=i.rightkern @@ -10854,6 +11034,10 @@ local function inject_pairs_only(head,where) insert_node_after(head,n,newkern(rightkern)) n=getnext(n) end + local yoffset=i.yoffset + if yoffset and yoffset~=0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -10869,14 +11053,10 @@ local function inject_pairs_only(head,where) local h=d for n in traverse_id(glyph_code,d) do if getsubtype(n)<256 then - local p=rawget(properties,n) - if p then - local i=rawget(p,"postinjections") + local pn=rawget(properties,n) + if pn then + local i=rawget(pn,"postinjections") if i then - local yoffset=i.yoffset - if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) - end local leftkern=i.leftkern if leftkern and leftkern~=0 then h=insert_node_before(h,n,newkern(leftkern)) @@ -10886,6 +11066,10 @@ local function inject_pairs_only(head,where) insert_node_after(head,n,newkern(rightkern)) n=getnext(n) end + local yoffset=i.yoffset + if yoffset and yoffset~=0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -10901,14 +11085,10 @@ local function inject_pairs_only(head,where) local h=d for n in traverse_id(glyph_code,d) do if getsubtype(n)<256 then - local p=rawget(properties,n) - if p then - local i=rawget(p,"replaceinjections") + local pn=rawget(properties,n) + if pn then + local i=rawget(pn,"replaceinjections") if i then - local yoffset=i.yoffset - if yoffset and yoffset~=0 then - setfield(n,"yoffset",yoffset) - end local leftkern=i.leftkern if leftkern and leftkern~=0 then h=insert_node_before(h,n,newkern(leftkern)) @@ -10918,6 +11098,10 @@ local function inject_pairs_only(head,where) insert_node_after(head,n,newkern(rightkern)) n=getnext(n) end + local yoffset=i.yoffset + if yoffset and yoffset~=0 then + setfield(n,"yoffset",yoffset) + end end end else @@ -10942,7 +11126,7 @@ local function inject_pairs_only(head,where) end return tonode(head),true end -function injections.handler(head,where) +function injections.handler(head,where) if nofregisteredmarks>0 or nofregisteredcursives>0 then return inject_everything(head,where) elseif nofregisteredpairs>0 then @@ -11342,14 +11526,12 @@ if not modules then modules={} end modules ['font-otn']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files", } -local concat,insert,remove=table.concat,table.insert,table.remove -local gmatch,gsub,find,match,lower,strip=string.gmatch,string.gsub,string.find,string.match,string.lower,string.strip -local type,next,tonumber,tostring=type,next,tonumber,tostring -local lpegmatch=lpeg.match +local type,next,tonumber=type,next,tonumber local random=math.random local formatters=string.formatters local logs,trackers,nodes,attributes=logs,trackers,nodes,attributes local registertracker=trackers.register +local registerdirective=directives.register local fonts=fonts local otf=fonts.handlers.otf local trace_lookups=false registertracker("otf.lookups",function(v) trace_lookups=v end) @@ -11368,6 +11550,13 @@ local trace_applied=false registertracker("otf.applied",function(v) trace_applie local trace_steps=false registertracker("otf.steps",function(v) trace_steps=v end) local trace_skips=false registertracker("otf.skips",function(v) trace_skips=v end) local trace_directions=false registertracker("otf.directions",function(v) trace_directions=v end) +local trace_kernruns=false registertracker("otf.kernruns",function(v) trace_kernruns=v end) +local trace_discruns=false registertracker("otf.discruns",function(v) trace_discruns=v end) +local trace_compruns=false registertracker("otf.compruns",function(v) trace_compruns=v end) +local quit_on_no_replacement=true +local zwnjruns=true +registerdirective("otf.zwnjruns",function(v) zwnjruns=v end) +registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement=value end) local report_direct=logs.reporter("fonts","otf direct") local report_subchain=logs.reporter("fonts","otf subchain") local report_chain=logs.reporter("fonts","otf chain") @@ -11426,8 +11615,6 @@ local math_code=nodecodes.math local dir_code=whatcodes.dir local localpar_code=whatcodes.localpar local discretionary_code=disccodes.discretionary -local regular_code=disccodes.regular -local automatic_code=disccodes.automatic local ligature_code=glyphcodes.ligature local privateattribute=attributes.private local a_state=privateattribute('state') @@ -11461,6 +11648,13 @@ local lookuptags=false local handlers={} local rlmode=0 local featurevalue=false +local sweephead={} +local sweepnode=nil +local sweepprev=nil +local sweepnext=nil +local notmatchpre={} +local notmatchpost={} +local notmatchreplace={} local checkstep=(nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end local registerstep=(nodes and nodes.tracers and nodes.tracers.steppers.register) or function() end local registermessage=(nodes and nodes.tracers and nodes.tracers.steppers.message) or function() end @@ -11530,6 +11724,65 @@ local function copy_glyph(g) return n end end +local function flattendisk(head,disc) + local replace=getfield(disc,"replace") + setfield(disc,"replace",nil) + free_node(disc) + if head==disc then + local next=getnext(disc) + if replace then + if next then + local tail=find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + end + return replace,replace + elseif next then + return next,next + else + return + end + else + local next=getnext(disc) + local prev=getprev(disc) + if replace then + local tail=find_node_tail(replace) + if next then + setfield(tail,"next",next) + setfield(next,"prev",tail) + end + setfield(prev,"next",replace) + setfield(replace,"prev",prev) + return head,replace + else + if next then + setfield(next,"prev",prev) + end + setfield(prev,"next",next) + return head,next + end + end +end +local function appenddisc(disc,list) + local post=getfield(disc,"post") + local replace=getfield(disc,"replace") + local phead=list + local rhead=copy_node_list(list) + local ptail=find_node_tail(post) + local rtail=find_node_tail(replace) + if post then + setfield(ptail,"next",phead) + setfield(phead,"prev",ptail) + else + setfield(disc,"post",phead) + end + if replace then + setfield(rtail,"next",rhead) + setfield(rhead,"prev",rtail) + else + setfield(disc,"replace",rhead) + end +end local function markstoligature(kind,lookupname,head,start,stop,char) if start==stop and getchar(start)==char then return head,start @@ -11557,8 +11810,8 @@ local function markstoligature(kind,lookupname,head,start,stop,char) return head,base end end -local function getcomponentindex(start) - if getid(start)~=glyph_code then +local function getcomponentindex(start) + if getid(start)~=glyph_code then return 0 elseif getsubtype(start)==ligature_code then local i=0 @@ -11574,14 +11827,22 @@ local function getcomponentindex(start) return 0 end end +local a_noligature=attributes.private("noligature") local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) + if getattr(start,a_noligature)==1 then + return head,start + end if start==stop and getchar(start)==char then resetinjection(start) setfield(start,"char",char) return head,start end + local components=getfield(start,"components") + if components then + end local prev=getprev(start) local next=getnext(stop) + local comp=start setfield(start,"prev",nil) setfield(stop,"next",nil) local base=copy_glyph(start) @@ -11591,15 +11852,15 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun resetinjection(base) setfield(base,"char",char) setfield(base,"subtype",ligature_code) - setfield(base,"components",start) + setfield(base,"components",comp) if prev then setfield(prev,"next",base) end if next then setfield(next,"prev",base) end - setfield(base,"next",next) setfield(base,"prev",prev) + setfield(base,"next",next) if not discfound then local deletemarks=markflag~="mark" local components=start @@ -11617,7 +11878,9 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun if trace_marks then logwarning("%s: keep mark %s, gets index %s",pref(kind,lookupname),gref(char),getligaindex(start)) end - head,current=insert_node_after(head,current,copy_node(start)) + local n=copy_node(start) + copyinjection(n,start) + head,current=insert_node_after(head,current,n) elseif trace_marks then logwarning("%s: delete mark %s",pref(kind,lookupname),gref(char)) end @@ -11636,16 +11899,75 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun end start=getnext(start) end + else + local discprev=getfield(discfound,"prev") + local discnext=getfield(discfound,"next") + if discprev and discnext then + local pre=getfield(discfound,"pre") + local post=getfield(discfound,"post") + local replace=getfield(discfound,"replace") + if not replace then + local prev=getfield(base,"prev") + local copied=copy_node_list(comp) + setfield(discnext,"prev",nil) + setfield(discprev,"next",nil) + if pre then + setfield(discprev,"next",pre) + setfield(pre,"prev",discprev) + end + pre=comp + if post then + local tail=find_node_tail(post) + setfield(tail,"next",discnext) + setfield(discnext,"prev",tail) + setfield(post,"prev",nil) + else + post=discnext + end + setfield(prev,"next",discfound) + setfield(discfound,"prev",prev) + setfield(discfound,"next",next) + setfield(next,"prev",discfound) + setfield(base,"next",nil) + setfield(base,"prev",nil) + setfield(base,"components",copied) + setfield(discfound,"pre",pre) + setfield(discfound,"post",post) + setfield(discfound,"replace",base) + setfield(discfound,"subtype",discretionary_code) + base=prev + end + end end return head,base end -function handlers.gsub_single(head,start,kind,lookupname,replacement) - if trace_singles then - logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) +local function multiple_glyphs(head,start,multiple,ignoremarks) + local nofmultiples=#multiple + if nofmultiples>0 then + resetinjection(start) + setfield(start,"char",multiple[1]) + if nofmultiples>1 then + local sn=getnext(start) + for k=2,nofmultiples do + local n=copy_node(start) + resetinjection(n) + setfield(n,"char",multiple[k]) + setfield(n,"prev",start) + setfield(n,"next",sn) + if sn then + setfield(sn,"prev",n) + end + setfield(start,"next",n) + start=n + end + end + return head,start,true + else + if trace_multiples then + logprocess("no multiple for %s",gref(getchar(start))) + end + return head,start,false end - resetinjection(start) - setfield(start,"char",replacement) - return head,start,true end local function get_alternative_glyph(start,alternatives,value,trace_alternatives) local n=#alternatives @@ -11678,33 +12000,13 @@ local function get_alternative_glyph(start,alternatives,value,trace_alternatives end end end -local function multiple_glyphs(head,start,multiple,ignoremarks) - local nofmultiples=#multiple - if nofmultiples>0 then - resetinjection(start) - setfield(start,"char",multiple[1]) - if nofmultiples>1 then - local sn=getnext(start) - for k=2,nofmultiples do - local n=copy_node(start) - resetinjection(n) - setfield(n,"char",multiple[k]) - setfield(n,"next",sn) - setfield(n,"prev",start) - if sn then - setfield(sn,"prev",n) - end - setfield(start,"next",n) - start=n - end - end - return head,start,true - else - if trace_multiples then - logprocess("no multiple for %s",gref(getchar(start))) - end - return head,start,false +function handlers.gsub_single(head,start,kind,lookupname,replacement) + if trace_singles then + logprocess("%s: replacing %s by single %s",pref(kind,lookupname),gref(getchar(start)),gref(replacement)) end + resetinjection(start) + setfield(start,"char",replacement) + return head,start,true end function handlers.gsub_alternate(head,start,kind,lookupname,alternative,sequence) local value=featurevalue==true and tfmdata.shared.features[kind] or featurevalue @@ -11729,7 +12031,7 @@ function handlers.gsub_multiple(head,start,kind,lookupname,multiple,sequence) return multiple_glyphs(head,start,multiple,sequence.flags[1]) end function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) - local s,stop,discfound=getnext(start),nil,false + local s,stop=getnext(start),nil local startchar=getchar(start) if marks[startchar] then while s do @@ -11757,23 +12059,29 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) else head,start=markstoligature(kind,lookupname,head,start,stop,lig) end - return head,start,true + return head,start,true,false else end end else local skipmark=sequence.flags[1] + local discfound=false + local lastdisc=nil while s do local id=getid(s) - if id==glyph_code and getsubtype(s)<256 then - if getfont(s)==currentfont then + if id==glyph_code and getsubtype(s)<256 then + if getfont(s)==currentfont then local char=getchar(s) if skipmark and marks[char] then s=getnext(s) - else - local lg=ligature[char] + else + local lg=ligature[char] if lg then - stop=s + if not discfound and lastdisc then + discfound=lastdisc + lastdisc=nil + end + stop=s ligature=lg s=getnext(s) else @@ -11784,13 +12092,13 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) break end elseif id==disc_code then - discfound=true + lastdisc=s s=getnext(s) else break end end - local lig=ligature.ligature + local lig=ligature.ligature if lig then if stop then if trace_ligatures then @@ -11807,12 +12115,71 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence) logprocess("%s: replacing %s by (no real) ligature %s case 3",pref(kind,lookupname),gref(startchar),gref(lig)) end end - return head,start,true + return head,start,true,discfound else end end + return head,start,false,discfound +end +function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence,injection) + local startchar=getchar(start) + local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,injection) + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) + end return head,start,false end +function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash,i,injection) + local snext=getnext(start) + if not snext then + return head,start,false + else + local prev=start + local done=false + local factor=tfmdata.parameters.factor + local lookuptype=lookuptypes[lookupname] + while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do + local nextchar=getchar(snext) + local krn=kerns[nextchar] + if not krn and marks[nextchar] then + prev=snext + snext=getnext(snext) + else + if not krn then + elseif type(krn)=="table" then + if lookuptype=="pair" then + local a,b=krn[2],krn[3] + if a and #a>0 then + local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,injection) + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b and #b>0 then + local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,injection) + if trace_kerns then + local startchar=getchar(start) + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + else + report_process("%s: check this out (old kern stuff)",pref(kind,lookupname)) + end + done=true + elseif krn~=0 then + local k=setkern(snext,factor,rlmode,krn,injection) + if trace_kerns then + logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) + end + done=true + end + break + end + end + return head,start,done + end +end function handlers.gpos_mark2base(head,start,kind,lookupname,markanchors,sequence) local markchar=getchar(start) if marks[markchar] then @@ -11965,7 +12332,7 @@ function handlers.gpos_mark2mark(head,start,kind,lookupname,markanchors,sequence if al[anchor] then local ma=markanchors[anchor] if ma then - local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar]) + local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true) if trace_marks then logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", pref(kind,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) @@ -12043,65 +12410,6 @@ function handlers.gpos_cursive(head,start,kind,lookupname,exitanchors,sequence) return head,start,false end end -function handlers.gpos_single(head,start,kind,lookupname,kerns,sequence) - local startchar=getchar(start) - local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),dx,dy,w,h) - end - return head,start,false -end -function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence) - local snext=getnext(start) - if not snext then - return head,start,false - else - local prev,done=start,false - local factor=tfmdata.parameters.factor - local lookuptype=lookuptypes[lookupname] - while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do - local nextchar=getchar(snext) - local krn=kerns[nextchar] - if not krn and marks[nextchar] then - prev=snext - snext=getnext(snext) - else - if not krn then - elseif type(krn)=="table" then - if lookuptype=="pair" then - local a,b=krn[2],krn[3] - if a and #a>0 then - local startchar=getchar(start) - local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - if b and #b>0 then - local startchar=getchar(start) - local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) - if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(kind,lookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - else - report_process("%s: check this out (old kern stuff)",pref(kind,lookupname)) - end - done=true - elseif krn~=0 then - local k=setkern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",pref(kind,lookupname),k,gref(getchar(prev)),gref(nextchar)) - end - done=true - end - break - end - end - return head,start,done - end -end -local chainmores={} local chainprocs={} local function logprocess(...) if trace_steps then @@ -12121,10 +12429,6 @@ function chainprocs.chainsub(head,start,stop,kind,chainname,currentcontext,looku logwarning("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname)) return head,start,false end -function chainmores.chainsub(head,start,stop,kind,chainname,currentcontext,lookuphash,lookuplist,chainlookupname,n) - logprocess("%s: a direct call to chainsub cannot happen",cref(kind,chainname,chainlookupname)) - return head,start,false -end function chainprocs.reversesub(head,start,stop,kind,chainname,currentcontext,lookuphash,replacements) local char=getchar(start) local replacement=replacements[char] @@ -12143,7 +12447,7 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo local current=start local subtables=currentlookup.subtables if #subtables>1 then - logwarning("todo: check if we need to loop over the replacements: %s",concat(subtables," ")) + logwarning("todo: check if we need to loop over the replacements: % t",subtables) end while current do if getid(current)==glyph_code then @@ -12177,7 +12481,6 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo end return head,start,false end -chainmores.gsub_single=chainprocs.gsub_single function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) local startchar=getchar(start) local subtables=currentlookup.subtables @@ -12202,7 +12505,6 @@ function chainprocs.gsub_multiple(head,start,stop,kind,chainname,currentcontext, end return head,start,false end -chainmores.gsub_multiple=chainprocs.gsub_multiple function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) local current=start local subtables=currentlookup.subtables @@ -12244,7 +12546,6 @@ function chainprocs.gsub_alternate(head,start,stop,kind,chainname,currentcontext end return head,start,false end -chainmores.gsub_alternate=chainprocs.gsub_alternate function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex) local startchar=getchar(start) local subtables=currentlookup.subtables @@ -12264,13 +12565,19 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, local s=getnext(start) local discfound=false local last=stop - local nofreplacements=0 + local nofreplacements=1 local skipmark=currentlookup.flags[1] while s do local id=getid(s) if id==disc_code then - s=getnext(s) - discfound=true + if not discfound then + discfound=s + end + if s==stop then + break + else + s=getnext(s) + end else local schar=getchar(s) if skipmark and marks[schar] then @@ -12303,7 +12610,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end head,start=toligature(kind,lookupname,head,start,stop,l2,currentlookup.flags[1],discfound) - return head,start,true,nofreplacements + return head,start,true,nofreplacements,discfound elseif trace_bugs then if start==stop then logwarning("%s: replacing character %s by ligature fails",cref(kind,chainname,chainlookupname,lookupname,chainindex),gref(startchar)) @@ -12313,10 +12620,83 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext, end end end - return head,start,false,0 + return head,start,false,0,false end -chainmores.gsub_ligature=chainprocs.gsub_ligature -function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) +function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) + local startchar=getchar(start) + local subtables=currentlookup.subtables + local lookupname=subtables[1] + local kerns=lookuphash[lookupname] + if kerns then + kerns=kerns[startchar] + if kerns then + local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns) + if trace_kerns then + logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) + end + end + end + return head,start,false +end +function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) + local snext=getnext(start) + if snext then + local startchar=getchar(start) + local subtables=currentlookup.subtables + local lookupname=subtables[1] + local kerns=lookuphash[lookupname] + if kerns then + kerns=kerns[startchar] + if kerns then + local lookuptype=lookuptypes[lookupname] + local prev,done=start,false + local factor=tfmdata.parameters.factor + while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do + local nextchar=getchar(snext) + local krn=kerns[nextchar] + if not krn and marks[nextchar] then + prev=snext + snext=getnext(snext) + else + if not krn then + elseif type(krn)=="table" then + if lookuptype=="pair" then + local a,b=krn[2],krn[3] + if a and #a>0 then + local startchar=getchar(start) + local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a) + if trace_kerns then + logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + if b and #b>0 then + local startchar=getchar(start) + local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b) + if trace_kerns then + logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) + end + end + else + report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname)) + end + done=true + elseif krn~=0 then + local k=setkern(snext,factor,rlmode,krn) + if trace_kerns then + logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) + end + done=true + end + break + end + end + return head,start,done + end + end + end + return head,start,false +end +function chainprocs.gpos_mark2base(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname) local markchar=getchar(start) if marks[markchar] then local subtables=currentlookup.subtables @@ -12479,7 +12859,7 @@ function chainprocs.gpos_mark2mark(head,start,stop,kind,chainname,currentcontext if al[anchor] then local ma=markanchors[anchor] if ma then - local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar]) + local dx,dy,bound=setmark(start,base,tfmdata.parameters.factor,rlmode,ba,ma,characters[basechar],true) if trace_marks then logprocess("%s, anchor %s, bound %s: anchoring mark %s to basemark %s => (%p,%p)", cref(kind,chainname,chainlookupname,lookupname),anchor,bound,gref(markchar),gref(basechar),dx,dy) @@ -12566,113 +12946,286 @@ function chainprocs.gpos_cursive(head,start,stop,kind,chainname,currentcontext,l end return head,start,false end -function chainprocs.gpos_single(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) - local startchar=getchar(start) - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local kerns=lookuphash[lookupname] - if kerns then - kerns=kerns[startchar] - if kerns then - local dx,dy,w,h=setpair(start,tfmdata.parameters.factor,rlmode,sequence.flags[4],kerns,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),dx,dy,w,h) +local function show_skip(kind,chainname,char,ck,class) + if ck[9] then + logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a, %a => %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10]) + else + logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2]) + end +end +local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,chainindex,sequence,chainproc) + if not start then + return head,start,false + end + local startishead=start==head + local seq=ck[3] + local f=ck[4] + local l=ck[5] + local s=#seq + local done=false + local sweepnode=sweepnode + local sweeptype=sweeptype + local sweepoverflow=false + local checkdisc=getprev(head) + local keepdisc=not sweepnode + local lookaheaddisc=nil + local backtrackdisc=nil + local current=start + local last=start + local prev=getprev(start) + local i=f + while i<=l do + local id=getid(current) + if id==glyph_code then + i=i+1 + last=current + current=getnext(current) + elseif id==disc_code then + if keepdisc then + keepdisc=false + if notmatchpre[current]~=notmatchreplace[current] then + lookaheaddisc=current + end + local replace=getfield(current,"replace") + while replace and i<=l do + if getid(replace)==glyph_code then + i=i+1 + end + replace=getnext(replace) + end + last=current + current=getnext(c) + else + head,current=flattendisk(head,current) + end + else + last=current + current=getnext(current) + end + if current then + elseif sweepoverflow then + break + elseif sweeptype=="post" or sweeptype=="replace" then + current=getnext(sweepnode) + if current then + sweeptype=nil + sweepoverflow=true + else + break end end end - return head,start,false -end -chainmores.gpos_single=chainprocs.gpos_single -function chainprocs.gpos_pair(head,start,stop,kind,chainname,currentcontext,lookuphash,currentlookup,chainlookupname,chainindex,sequence) - local snext=getnext(start) - if snext then - local startchar=getchar(start) - local subtables=currentlookup.subtables - local lookupname=subtables[1] - local kerns=lookuphash[lookupname] - if kerns then - kerns=kerns[startchar] - if kerns then - local lookuptype=lookuptypes[lookupname] - local prev,done=start,false - local factor=tfmdata.parameters.factor - while snext and getid(snext)==glyph_code and getfont(snext)==currentfont and getsubtype(snext)<256 do - local nextchar=getchar(snext) - local krn=kerns[nextchar] - if not krn and marks[nextchar] then - prev=snext - snext=getnext(snext) - else - if not krn then - elseif type(krn)=="table" then - if lookuptype=="pair" then - local a,b=krn[2],krn[3] - if a and #a>0 then - local startchar=getchar(start) - local x,y,w,h=setpair(start,factor,rlmode,sequence.flags[4],a,characters[startchar]) - if trace_kerns then - logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - if b and #b>0 then - local startchar=getchar(start) - local x,y,w,h=setpair(snext,factor,rlmode,sequence.flags[4],b,characters[nextchar]) - if trace_kerns then - logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(kind,chainname,chainlookupname),gref(startchar),gref(nextchar),x,y,w,h) - end - end - else - report_process("%s: check this out (old kern stuff)",cref(kind,chainname,chainlookupname)) - local a,b=krn[2],krn[6] - if a and a~=0 then - local k=setkern(snext,factor,rlmode,a) - if trace_kerns then - logprocess("%s: inserting first kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) - end - end - if b and b~=0 then - logwarning("%s: ignoring second kern xoff %s",cref(kind,chainname,chainlookupname),b*factor) - end - end - done=true - elseif krn~=0 then - local k=setkern(snext,factor,rlmode,krn) - if trace_kerns then - logprocess("%s: inserting kern %s between %s and %s",cref(kind,chainname,chainlookupname),k,gref(getchar(prev)),gref(nextchar)) - end - done=true + if sweepoverflow then + local prev=current and getprev(current) + if not current or prev~=sweepnode then + local head=getnext(sweepnode) + local tail=nil + if prev then + tail=prev + setfield(current,"prev",sweepnode) + else + tail=find_node_tail(head) + end + setfield(sweepnode,"next",current) + setfield(head,"prev",nil) + setfield(tail,"next",nil) + appenddisc(sweepnode,head) + end + end + if l %a",cref(kind,chainname),gref(char),class,ck[1],ck[2],ck[9],ck[10]) + if f>1 then + local current=prev + local i=f + local t=sweeptype=="pre" or sweeptype=="replace" + if not current and t and current==checkdisk then + current=getprev(sweepnode) + end + while current and i>1 do + local id=getid(current) + if id==glyph_code then + i=i-1 + elseif id==disc_code then + if keepdisc then + keepdisc=false + if notmatchpost[current]~=notmatchreplace[current] then + backtrackdisc=current + end + local replace=getfield(current,"replace") + while replace and i>1 do + if getid(replace)==glyph_code then + i=i-1 + end + replace=getnext(replace) + end + elseif notmatchpost[current]~=notmatchreplace[current] then + head,current=flattendisk(head,current) + end + end + current=getprev(current) + if t and current==checkdisk then + current=getprev(sweepnode) + end + end + end + local ok=false + if lookaheaddisc then + local cf=start + local cl=getprev(lookaheaddisc) + local cprev=getprev(start) + local insertedmarks=0 + while cprev and getid(cf)==glyph_code and getfont(cf)==currentfont and getsubtype(cf)<256 and marks[getchar(cf)] do + insertedmarks=insertedmarks+1 + cf=cprev + startishead=cf==head + cprev=getprev(cprev) + end + setfield(lookaheaddisc,"prev",cprev) + if cprev then + setfield(cprev,"next",lookaheaddisc) + end + setfield(cf,"prev",nil) + setfield(cl,"next",nil) + if startishead then + head=lookaheaddisc + end + local replace=getfield(lookaheaddisc,"replace") + local pre=getfield(lookaheaddisc,"pre") + local new=copy_node_list(cf) + local cnew=new + for i=1,insertedmarks do + cnew=getnext(cnew) + end + local clast=cnew + for i=f,l do + clast=getnext(clast) + end + if not notmatchpre[lookaheaddisc] then + cf,start,ok=chainproc(cf,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if not notmatchreplace[lookaheaddisc] then + new,cnew,ok=chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if pre then + setfield(cl,"next",pre) + setfield(pre,"prev",cl) + end + if replace then + local tail=find_node_tail(new) + setfield(tail,"next",replace) + setfield(replace,"prev",tail) + end + setfield(lookaheaddisc,"pre",cf) + setfield(lookaheaddisc,"replace",new) + start=getprev(lookaheaddisc) + sweephead[cf]=getnext(clast) + sweephead[new]=getnext(last) + elseif backtrackdisc then + local cf=getnext(backtrackdisc) + local cl=start + local cnext=getnext(start) + local insertedmarks=0 + while cnext and getid(cnext)==glyph_code and getfont(cnext)==currentfont and getsubtype(cnext)<256 and marks[getchar(cnext)] do + insertedmarks=insertedmarks+1 + cl=cnext + cnext=getnext(cnext) + end + if cnext then + setfield(cnext,"prev",backtrackdisc) + end + setfield(backtrackdisc,"next",cnext) + setfield(cf,"prev",nil) + setfield(cl,"next",nil) + local replace=getfield(backtrackdisc,"replace") + local post=getfield(backtrackdisc,"post") + local new=copy_node_list(cf) + local cnew=find_node_tail(new) + for i=1,insertedmarks do + cnew=getprev(cnew) + end + local clast=cnew + for i=f,l do + clast=getnext(clast) + end + if not notmatchpost[backtrackdisc] then + cf,start,ok=chainproc(cf,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if not notmatchreplace[backtrackdisc] then + new,cnew,ok=chainproc(new,cnew,clast,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end + if post then + local tail=find_node_tail(post) + setfield(tail,"next",cf) + setfield(cf,"prev",tail) + else + post=cf + end + if replace then + local tail=find_node_tail(replace) + setfield(tail,"next",new) + setfield(new,"prev",tail) + else + replace=new + end + setfield(backtrackdisc,"post",post) + setfield(backtrackdisc,"replace",replace) + start=getprev(backtrackdisc) + sweephead[post]=getnext(clast) + sweephead[replace]=getnext(last) else - logwarning("%s: skipping char %s, class %a, rule %a, lookuptype %a",cref(kind,chainname),gref(char),class,ck[1],ck[2]) + head,start,ok=chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) end + return head,start,ok end -local quit_on_no_replacement=true -directives.register("otf.chain.quitonnoreplacement",function(value) - quit_on_no_replacement=value -end) local function normal_handle_contextchain(head,start,kind,chainname,contexts,sequence,lookuphash) + local sweepnode=sweepnode + local sweeptype=sweeptype + local diskseen=false + local checkdisc=getprev(head) local flags=sequence.flags local done=false local skipmark=flags[1] local skipligature=flags[2] local skipbase=flags[3] - local someskip=skipmark or skipligature or skipbase - local markclass=sequence.markclass + local markclass=sequence.markclass local skipped=false - for k=1,#contexts do + for k=1,#contexts do local match=true local current=start local last=start @@ -12682,14 +13235,20 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if s==1 then match=getid(current)==glyph_code and getfont(current)==currentfont and getsubtype(current)<256 and seq[1][getchar(current)] else - local f,l=ck[4],ck[5] + local f=ck[4] + local l=ck[5] if f==1 and f==l then else if f==l then else + local discfound=nil local n=f+1 last=getnext(last) while n<=l do + if not last and (sweeptype=="post" or sweeptype=="replace") then + last=getnext(sweepnode) + sweeptype=nil + end if last then local id=getid(last) if id==glyph_code then @@ -12697,7 +13256,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq local char=getchar(last) local ccd=descriptions[char] if ccd then - local class=ccd.class + local class=ccd.class or "base" if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then skipped=true if trace_skips then @@ -12710,18 +13269,76 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end n=n+1 else - match=false + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpre[discfound] + else + match=false + end break end else - match=false + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpre[discfound] + else + match=false + end break end else - match=false + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpre[discfound] + else + match=false + end break end elseif id==disc_code then + diskseen=true + discfound=last + notmatchpre[last]=nil + notmatchpost[last]=true + notmatchreplace[last]=nil + local pre=getfield(last,"pre") + local replace=getfield(last,"replace") + if pre then + local n=n + while pre do + if seq[n][getchar(pre)] then + n=n+1 + pre=getnext(pre) + if n>l then + break + end + else + notmatchpre[last]=true + break + end + end + if n<=l then + notmatchpre[last]=true + end + else + notmatchpre[last]=true + end + if replace then + while replace do + if seq[n][getchar(replace)] then + n=n+1 + replace=getnext(replace) + if n>l then + break + end + else + notmatchreplace[last]=true + match=not notmatchpre[last] + break + end + end + match=not notmatchpre[last] + end last=getnext(last) else match=false @@ -12737,49 +13354,132 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if match and f>1 then local prev=getprev(start) if prev then - local n=f-1 - while n>=1 do - if prev then - local id=getid(prev) - if id==glyph_code then - if getfont(prev)==currentfont and getsubtype(prev)<256 then - local char=getchar(prev) - local ccd=descriptions[char] - if ccd then - local class=ccd.class - if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then - skipped=true - if trace_skips then - show_skip(kind,chainname,char,ck,class) + if prev==checkdisc and (sweeptype=="pre" or sweeptype=="replace") then + prev=getprev(sweepnode) + end + if prev then + local discfound=nil + local n=f-1 + while n>=1 do + if prev then + local id=getid(prev) + if id==glyph_code then + if getfont(prev)==currentfont and getsubtype(prev)<256 then + local char=getchar(prev) + local ccd=descriptions[char] + if ccd then + local class=ccd.class + if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then + skipped=true + if trace_skips then + show_skip(kind,chainname,char,ck,class) + end + elseif seq[n][char] then + n=n -1 + else + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpost[discfound] + else + match=false + end + break end - elseif seq[n][char] then - n=n -1 else - match=false + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpost[discfound] + else + match=false + end break end else - match=false + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpost[discfound] + else + match=false + end break end + elseif id==disc_code then + diskseen=true + discfound=prev + notmatchpre[prev]=true + notmatchpost[prev]=nil + notmatchreplace[prev]=nil + local pre=getfield(prev,"pre") + local post=getfield(prev,"post") + local replace=getfield(prev,"replace") + if pre~=start and post~=start and replace~=start then + if post then + local n=n + local posttail=find_node_tail(post) + while posttail do + if seq[n][getchar(posttail)] then + n=n-1 + if posttail==post then + break + else + posttail=getprev(posttail) + if n<1 then + break + end + end + else + notmatchpost[prev]=true + break + end + end + if n>=1 then + notmatchpost[prev]=true + end + else + notmatchpost[prev]=true + end + if replace then + local replacetail=find_node_tail(replace) + while replacetail do + if seq[n][getchar(replacetail)] then + n=n-1 + if replacetail==replace then + break + else + replacetail=getprev(replacetail) + if n<1 then + break + end + end + else + notmatchreplace[prev]=true + match=not notmatchpost[prev] + break + end + end + if not match then + break + end + else + end + else + end + elseif seq[n][32] then + n=n -1 else match=false break end - elseif id==disc_code then - elseif seq[n][32] then - n=n -1 + prev=getprev(prev) + elseif seq[n][32] then + n=n-1 else match=false break end - prev=getprev(prev) - elseif seq[n][32] then - n=n -1 - else - match=false - break end + else + match=false end else match=false @@ -12787,7 +13487,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end if match and s>l then local current=last and getnext(last) + if not current then + if sweeptype=="post" or sweeptype=="replace" then + current=getnext(sweepnode) + end + end if current then + local discfound=nil local n=l+1 while n<=s do if current then @@ -12803,21 +13509,82 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if trace_skips then show_skip(kind,chainname,char,ck,class) end - elseif seq[n][char] then + elseif seq[n][char] then + n=n+1 + else + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpre[discfound] + else + match=false + end + break + end + else + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpre[discfound] + else + match=false + end + break + end + else + if discfound then + notmatchreplace[discfound]=true + match=not notmatchpre[discfound] + else + match=false + end + break + end + elseif id==disc_code then + diskseen=true + discfound=current + notmatchpre[current]=nil + notmatchpost[current]=true + notmatchreplace[current]=nil + local pre=getfield(current,"pre") + local replace=getfield(current,"replace") + if pre then + local n=n + while pre do + if seq[n][getchar(pre)] then + n=n+1 + pre=getnext(pre) + if n>s then + break + end + else + notmatchpre[current]=true + break + end + end + if n<=s then + notmatchpre[current]=true + end + else + notmatchpre[current]=true + end + if replace then + while replace do + if seq[n][getchar(replace)] then n=n+1 + replace=getnext(replace) + if n>s then + break + end else - match=false + notmatchreplace[current]=true + match=notmatchpre[current] break end - else - match=false + end + if not match then break end else - match=false - break end - elseif id==disc_code then elseif seq[n][32] then n=n+1 else @@ -12838,6 +13605,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end if match then + local diskchain=diskseen or sweepnode if trace_contexts then local rule,lookuptype,f,l=ck[1],ck[2],ck[4],ck[5] local char=getchar(start) @@ -12856,10 +13624,14 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq local chainlookupname=chainlookups[1] local chainlookup=lookuptable[chainlookupname] if chainlookup then - local cp=chainprocs[chainlookup.type] - if cp then + local chainproc=chainprocs[chainlookup.type] + if chainproc then local ok - head,start,ok=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + if diskchain then + head,start,ok=chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence,chainproc) + else + head,start,ok=chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence) + end if ok then done=true end @@ -12871,13 +13643,13 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end else local i=1 - while true do + while start and true do if skipped then - while true do + while true do local char=getchar(start) local ccd=descriptions[char] if ccd then - local class=ccd.class + local class=ccd.class or "base" if class==skipmark or class==skipligature or class==skipbase or (markclass and class=="mark" and not markclass[char]) then start=getnext(start) else @@ -12893,26 +13665,33 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq if not chainlookup then i=i+1 else - local cp=chainmores[chainlookup.type] - if not cp then + local chainproc=chainprocs[chainlookup.type] + if not chainproc then logprocess("%s: %s is not yet supported",cref(kind,chainname,chainlookupname),chainlookup.type) i=i+1 else local ok,n - head,start,ok,n=cp(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) + if diskchain then + head,start,ok=chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,nil,sequence,chainproc) + else + head,start,ok,n=chainproc(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,i,sequence) + end if ok then done=true - i=i+(n or 1) - else - i=i+1 + if n and n>1 then + if i+n>nofchainlookups then + break + else + end + end end + i=i+1 end end - if i>nofchainlookups then + if i>nofchainlookups or not start then break elseif start then start=getnext(start) - else end end end @@ -12927,8 +13706,16 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq end end end + if done then + break + end end end + if diskseen then + notmatchpre={} + notmatchpost={} + notmatchreplace={} + end return head,start,done end local verbose_handle_contextchain=function(font,...) @@ -12999,7 +13786,7 @@ local function initialize(sequence,script,language,enabled) local scripts=features[kind] local languages=scripts[script] or scripts[wildcard] if languages and (languages[language] or languages[wildcard]) then - return { valid,autofeatures[kind] or false,sequence.chain or 0,kind,sequence } + return { valid,autofeatures[kind] or false,sequence,kind } end end end @@ -13039,6 +13826,175 @@ function otf.dataset(tfmdata,font) end return rl end +local function kernrun(disc,run) + if trace_kernruns then + report_run("kern") + end + local prev=getprev(disc) + local next=getnext(disc) + local pre=getfield(disc,"pre") + local post=getfield(disc,"post") + local replace=getfield(disc,"replace") + local prevmarks=prev + while prevmarks and getid(prevmarks)==glyph_code and marks[getchar(prevmarks)] and getfont(prevmarks)==currentfont and getsubtype(prevmarks)<256 do + prevmarks=getprev(prevmarks) + end + if prev and (pre or replace) and not (getid(prev)==glyph_code and getfont(prev)==currentfont and getsubtype(prev)<256) then + prev=false + end + if next and (post or replace) and not (getid(next)==glyph_code and getfont(next)==currentfont and getsubtype(next)<256) then + next=false + end + if not pre then + elseif prev then + local nest=getprev(pre) + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + run(prevmarks,"preinjections") + setfield(pre,"prev",nest) + setfield(prev,"next",disc) + else + run(pre,"preinjections") + end + if not post then + elseif next then + local tail=find_node_tail(post) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(post,"postinjections",next) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(post,"postinjections") + end + if not replace and prev and next then + setfield(prev,"next",next) + setfield(next,"prev",prev) + run(prevmarks,"injections",next) + setfield(prev,"next",disc) + setfield(next,"prev",disc) + elseif prev and next then + local tail=find_node_tail(replace) + local nest=getprev(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(prevmarks,"replaceinjections",next) + setfield(replace,"prev",nest) + setfield(prev,"next",disc) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + elseif prev then + local nest=getprev(replace) + setfield(replace,"prev",prev) + setfield(prev,"next",replace) + run(prevmarks,"replaceinjections") + setfield(replace,"prev",nest) + setfield(prev,"next",disc) + elseif next then + local tail=find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + run(replace,"replaceinjections",next) + setfield(tail,"next",nil) + setfield(next,"prev",disc) + else + run(replace,"replaceinjections") + end +end +local function comprun(disc,run) + if trace_compruns then + report_run("comp: %s",languages.serializediscretionary(disc)) + end + local pre=getfield(disc,"pre") + if pre then + sweepnode=disc + sweeptype="pre" + local new,done=run(pre) + if done then + setfield(disc,"pre",new) + end + end + local post=getfield(disc,"post") + if post then + sweepnode=disc + sweeptype="post" + local new,done=run(post) + if done then + setfield(disc,"post",new) + end + end + local replace=getfield(disc,"replace") + if replace then + sweepnode=disc + sweeptype="replace" + local new,done=run(replace) + if done then + setfield(disc,"replace",new) + end + end + sweepnode=nil + sweeptype=nil +end +local function testrun(disc,trun,crun) + local next=getnext(disc) + if next then + local replace=getfield(disc,"replace") + if replace then + local prev=getprev(disc) + if prev then + local tail=find_node_tail(replace) + setfield(tail,"next",next) + setfield(next,"prev",tail) + if trun(replace,next) then + setfield(disc,"replace",nil) + setfield(prev,"next",replace) + setfield(replace,"prev",prev) + setfield(next,"prev",tail) + setfield(tail,"next",next) + setfield(disc,"prev",nil) + setfield(disc,"next",nil) + flush_node_list(disc) + return replace + else + setfield(tail,"next",nil) + setfield(next,"prev",disc) + end + else + end + else + end + else + end + comprun(disc,crun) + return next +end +local function discrun(disc,drun,krun) + local next=getnext(disc) + local prev=getprev(disc) + if trace_discruns then + report_run("disc") + end + if next and prev then + setfield(prev,"next",next) + drun(prev) + setfield(prev,"next",disc) + end + local pre=getfield(disc,"pre") + if not pre then + elseif prev then + local nest=getprev(pre) + setfield(pre,"prev",prev) + setfield(prev,"next",pre) + krun(prev,"preinjections") + setfield(pre,"prev",nest) + setfield(prev,"next",disc) + else + krun(pre,"preinjections") + end + return next +end local function featuresprocessor(head,font,attr) local lookuphash=lookuphashes[font] if not lookuphash then @@ -13059,23 +14015,25 @@ local function featuresprocessor(head,font,attr) lookuptags=resources.lookuptags currentfont=font rlmode=0 + sweephead={} local sequences=resources.sequences local done=false local datasets=otf.dataset(tfmdata,font,attr) local dirstack={} for s=1,#datasets do local dataset=datasets[s] - featurevalue=dataset[1] - local sequence=dataset[5] + featurevalue=dataset[1] + local attribute=dataset[2] + local sequence=dataset[3] + local kind=dataset[4] local rlparmode=0 local topstack=0 local success=false - local attribute=dataset[2] - local chain=dataset[3] local typ=sequence.type + local gpossing=typ=="gpos_single" or typ=="gpos_pair" local subtables=sequence.subtables - if chain<0 then - local handler=handlers[typ] + local handler=handlers[typ] + if typ=="gsub_reversecontextchain" then local start=find_node_tail(head) while start do local id=getid(start) @@ -13088,13 +14046,14 @@ local function featuresprocessor(head,font,attr) a=true end if a then + local char=getchar(start) for i=1,#subtables do local lookupname=subtables[i] local lookupcache=lookuphash[lookupname] if lookupcache then - local lookupmatch=lookupcache[getchar(start)] + local lookupmatch=lookupcache[char] if lookupmatch then - head,start,success=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head,start,success=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if success then break end @@ -13115,7 +14074,6 @@ local function featuresprocessor(head,font,attr) end end else - local handler=handlers[typ] local ns=#subtables local start=head rlmode=0 @@ -13125,12 +14083,19 @@ local function featuresprocessor(head,font,attr) if not lookupcache then report_missing_cache(typ,lookupname) else - local function subrun(start) - local head=start + local function c_run(head) local done=false + local start=sweephead[head] + if start then + sweephead[head]=nil + else + start=head + end while start do local id=getid(start) - if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then + if id~=glyph_code then + start=getnext(start) + elseif getfont(start)==font and getsubtype(start)<256 then local a=getattr(start,0) if a then a=(a==attr) and (not attribute or getprop(start,a_state)==attribute) @@ -13141,7 +14106,7 @@ local function featuresprocessor(head,font,attr) local lookupmatch=lookupcache[getchar(start)] if lookupmatch then local ok - head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then done=true end @@ -13151,43 +14116,98 @@ local function featuresprocessor(head,font,attr) start=getnext(start) end else - start=getnext(start) + return head,false end end if done then - success=true - return head + success=true end + return head,done end - local function kerndisc(disc) - local prev=getprev(disc) - local next=getnext(disc) - if prev and next then - setfield(prev,"next",next) - local a=getattr(prev,0) - if a then - a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute) + local function t_run(start,stop) + while start~=stop do + local id=getid(start) + if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then + local a=getattr(start,0) + if a then + a=(a==attr) and (not attribute or getprop(start,a_state)==attribute) + else + a=not attribute or getprop(start,a_state)==attribute + end + if a then + local lookupmatch=lookupcache[getchar(start)] + if lookupmatch then + local s=getnext(start) + local l=nil + while s do + local lg=lookupmatch[getchar(s)] + if lg then + l=lg + s=getnext(s) + else + break + end + end + if l and l.ligature then + return true + end + end + end + start=getnext(start) else - a=not attribute or getprop(prev,a_state)==attribute + break end - if a then - local lookupmatch=lookupcache[getchar(prev)] - if lookupmatch then - local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) - if ok then - done=true - success=true + end + end + local function d_run(prev) + local a=getattr(prev,0) + if a then + a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute) + else + a=not attribute or getprop(prev,a_state)==attribute + end + if a then + local lookupmatch=lookupcache[getchar(prev)] + if lookupmatch then + local h,d,ok=handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1) + if ok then + done=true + success=true + end + end + end + end + local function k_run(sub,injection,last) + local a=getattr(sub,0) + if a then + a=(a==attr) and (not attribute or getprop(sub,a_state)==attribute) + else + a=not attribute or getprop(sub,a_state)==attribute + end + if a then + for n in traverse_nodes(sub) do + if n==last then + break + end + local id=getid(n) + if id==glyph_code then + local lookupmatch=lookupcache[getchar(n)] + if lookupmatch then + local h,d,ok=handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection) + if ok then + done=true + success=true + end end + else end end - setfield(prev,"next",disc) end - return next end while start do local id=getid(start) if id==glyph_code then - if getfont(start)==font and getsubtype(start)<256 then + if getfont(start)==font and getsubtype(start)<256 then local a=getattr(start,0) if a then a=(a==attr) and (not attribute or getprop(start,a_state)==attribute) @@ -13195,13 +14215,18 @@ local function featuresprocessor(head,font,attr) a=not attribute or getprop(start,a_state)==attribute end if a then - local lookupmatch=lookupcache[getchar(start)] + local char=getchar(start) + local lookupmatch=lookupcache[char] if lookupmatch then local ok - head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,1) + head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,1) if ok then success=true + elseif gpossing and zwnjruns and char==zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char==zwnj then + discrun(start,d_run) end if start then start=getnext(start) end else @@ -13211,41 +14236,30 @@ local function featuresprocessor(head,font,attr) start=getnext(start) end elseif id==disc_code then - if getsubtype(start)==discretionary_code then - local pre=getfield(start,"pre") - if pre then - local new=subrun(pre) - if new then setfield(start,"pre",new) end - end - local post=getfield(start,"post") - if post then - local new=subrun(post) - if new then setfield(start,"post",new) end - end - local replace=getfield(start,"replace") - if replace then - local new=subrun(replace) - if new then setfield(start,"replace",new) end - end -elseif typ=="gpos_single" or typ=="gpos_pair" then - kerndisc(start) + if gpossing then + kernrun(start,k_run) + start=getnext(start) + elseif typ=="gsub_ligature" then + start=testrun(start,t_run,c_run) + else + comprun(start,c_run) + start=getnext(start) end - start=getnext(start) elseif id==whatsit_code then local subtype=getsubtype(start) if subtype==dir_code then local dir=getfield(start,"dir") - if dir=="+TRT" or dir=="+TLT" then + if dir=="+TLT" then topstack=topstack+1 dirstack[topstack]=dir - elseif dir=="-TRT" or dir=="-TLT" then - topstack=topstack-1 - end - local newdir=dirstack[topstack] - if newdir=="+TRT" then - rlmode=-1 - elseif newdir=="+TLT" then rlmode=1 + elseif dir=="+TRT" then + topstack=topstack+1 + dirstack[topstack]=dir + rlmode=-1 + elseif dir=="-TLT" or dir=="-TRT" then + topstack=topstack-1 + rlmode=dirstack[topstack]=="+TRT" and -1 or 1 else rlmode=rlparmode end @@ -13275,12 +14289,19 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then end end else - local function subrun(start) - local head=start + local function c_run(head) local done=false + local start=sweephead[head] + if start then + sweephead[head]=nil + else + start=head + end while start do local id=getid(start) - if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then + if id~=glyph_code then + start=getnext(start) + elseif getfont(start)==font and getsubtype(start)<256 then local a=getattr(start,0) if a then a=(a==attr) and (not attribute or getprop(start,a_state)==attribute) @@ -13288,14 +14309,15 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then a=not attribute or getprop(start,a_state)==attribute end if a then + local char=getchar(start) for i=1,ns do local lookupname=subtables[i] local lookupcache=lookuphash[lookupname] if lookupcache then - local lookupmatch=lookupcache[getchar(start)] + local lookupmatch=lookupcache[char] if lookupmatch then local ok - head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then done=true break @@ -13312,46 +14334,120 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then start=getnext(start) end else - start=getnext(start) + return head,false end end if done then success=true - return head end + return head,done end - local function kerndisc(disc) - local prev=getprev(disc) - local next=getnext(disc) - if prev and next then - setfield(prev,"next",next) - local a=getattr(prev,0) - if a then - a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute) - else - a=not attribute or getprop(prev,a_state)==attribute + local function d_run(prev) + local a=getattr(prev,0) + if a then + a=(a==attr) and (not attribute or getprop(prev,a_state)==attribute) + else + a=not attribute or getprop(prev,a_state)==attribute + end + if a then + local char=getchar(prev) + for i=1,ns do + local lookupname=subtables[i] + local lookupcache=lookuphash[lookupname] + if lookupcache then + local lookupmatch=lookupcache[char] + if lookupmatch then + local h,d,ok=handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,i) + if ok then + done=true + break + end + end + else + report_missing_cache(typ,lookupname) + end end - if a then - for i=1,ns do - local lookupname=subtables[i] - local lookupcache=lookuphash[lookupname] - if lookupcache then - local lookupmatch=lookupcache[getchar(prev)] - if lookupmatch then - local h,d,ok=handler(head,prev,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) - if ok then - done=true - break + end + end + local function k_run(sub,injection,last) + local a=getattr(sub,0) + if a then + a=(a==attr) and (not attribute or getprop(sub,a_state)==attribute) + else + a=not attribute or getprop(sub,a_state)==attribute + end + if a then + for n in traverse_nodes(sub) do + if n==last then + break + end + local id=getid(n) + if id==glyph_code then + local char=getchar(n) + for i=1,ns do + local lookupname=subtables[i] + local lookupcache=lookuphash[lookupname] + if lookupcache then + local lookupmatch=lookupcache[char] + if lookupmatch then + local h,d,ok=handler(head,n,kind,lookupname,lookupmatch,sequence,lookuphash,i,injection) + if ok then + done=true + break + end end + else + report_missing_cache(typ,lookupname) + end + end + else + end + end + end + end + local function t_run(start,stop) + while start~=stop do + local id=getid(start) + if id==glyph_code and getfont(start)==font and getsubtype(start)<256 then + local a=getattr(start,0) + if a then + a=(a==attr) and (not attribute or getprop(start,a_state)==attribute) + else + a=not attribute or getprop(start,a_state)==attribute + end + if a then + local char=getchar(start) + for i=1,ns do + local lookupname=subtables[i] + local lookupcache=lookuphash[lookupname] + if lookupcache then + local lookupmatch=lookupcache[char] + if lookupmatch then + local s=getnext(start) + local l=nil + while s do + local lg=lookupmatch[getchar(s)] + if lg then + l=lg + s=getnext(s) + else + break + end + end + if l and l.ligature then + return true + end + end + else + report_missing_cache(typ,lookupname) end - else - report_missing_cache(typ,lookupname) end end + start=getnext(start) + else + break end - setfield(prev,"next",disc) end - return next end while start do local id=getid(start) @@ -13368,16 +14464,21 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then local lookupname=subtables[i] local lookupcache=lookuphash[lookupname] if lookupcache then - local lookupmatch=lookupcache[getchar(start)] + local char=getchar(start) + local lookupmatch=lookupcache[char] if lookupmatch then local ok - head,start,ok=handler(head,start,dataset[4],lookupname,lookupmatch,sequence,lookuphash,i) + head,start,ok=handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i) if ok then success=true break elseif not start then break + elseif gpossing and zwnjruns and char==zwnj then + discrun(start,d_run) end + elseif gpossing and zwnjruns and char==zwnj then + discrun(start,d_run) end else report_missing_cache(typ,lookupname) @@ -13391,41 +14492,30 @@ elseif typ=="gpos_single" or typ=="gpos_pair" then start=getnext(start) end elseif id==disc_code then - if getsubtype(start)==discretionary_code then - local pre=getfield(start,"pre") - if pre then - local new=subrun(pre) - if new then setfield(start,"pre",new) end - end - local post=getfield(start,"post") - if post then - local new=subrun(post) - if new then setfield(start,"post",new) end - end - local replace=getfield(start,"replace") - if replace then - local new=subrun(replace) - if new then setfield(start,"replace",new) end - end -elseif typ=="gpos_single" or typ=="gpos_pair" then - kerndisc(start) + if gpossing then + kernrun(start,k_run) + start=getnext(start) + elseif typ=="gsub_ligature" then + start=testrun(start,t_run,c_run) + else + comprun(start,c_run) + start=getnext(start) end - start=getnext(start) elseif id==whatsit_code then local subtype=getsubtype(start) if subtype==dir_code then local dir=getfield(start,"dir") - if dir=="+TRT" or dir=="+TLT" then + if dir=="+TLT" then topstack=topstack+1 dirstack[topstack]=dir - elseif dir=="-TRT" or dir=="-TLT" then - topstack=topstack-1 - end - local newdir=dirstack[topstack] - if newdir=="+TRT" then - rlmode=-1 - elseif newdir=="+TLT" then rlmode=1 + elseif dir=="+TRT" then + topstack=topstack+1 + dirstack[topstack]=dir + rlmode=-1 + elseif dir=="-TLT" or dir=="-TRT" then + topstack=topstack-1 + rlmode=dirstack[topstack]=="+TRT" and -1 or 1 else rlmode=rlparmode end @@ -13473,43 +14563,46 @@ local function generic(lookupdata,lookupname,unicode,lookuphash) lookuphash[lookupname]={ [unicode]=lookupdata } end end +local function ligature(lookupdata,lookupname,unicode,lookuphash) + local target=lookuphash[lookupname] + if not target then + target={} + lookuphash[lookupname]=target + end + for i=1,#lookupdata do + local li=lookupdata[i] + local tu=target[li] + if not tu then + tu={} + target[li]=tu + end + target=tu + end + target.ligature=unicode +end +local function pair(lookupdata,lookupname,unicode,lookuphash) + local target=lookuphash[lookupname] + if not target then + target={} + lookuphash[lookupname]=target + end + local others=target[unicode] + local paired=lookupdata[1] + if others then + others[paired]=lookupdata + else + others={ [paired]=lookupdata } + target[unicode]=others + end +end local action={ substitution=generic, multiple=generic, alternate=generic, position=generic, - ligature=function(lookupdata,lookupname,unicode,lookuphash) - local target=lookuphash[lookupname] - if not target then - target={} - lookuphash[lookupname]=target - end - for i=1,#lookupdata do - local li=lookupdata[i] - local tu=target[li] - if not tu then - tu={} - target[li]=tu - end - target=tu - end - target.ligature=unicode - end, - pair=function(lookupdata,lookupname,unicode,lookuphash) - local target=lookuphash[lookupname] - if not target then - target={} - lookuphash[lookupname]=target - end - local others=target[unicode] - local paired=lookupdata[1] - if others then - others[paired]=lookupdata - else - others={ [paired]=lookupdata } - target[unicode]=others - end - end, + ligature=ligature, + pair=pair, + kern=pair, } local function prepare_lookups(tfmdata) local rawdata=tfmdata.shared.rawdata @@ -13520,13 +14613,14 @@ local function prepare_lookups(tfmdata) local lookuptypes=resources.lookuptypes local characters=tfmdata.characters local descriptions=tfmdata.descriptions + local duplicates=resources.duplicates for unicode,character in next,characters do local description=descriptions[unicode] if description then local lookups=description.slookups if lookups then for lookupname,lookupdata in next,lookups do - action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash) + action[lookuptypes[lookupname]](lookupdata,lookupname,unicode,lookuphash,duplicates) end end local lookups=description.mlookups @@ -13535,7 +14629,7 @@ local function prepare_lookups(tfmdata) local lookuptype=lookuptypes[lookupname] for l=1,#lookuplist do local lookupdata=lookuplist[l] - action[lookuptype](lookupdata,lookupname,unicode,lookuphash) + action[lookuptype](lookupdata,lookupname,unicode,lookuphash,duplicates) end end end @@ -13557,7 +14651,7 @@ local function prepare_lookups(tfmdata) for name,anchor in next,anchors do local lookups=anchor_to_lookup[name] if lookups then - for lookup,_ in next,lookups do + for lookup in next,lookups do local target=lookuphash[lookup] if target then target[unicode]=anchors @@ -13639,7 +14733,7 @@ local function prepare_contextchains(tfmdata) if sequence[1] then nt=nt+1 t[nt]={ nofrules,lookuptype,sequence,start,stop,rule.lookups,replacements } - for unic,_ in next,sequence[start] do + for unic in next,sequence[start] do local cu=contexts[unic] if not cu then contexts[unic]=t @@ -13698,9 +14792,8 @@ if not modules then modules={} end modules ['font-otp']={ copyright="PRAGMA ADE / ConTeXt Development Team", license="see context related readme files" } -local next,type=next,type +local next,type,tostring=next,type,tostring local sort,concat=table.sort,table.concat -local sortedhash=table.sortedhash local trace_packing=false trackers.register("otf.packing",function(v) trace_packing=v end) local trace_loading=false trackers.register("otf.loading",function(v) trace_loading=v end) local report_otf=logs.reporter("fonts","otf loading") @@ -14676,10 +15769,11 @@ end function resolvers.name(specification) local resolve=fonts.names.resolve if resolve then - local resolved,sub=resolve(specification.name,specification.sub,specification) + local resolved,sub,subindex=resolve(specification.name,specification.sub,specification) if resolved then specification.resolved=resolved specification.sub=sub + specification.subindex=subindex local suffix=lower(suffixonly(resolved)) if fonts.formats[suffix] then specification.forced=suffix @@ -14696,10 +15790,11 @@ end function resolvers.spec(specification) local resolvespec=fonts.names.resolvespec if resolvespec then - local resolved,sub=resolvespec(specification.name,specification.sub,specification) + local resolved,sub,subindex=resolvespec(specification.name,specification.sub,specification) if resolved then specification.resolved=resolved specification.sub=sub + specification.subindex=subindex specification.forced=lower(suffixonly(resolved)) specification.forcedname=resolved specification.name=removesuffix(resolved) @@ -15341,12 +16436,30 @@ function nodes.handlers.nodepass(head) local range=basefonts[i] local start=range[1] local stop=range[2] - if stop then - start,stop=ligaturing(start,stop) - start,stop=kerning(start,stop) - elseif start then - start=ligaturing(start) - start=kerning(start) + if start or stop then + local prev=nil + local next=nil + local front=start==head + if stop then + next=stop.next + start,stop=ligaturing(start,stop) + start,stop=kerning(start,stop) + elseif start then + prev=start.prev + start=ligaturing(start) + start=kerning(start) + end + if prev then + start.prev=prev + prev.next=start + end + if next then + stop.next=next + next.prev=stop + end + if front then + head=start + end end end end @@ -15356,7 +16469,7 @@ function nodes.handlers.nodepass(head) end end function nodes.handlers.basepass(head) - if not basepass then + if basepass then head=ligaturing(head) head=kerning(head) end -- cgit v1.2.3 From 7fd7d54817edbf75ff4e0a574769a27a851a5240 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 07:21:18 +0100 Subject: [tool] adapt outdated usage info --- src/luaotfload-tool.lua | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index 181bd5c..8b7bc33 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -109,6 +109,7 @@ config.lualibs.prefer_merged = true config.lualibs.load_extended = true require "lualibs" + local iosavedata = io.savedata local lfsisdir = lfs.isdir local lfsisfile = lfs.isfile @@ -138,7 +139,7 @@ local backup = { } texio.write, texio.write_nl = dummy_function, dummy_function -require"luaotfload-basics-gen.lua" +require "luaotfload-basics-gen.lua" texio.write, texio.write_nl = backup.write, backup.write_nl utilities = backup.utilities @@ -216,8 +217,7 @@ Usage: %s [OPTIONS...] -q --quiet don't output anything -v --verbose=LEVEL be more verbose (print the searched directories) - -vv print the loaded fonts - -vvv print all steps of directory searching + -v, -vv .. -vvvvvvvvv set loglevel in unary --log=stdout redirect log output to stdout -V --version print version and exit -- cgit v1.2.3 From 1bffc1c923412efa9b45f370d771d1ebacbcbaef Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 07:26:34 +0100 Subject: [log] fix format strings passed to os.date() In the name of MS compiler compatibility bow before the Middle Ages. --- src/luaotfload-log.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/luaotfload-log.lua b/src/luaotfload-log.lua index 7c012f4..e5db310 100644 --- a/src/luaotfload-log.lua +++ b/src/luaotfload-log.lua @@ -91,7 +91,7 @@ local set_logout = function (s, finalizers) logout = "redirect" local chan = choose_logfile () chan:write (stringformat ("logging initiated at %s", - osdate ("%Y-%m-%d %h:%m:%s", --- i. e. osdate "%F %T" + osdate ("%Y-%m-%d %H:%M:%S", --- i. e. osdate "%F %T" ostime ()))) local writefile = function (...) if select ("#", ...) == 2 then @@ -118,7 +118,7 @@ local set_logout = function (s, finalizers) finalizers[#finalizers+1] = function () chan:write (stringformat ("\nlogging finished at %s\n", - osdate ("%Y-%m-%d %h:%m:%s", --- i. e. osdate "%F %T" + osdate ("%Y-%m-%d %H:%M:%S", --- i. e. osdate "%F %T" ostime ()))) chan:close () texiowrite = texio.write -- cgit v1.2.3 From e52df63570da80bf121fd9b9294de5a2d037f1b6 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 07:37:39 +0100 Subject: [main] dejumble module loader message --- src/luaotfload-main.lua | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 3d68a17..ff2b48d 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -109,15 +109,15 @@ end local make_loader_name = function (prefix, name) local msg = luaotfload.log and luaotfload.log.report or print - if prefix then + if prefix and name then msg ("log", 7, "load", - "Composing fontloader name from constitutents %s, %s", + "Composing module name from constituents %s, %s", prefix, name) return prefix .. "-" .. name .. ".lua" end msg ("log", 7, "load", - "Loading fontloader file %s literally.", - name) + "Loading module %s literally.", + tostring (name)) return name end -- cgit v1.2.3 From 4ab63d7a670d90f9ffcbd2c35b363c432c043d5d Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 07:39:59 +0100 Subject: [diagnose] fix indentation of status message --- src/luaotfload-diagnostics.lua | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/luaotfload-diagnostics.lua b/src/luaotfload-diagnostics.lua index 80e461c..255b5a5 100644 --- a/src/luaotfload-diagnostics.lua +++ b/src/luaotfload-diagnostics.lua @@ -655,27 +655,27 @@ local diagnose = function (job) you may sleep well.") return true, false end - out ( [[=============================================== - WARNING - =============================================== + out ( [[=============================================== + WARNING + =============================================== - The diagnostic detected %d errors. + The diagnostic detected %d errors. - This version of luaotfload may have been - tampered with. Modified versions of the - luaotfload source are unsupported. Read the log - carefully and get a clean version from CTAN or - github: + This version of luaotfload may have been + tampered with. Modified versions of the + luaotfload source are unsupported. Read the log + carefully and get a clean version from CTAN or + github: - × http://www.ctan.org/pkg/luaotfload - × https://github.com/lualatex/luaotfload/releases + × http://www.ctan.org/pkg/luaotfload + × https://github.com/lualatex/luaotfload/releases - If you are uncertain as to how to proceed, then - ask on the lualatex mailing list: + If you are uncertain as to how to proceed, then + ask on the lualatex mailing list: - http://www.tug.org/mailman/listinfo/lualatex-dev + http://www.tug.org/mailman/listinfo/lualatex-dev - =============================================== + =============================================== ]], errcnt) return true, false end -- cgit v1.2.3 From dfdee4a9f3e968c5493f9e4166503624edfe5eb0 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 08:03:33 +0100 Subject: [db] fix passing inverse format list --- src/luaotfload-database.lua | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index b871954..086f46f 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -1921,9 +1921,8 @@ end local p_font_filter do - local current_formats = { } - local extension_pattern = function (list) + if type (list) ~= "table" or #list == 0 then return P(-1) end local pat for i=#list, 1, -1 do local e = list[i] @@ -1940,6 +1939,8 @@ do --- small helper to adjust the font filter pattern (--formats --- option) + local current_formats = { } + set_font_filter = function (formats) if not formats or type (formats) ~= "string" then -- cgit v1.2.3 From 6c0c403a3b6fa01604935960a46eb1e10a4586af Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 29 Oct 2015 08:22:36 +0100 Subject: [tool,resolvers,db] fix references to the fonts table This makes the ``--find`` option to luaotfload-too work again. --- src/luaotfload-database.lua | 3 ++- src/luaotfload-main.lua | 2 +- src/luaotfload-resolvers.lua | 32 ++++++++++++++++---------------- src/luaotfload-tool.lua | 7 +++---- 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index 086f46f..b84b48d 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -3501,7 +3501,8 @@ return { logreport = luaotfload.log.report local fonts = fonts fonts.names = fonts.names or names - fonts.definers = fonts.definers or { } + fonts.formats = fonts.formats or { } + fonts.definers = fonts.definers or { resolvers = { } } names.blacklist = blacklist names.version = 2.51 diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index ff2b48d..98afee0 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -194,7 +194,7 @@ luaotfload.main = function () initialize "colors" --- Per-font colors. luaotfload.resolvers = loadmodule "resolvers" --- Font lookup - luaotfload.resolvers.install () + luaotfload.resolvers.init () if not config.actions.reconfigure () then logreport ("log", 0, "load", "Post-configuration hooks failed.") diff --git a/src/luaotfload-resolvers.lua b/src/luaotfload-resolvers.lua index 42ea2fd..2e34a4e 100644 --- a/src/luaotfload-resolvers.lua +++ b/src/luaotfload-resolvers.lua @@ -37,15 +37,9 @@ 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. @@ -70,9 +64,9 @@ encodings.known = encodings.known or { } local resolve_file resolve_file = function (specification) - local name = names.lookup_font_file (specification.name) + local name = fonts.names.lookup_font_file (specification.name) local suffix = filesuffix (name) - if formats[suffix] then + if fonts.formats[suffix] then specification.forced = stringlower (suffix) specification.forcedname = fileremovesuffix(name) else @@ -101,7 +95,7 @@ resolve_path = function (specification) resolve_file (specification) else local suffix = filesuffix (name) - if formats[suffix] then + if fonts.formats[suffix] then specification.forced = stringlower (suffix) specification.name = fileremovesuffix(name) specification.forcedname = name @@ -122,9 +116,9 @@ end local resolve_name resolve_name = function (specification) - local resolver = names.lookup_font_name_cached + local resolver = fonts.names.lookup_font_name_cached if config.luaotfload.run.resolver == "normal" then - resolver = names.lookup_font_name + resolver = fonts.names.lookup_font_name end local resolved, subfont = resolver (specification) if resolved then @@ -210,7 +204,7 @@ local resolve_kpse resolve_kpse = function (specification) local name = specification.name local suffix = filesuffix (name) - if suffix and formats[suffix] then + if suffix and fonts.formats[suffix] then name = fileremovesuffix (name) if resolvers.findfile (name, suffix) then specification.forced = stringlower (suffix) @@ -218,7 +212,7 @@ resolve_kpse = function (specification) return end end - for t, format in next, formats do --- brute force + for t, format in next, fonts.formats do --- brute force if kpsefind_file (name, format) then specification.forced = t specification.name = name @@ -238,8 +232,11 @@ local resolve_my = function (specification) end return { - install = function ( ) - luatexbase.create_callback ("luaotfload.resolve_font", "simple", function () end) + init = function ( ) + if luatexbase and luatexbase.create_callback then + luatexbase.create_callback ("luaotfload.resolve_font", + "simple", function () end) + end logreport ("log", 5, "resolvers", "installing font resolvers", name) local request_resolvers = fonts.definers.resolvers request_resolvers.file = resolve_file @@ -248,8 +245,11 @@ return { request_resolvers.path = resolve_path request_resolvers.kpse = resolve_kpse request_resolvers.my = resolve_my + fonts.formats.ofm = "type1" + fonts.encodings = fonts.encodings or { } + fonts.encodings.known = fonts.encodings.known or { } return true - end, --- [.install] + end, --- [.init] } --- vim:ft=lua:ts=8:sw=4:et diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index 8b7bc33..e92f5fb 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -76,7 +76,6 @@ else -- 5.2 runtime = { "stock", _VERSION } end - local C, Ct, P, S = lpeg.C, lpeg.Ct, lpeg.P, lpeg.S local lpegmatch = lpeg.match @@ -84,7 +83,6 @@ local loader_file = "luatexbase.loader.lua" local loader_path = assert(kpsefind_file(loader_file, "lua"), "File '"..loader_file.."' not found") - string.quoted = string.quoted or function (str) return string.format("%q",str) end @@ -171,6 +169,7 @@ loadmodule "log.lua" --- this populates the luaotfload.log.* namespace loadmodule "parsers" --- fonts.conf, configuration, and request syntax loadmodule "configuration" --- configuration file handling loadmodule "database" +loadmodule "resolvers" --- Font lookup local logreport @@ -237,7 +236,7 @@ Usage: %s [OPTIONS...] -c --no-compress do not gzip index file (text version only) -l --flush-lookups empty lookup cache of font requests -D --dry-run skip loading of fonts, just scan - --formats=[+|-]EXTENSIONS set, add, or subtract formats to index + --formats=[+|-]EXTENSIONS set, add, or subtract file formats -p --prefer-texmf prefer fonts in the TEXMF over system fonts --max-fonts=N process at most N font files @@ -1227,7 +1226,7 @@ actions.query = function (job) if tmpspec.lookup == "name" or tmpspec.lookup == "anon" --- not *exactly* as resolvers.anon then - foundname, subfont = fonts.names.resolve_name (tmpspec) + foundname, subfont = fonts.definers.resolvers.name (tmpspec) if foundname then foundname, _, success = fonts.names.font_file_lookup (foundname) end -- cgit v1.2.3 From 72a9a971cb229656e021ab56894ac73baa62c0c0 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 30 Oct 2015 00:15:55 +0100 Subject: [tool] fix --file lookup --- src/luaotfload-tool.lua | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index e92f5fb..5508ffc 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -1226,13 +1226,12 @@ actions.query = function (job) if tmpspec.lookup == "name" or tmpspec.lookup == "anon" --- not *exactly* as resolvers.anon then - foundname, subfont = fonts.definers.resolvers.name (tmpspec) + foundname, _, success = fonts.names.lookup_font_name (tmpspec) if foundname then - foundname, _, success = fonts.names.font_file_lookup (foundname) + foundname, _, success = fonts.names.lookup_font_file (foundname) end elseif tmpspec.lookup == "file" then - foundname, _, success = - fonts.names.font_file_lookup (tmpspec.name) + foundname, _, success = fonts.names.lookup_font_file (tmpspec.name) end if success then -- cgit v1.2.3 From 32d25b33ee109f1979db85d7ddf563246d6bcb7f Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 30 Oct 2015 07:42:58 +0100 Subject: [tool] display fuzzy hint only when not fuzzing --- src/luaotfload-tool.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index 5508ffc..022b659 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -1250,13 +1250,14 @@ actions.query = function (job) end else logreport (false, 0, "resolve", "Cannot find %q in index.", query) - logreport (false, 0, "resolve", - "Hint: use the --fuzzy option to display suggestions.", - query) if job.fuzzy == true then logreport (false, 0, "resolve", "Looking for close matches, this may take a while ...") local _success = fonts.names.find_closest(query, job.fuzzy_limit) + else + logreport (false, 0, "resolve", + "Hint: use the --fuzzy option to display suggestions.", + query) end end return true, true -- cgit v1.2.3 From e1a19fbda5bb54a1378620c8df9c2d42ed087fee Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 30 Oct 2015 07:53:08 +0100 Subject: [db] omit duplicate entries from fuzzed lookup results --- src/luaotfload-database.lua | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index b84b48d..1bc2768 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -1171,6 +1171,25 @@ local iterative_levenshtein = function (s1, s2) return costs[len2]--- lower right has the distance end +--- string list -> string list +local delete_dupes = function (lst) + local n0 = #lst + if n0 == 0 then return lst end + tablesort (lst) + local ret = { } + local last + for i = 1, n0 do + local cur = lst[i] + if cur ~= last then + last = cur + ret[#ret + 1] = cur + end + end + logreport (false, 8, "query", + "Removed %d duplicate names.", n0 - #ret) + return ret +end + --- string -> int -> bool find_closest = function (name, limit) local name = sanitize_fontname (name) @@ -1216,6 +1235,7 @@ find_closest = function (name, limit) else --- append namelst[#namelst+1] = fullname end + by_distance[dist] = namelst end @@ -1229,11 +1249,11 @@ find_closest = function (name, limit) for i = 1, limit do local dist = distances[i] - local namelst = by_distance[dist] + local namelst = delete_dupes (by_distance[dist]) logreport (false, 0, "query", "Distance from \"%s\": %s\n " .. tableconcat (namelst, "\n "), - name, dist) + name, dist) end return true -- cgit v1.2.3 From 330440f784cb12b0902fd80271e568c59da64771 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 5 Nov 2015 22:05:00 +0100 Subject: [main] clean up unused and irrelevant pieces --- src/luaotfload-main.lua | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 98afee0..5fa316d 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -7,23 +7,15 @@ -- MODIFIED: 2015-06-09 23:08:18+0200 ----------------------------------------------------------------------- -- ---- Note: ---- This file was part of the original luaotfload.dtx and has been ---- converted to a pure Lua file during the transition from Luaotfload ---- version 2.4 to 2.5. Thus, the comments are still in TeX (Latex) ---- markup. -local os = os local osgettimeofday = os.gettimeofday - -local initial_log_level = 0 -luaotfload = luaotfload or { } config = config or { } +luaotfload = luaotfload or { } local luaotfload = luaotfload luaotfload.log = luaotfload.log or { } luaotfload.version = "2.6" luaotfload.loaders = { } -luaotfload.min_luatex_version = 79 --- i. e. 0.79 +luaotfload.min_luatex_version = 80 --- i. e. 0.79 luaotfload.fontloader_package = "reference" --- default: from current Context local authors = "\z @@ -40,7 +32,7 @@ local authors = "\z luaotfload.module = { name = "luaotfload-main", version = 2.60001, - date = "2015/05/26", + date = "2015/11/05", description = "OpenType layout system.", author = authors, copyright = authors, -- cgit v1.2.3 From 8395eb8efec1ac9e311541d9834f1a939b91e710 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 5 Nov 2015 22:08:47 +0100 Subject: [*] kill off file headers We have the VCS info in the status file; these things are just silly. --- src/luaotfload-auxiliary.lua | 2 -- src/luaotfload-configuration.lua | 1 - src/luaotfload-diagnostics.lua | 2 -- src/luaotfload-init.lua | 2 -- src/luaotfload-loaders.lua | 1 - src/luaotfload-main.lua | 2 -- src/luaotfload-parsers.lua | 4 +--- src/luaotfload-resolvers.lua | 2 -- src/luaotfload-tool.lua | 2 -- 9 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/luaotfload-auxiliary.lua b/src/luaotfload-auxiliary.lua index dce0d60..15541af 100644 --- a/src/luaotfload-auxiliary.lua +++ b/src/luaotfload-auxiliary.lua @@ -4,8 +4,6 @@ -- DESCRIPTION: part of luaotfload -- REQUIREMENTS: luaotfload 2.6 -- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang --- VERSION: 2.6 --- MODIFIED: 2015-03-29 12:43:26+0200 ----------------------------------------------------------------------- -- diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index 86a302e..6f94195 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -5,7 +5,6 @@ -- REQUIREMENTS: Luaotfload 2.6 or above -- AUTHOR: Philipp Gesang (Phg), -- AUTHOR: Dohyun Kim --- VERSION: same as Luaotfload ------------------------------------------------------------------------------- -- diff --git a/src/luaotfload-diagnostics.lua b/src/luaotfload-diagnostics.lua index 255b5a5..582105a 100644 --- a/src/luaotfload-diagnostics.lua +++ b/src/luaotfload-diagnostics.lua @@ -4,8 +4,6 @@ -- DESCRIPTION: functionality accessible by the --diagnose option -- REQUIREMENTS: luaotfload-tool.lua -- AUTHOR: Philipp Gesang (Phg), --- VERSION: 2.5 --- MODIFIED: 2014-01-02 21:23:06+0100 ----------------------------------------------------------------------- -- local names = fonts.names diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index af71cb2..1c2046d 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -4,8 +4,6 @@ -- DESCRIPTION: Luaotfload font loader initialization -- REQUIREMENTS: luatex v.0.80 or later; packages lualibs, luatexbase -- AUTHOR: Philipp Gesang (Phg), --- VERSION: 1.0 --- CREATED: 2015-05-26 07:50:54+0200 ----------------------------------------------------------------------- -- diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index b644266..38062f6 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -4,7 +4,6 @@ -- DESCRIPTION: Luaotfload callback handling -- REQUIREMENTS: luatex v.0.80 or later; packages lualibs, luatexbase -- AUTHOR: Philipp Gesang (Phg), , Hans Hagen, Khaled Hosny, Elie Roux --- VERSION: just consult Git, okay? ----------------------------------------------------------------------- -- --- Contains parts of the earlier main script. diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 5fa316d..85c9cee 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -3,8 +3,6 @@ -- 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 --- MODIFIED: 2015-06-09 23:08:18+0200 ----------------------------------------------------------------------- -- diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua index 151cb9e..0349cdc 100644 --- a/src/luaotfload-parsers.lua +++ b/src/luaotfload-parsers.lua @@ -2,10 +2,8 @@ ------------------------------------------------------------------------------- -- FILE: luaotfload-parsers.lua -- DESCRIPTION: various lpeg-based parsers used in Luaotfload --- REQUIREMENTS: Luaotfload > 2.6 +-- REQUIREMENTS: Luaotfload >= 2.6 -- AUTHOR: Philipp Gesang (Phg), --- VERSION: same as Luaotfload --- CREATED: 2014-01-14 10:15:20+0100 ------------------------------------------------------------------------------- -- diff --git a/src/luaotfload-resolvers.lua b/src/luaotfload-resolvers.lua index 2e34a4e..3d7f6b0 100644 --- a/src/luaotfload-resolvers.lua +++ b/src/luaotfload-resolvers.lua @@ -5,8 +5,6 @@ -- DESCRIPTION: Resolvers for hooking into the fontloader -- REQUIREMENTS: Luaotfload and a decent bit of courage -- AUTHOR: Philipp Gesang (Phg), --- VERSION: 1.0 --- CREATED: 2015-07-23 07:31:50+0200 ----------------------------------------------------------------------- -- --- The bare fontloader uses a set of simplistic file name resolvers diff --git a/src/luaotfload-tool.lua b/src/luaotfload-tool.lua index 6c54f29..e9a434a 100755 --- a/src/luaotfload-tool.lua +++ b/src/luaotfload-tool.lua @@ -4,9 +4,7 @@ -- DESCRIPTION: database functionality -- REQUIREMENTS: luaotfload 2.6 -- AUTHOR: Khaled Hosny, Élie Roux, Philipp Gesang --- VERSION: 2.6 -- LICENSE: GPL v2.0 --- MODIFIED: 2015-03-29 12:43:00+0200 ----------------------------------------------------------------------- luaotfload = luaotfload or { } -- cgit v1.2.3 From 0a1d8feda744a647f56d97805e6e5d07d107cd71 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 5 Nov 2015 22:16:05 +0100 Subject: [mk*] kill version and modification headers from scripts too --- scripts/mkcharacters | 2 -- scripts/mkglyphlist | 2 -- scripts/mkimport | 2 -- scripts/mktests | 2 -- 4 files changed, 8 deletions(-) diff --git a/scripts/mkcharacters b/scripts/mkcharacters index abed2c9..9e9fd1a 100755 --- a/scripts/mkcharacters +++ b/scripts/mkcharacters @@ -5,8 +5,6 @@ -- DESCRIPTION: import parts of char-def.lua -- REQUIREMENTS: lua, ConTeXt, the lualibs package -- AUTHOR: Philipp Gesang (Phg), --- VERSION: 2.5 --- MODIFIED: 2014-02-11 07:24:25+0100 ----------------------------------------------------------------------- -- we create a stripped-down version of char-def.lua ----------------------------------------------------------------------- diff --git a/scripts/mkglyphlist b/scripts/mkglyphlist index 8fde098..f66a686 100755 --- a/scripts/mkglyphlist +++ b/scripts/mkglyphlist @@ -5,8 +5,6 @@ -- DESCRIPTION: part of the luaotfload package -- REQUIREMENTS: lua, lpeg, luasocket, the lualibs package -- AUTHOR: Philipp Gesang (Phg), --- VERSION: 2.5 --- MODIFIED: 2014-02-11 06:44:50+0100 ----------------------------------------------------------------------- -- interesting thread on the Context list: -- http://www.ntg.nl/pipermail/ntg-context/2008/029057.html diff --git a/scripts/mkimport b/scripts/mkimport index 0833ccb..e8b83c0 100755 --- a/scripts/mkimport +++ b/scripts/mkimport @@ -5,8 +5,6 @@ -- DESCRIPTION: check luaotfload imports against Context -- REQUIREMENTS: luatex, the lualibs package, Context MkIV -- AUTHOR: Philipp Gesang (Phg), --- VERSION: 42 --- CREATED: 2014-12-08 22:36:15+0100 ------------------------------------------------------------------------------- -- diff --git a/scripts/mktests b/scripts/mktests index b36b6dd..757e360 100755 --- a/scripts/mktests +++ b/scripts/mktests @@ -5,8 +5,6 @@ -- DESCRIPTION: test the behavior of Luaotfload -- REQUIREMENTS: Luatex > 0.76, Luaotfload -- AUTHOR: Philipp Gesang (Phg), --- VERSION: 2.4 --- MODIFIED: 2014-05-15 22:16:47+0200 ----------------------------------------------------------------------- -- --===================================================================-- -- cgit v1.2.3 From de66d7228b7b91c93cb38c8bf50008f7137b0985 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 5 Nov 2015 23:07:53 +0100 Subject: [graph] update to current state of affairs --- doc/Makefile | 2 +- doc/filegraph.dot | 175 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 126 insertions(+), 51 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index ed340a4..6d68281 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -47,7 +47,7 @@ $(DOTPDF): $(DOT) @echo "creating file graph ($(DOTPDF))" $(DO_GRAPHVIZ) -.PHONY: clean mrproper +.PHONY: clean mrproper graph doc all manuals clean: @$(RM) -- *.log *.aux *.toc *.idx *.ind *.ilg *.out diff --git a/doc/filegraph.dot b/doc/filegraph.dot index e1a9937..af3c8ad 100644 --- a/doc/filegraph.dot +++ b/doc/filegraph.dot @@ -10,8 +10,8 @@ strict digraph luaotfload_files { //looks weird with circo ... size = "21cm"; rankdir = LR; - ranksep = 0.618; - nodesep = 1.618; + ranksep = 0.618; + nodesep = 1.618; edge [ arrowhead = onormal, @@ -30,37 +30,38 @@ strict digraph luaotfload_files { //looks weird with circo ... fontdbutil -> font_names [label="--update", style=dashed] - luaotfload -> otfl_fonts_merged [label="merged"] - luaotfload -> merged_lua_libs [label="unmerged", style=solid] - luaotfload -> merged_luatex_fonts [label="unmerged", style=solid] - luaotfload -> merged_context_libs [label="unmerged", style=solid] + luaotfload -> merged_lua_libs [style=solid] + luaotfload -> luaotfload_init [label="main()", style=solid] + luaotfload -> luaotfload_libs [label="main()", style=solid] - luaotfload -> luaotfload_libs - luaotfload -> otfl_blacklist_cnf - - otfl_fonts_merged -> merged_lua_libs [label="merged", - style=dotted, - lhead=cluster_merged] - otfl_fonts_merged -> merged_luatex_fonts [label="merged", + fontloader -> merged_luatex_fonts [label="merged", style=dotted, lhead=cluster_merged] - otfl_fonts_merged -> merged_context_libs [label="merged", + fontloader -> merged_context_libs [label="merged", style=dotted, lhead=cluster_merged] + luaotfload_init -> luaotfload_log [label="init_early()", style=solid] + luaotfload_init -> luaotfload_basics_gen [label="init_early()", style=solid] + luaotfload_init -> fontloader [label="init_main()", style=solid] + + luaotfload_init -> merged_luatex_fonts [label="unmerged", style=solid] + luaotfload_init -> merged_context_libs [label="unmerged", style=solid] + merged_luatex_fonts -> font_age [label="luatex-fonts-enc.lua", ltail=cluster_merged] fontdbutil -> fontdbutil_diagnostics [label="--diagnose"] - fontdbutil -> status [label="version information"] - fontdbutil_diagnostics -> status [constraint=no, label="hash files"] + luaotfload_package -> fontloader [label="merges", style=dashed] merged_luatex_fonts -> characters [label="luaotfload-auxiliary.lua", ltail=cluster_merged] - luaotfload_libs -> font_names [label="luaotfload-database.lua"] + luaotfload_libs -> font_names [label="luaotfload-database.lua"] + luaotfload_libs -> otfl_blacklist_cnf [label="luaotfload-database.lua"] + mkstatus -> status [label="generates from distribution files", style=dashed] @@ -71,13 +72,30 @@ strict digraph luaotfload_files { //looks weird with circo ... mkcharacters -> characters [label="generates from Context’s char-def.lua", style=dashed] + fontdbutil_diagnostics -> status [label="hash files"] + + mkimport -> merged_luatex_fonts [label="pulls", style=dashed, constraint=no]; + mkimport -> merged_context_libs [label="pulls", style=dashed, constraint=no]; + subgraph { rank = same; - mkcharacters; - mkglyphlist; - mkstatus; fontdbutil; luaotfload } + subgraph cluster_scripts { + node [style=filled, color=white]; + style = "filled,rounded"; + color = "#44000011:#CCCCCC77"; + //nodesep = "3.0"; + rank = same; + label = "Standalone scripts"; + gradientangle=90; + mkcharacters; + mkglyphlist; + mkimport; + mktest; + mkstatus; + } + /* ···································································· * main files * ································································· */ @@ -90,6 +108,14 @@ strict digraph luaotfload_files { //looks weird with circo ... style = "filled,rounded", penwidth=2] + luaotfload_package [label = "luaotfload-package.lua", + shape = rect, + width = "3.2cm", + height = "1.2cm", + color = "#01012222", + style = "filled,rounded", + penwidth=2] + fontdbutil_diagnostics [label = "luaotfload-diagnostics.lua", shape = rect, width = "3.2cm", @@ -98,27 +124,43 @@ strict digraph luaotfload_files { //looks weird with circo ... style = "filled,rounded", penwidth=2] + mktest [label = "mktest", + shape = rect, + width = "3.2cm", + height = "0.618cm", + color = "#FFFFFF66", + style = "filled,rounded", + penwidth=2] + + mkimport [label = "mkimport", + shape = rect, + width = "3.2cm", + height = "0.618cm", + color = "#FFFFFF66", + style = "filled,rounded", + penwidth=2] + mkstatus [label = "mkstatus", shape = rect, width = "3.2cm", - height = "1.2cm", - color = "#01012222", + height = "0.618cm", + color = "#FFFFFF66", style = "filled,rounded", penwidth=2] mkglyphlist [label = "mkglyphlist", shape = rect, width = "3.2cm", - height = "1.2cm", - color = "#01012222", + height = "0.618cm", + color = "#FFFFFF66", style = "filled,rounded", penwidth=2] mkcharacters [label = "mkcharacters", shape = rect, width = "3.2cm", - height = "1.2cm", - color = "#01012222", + height = "0.618cm", + color = "#FFFFFF66", style = "filled,rounded", penwidth=2] @@ -138,13 +180,37 @@ strict digraph luaotfload_files { //looks weird with circo ... * style = "filled,rounded", * penwidth=2] */ - otfl_fonts_merged [label = "luaotfload-fontloader.lua", - shape = rect, - width = "3.2cm", - height = "1.2cm", - color = "#01012222", - style = "filled,rounded", - penwidth=2] + luaotfload_init [label = "luaotfload-init.lua", + shape = rect, + width = "3.2cm", + height = "1.2cm", + color = "#44440122", + style = "filled,rounded", + penwidth=2] + + luaotfload_log [label = "luaotfload-log.lua", + shape = rect, + width = "3.2cm", + height = "1.2cm", + color = "#44440122", + style = "filled,rounded", + penwidth=2] + + luaotfload_basics_gen [label = "fontloader-basics-gen.lua", + shape = rect, + width = "3.2cm", + height = "1.2cm", + color = "#FFFFFF66", + style = "filled,rounded", + penwidth=2] + + fontloader [label = "fontloader-reference.lua", + shape = rect, + width = "3.2cm", + height = "1.2cm", + color = "#FFFFFF66", + style = "filled,rounded", + penwidth=2] /* ···································································· * luaotfload files @@ -193,15 +259,16 @@ strict digraph luaotfload_files { //looks weird with circo ... luaotfload_libs [ shape = box, style = "filled,rounded", - color = "grey90:goldenrod4", + color = "grey90", fontsize = 10, label = < - - - - + + + + +
Luaotfload Libraries
luaotfload-auxiliary.lua luaotfload-features.lua
luaotfload-loaders.lua luaotfload-color.lua
luaotfload-log.lua luaotfload-letterspace.lua
luaotfload-parsers.lua luaotfload-database.lua
luaotfload-auxiliary.lua luaotfload-features.lua
luaotfload-loaders.lua luaotfload-colors.lua
luaotfload-resolvers.lua luaotfload-letterspace.lua
luaotfload-parsers.lua luaotfload-database.lua
luaotfload-configuration.lua
>, ] @@ -213,28 +280,40 @@ strict digraph luaotfload_files { //looks weird with circo ... subgraph cluster_merged { node [style=filled, color=white]; style = "filled,rounded"; - color = "grey90:dodgerblue4"; + color = "#912CEE33"; //nodesep = "3.0"; rank = same; label = "Merged Libraries"; gradientangle=0; - merged_lua_libs; merged_luatex_fonts; merged_context_libs; } - otfl_fonts_merged -> merged_lua_libs - otfl_fonts_merged -> merged_luatex_fonts - otfl_fonts_merged -> merged_context_libs + fontloader -> merged_luatex_fonts + fontloader -> merged_context_libs + + subgraph cluster_fontloader { + node [style=filled, color=white]; + style = "filled,rounded"; + color = "bisque"; + //nodesep = "3.0"; + rank = same; + label = "Fontloader"; + gradientangle=0; + luaotfload_basics_gen; + fontloader; + } merged_lua_libs [ shape = box, style = "filled,rounded", - color = "#FFFFFFAA", + color = "#CCCC1166", + fontsize = 10, fontsize = 10, label = < - + @@ -251,17 +330,13 @@ strict digraph luaotfload_files { //looks weird with circo ... label = <
Lua Libraries from Context + Lualibs – Lua Libraries from Context
l-lua.lua l-lpeg.lua l-function.lua
l-string.lua l-table.lua l-io.lua
l-file.lua l-boolean.lua l-math.lua
- + - - - -
Font Loader (LuaTeX-Fonts)
luatex-basics-gen.lua luatex-basics-nod.lua
luatex-fonts-cbk.lua luatex-basics-nod.lua
luatex-fonts-enc.lua luatex-fonts-syn.lua
luatex-font-tfm.lua luatex-font-afm.lua
luatex-font-afk.lua luatex-fonts-tfm.lua
luatex-fonts-chr.lua luatex-fonts-lua.lua
luatex-fonts-inj.lua luatex-fonts-otn.lua
luatex-fonts-def.lua luatex-fonts-ext.lua
luatex-fonts-cbk.lua
>, ] -- cgit v1.2.3 From 6b80e23341e454f6416d8c36c16820dcdf9a7bba Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 5 Nov 2015 23:09:12 +0100 Subject: [doc] kill off Context prototype This was an experiment to improve documentation. Certain items like the BNF syntax of the request parser proved too tedious to convert. Also verbatim semantics differ greatly which requires tons of hacks to work around. Not worth it. --- doc/luaotfload-context.tex | 485 --------------------------------------------- 1 file changed, 485 deletions(-) delete mode 100644 doc/luaotfload-context.tex diff --git a/doc/luaotfload-context.tex b/doc/luaotfload-context.tex deleted file mode 100644 index 6c8d4b2..0000000 --- a/doc/luaotfload-context.tex +++ /dev/null @@ -1,485 +0,0 @@ -% macros=mkvi -%% Copyright (C) 2009-2014 -%% -%% by Elie Roux -%% and Khaled Hosny -%% and Philipp Gesang -%% -%% This file is part of Luaotfload. -%% -%% Home: https://github.com/lualatex/luaotfload -%% Support: . -%% -%% Luaotfload is under the GPL v2.0 (exactly) license. -%% -%% ---------------------------------------------------------------------------- -%% -%% Luaotfload is free software; you can redistribute it and/or -%% modify it under the terms of the GNU General Public License -%% as published by the Free Software Foundation; version 2 -%% of the License. -%% -%% Luaotfload is distributed in the hope that it will be useful, -%% but WITHOUT ANY WARRANTY; without even the implied warranty of -%% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -%% GNU General Public License for more details. -%% -%% You should have received a copy of the GNU General Public License -%% along with Luaotfload; if not, see . -%% -%% ---------------------------------------------------------------------------- -%% - -\unprotect - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% layout and paper -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\setuppapersize [A5] [A5] %% 148×210 - -\definelayout [mainlayout] [ - backspace=15mm, %% 133 - textwidth=103mm, - topspace=15mm, -] - -\setuplayout [mainlayout] - -\setuppagenumbering [location=,alternative=doublesided] - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% colors -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\usecolors [x11] -\definecolor [primarycolor] [dodgerblue4] -\definecolor [secondarycolor] [goldenrod4] - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% interaction -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\setupinteraction [ - state=start, - page=no, - click=yes, - style=italic, - color=primarycolor, - contrastcolor=secondarycolor, - title={The Luaotfload package}, - subtitle={OpenType layout system for Plain TeX and LaTeX}, - author={Elie Roux & Khaled Hosny & Philipp Gesang}, - keywords={luatex, lualatex, unicode, opentype}, -] - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% fonts -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\usemodule [simplefonts] - -\definefontfeature [default] [default] [mode=base,liga=yes,dlig=yes,tlig=yes,onum=yes] -\definefontfeature [monospace] [liga=no,tlig=no,onum=no] - -\definefontfamily [mainface] [serif] [Linux Libertine O] [features=default] -%definefontfamily [mainface] [serif] [Liberation Serif] [feature=default] -%definefontfamily [mainface] [sans] [Iwona] [feature=default] -\definefontfamily [mainface] [sans] [Iwona Medium] [ - feature=default, - it=file:IwonaMedium-Italic.otf, - tf=file:IwonaMedium-Regular.otf, - bf=file:Iwona-Bold.otf, - bi=file:Iwona-BoldItalic.otf, -] -%definefontfamily [mainface] [sans] [DejaVu Sans] [feature=default] -\definefontfamily [mainface] [mono] [Liberation Mono] [scale=0.85,features=monospace] - -\setupbodyfont [mainface,10pt] - -\def \LUA {Lua} -\def \LUALATEX {Lua\LATEX} -\def \OpenType {\identifier{Open\kern-.25ex Type}} - -\definealternativestyle [emphasis:texmacro] [\ss \it \letterbackslash] [\ss \it \letterbackslash] -\definealternativestyle [emphasis:identifier] [\ss] [\ss] -\definealternativestyle [emphasis:normal] [\sl] [\sl] -\definealternativestyle [emphasis:abbrev] [{\feature [+][smallcaps]}] [{\feature [+][smallcaps]}] -\definealternativestyle [emphasis:Largefont] [{\switchtobodyfont[14pt]}] [{\switchtobodyfont[14pt]}] -\definealternativestyle [emphasis:smallcaps] [{\feature [+][smallcaps]}] [{\feature [+][smallcaps]}] -%definealternativestyle [emphasis:nonproportional] [\mono] [\mono] -\definealternativestyle [emphasis:nonproportional] [\tt] [\tt] -\definealternativestyle [head:section] [{\roman\feature[+][smallcaps]}] [{\roman\feature[+][smallcaps]}] -\definealternativestyle [head:subsection] [{\roman\feature[+][smallcaps]}] [{\roman\feature[+][smallcaps]}] -\definealternativestyle [head:subsubsection] [{\roman\feature[+][smallcaps]}] [{\roman\feature[+][smallcaps]}] -\definealternativestyle [typing:luafunction] [\italic] [\italic] -\definealternativestyle [typing:fileent] [\tt] [\tt] - -\definehighlight [texmacro] [style=emphasis:texmacro] %% cs -\definehighlight [identifier] [style=emphasis:identifier] %% names -\definehighlight [abbrev] [style=emphasis:abbrev] %% acronyms -\definehighlight [emphasis] [style=emphasis:normal] %% level 1 emph - -\definehighlight [Largefont] [style=emphasis:Largefont] %% font size -\definehighlight [smallcaps] [style=emphasis:smallcaps] %% font feature -\definehighlight [nonproportional] [style=emphasis:nonproportional] %% font switch - -\definetype [fileent] [style=typing:fileent] -\definetype [luafunction] [style=typing:luafunction] -\setuptyping [style=ttx] - -\definebodyfontenvironment [8pt] -\definebodyfontenvironment [10pt] -\definebodyfontenvironment [12pt] - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% headings -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\setuphead [section] [style=head:section, alternative=inmargin] -\setuphead [subsection] [style=head:subsection, alternative=inmargin] -\setuphead [subsubsection] [style=head:subsubsection,alternative=inmargin] - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% running headers -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\setupheadertexts - [{\tfx \getmarking[section]}] [pagenumber] - [pagenumber] [{\tfx \fileent{Luaotfload} Manual}] - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% structurals -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% section -\def \beginsection {\dosingleempty \section_begin_indeed} - -\def \section_begin_indeed [#ref]#title{% - \iffirstargument - \startsection [reference=#ref,title=#title]% - \else - \startsection [title=#title]% - \fi -} - -\let \endsection \stopsection - -%% subsection -\def \beginsubsection {\dosingleempty \section_begin_indeed} - -\def \subsection_begin_indeed [#ref]#title{% - \iffirstargument - \startsubsection [reference=#ref,title=#title]% - \else - \startsubsection [title=#title]% - \fi -} - -\let \endsubsection \stopsection - -%% subsubsection -\def \beginsubsubsection {\dosingleempty \section_begin_indeed} - -\def \subsubsection_begin_indeed [#ref]#title{% - \iffirstargument - \startsubsubsection [reference=#ref,title=#title]% - \else - \startsubsubsection [title=#title]% - \fi -} - -\let \endsubsubsection \stopsection - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% inline verbatim -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -%% Context offers both \type{…} and \type<<…>>, but not an unbalanced -%% one that we could map directly onto Latex’s \verb|…|. - -\definetype [inlinecode_indeed] [style=emphasis:nonproportional] - -%% The listings macros don’t seem to handle backslashes and braces -%% well. We emulate this behavior by handling the escaping in Lua. - -\startluacode - local lpeg = require "lpeg" - local Cs, P, S = lpeg.Cs, lpeg.P, lpeg.S - local lpegmatch = lpeg.match - local unescape_char = S[[\letterbackslash\letterleftbrace\letterrightbrace]] - local backslash = P[[\letterbackslash]] - local unescape = Cs (((backslash / "" * unescape_char) + 1)^0) - commands.unescape_things = function (str) - context.type (lpegmatch (unescape, str)) - end -\stopluacode - -\unexpanded \def \inlinecode #content{% - \ctxcommand {unescape_things \!!bs \detokenize {#content}\!!es}% -} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% codelistings -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% Now *that’s* what I call easy. - -\unexpanded \def \beginlisting {% - \grabbufferdatadirect{listing}{beginlisting}{endlisting}% -} - -\unexpanded \def \endlisting {\typebuffer [listing]} - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% enumerations and lists -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\definedescription [descriptionitem] [ - align=right, - alternative=hanging, - width=2em, -] - -\def \begindescriptions {% - \begingroup - \def \beginnormalitem ##1\endnormalitem{% - \startitem##1\stopitem - } - \let \endnormalitem \relax - \let \beginaltitem \startdescriptionitem - \let \endaltitem \stopdescriptionitem -} - -\let \enddescriptions \endgroup - - -\definedescription [definitionitem] [ - align=right, - alternative=hanging, -] - -\def \begindefinitions {% - \begingroup - \def \beginnormalitem ##1\endnormalitem{% - \startitem##1\stopitem - } - \let \endnormalitem \relax - \let \beginaltitem \startdefinitionitem - \let \endaltitem \stopdefinitionitem -} - -\let \enddefinitions \endgroup - - -\definedescription [filelistitem] [ - align=normal, - alternative=hanging, - headstyle=typing:fileent, - width=4cm, -] - -\def \beginfilelist {% - \begingroup - \def \beginnormalitem ##1\endnormalitem{% - \startitem##1\stopitem - } - \let \endnormalitem \relax - \let \beginaltitem \startfilelistitem - \let \endaltitem \stopfilelistitem -} - -\let \endfilelist \endgroup - -\definedescription [functionlistitem] [ - align=normal, - alternative=hanging, - headstyle=typing:luafunction, - width=4cm, -] - -\def \beginfunctionlist {% - \begingroup - \def \beginnormalitem ##1\endnormalitem{% - \startitem##1\stopitem - } - \let \endnormalitem \relax - \let \beginaltitem \startfunctionlistitem - \let \endaltitem \stopfunctionlistitem -} - -\let \endfunctionlist \endgroup - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% columns -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\def \begindoublecolumns {\startcolumns [2]} -\let \enddoublecolumns \stopcolumns - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% alignment -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\setupnarrower [before={\blank[line]},after={\blank[line]}] -\let \beginnarrower \startnarrower -\let \endnarrower \stopnarrower - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% special elements -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\definefont [lmromantenregular] [file:lmroman10-regular.otf*default] - -\def \meta #1{% - {\lmromantenregular<}% - {\italic #1}% - {\lmromantenregular>}% -} - -\def \beginabstractcontent {% - \grabbufferdatadirect{abstractcontent}{beginabstractcontent}{endabstractcontent}% -} - -\let \endabstractcontent \relax - -\def \setdocumenttitle #1{\setvalue {document_title}{#1}} -\def \setdocumentdate #1{\setvalue {document_date}{#1}} -\def \setdocumentauthor #1{\setvalue {document_author}{#1}} - -\let \typesetdocumenttitle \relax -\let \beginfrontmatter \relax - -\def \endfrontmatter { - \startstandardmakeup - \vfill - \strut \hfill - \startframed [frame=off,align=middle,width=.5\textwidth] - \Largefont{\getvalue {document_title}} - \stopframed - \hfill \strut \par - - \blank [2*big] - - \strut \hfill - \startframed [frame=off,align=middle,width=.65\textwidth] - \setuplocalinterlinespace [18pt] - \getvalue {document_author} - \stopframed - \hfill \strut \par - - \vfill - \strut \hfill \getvalue {document_date} \hfill \strut - \blank [2*big] - - \strut \hfill - \startframed [width=.7\textwidth,align=normal,style=tfx,frame=off]% - \getbuffer [abstractcontent] - \stopframed - \hfill \strut - \stopstandardmakeup -} - -\let \typesetcontent \completecontent - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% floats -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% XXX we can improve on this part later - -\usemodule [vim] -\definevimtyping [bnf] [syntax=bnf] -\definefloat [syntax] [figure] - -\def \beginsyntaxfloat #reference#caption{% - \begingroup - \edef \currentreference {#reference}% - \edef \currentcaption {#caption}% - \grabbufferdatadirect{rawsyntaxdata}{beginsyntaxfloat}{endsyntaxfloat}% -} - -\def \endsyntaxfloat {% - \savebuffer [rawsyntaxdata] [rawsyntaxdata] - \startplacesyntax [ - reference=\currentreference, - title={\currentcaption}, - ] - %% there’s no \typebnfbuffer in t-vim :( - \typebnffile {\jobname-rawsyntaxdata.tmp} - \stopplacesyntax - \endgroup% -} - -\def \figurefloat #reference#caption#file{% - \startplacefigure [ - reference=#reference, - title={#caption}, - ] - \externalfigure [#file] [width=\textwidth] - \stopplacefigure -} - - -\def \tablefloat #reference#caption#content{% - \startplacetable [ - reference=#reference, - title={#caption}, - ] - #content - \stopplacetable -} - - -%% tables - - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% tables -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\setupxtable [frame=off,option=stretch,textwidth=\dimexpr(\textwidth/2)] - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% hyperlinks and references -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\unexpanded \def \hyperlink{% - \dosingleempty \hyperlink_indeed% -} - -\def \hyperlink_indeed [#text]#url{% - \iffirstargument - \useURL [temporary_url] [#url] [] [#text]% - \else - \useURL [temporary_url] [#url]% - \fi% - \from [temporary_url]% -} - - -\def \email #1{\goto{#1}[url(mailto:#1)]} - -\def \label #tag{\reference [#tag]\empty} -\def \pageref #tag{\at{page}{#tag}} - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% escaped characters -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\let \charpercent \letterpercent -\let \charbackslash \letterbackslash -\let \chartilde \lettertilde - -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -%% main -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - -\protect - -\newif \ifcontextmkiv \contextmkivtrue - -\starttext - \input luaotfload-main.tex -\stoptext - -- cgit v1.2.3 From 4540a7d25d8a2dbbc3c773f2f27f2f1d7604b2ea Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 5 Nov 2015 23:29:15 +0100 Subject: [doc] fix manual build MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit ``\luafunction`` appears to now have some fragile semantics that we’d rather avoid. Also the Latex folks finally got rid of the ``\luatex…`` namespace for primitives. --- doc/luaotfload-latex.tex | 6 +++--- doc/luaotfload-main.tex | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/doc/luaotfload-latex.tex b/doc/luaotfload-latex.tex index 34c494d..9f09f4f 100644 --- a/doc/luaotfload-latex.tex +++ b/doc/luaotfload-latex.tex @@ -1,4 +1,4 @@ -\luatexsuppresslongerror1%% sigh ... +\suppresslongerror1%% sigh ... %% Copyright (C) 2009-2014 %% %% by Elie Roux @@ -129,7 +129,7 @@ \definehighlight [fileent][\ttfamily\restoreunderscore] %% files, dirs \definehighlight [texmacro][\sffamily\itshape\textbackslash] %% cs -\definehighlight [luafunction][\sffamily\itshape\restoreunderscore] %% lua identifiers +\definehighlight [luaident][\sffamily\itshape\restoreunderscore] %% lua identifiers \definehighlight [identifier][\sffamily] %% names \definehighlight [abbrev][\rmfamily\scshape] %% acronyms \definehighlight [emphasis][\rmfamily\slshape] %% level 1 emph @@ -301,7 +301,7 @@ \definelist [descriptions]{\normalitem {\textbf \first}\hfill\break} \definelist [definitions]{\normalitem {\fileent {\first}}} \definelist [filelist]{\normalitem {\fileent {\first}}\space--\hskip 1em} -\definelist [functionlist]{\normalitem {\luafunction {\first}}\hfill\break} +\definelist [functionlist]{\normalitem {\luaident {\first}}\hfill\break} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %% columns diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index c01beba..8f548fa 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -32,7 +32,7 @@ \beginfrontmatter \setdocumenttitle {The \identifier{luaotfload} package} - \setdocumentdate {2015/03/29 v2.6} + \setdocumentdate {2015/11/05 v2.6} \setdocumentauthor {Elie Roux · Khaled Hosny · Philipp Gesang\\ Home: \hyperlink {https://github.com/lualatex/luaotfload}\\ Support: \email {lualatex-dev@tug.org}} @@ -233,7 +233,7 @@ where \meta{prefix} is either \inlinecode{file:} or \inlinecode {name:}.\footnot needed, for instance when supplying a customized tex distribution. The \inlinecode {my} lookup takes this a step further: it lets you define - a custom resolver function and hook it into the \luafunction{resolve_font} + a custom resolver function and hook it into the \luaident{resolve_font} callback. % This ensures full control over how a file is located. @@ -664,7 +664,7 @@ obviously, \inlinecode{random}. Specific pairs of letters and ligatures may be exempt from letterspacing by defining the \LUA functions - \luafunction{keeptogether} and \luafunction{keepligature}, + \luaident{keeptogether} and \luaident{keepligature}, respectively, inside the namespace \inlinecode {luaotfload.letterspace}. % Both functions are called whenever the letterspacing callback @@ -673,10 +673,10 @@ obviously, \inlinecode{random}. If they return a true-ish value, no extra kern is inserted at the current position. % - \luafunction{keeptogether} receives a pair of consecutive + \luaident{keeptogether} receives a pair of consecutive glyph nodes in order of their appearance in the node list. % - \luafunction{keepligature} receives a single node which can be + \luaident{keepligature} receives a single node which can be analyzed into components. % (For details refer to the \emphasis{glyph nodes} section in the @@ -1254,7 +1254,7 @@ The purpose of this addition twofold. Firstly, \identifier{luaotfload} failed to provide a stable interface to internals in the past which resulted in an unmanageable situation of different packages abusing the raw access to font objects by means -of the \luafunction{patch_font} callback. +of the \luaident{patch_font} callback. % When the structure of the font object changed due to an update, all of these imploded and several packages had to be fixed while @@ -1275,7 +1275,7 @@ additions. \beginsubsection {Callback Functions} -The \luafunction{patch_font} callback is inserted in the wrapper +The \luaident{patch_font} callback is inserted in the wrapper \identifier{luaotfload} provides for the font definition callback. % At this place it allows manipulating the font object immediately after @@ -1367,8 +1367,8 @@ are defined for which scripts. \beginfunctionlist \beginaltitem {aux.font_has_glyph (id : int, index : int)} - Predicate that returns true if the font \luafunction{id} - has glyph \luafunction{index}. + Predicate that returns true if the font \luaident{id} + has glyph \luaident{index}. \endaltitem \beginaltitem {aux.slot_of_name(name : string)} @@ -1377,33 +1377,33 @@ are defined for which scripts. \endaltitem \beginaltitem {aux.name_of_slot(slot : int)} - The inverse of \luafunction{slot_of_name}; note that this + The inverse of \luaident{slot_of_name}; note that this might be incomplete as multiple glyph names may map to the same codepoint, only one of which is returned by - \luafunction{name_of_slot}. + \luaident{name_of_slot}. \endaltitem \beginaltitem {aux.provides_script(id : int, script : string)} - Test if a font supports \luafunction{script}. + Test if a font supports \luaident{script}. \endaltitem \beginaltitem {aux.provides_language(id : int, script : string, language : string)} - Test if a font defines \luafunction{language} for a given - \luafunction{script}. + Test if a font defines \luaident{language} for a given + \luaident{script}. \endaltitem \beginaltitem {aux.provides_feature(id : int, script : string, language : string, feature : string)} - Test if a font defines \luafunction{feature} for - \luafunction{language} for a given \luafunction{script}. + Test if a font defines \luaident{feature} for + \luaident{language} for a given \luaident{script}. \endaltitem \beginaltitem {aux.get_math_dimension(id : int, dimension : string)} - Get the dimension \luafunction{dimension} of font \luafunction{id}. + Get the dimension \luaident{dimension} of font \luaident{id}. \endaltitem \beginaltitem {aux.sprint_math_dimension(id : int, dimension : string)} - Same as \luafunction{get_math_dimension()}, but output the value + Same as \luaident{get_math_dimension()}, but output the value in scaled points at the \TEX end. \endaltitem @@ -1416,7 +1416,7 @@ are defined for which scripts. %% not implemented, may come back later \beginfunctionlist % \beginaltitem {aux.scan_external_dir(dir : string)} -% Include fonts in directory \luafunction{dir} in font lookups without +% Include fonts in directory \luaident{dir} in font lookups without % adding them to the database. % \beginaltitem {aux.read_font_index (void)} @@ -1527,9 +1527,9 @@ Another strategy that helps avoiding problems is to not access raw Some of them, even though they are dangerous to access, have not been overridden or disabled. % -Thus, whenever possible prefer the functions in the \luafunction{aux} +Thus, whenever possible prefer the functions in the \luaident{aux} namespace over direct manipulation of font objects. For example, raw -access to the \luafunction{font.fonts} table like: +access to the \luaident{font.fonts} table like: \beginlisting local somefont = font.fonts[2] @@ -1537,16 +1537,16 @@ access to the \luafunction{font.fonts} table like: \noindent can render already defined fonts unusable. % -Instead, the function \luafunction{font.getfont()} should be used +Instead, the function \luaident{font.getfont()} should be used because it has been replaced by a safe variant. -However, \luafunction{font.getfont()} only covers fonts handled by the +However, \luaident{font.getfont()} only covers fonts handled by the font loader, e.~g. \identifier{OpenType} and \identifier{TrueType} fonts, but not \abbrev{tfm} or \abbrev{ofm}. % Should you absolutely require access to all fonts known to \LUATEX, including the virtual and autogenerated ones, then you need to query -both \luafunction{font.getfont()} and \luafunction{font.fonts}. +both \luaident{font.getfont()} and \luaident{font.fonts}. % In this case, best define you own accessor: -- cgit v1.2.3 From 3f18c8edd4a571eb57faebc18a423e541f474ea2 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 5 Nov 2015 23:39:38 +0100 Subject: [*] update NEWS --- NEWS | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS b/NEWS index bf2441d..d5688b6 100644 --- a/NEWS +++ b/NEWS @@ -15,6 +15,8 @@ Change History initialization * Write names index if fonts were removed * Separate module loading from initialization + * Custom fontloader package with the files from Lualibs removed + * Lualibs are now a dependency when used in a TeX run as well 2014/07/13, luaotfload v2.5 * Remove legacy code. -- cgit v1.2.3 From 6a7d1e67bb6e6fd073450a104ebe3ca934eaf14c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 6 Nov 2015 00:02:56 +0100 Subject: [doc] update manual wrt files --- doc/luaotfload-main.tex | 104 ++++++++++++++++++++++++++++-------------------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index 8f548fa..a5ed940 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -1056,23 +1056,21 @@ An example with explicit paths: \endsection %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\beginsection {Files from \CONTEXT and \LUATEX-Fonts} +\beginsection {The Fontloader Package} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\identifier{luaotfload} relies on code originally written by Hans -Hagen for the \hyperlink[\identifier{\CONTEXT}]{http://wiki.contextgarden.net} +To a large extent, \identifier{luaotfload} relies on code originally +written by Hans Hagen for the +\hyperlink[\identifier{\CONTEXT}]{http://wiki.contextgarden.net} format. % -It integrates the font loader as distributed in -the \identifier{\LUATEX-Fonts} package. +It integrates the font loader, written entirely in \LUA, as distributed +in the \identifier{\LUATEX-Fonts} package. % The original \LUA source files have been combined using the -\fileent{mtx-package} script into a single, self-contained blob. -In this form the font loader has no further dependencies\footnote{% - It covers, however, to some extent the functionality of the - \identifier{lualibs} package. -} -and requires only minor adaptions to integrate into +\fileent{mtx-package} script into a single, self-contained blob. In +this form the font loader depends only on the \identifier{lualibs} +package and requires only minor adaptions to integrate into \identifier{luaotfload}. % The guiding principle is to let \CONTEXT/\LUATEX-Fonts take care of @@ -1093,13 +1091,13 @@ Below is a commented list of the files distributed with See figure \ref{file-graph} on page \pageref{file-graph} for a graphical representation of the dependencies. % -From \LUATEX-Fonts, only the file \fileent{luatex-fonts-merged.lua} -has been imported as \fileent{luaotfload-fontloader.lua}. -% -It is generated by \fileent{mtx-package}, a \LUA source code merging -too developed by Hans Hagen.\footnote{% - \fileent{mtx-package} is - \hyperlink [part of \CONTEXT]{http://repo.or.cz/w/context.git/blob_plain/refs/heads/origin:/scripts/context/lua/mtx-package.lua} +Through the script \fileent{luaotfload-package.lua} the \CONTEXT +utility \fileent{mtx-package} is invoked to create the +\identifier{luaotfload} fontloader as a merged (amalgamated) source +file.\footnote{% + \fileent{mtx-package}, a \LUA source code merging tool developed by + Hans Hagen, is + \hyperlink [part of \CONTEXT]{https://bitbucket.org/phg/context-mirror/src/726a663be481042003566d4614266b940b5a0c91/scripts/context/lua/mtx-package.lua?at=beta} and requires \fileent{mtxrun}. Run \inlinecode {mtxrun --script package --help} @@ -1107,31 +1105,46 @@ too developed by Hans Hagen.\footnote{% For the actual merging code see the file \fileent{util-mrg.lua} that is part of \CONTEXT. } -It houses several \LUA files that can be classed in three -categories. +% +This file constitutes the “reference fontloader” and is part of the +\identifier{luaotfload} package as \fileent{fontloader-reference.lua}. +A companion to it, \fileent{luatex-basics-gen.lua} must be loaded +beforehand to set up parts of the environment required by the \CONTEXT +libraries. +% +During a \TEX\ run, the fontloader initialization and injection happens +in the module \fileent{luaotfload-init.lua}. + +A number of \emphasis{\LUA utility libraries} that are already provided +by \identifier{lualibs} package are not part of the \identifier{luaotfload} +fontloader.\footnote{% + Faithful listeners will remember the pre-2.6 era when the fontloader + used to be integrated as-is which caused all kinds of code + duplication with the pervasive \identifier{Lualibs} package. + This conceptual glitch has since been amended by tightening the + coupling with the excellent \CONTEXT\ toolchain. +} +\beginnarrower + \begindoublecolumns + \begindefinitions + \beginaltitem {l-lua.lua} \endaltitem + \beginaltitem {l-lpeg.lua} \endaltitem + \beginaltitem {l-function.lua} \endaltitem + \beginaltitem {l-string.lua} \endaltitem + \beginaltitem {l-table.lua} \endaltitem + \beginaltitem {l-io.lua} \endaltitem + \beginaltitem {l-file.lua} \endaltitem + \beginaltitem {l-boolean.lua} \endaltitem + \beginaltitem {l-math.lua} \endaltitem + \beginaltitem {util-str.lua} \endaltitem + \enddefinitions + \enddoublecolumns +\endnarrower -\begindefinitions - \beginnormalitem - \emphasis{\LUA utility libraries}, a subset - of what is provided by the \identifier{lualibs} - package. - - \begindoublecolumns - \begindefinitions - \beginaltitem {l-lua.lua} \endaltitem - \beginaltitem {l-lpeg.lua} \endaltitem - \beginaltitem {l-function.lua} \endaltitem - \beginaltitem {l-string.lua} \endaltitem - \beginaltitem {l-table.lua} \endaltitem - \beginaltitem {l-io.lua} \endaltitem - \beginaltitem {l-file.lua} \endaltitem - \beginaltitem {l-boolean.lua} \endaltitem - \beginaltitem {l-math.lua} \endaltitem - \beginaltitem {util-str.lua} \endaltitem - \enddefinitions - \enddoublecolumns - \endnormalitem +The reference fontloader is home to several \LUA files that can be +grouped twofold as below: +\begindefinitions \beginnormalitem The \emphasis{font loader} itself. These files have been written for @@ -1139,7 +1152,6 @@ categories. with \identifier{luaotfload}. \begindoublecolumns \begindefinitions - \beginaltitem{luatex-basics-gen.lua} \endaltitem \beginaltitem{luatex-basics-nod.lua} \endaltitem \beginaltitem{luatex-fonts-enc.lua} \endaltitem \beginaltitem{luatex-fonts-syn.lua} \endaltitem @@ -1209,7 +1221,10 @@ files not contained in the merge. Some of these have no equivalent in font feature handling; incorporates some of the code from \fileent{font-otc} from \CONTEXT; \endaltitem - \beginaltitem {luaotfload-override.lua} + \beginaltitem {luaotfload-configuration.lua} + handling of \fileent{luaotfload.conf(5)}. + \endaltitem + \beginaltitem {luaotfload-log.lua} overrides the \CONTEXT logging functionality. \endaltitem \beginaltitem {luaotfload-loaders.lua} @@ -1222,6 +1237,9 @@ files not contained in the merge. Some of these have no equivalent in \beginaltitem {luaotfload-database.lua} font names database. \endaltitem + \beginaltitem {luaotfload-resolvers.lua} + file name resolvers. + \endaltitem \beginaltitem {luaotfload-colors.lua} color handling. \endaltitem -- cgit v1.2.3 From 8860ba7e4cb6009ac4abca9abd37cf276c786a45 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 6 Nov 2015 00:10:40 +0100 Subject: [doc] adapt to state of the art; stub section for configuration --- doc/luaotfload-main.tex | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index a5ed940..46f66b5 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -1072,9 +1072,10 @@ The original \LUA source files have been combined using the this form the font loader depends only on the \identifier{lualibs} package and requires only minor adaptions to integrate into \identifier{luaotfload}. -% -The guiding principle is to let \CONTEXT/\LUATEX-Fonts take care of -the implementation, and update the imported code from time to time. + +The guiding principle is to let \CONTEXT/\LUATEX-Fonts take care of the +implementation, and update the imported code as frequently as +necessary. % As maintainers, we aim at importing files from upstream essentially \emphasis{unmodified}, except for renaming them to prevent name @@ -1194,11 +1195,12 @@ merged file, it will load the individual \LUA libraries instead. % Their names remain the same as in \CONTEXT (without the -\inlinecode {otfl}-prefix) since we imported the relevant section of -\fileent{luatex-fonts.lua} unmodified into \fileent{luaotfload-main.lua}. -Thus if you prefer running bleeding edge code from the -\CONTEXT beta, all you have to do is remove -\fileent{luaotfload-merged.lua} from the search path. +\inlinecode {luaotfload}-prefix) since the initialization mirrors +the sequence in \LUATEX-Fonts. +%% FIXME this is a config option nowadays! +%Thus if you prefer running bleeding edge code from the \CONTEXT beta, +%all you have to do is remove \fileent{luaotfload-merged.lua} from the +%search path. Also, the merged file at some point loads the Adobe Glyph List from a \LUA table that is contained in \fileent{luaotfload-glyphlist.lua}, @@ -1206,8 +1208,9 @@ which is automatically generated by the script \fileent{mkglyphlist}.\footnote{% See \fileent{luaotfload-font-enc.lua}. The hard-coded file name is why we have to replace the procedure - that loads the file in \fileent{luaotfload-override.lua}. + that loads the file in \fileent{luaotfload-init.lua}. } +% There is a make target \identifier{glyphs} that will create a fresh glyph list so we don’t need to import it from \CONTEXT any longer. @@ -1259,6 +1262,13 @@ files not contained in the merge. Some of these have no equivalent in \endsection +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\beginsection {Configuration Files} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +\emphasis{Caution}: For the authoritative documentation, consult the +manpage for \fileent{luaotfload.conf(5)}. + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \beginsection {Auxiliary Functions} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -- cgit v1.2.3 From 28dc7605d7875058227c5690a8f6354e1979d1b5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 6 Nov 2015 00:17:32 +0100 Subject: [doc] remove redundant namespace prefixing for primitives --- doc/luaotfload-latex.tex | 18 +++++++++--------- doc/luaotfload-main.tex | 40 ++++++++++++++++++++-------------------- 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/doc/luaotfload-latex.tex b/doc/luaotfload-latex.tex index 9f09f4f..32ad3cb 100644 --- a/doc/luaotfload-latex.tex +++ b/doc/luaotfload-latex.tex @@ -220,9 +220,9 @@ \newcount \othercatcode \othercatcode 12 \newcount \activecatcode \othercatcode 13 -\newluatexcatcodetable \vrbcatcodes -\setluatexcatcodetable \vrbcatcodes {% - \luatexcatcodetable \CatcodeTableIniTeX +\newcatcodetable \vrbcatcodes +\setcatcodetable \vrbcatcodes {% + \catcodetable \CatcodeTableIniTeX \catcode 9 \othercatcode %% \tabasciicode \catcode 13 \othercatcode %% \endoflineasciicode \catcode 12 \othercatcode %% \formfeedasciicode @@ -230,22 +230,22 @@ \catcode 32 \othercatcode %% \spaceasciicode } -\newluatexcatcodetable \literalcatcodes -\setluatexcatcodetable \literalcatcodes {% - \luatexcatcodetable \CatcodeTableString +\newcatcodetable \literalcatcodes +\setcatcodetable \literalcatcodes {% + \catcodetable \CatcodeTableString \catcode 32 \activecatcode %% \spaceasciicode } \def \beginlisting {% \begingroup - \luatexcatcodetable \vrbcatcodes + \catcodetable \vrbcatcodes \beginlistingindeed% } \directlua { local texprint = tex.print local stringsub = string.sub - local backslash = string.byte (0x5c) + local backslash = string.char (0x5c) document = document or { } document.printlines = function (buffer) for _, line in next, string.explode (buffer, "\noexpand\n") do @@ -266,7 +266,7 @@ \begin {quote} \bgroup \addfontfeature {RawFeature=-tlig;-liga}%% So one can’t just turn them all off at once using the ``Ligatures`` key? - \luatexcatcodetable \literalcatcodes + \catcodetable \literalcatcodes \obeyspaces \obeylines \directlua{document.printlines ([==[\detokenize {#1}]==])} diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index 46f66b5..7badffd 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -1116,31 +1116,31 @@ libraries. During a \TEX\ run, the fontloader initialization and injection happens in the module \fileent{luaotfload-init.lua}. -A number of \emphasis{\LUA utility libraries} that are already provided -by \identifier{lualibs} package are not part of the \identifier{luaotfload} -fontloader.\footnote{% +A number of \emphasis{\LUA utility libraries} are not part of the +\identifier{luaotfload} fontloader, contrary to its equivalent in +\LUATEX-Fonts. These are already provided by the \identifier{lualibs} +and have thus been omitted from the merge.\footnote{% Faithful listeners will remember the pre-2.6 era when the fontloader used to be integrated as-is which caused all kinds of code - duplication with the pervasive \identifier{Lualibs} package. + duplication with the pervasive \identifier{lualibs} package. This conceptual glitch has since been amended by tightening the coupling with the excellent \CONTEXT\ toolchain. } -\beginnarrower - \begindoublecolumns - \begindefinitions - \beginaltitem {l-lua.lua} \endaltitem - \beginaltitem {l-lpeg.lua} \endaltitem - \beginaltitem {l-function.lua} \endaltitem - \beginaltitem {l-string.lua} \endaltitem - \beginaltitem {l-table.lua} \endaltitem - \beginaltitem {l-io.lua} \endaltitem - \beginaltitem {l-file.lua} \endaltitem - \beginaltitem {l-boolean.lua} \endaltitem - \beginaltitem {l-math.lua} \endaltitem - \beginaltitem {util-str.lua} \endaltitem - \enddefinitions - \enddoublecolumns -\endnarrower + +\begindoublecolumns + \begindefinitions + \beginaltitem {l-lua.lua} \endaltitem + \beginaltitem {l-lpeg.lua} \endaltitem + \beginaltitem {l-function.lua} \endaltitem + \beginaltitem {l-string.lua} \endaltitem + \beginaltitem {l-table.lua} \endaltitem + \beginaltitem {l-io.lua} \endaltitem + \beginaltitem {l-file.lua} \endaltitem + \beginaltitem {l-boolean.lua} \endaltitem + \beginaltitem {l-math.lua} \endaltitem + \beginaltitem {util-str.lua} \endaltitem + \enddefinitions +\enddoublecolumns The reference fontloader is home to several \LUA files that can be grouped twofold as below: -- cgit v1.2.3 From 15685e52158389814e17d0b855a78851b3b3f879 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 7 Nov 2015 00:28:03 +0100 Subject: [doc] revise listings printer --- doc/Makefile | 2 +- doc/luaotfload-latex.tex | 73 ++++++++++++++++++++++++++++++++++++------------ 2 files changed, 56 insertions(+), 19 deletions(-) diff --git a/doc/Makefile b/doc/Makefile index 6d68281..0355a0e 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -1,6 +1,6 @@ NAME = luaotfload DOCPDF = $(NAME).pdf -DOCSRC = $(NAME)-latex.tex +DOCSRC = $(NAME)-latex.tex $(NAME)-main.tex SCRIPTNAME = luaotfload-tool TOOLMANSRC = $(SCRIPTNAME).rst diff --git a/doc/luaotfload-latex.tex b/doc/luaotfload-latex.tex index 32ad3cb..e3541c5 100644 --- a/doc/luaotfload-latex.tex +++ b/doc/luaotfload-latex.tex @@ -230,48 +230,85 @@ \catcode 32 \othercatcode %% \spaceasciicode } +\directlua { + document = document or { } + document.vrbcatcodesidx = tonumber (\the \vrbcatcodes) +} + \newcatcodetable \literalcatcodes \setcatcodetable \literalcatcodes {% \catcodetable \CatcodeTableString \catcode 32 \activecatcode %% \spaceasciicode } +\def \listingsurroundskip {\vskip \baselineskip} + \def \beginlisting {% + \noindent \begingroup \catcodetable \vrbcatcodes \beginlistingindeed% } \directlua { - local texprint = tex.print - local stringsub = string.sub - local backslash = string.char (0x5c) - document = document or { } + local texsprint = tex.sprint + local stringis_empty = string.is_empty + local stringsub = string.sub + local stringgsub = string.gsub + %local backslash = unicode.utf8.char (0x200c) + local backslash = unicode.utf8.char (0x5c) + local escaped = [[\string\string\string\]] document.printlines = function (buffer) - for _, line in next, string.explode (buffer, "\noexpand\n") do - if stringsub (line, 1, 1) == " " then - line = backslash .. line + local lines = string.explode (buffer, "\noexpand\n") + print "" + for i, line in next, lines do + local line = stringgsub (line, backslash, escaped) + if stringis_empty (line) then + print (i, "listing: ") + texsprint [[\string\listingpar]] + else + local line = [[\string\beginlistingline]] + .. line + .. [[\string\endlistingline]] + .. [[\string\listingpar]] + print (i, "listing: «" .. line .. "»") + texsprint (document.vrbcatcodesidx, line) end - texprint (-1, line) - texprint (-1, "") end end } +\def \listingpar {\endgraf} + +\let \endlistingline \relax +\let \endlisting \relax + +\protected \def \beginlistingline{% + \leavevmode + \begingroup + \beginlistinglineindeed% +} + +\def \beginlistinglineindeed #1\endlistingline{% + \endgroup + \hbox{% + \addfontfeature {RawFeature=-tlig;-liga}%% So one can’t just turn them all off at once using the ``Ligatures`` key? + \obeyspaces + #1}% +} + \def \beginlistingindeed#1\endlisting{% \endgroup \begingroup + \endgraf + \listingsurroundskip \ttfamily \small - \begin {quote} - \bgroup - \addfontfeature {RawFeature=-tlig;-liga}%% So one can’t just turn them all off at once using the ``Ligatures`` key? - \catcodetable \literalcatcodes - \obeyspaces - \obeylines - \directlua{document.printlines ([==[\detokenize {#1}]==])} - \egroup - \end {quote} + \parindent = 0em + \leftskip = 2em + \hangindent = 2em + \directlua{document.printlines ([==[\detokenize {#1}]==])}% + \listingsurroundskip \endgroup } -- cgit v1.2.3 From 65c8b21ab3bf907357b203a7b5c6fb5b0a971cea Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 7 Nov 2015 00:42:06 +0100 Subject: [doc] expand documentation of config files --- doc/luaotfload-main.tex | 73 ++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 66 insertions(+), 7 deletions(-) diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index 7badffd..4b5e2e8 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -686,7 +686,7 @@ obviously, \inlinecode{random}. user. \endaltitem -\ifcontextmkiv +\iffalse \startbuffer [printvectors] \directlua{inspect(fonts.protrusions.setups.default) inspect(fonts.expansions.setups.default)} @@ -706,7 +706,7 @@ obviously, \inlinecode{random}. % Alternatively and with loss of information, you can dump those tables into your terminal by issuing - \unless \ifcontextmkiv + \unless \iffalse \beginlisting \directlua{inspect(fonts.protrusions.setups.default) inspect(fonts.expansions.setups.default)} @@ -763,7 +763,7 @@ Currently (2014) there are three of them: remapping feature. }: - \unless \ifcontextmkiv + \unless \iffalse %% Using braced arg syntax with inline code appears to be %% impossible within Latex tables -- just ignore the weird %% exclamation points below. @@ -905,7 +905,7 @@ directories. \tablefloat {table-searchpaths} {List of paths searched for each supported operating system.} {% - \unless \ifcontextmkiv + \unless \iffalse \begincentered \begintabulate [lp{.5\textwidth}] \beginrow @@ -1262,18 +1262,77 @@ files not contained in the merge. Some of these have no equivalent in \endsection +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\beginsection {Packaging a Fontloader} +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +TODO % it’s simple, though + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \beginsection {Configuration Files} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\emphasis{Caution}: For the authoritative documentation, consult the -manpage for \fileent{luaotfload.conf(5)}. +\beginnarrower + \emphasis{Caution}: For the authoritative documentation, consult the + manpage for \fileent{luaotfload.conf(5)}. +\endnarrower + +The runtime behavior of \identifier{Luaotfload} can be customized by +means of a configuration file. +% location +At startup, it attempts to locate a file called \fileent +{luaotfload.conf} or \fileent {luaotfloadrc} at a number of candidate +locations: + +\begincentered + \begindefinitions + \beginnormalitem \fileent{./luaotfload.conf} \endnormalitem + \beginnormalitem \fileent{./luaotfloadrc} \endnormalitem + \beginnormalitem \fileent{\$XDG_CONFIG_HOME/luaotfload/luaotfload.conf} \endnormalitem + \beginnormalitem \fileent{\$XDG_CONFIG_HOME/luaotfload/luaotfload.rc} \endnormalitem + \beginnormalitem \fileent{~/.luaotfloadrc} \endnormalitem + \enddefinitions +\endcentered + +\beginnarrower + \emphasis{Caution}: The configuration potentially modifies the final + document. A project-local file belongs under version control along + with the rest of the document. This is to ensure that everybody who + builds the project also receives the same customizations as the + author. +\endnarrower + +% syntax +% example settings + +An example for customization via \fileent {luaotfload.conf} might look +as below: + +\beginlisting +; Example luaotfload.conf containing a rudimentary configuration +[db] + update-live = false +[run] + color-callback = pre_linebreak_filter + definer = info_patch + log-level = 5 +[default-features] + global = mode=base +\endlisting + +This specifies that for the given project, \identifier{Luaotfload} +shall not attempt to automatically scan for fonts if it can’t resolve a +request. The font-based colorization will happen during \LUATEX’s +pre-linebreak filter. The fontloader will output verbose information +about the fonts at definition time along with globally increased +verbosity. Lastly, the fontloader defaults to the less expensive +\luaident{base} mode like it does in \CONTEXT. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \beginsection {Auxiliary Functions} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -With release version 2.2, \identifier{luaotfload} received +With release version 2.2, \identifier{Luaotfload} received additional functions for package authors to call from outside (see the file \fileent{luaotfload-auxiliary.lua} for details). % -- cgit v1.2.3 From 54e6a5293dbff1e3775c2c3478b80c244608a4a5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 7 Nov 2015 08:26:48 +0100 Subject: [doc] briefly describe config file syntax --- doc/luaotfload-main.tex | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index 4b5e2e8..112572f 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -1303,8 +1303,14 @@ locations: \endnarrower % syntax +The syntax is fairly close to the format used by +\fileent{git-config(1)} which in turn was derived from the popular +\identifier{.INI} format: Lines of key-value pairs are grouped under +different configuration “sections”.\footnote{% + The configuration parser in \fileent {luoatfload-parsers.lua} might + be employed by other packages for similar purposes. +} % example settings - An example for customization via \fileent {luaotfload.conf} might look as below: -- cgit v1.2.3 From 55945326011925fa81cca8cf2b5b9376025451a5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 7 Nov 2015 08:44:55 +0100 Subject: [doc] introduce fontloader switching --- doc/luaotfload-main.tex | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index 112572f..cc242e8 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -43,6 +43,11 @@ This package is an adaptation of the \CONTEXT font loading system. It allows for loading \OpenType fonts with an extended syntax and adds support for a variety of font features. + + After discussion of the font loading API, this manual gives an + overview of the core components of \identifier{Luaotfload}: The + packaged font loader code, the names database, configuration, and + helper functions on the \LUA\ end. \endabstractcontent \endfrontmatter @@ -1056,9 +1061,11 @@ An example with explicit paths: \endsection %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\beginsection {The Fontloader Package} +\beginsection {The Fontloader} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\beginsubsection {Overview} + To a large extent, \identifier{luaotfload} relies on code originally written by Hans Hagen for the \hyperlink[\identifier{\CONTEXT}]{http://wiki.contextgarden.net} @@ -1086,6 +1093,10 @@ This job has been greatly alleviated since the advent of manually spotted and extracted from the \CONTEXT source code in a complicated and error-prone fashion. +\endsubsection + +\beginsubsection {Contents and Dependencies} + Below is a commented list of the files distributed with \identifier{luaotfload} in one way or the other. % @@ -1260,14 +1271,23 @@ files not contained in the merge. Some of these have no equivalent in {Schematic of the files in \identifier{Luaotfload}} {filegraph.pdf} -\endsection +\endsubsection -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -\beginsection {Packaging a Fontloader} -%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +\beginsubsection {Packaging} + +The fontloader code is integrated as an isolated component that can be +switched out on demand. +To specify the fontloader you wish to use, the configuration file +(described in section \ref{sec:conf}) provides the option +\inlinecode{fontloader}. Its value can be one of the identifiers +\inlinecode{default} or \inlinecode{reference} or the name of a file +somewhere in the search path of \LUATEX. TODO % it’s simple, though +\endsubsection +\endsection + %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% \beginsection {Configuration Files} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@ -1277,6 +1297,7 @@ TODO % it’s simple, though manpage for \fileent{luaotfload.conf(5)}. \endnarrower +\label{sec:conf} The runtime behavior of \identifier{Luaotfload} can be customized by means of a configuration file. % location -- cgit v1.2.3 From 389fe13c73832215d8486e43ed3c52f6c96f45ca Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 9 Nov 2015 08:03:29 +0100 Subject: [main,init] add no-op loader for fontloader files --- src/luaotfload-init.lua | 38 +++++++++++++++++++++++--------------- src/luaotfload-main.lua | 12 ++++++++++++ 2 files changed, 35 insertions(+), 15 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index 1c2046d..1d6d1a5 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -203,6 +203,7 @@ end --- [init_adapt] local init_main = function () local load_fontloader_module = luaotfload.loaders.fontloader + local ignore_module = luaotfload.loaders.ignore --[[doc-- @@ -214,26 +215,33 @@ local init_main = function () --doc]]-- + logreport ("log", 4, "init", + "Loading fontloader as merged package.") load_fontloader_module (luaotfload.fontloader_package) ---load_fontloader_module "font-odv.lua" --- <= Devanagari support from Context if not fonts then - --- the loading sequence is known to change, so this might have to - --- be updated with future updates! - --- do not modify it though unless there is a change to the merged - --- package! - load_fontloader_module "l-lua" - load_fontloader_module "l-lpeg" - load_fontloader_module "l-function" - load_fontloader_module "l-string" - load_fontloader_module "l-table" - load_fontloader_module "l-io" - load_fontloader_module "l-file" - load_fontloader_module "l-boolean" - load_fontloader_module "l-math" - load_fontloader_module "util-str" - load_fontloader_module "luatex-basics-gen" + logreport ("log", 4, "init", + "Loading fontloader components individually.") + --- The loading sequence is known to change, so this might have to be + --- updated with future updates. Do not modify it though unless there is + --- a change to the upstream package! + + --- Since 2.6 those are directly provided by the Lualibs package. + ignore_module "l-lua" + ignore_module "l-lpeg" + ignore_module "l-function" + ignore_module "l-string" + ignore_module "l-table" + ignore_module "l-io" + ignore_module "l-file" + ignore_module "l-boolean" + ignore_module "l-math" + ignore_module "util-str" + ignore_module "luatex-basics-gen" + + --- These constitute the fontloader proper. load_fontloader_module "data-con" load_fontloader_module "luatex-basics-nod" load_fontloader_module "font-ini" diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 85c9cee..686ce0e 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -127,11 +127,23 @@ local make_loader = function (prefix) end end +--[[doc-- + Certain files are kept around that aren’t loaded because they are part of + the imported fontloader. In order to keep the initialization structure + intact we also provide a no-op version of the module loader that can be + called in the expected places. +--doc]]-- + +local dummy_loader = function (name) + luaotfload.log.report("log", 3, "load", "Skipping module “%s”.", name) +end + local install_loaders = function () local loaders = { } local loadmodule = make_loader "luaotfload" loaders.luaotfload = loadmodule loaders.fontloader = make_loader "fontloader" + loaders.ignore = dummy_loader ----loaders.plaintex = make_loader "luatex" --=> for Luatex-Plain loaders.initialize = function (name) -- cgit v1.2.3 From 60f41dfbc13f06a1b43a4e66798a0d043d210eee Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 9 Nov 2015 08:16:19 +0100 Subject: [init,conf] enable direct loading of fontloader components MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For now, this pertains only to the modules we ship in Luaotfload. For loading from Context we still need a step to distinguish between the namespaced versions of the files, the pure ones in texmf/…/base, and the Luatex-Fonts ones. But yeah, setting [run] fontloader = unpackaged in the luaotfloadrc now works splendidly. --- src/luaotfload-configuration.lua | 8 +++--- src/luaotfload-init.lua | 53 +++++++++++++++++++++++++--------------- 2 files changed, 38 insertions(+), 23 deletions(-) diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index 6f94195..1fe30fe 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -127,9 +127,11 @@ local feature_presets = { --doc]]-- local registered_loaders = { - default = luaotfloadstatus and luaotfloadstatus.notes.loader or "reference", - reference = "reference", - tl2014 = "tl2014", + default = luaotfloadstatus and luaotfloadstatus.notes.loader or "reference", + reference = "reference", + unpackaged = "unpackaged", + context = "context", + tl2014 = "tl2014", } --[[doc-- diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index 1d6d1a5..c2899d7 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -215,14 +215,11 @@ local init_main = function () --doc]]-- - logreport ("log", 4, "init", - "Loading fontloader as merged package.") - load_fontloader_module (luaotfload.fontloader_package) - - ---load_fontloader_module "font-odv.lua" --- <= Devanagari support from Context + local fontloader = config.luaotfload and config.luaotfload.run.fontloader + or "reference" - if not fonts then - logreport ("log", 4, "init", + if fontloader == "unpackaged" then + logreport ("both", 4, "init", "Loading fontloader components individually.") --- The loading sequence is known to change, so this might have to be --- updated with future updates. Do not modify it though unless there is @@ -243,27 +240,43 @@ local init_main = function () --- These constitute the fontloader proper. load_fontloader_module "data-con" - load_fontloader_module "luatex-basics-nod" + load_fontloader_module "basics-nod" load_fontloader_module "font-ini" load_fontloader_module "font-con" - load_fontloader_module "luatex-fonts-enc" + load_fontloader_module "fonts-enc" load_fontloader_module "font-cid" load_fontloader_module "font-map" - load_fontloader_module "luatex-fonts-syn" - load_fontloader_module "luatex-fonts-tfm" + load_fontloader_module "fonts-syn" + load_fontloader_module "fonts-tfm" load_fontloader_module "font-oti" load_fontloader_module "font-otf" load_fontloader_module "font-otb" - load_fontloader_module "luatex-fonts-inj" --> since 2014-01-07, replaces node-inj.lua - load_fontloader_module "luatex-fonts-ota" - load_fontloader_module "luatex-fonts-otn" --> since 2014-01-07, replaces font-otn.lua - load_fontloader_module "font-otp" --> since 2013-04-23 - load_fontloader_module "luatex-fonts-lua" + load_fontloader_module "fonts-inj" --> since 2014-01-07, replaces node-inj.lua + load_fontloader_module "fonts-ota" + load_fontloader_module "fonts-otn" --> since 2014-01-07, replaces font-otn.lua + load_fontloader_module "font-otp" --> since 2013-04-23 + load_fontloader_module "fonts-lua" load_fontloader_module "font-def" - load_fontloader_module "luatex-fonts-def" - load_fontloader_module "luatex-fonts-ext" - load_fontloader_module "luatex-fonts-cbk" - end --- non-merge fallback scope + load_fontloader_module "fonts-def" + load_fontloader_module "fonts-ext" + load_fontloader_module "fonts-cbk" + + elseif fontloader == "context" then + logreport ("both", 4, "init", + "Loading fontloader components from context.") + logreport ("both", 0, "init", "NOT IMPLEMENTED YET.") + os.exit(-42) + + elseif fontloader then + fontloader = tostring (fontloader) + --- “reference”, “default” + logreport ("both", 4, "init", + "Attempting to load fontloader “%s”.", + fontloader) + load_fontloader_module (luaotfload.fontloader_package) + end + + ---load_fontloader_module "font-odv.lua" --- <= Devanagari support from Context end --- [init_main] -- cgit v1.2.3 From a67b8e37ab846a79c69ee26761835934680e41b4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 10 Nov 2015 08:02:36 +0100 Subject: [main] implement a loader for Context files --- src/luaotfload-main.lua | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 686ce0e..0ed57da 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -99,16 +99,24 @@ end local make_loader_name = function (prefix, name) local msg = luaotfload.log and luaotfload.log.report or print - if prefix and name then - msg ("log", 7, "load", - "Composing module name from constituents %s, %s", - prefix, name) - return prefix .. "-" .. name .. ".lua" + if not name then + msg ("both", 0, "load", + "Fatal error: make_loader_name (“%s”, “%s”).", + tostring (prefix), tostring (name)) + return "dummy-name" end - msg ("log", 7, "load", - "Loading module %s literally.", - tostring (name)) - return name + name = tostring (name) + if prefix == false then + msg ("log", 9, "load", + "No prefix requested, passing module name “%s” unmodified.", + name) + return tostring (name) .. ".lua" + end + prefix = tostring (prefix) + msg ("log", 9, "load", + "Composing module name from constituents %s, %s.", + prefix, name) + return prefix .. "-" .. name .. ".lua" end local timing_info = { @@ -135,7 +143,17 @@ end --doc]]-- local dummy_loader = function (name) - luaotfload.log.report("log", 3, "load", "Skipping module “%s”.", name) + luaotfload.log.report("log", 3, "load", "Skipping module “%s” on purpose.", name) +end + +local context_loader = function (name) + luaotfload.log.report("log", 3, "load", "Loading module “%s” from Context.", name) + local t_0 = osgettimeofday () + local modname = make_loader_name (false, name) + local data = require (modname) + local t_end = osgettimeofday () + timing_info.t_load [name] = t_end - t_0 + return data end local install_loaders = function () @@ -143,6 +161,7 @@ local install_loaders = function () local loadmodule = make_loader "luaotfload" loaders.luaotfload = loadmodule loaders.fontloader = make_loader "fontloader" + loaders.context = context_loader loaders.ignore = dummy_loader ----loaders.plaintex = make_loader "luatex" --=> for Luatex-Plain -- cgit v1.2.3 From 43f18a389a1380e950cea104f3ada32c88c47863 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 10 Nov 2015 08:06:55 +0100 Subject: [init] access the context loader from init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Works fine now by choosing the “context” fontloader in luaotfloadrc. --- src/luaotfload-init.lua | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index c2899d7..ca5d9ec 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -203,6 +203,7 @@ end --- [init_adapt] local init_main = function () local load_fontloader_module = luaotfload.loaders.fontloader + local load_context_module = luaotfload.loaders.context local ignore_module = luaotfload.loaders.ignore --[[doc-- @@ -265,7 +266,41 @@ local init_main = function () logreport ("both", 4, "init", "Loading fontloader components from context.") logreport ("both", 0, "init", "NOT IMPLEMENTED YET.") - os.exit(-42) + --- Since 2.6 those are directly provided by the Lualibs package. + ignore_module "l-lua" + ignore_module "l-lpeg" + ignore_module "l-function" + ignore_module "l-string" + ignore_module "l-table" + ignore_module "l-io" + ignore_module "l-file" + ignore_module "l-boolean" + ignore_module "l-math" + ignore_module "util-str" + + --- These constitute the fontloader proper. + load_context_module "luatex-basics-gen" + load_context_module "data-con" + load_context_module "luatex-basics-nod" + load_context_module "font-ini" + load_context_module "font-con" + load_context_module "luatex-fonts-enc" + load_context_module "font-cid" + load_context_module "font-map" + load_context_module "luatex-fonts-syn" + load_context_module "luatex-fonts-tfm" + load_context_module "font-oti" + load_context_module "font-otf" + load_context_module "font-otb" + load_context_module "luatex-fonts-inj" --> since 2014-01-07, replaces node-inj.lua + load_context_module "luatex-fonts-ota" + load_context_module "luatex-fonts-otn" --> since 2014-01-07, replaces font-otn.lua + load_context_module "font-otp" --> since 2013-04-23 + load_context_module "luatex-fonts-lua" + load_context_module "font-def" + load_context_module "luatex-fonts-def" + load_context_module "luatex-fonts-ext" + load_context_module "luatex-fonts-cbk" elseif fontloader then fontloader = tostring (fontloader) -- cgit v1.2.3 From 952d2c9b24c1b2e6f0f48df28981c1f2674137f4 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 10 Nov 2015 08:17:38 +0100 Subject: [doc] add directions for loading Context libs --- doc/luaotfload-main.tex | 24 +++++++++++------------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/doc/luaotfload-main.tex b/doc/luaotfload-main.tex index cc242e8..5ea70d8 100644 --- a/doc/luaotfload-main.tex +++ b/doc/luaotfload-main.tex @@ -1201,17 +1201,17 @@ grouped twofold as below: \endnormalitem \enddefinitions -Note that if \identifier{luaotfload} cannot locate the -merged file, it will load the individual \LUA libraries -instead. -% -Their names remain the same as in \CONTEXT (without the -\inlinecode {luaotfload}-prefix) since the initialization mirrors -the sequence in \LUATEX-Fonts. -%% FIXME this is a config option nowadays! -%Thus if you prefer running bleeding edge code from the \CONTEXT beta, -%all you have to do is remove \fileent{luaotfload-merged.lua} from the -%search path. +As an alternative to the merged file, \identifier {Luaotfload} may load +individual unpackaged \LUA libraries that come with the source, or even +use the files from Context directly. +% +Thus if you prefer running bleeding edge code from the \CONTEXT beta, +all you have to do is to choose the \inlinecode {context} fontloader +via the configuration file (see section \ref{sec:conf} below). +% +This will make \identifier {Luaotfload} locate the \CONTEXT source via +\identifier{kpathsea} lookups and use those instead of the fontloader +%% TODO allow choosing the context path Also, the merged file at some point loads the Adobe Glyph List from a \LUA table that is contained in \fileent{luaotfload-glyphlist.lua}, @@ -1283,8 +1283,6 @@ To specify the fontloader you wish to use, the configuration file \inlinecode{default} or \inlinecode{reference} or the name of a file somewhere in the search path of \LUATEX. -TODO % it’s simple, though - \endsubsection \endsection -- cgit v1.2.3 From 54e74772fab02405bf90362d76884e88b63eb381 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 12 Nov 2015 08:15:06 +0100 Subject: [conf] implement path-based fontloader specification MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Makes the config test for paths specified as “context:/path/to/texmf” and return a ("context", path) pair that is intended for use as the base path of the fontloader files. --- src/luaotfload-configuration.lua | 31 ++++++++++++++++++++++++++++--- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index 1fe30fe..4ac8c50 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -134,6 +134,33 @@ local registered_loaders = { tl2014 = "tl2014", } +local pick_fontloader = function (s) + local ldr = registered_loaders[s] + if ldr ~= nil and type (ldr) == "string" then + logreport ("log", 2, "conf", "Using predefined fontloader \"%s\".", ldr) + return ldr + end + local idx = stringfind (s, ":") + if idx and idx > 2 then + if stringsub (s, 1, idx - 1) == "context" then + local pth = stringsub (s, idx + 1) + pth = stringstrip (pth) + logreport ("log", 2, "conf", "Context base path specified at \"%s\".", pth) + if lfsisdir (pth) then + logreport ("log", 5, "conf", "Context base path exists at \"%s\".", pth) + return { "context", pth } + end + pth = kpseexpand_path (pth) + if lfsisdir (pth) then + logreport ("log", 5, "conf", "Context base path exists at \"%s\".", pth) + return { "context", pth } + end + logreport ("both", 0, "conf", "Context base path not found at \"%s\".", pth) + end + end + return nil +end + --[[doc-- The ``post_linebreak_filter`` has been made the default callback for @@ -468,10 +495,8 @@ local option_spec = { in_t = string_t, out_t = string_t, transform = function (id) - local ldr = registered_loaders[id] + local ldr = pick_fontloader (id) if ldr ~= nil then - logreport ("log", 2, "conf", - "Using predefined fontloader \"%s\".", ldr) return ldr end logreport ("log", 0, "conf", -- cgit v1.2.3 From d8f160fc0518155a9ae995dfb16fc0d29937aa7c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 17 Nov 2015 22:29:41 +0100 Subject: [conf] correctly set default fontloader --- src/luaotfload-configuration.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index 4ac8c50..0ce9467 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -198,7 +198,7 @@ local default_config = { definer = "patch", log_level = 0, color_callback = "post_linebreak_filter", - live = true, + fontloader = "default", }, misc = { bisect = false, -- cgit v1.2.3 From 6e2184e0226de1e76e7195493b781b99f56eb879 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 17 Nov 2015 22:33:04 +0100 Subject: [conf] return path instead of pair to prevent type-mismatch The (fontloader, path) return value cannot pass the post-config validation because the value of ``run.fontloader`` is of type string. Since the path is always checked during configuration we can just forward it as-is and attempt a path load later on. --- src/luaotfload-configuration.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index 0ce9467..efed573 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -148,12 +148,12 @@ local pick_fontloader = function (s) logreport ("log", 2, "conf", "Context base path specified at \"%s\".", pth) if lfsisdir (pth) then logreport ("log", 5, "conf", "Context base path exists at \"%s\".", pth) - return { "context", pth } + return pth end pth = kpseexpand_path (pth) if lfsisdir (pth) then logreport ("log", 5, "conf", "Context base path exists at \"%s\".", pth) - return { "context", pth } + return pth end logreport ("both", 0, "conf", "Context base path not found at \"%s\".", pth) end -- cgit v1.2.3 From ec1984766b941087425acca1b4d4fa8201c86639 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 17 Nov 2015 22:51:30 +0100 Subject: [init] rework fontloader choices --- src/luaotfload-init.lua | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index ca5d9ec..2676ec7 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -8,6 +8,7 @@ -- local setmetatable = setmetatable +local kpselookup = kpse.lookup --[[doc-- @@ -218,6 +219,7 @@ local init_main = function () local fontloader = config.luaotfload and config.luaotfload.run.fontloader or "reference" + fontloader = tostring (fontloader) if fontloader == "unpackaged" then logreport ("both", 4, "init", @@ -302,13 +304,34 @@ local init_main = function () load_context_module "luatex-fonts-ext" load_context_module "luatex-fonts-cbk" - elseif fontloader then - fontloader = tostring (fontloader) - --- “reference”, “default” - logreport ("both", 4, "init", - "Attempting to load fontloader “%s”.", + elseif lfs.isdir (fontloader) then + logreport ("both", 2, "init", + "Attempting to load Context files under prefix “%s”.", + fontloader) + TODO() + + elseif lfs.isfile (fontloader) then + logreport ("both", 2, "init", + "Attempting to load fontloader from absolute path “%s”.", + fontloader) + local _void = require (fontloader) + + elseif kpselookup (fontloader) then + local pth = kpselookup (fontloader) + logreport ("both", 2, "init", + "Attempting to load fontloader “%s” from kpse-resolved path “%s”.", + fontloader, path) + local _void = require (path) + + else --- “reference”, “default” + logreport ("log", 6, "init", + "No match for fontloader spec “%s”.", + fontloader) + fontloader = luaotfload.fontloader_package + logreport ("log", 4, "init", + "Using predefined fontloader “%s”.", fontloader) - load_fontloader_module (luaotfload.fontloader_package) + load_fontloader_module (fontloader) end ---load_fontloader_module "font-odv.lua" --- <= Devanagari support from Context -- cgit v1.2.3 From 2bcb46cfec8b8d988e12f44d6297f4fb5f9e879b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 17 Nov 2015 23:08:58 +0100 Subject: [init] unify both Context load branches --- src/luaotfload-init.lua | 103 +++++++++++++++++++++++++++++------------------- 1 file changed, 63 insertions(+), 40 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index 2676ec7..a42801f 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -182,6 +182,65 @@ local pop_namespaces = function (normalglobal, end end +local context_modules = { + + --- Since 2.6 those are directly provided by the Lualibs package. + { false, "l-lua" }, + { false, "l-lpeg" }, + { false, "l-function" }, + { false, "l-string" }, + { false, "l-table" }, + { false, "l-io" }, + { false, "l-file" }, + { false, "l-boolean" }, + { false, "l-math" }, + { false, "util-str" }, + + --- These constitute the fontloader proper. + { true, "luatex-basics-gen" }, + { true, "data-con" }, + { true, "luatex-basics-nod" }, + { true, "font-ini" }, + { true, "font-con" }, + { true, "luatex-fonts-enc" }, + { true, "font-cid" }, + { true, "font-map" }, + { true, "luatex-fonts-syn" }, + { true, "luatex-fonts-tfm" }, + { true, "font-oti" }, + { true, "font-otf" }, + { true, "font-otb" }, + { true, "luatex-fonts-inj" }, --> since 2014-01-07, replaces node-inj.lua + { true, "luatex-fonts-ota" }, + { true, "luatex-fonts-otn" }, --> since 2014-01-07, replaces font-otn.lua + { true, "font-otp" }, --> since 2013-04-23 + { true, "luatex-fonts-lua" }, + { true, "font-def" }, + { true, "luatex-fonts-def" }, + { true, "luatex-fonts-ext" }, + { true, "luatex-fonts-cbk" }, + +} --[[context_modules]] + +local load_context_modules = function (pth) + + local load_context_module = luaotfload.loaders.context + local ignore_module = luaotfload.loaders.ignore + + logreport ("both", 2, "init", + "Loading fontloader components from context.") + local n = #context_modules + for i = 1, n do + local state, spec = unpack (context_modules [i]) + if state == false then + ignore_module (spec) + elseif state == true then + load_context_module (spec) + end + end + +end + local init_adapt = function () local context_environment = { } @@ -204,7 +263,6 @@ end --- [init_adapt] local init_main = function () local load_fontloader_module = luaotfload.loaders.fontloader - local load_context_module = luaotfload.loaders.context local ignore_module = luaotfload.loaders.ignore --[[doc-- @@ -265,50 +323,15 @@ local init_main = function () load_fontloader_module "fonts-cbk" elseif fontloader == "context" then - logreport ("both", 4, "init", - "Loading fontloader components from context.") - logreport ("both", 0, "init", "NOT IMPLEMENTED YET.") - --- Since 2.6 those are directly provided by the Lualibs package. - ignore_module "l-lua" - ignore_module "l-lpeg" - ignore_module "l-function" - ignore_module "l-string" - ignore_module "l-table" - ignore_module "l-io" - ignore_module "l-file" - ignore_module "l-boolean" - ignore_module "l-math" - ignore_module "util-str" - - --- These constitute the fontloader proper. - load_context_module "luatex-basics-gen" - load_context_module "data-con" - load_context_module "luatex-basics-nod" - load_context_module "font-ini" - load_context_module "font-con" - load_context_module "luatex-fonts-enc" - load_context_module "font-cid" - load_context_module "font-map" - load_context_module "luatex-fonts-syn" - load_context_module "luatex-fonts-tfm" - load_context_module "font-oti" - load_context_module "font-otf" - load_context_module "font-otb" - load_context_module "luatex-fonts-inj" --> since 2014-01-07, replaces node-inj.lua - load_context_module "luatex-fonts-ota" - load_context_module "luatex-fonts-otn" --> since 2014-01-07, replaces font-otn.lua - load_context_module "font-otp" --> since 2013-04-23 - load_context_module "luatex-fonts-lua" - load_context_module "font-def" - load_context_module "luatex-fonts-def" - load_context_module "luatex-fonts-ext" - load_context_module "luatex-fonts-cbk" + logreport ("both", 2, "init", + "Attempting to load Context modules in lookup path.") + load_context_modules () elseif lfs.isdir (fontloader) then logreport ("both", 2, "init", "Attempting to load Context files under prefix “%s”.", fontloader) - TODO() + load_context_modules (fontloader) elseif lfs.isfile (fontloader) then logreport ("both", 2, "init", -- cgit v1.2.3 From 0bfd03b4fcdf1cbf3f1fb8e8afa7a2c4d917715a Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 17 Nov 2015 23:56:44 +0100 Subject: [main,init] implement path dependent loading of context modules --- src/luaotfload-init.lua | 61 ++++++++++++++++++++++++++++--------------------- src/luaotfload-main.lua | 39 ++++++++++++++++++++++++++----- 2 files changed, 68 insertions(+), 32 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index a42801f..2755f78 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -182,6 +182,10 @@ local pop_namespaces = function (normalglobal, end end +--- below paths are relative to the texmf-context +local ltx = "tex/generic/context/luatex" +local ctx = "tex/context/base" + local context_modules = { --- Since 2.6 those are directly provided by the Lualibs package. @@ -197,28 +201,28 @@ local context_modules = { { false, "util-str" }, --- These constitute the fontloader proper. - { true, "luatex-basics-gen" }, - { true, "data-con" }, - { true, "luatex-basics-nod" }, - { true, "font-ini" }, - { true, "font-con" }, - { true, "luatex-fonts-enc" }, - { true, "font-cid" }, - { true, "font-map" }, - { true, "luatex-fonts-syn" }, - { true, "luatex-fonts-tfm" }, - { true, "font-oti" }, - { true, "font-otf" }, - { true, "font-otb" }, - { true, "luatex-fonts-inj" }, --> since 2014-01-07, replaces node-inj.lua - { true, "luatex-fonts-ota" }, - { true, "luatex-fonts-otn" }, --> since 2014-01-07, replaces font-otn.lua - { true, "font-otp" }, --> since 2013-04-23 - { true, "luatex-fonts-lua" }, - { true, "font-def" }, - { true, "luatex-fonts-def" }, - { true, "luatex-fonts-ext" }, - { true, "luatex-fonts-cbk" }, + { ltx, "luatex-basics-gen" }, + { ctx, "data-con" }, + { ltx, "luatex-basics-nod" }, + { ctx, "font-ini" }, + { ctx, "font-con" }, + { ltx, "luatex-fonts-enc" }, + { ctx, "font-cid" }, + { ctx, "font-map" }, + { ltx, "luatex-fonts-syn" }, + { ltx, "luatex-fonts-tfm" }, + { ctx, "font-oti" }, + { ctx, "font-otf" }, + { ctx, "font-otb" }, + { ltx, "luatex-fonts-inj" }, --> since 2014-01-07, replaces node-inj.lua + { ltx, "luatex-fonts-ota" }, + { ltx, "luatex-fonts-otn" }, --> since 2014-01-07, replaces font-otn.lua + { ctx, "font-otp" }, --> since 2013-04-23 + { ltx, "luatex-fonts-lua" }, + { ctx, "font-def" }, + { ltx, "luatex-fonts-def" }, + { ltx, "luatex-fonts-ext" }, + { ltx, "luatex-fonts-cbk" }, } --[[context_modules]] @@ -231,11 +235,16 @@ local load_context_modules = function (pth) "Loading fontloader components from context.") local n = #context_modules for i = 1, n do - local state, spec = unpack (context_modules [i]) - if state == false then + local sub, spec = unpack (context_modules [i]) + if sub == false then ignore_module (spec) - elseif state == true then - load_context_module (spec) + elseif type (sub) == "string" then + load_context_module (spec, file.join (pth, sub)) + else + logreport ("both", 0, "init", + "Internal error, please report. \z + This is not your fault.") + os.exit (-1) end end diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index 0ed57da..62765e4 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -98,7 +98,8 @@ end --doc]]-- local make_loader_name = function (prefix, name) - local msg = luaotfload.log and luaotfload.log.report or print + local msg = luaotfload.log and luaotfload.log.report + or function (...) texio.write_nl ("log", ...) end if not name then msg ("both", 0, "load", "Fatal error: make_loader_name (“%s”, “%s”).", @@ -143,17 +144,43 @@ end --doc]]-- local dummy_loader = function (name) - luaotfload.log.report("log", 3, "load", "Skipping module “%s” on purpose.", name) + luaotfload.log.report ("log", 3, "load", + "Skipping module “%s” on purpose.", + name) end -local context_loader = function (name) - luaotfload.log.report("log", 3, "load", "Loading module “%s” from Context.", name) +local context_loader = function (name, path) + luaotfload.log.report ("log", 3, "load", + "Loading module “%s” from Context.", + name) local t_0 = osgettimeofday () local modname = make_loader_name (false, name) - local data = require (modname) + local modpath = modname + if path then + if lfs.isdir (path) then + luaotfload.log.report ("log", 3, "load", + "Prepending path “%s”.", + path) + modpath = file.join (path, modname) + else + luaotfload.log.report ("both", 0, "load", + "Non-existant path “%s” specified, ignoring.", + path) + end + end + local ret = require (modpath) local t_end = osgettimeofday () timing_info.t_load [name] = t_end - t_0 - return data + + if ret ~= true then + --- require () returns “true” upon success unless the loaded file + --- yields a non-zero exit code. This isn’t per se indicating that + --- something isn’t right, but against HH’s coding practices. We’ll + --- silently ignore this ever happening on lower log levels. + luaotfload.log.report ("log", 4, "load", + "Module “%s” returned “%s”.", ret) + end + return ret end local install_loaders = function () -- cgit v1.2.3 From 17b8126f260a4f80a041ab179ceb68abf425c359 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 18 Nov 2015 07:47:47 +0100 Subject: [init] fix pathless Context module loading --- src/luaotfload-init.lua | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index 2755f78..f1d1a8e 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -228,8 +228,8 @@ local context_modules = { local load_context_modules = function (pth) - local load_context_module = luaotfload.loaders.context - local ignore_module = luaotfload.loaders.ignore + local load_module = luaotfload.loaders.context + local ignore_module = luaotfload.loaders.ignore logreport ("both", 2, "init", "Loading fontloader components from context.") @@ -239,7 +239,11 @@ local load_context_modules = function (pth) if sub == false then ignore_module (spec) elseif type (sub) == "string" then - load_context_module (spec, file.join (pth, sub)) + if pth then + load_module (spec, file.join (pth, sub)) + else + load_module (spec) + end else logreport ("both", 0, "init", "Internal error, please report. \z -- cgit v1.2.3 From 85bc85c1f116f759c59ef06f27bb37c0d2bb80f6 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 18 Nov 2015 07:52:24 +0100 Subject: [init] handle case for reference loader first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since it’s the trivial case, expected in 99 % of runs. --- src/luaotfload-init.lua | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index f1d1a8e..5b21d70 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -292,7 +292,11 @@ local init_main = function () or "reference" fontloader = tostring (fontloader) - if fontloader == "unpackaged" then + if fontloader == "reference" or fontloader == "default" then + logreport ("log", 4, "init", "Using reference fontloader.") + load_fontloader_module (luaotfload.fontloader_package) + + elseif fontloader == "unpackaged" then logreport ("both", 4, "init", "Loading fontloader components individually.") --- The loading sequence is known to change, so this might have to be @@ -359,7 +363,7 @@ local init_main = function () fontloader, path) local _void = require (path) - else --- “reference”, “default” + else logreport ("log", 6, "init", "No match for fontloader spec “%s”.", fontloader) @@ -372,6 +376,9 @@ local init_main = function () ---load_fontloader_module "font-odv.lua" --- <= Devanagari support from Context + logreport ("both", 0, "init", + "Context OpenType loader version “%s”", + fonts.handlers.otf.version) end --- [init_main] local init_cleanup = function (store) -- cgit v1.2.3 From 671f654e671cc2b255b21b937bbfd7f63cf43c22 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 18 Nov 2015 08:04:17 +0100 Subject: [init] treat known fontloaders as special case Defaulting too soon will prevent loading other loaders like the TL 2014 one we ship for backwards compatibility. --- src/luaotfload-init.lua | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/src/luaotfload-init.lua b/src/luaotfload-init.lua index 5b21d70..0f7464a 100644 --- a/src/luaotfload-init.lua +++ b/src/luaotfload-init.lua @@ -363,13 +363,19 @@ local init_main = function () fontloader, path) local _void = require (path) + elseif fontloader then + logreport ("log", 4, "init", + "Using predefined fontloader “%s”.", + fontloader) + load_fontloader_module (fontloader) + else - logreport ("log", 6, "init", - "No match for fontloader spec “%s”.", + logreport ("log", 4, "init", + "No match for requested fontloader “%s”.", fontloader) fontloader = luaotfload.fontloader_package logreport ("log", 4, "init", - "Using predefined fontloader “%s”.", + "Defaulting to predefined fontloader “%s”.", fontloader) load_fontloader_module (fontloader) end -- cgit v1.2.3 From 66715ea0131082efdca3267d3ab663153b0372e9 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 19 Nov 2015 00:00:43 +0100 Subject: [man] document fontloader switch --- doc/luaotfload.conf.rst | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/doc/luaotfload.conf.rst b/doc/luaotfload.conf.rst index 2a339ce..12dd887 100644 --- a/doc/luaotfload.conf.rst +++ b/doc/luaotfload.conf.rst @@ -276,6 +276,8 @@ Section ``run`` +------------------+--------+------------------------------+ | resolver | s | ``"cached"`` | +------------------+--------+------------------------------+ +| fontloader | s | ``"default"`` | ++------------------+--------+------------------------------+ The ``color-callback`` option determines the stage at which fonts that defined with a ``color=xxyyzz`` feature will be colorized. By default @@ -294,6 +296,29 @@ one that comes with the vanilla fontloader. Beware that this might break tools like Fontspect that rely on the ``patch_font`` callback provided by Luaotfload to perform important corrections on font data. +The fontloader backend can be selected by setting the value of +``fontloader``. Other than the default, which selects the packaged +``reference`` loader as shipped with Luaotfload, a file name accessible +by kpathsea can be specified. Alternatively, the individual files that +constitute the fontloader can be loaded directly. While less efficient, +this greatly aids debugging since error messages will reference the +actual line numbers of the source files and explanatory comments are +not stripped. Currently, three distinct loading strategies are +available: ``unpackaged`` will load the batch that is part of +Luaotfload. These contain the identical source code that the reference +fontloader has been compiled from. Another option, ``context`` will +attempt to load the same files by their names in the Context format +from the search path. Consequently this option allows to use the +version of Context that comes with the TeX distribution. Distros tend +to prefer the stable version (“current” in Context jargon) of those +files so certain bugs encountered in the more bleeding edge Luaotfload +can be avoided this way. A third option is to use ``context`` with a +colon to specify a directory prefix where the *TEXMF* is located that +the files should be loaded from, e. g. ``context:~/context/tex/texmf-context``. +This can be used when referencing another distribution like the Context +minimals that is installed under a different path not indexed by +kpathsea. + The value of ``log-level`` sets the default verbosity of messages printed by Luaotfload. Only messages defined with a verbosity of less than or equal to the supplied value will be output on the terminal. -- cgit v1.2.3 From b3565971e4ea5525da149268b1cd372b8d77f42c Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 19 Nov 2015 08:11:22 +0100 Subject: [import] allow passing search location on command line MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit And btw don’t hard code my own homedir =) --- scripts/mkimport | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/scripts/mkimport b/scripts/mkimport index e8b83c0..9ea224a 100755 --- a/scripts/mkimport +++ b/scripts/mkimport @@ -51,7 +51,7 @@ local tableconcat = table.concat -- config ------------------------------------------------------------------------------- -local context_root = "/home/phg/context/tex/texmf-context" +local parms = { } local our_prefix = "fontloader" local luatex_fonts_prefix = "luatex" local fontloader_subdir = "src/fontloader" @@ -69,7 +69,6 @@ local subdirs = { local searchdirs = { --- order is important! fontloader_subdir, - context_root } local prefixes = { @@ -259,7 +258,7 @@ end local derive_category_path = function (cat) local subpath = origin_paths[cat] or die ("category " .. cat .. " unknown") - local location = file.join (context_root, subpath) + local location = file.join (parms.context_root, subpath) if not lfsisdir (location) then die ("invalid base path defined for category " .. cat .. " at " .. location) @@ -482,7 +481,8 @@ end --[[ [local import_file = function (name, kind)] ]] local import = function (arg) if #arg > 1 then - local name = arg[2] or die ("invalid filename " .. tostring (arg[2])) + local tgt = parms.target + local name = tgt or die ("invalid filename " .. tostring (tgt)) local stat = import_file (name) if stat == import_failed then die ("failed to import file " .. name) @@ -526,10 +526,10 @@ local search_paths = function (target) end - local found = find_in_path (context_root, origin_paths.context, target) + local found = find_in_path (parms.context_root, origin_paths.context, target) if found then return found end - local found = find_in_path (context_root, origin_paths.fontloader, target) + local found = find_in_path (parms.context_root, origin_paths.fontloader, target) if found then return found end return false end @@ -656,7 +656,7 @@ local describe = function (target, location) end local tell = function (arg) - local target = arg[2] + local target = parms.target if not target then die "no filename given" end local location = search (target) @@ -846,12 +846,31 @@ local check_job = function (j) return job_kind[j] or die ("invalid job type “%s”.", j) end +local parse_argv = function (argv) + local job + local tgt + local pth + + local argc = #arg + if argc < 1 or argc > 3 then return "help" end + job = arg[1] or "help" + if argc > 1 then + tgt = arg[2] + if argc == 3 then pth = arg[3] end + end + if not pth then pth = "~/context/tex/texmf-context" end + parms.context_root = kpse.expand_path (pth) + parms.target = tgt + searchdirs [#searchdirs + 1] = pth + return job +end + ------------------------------------------------------------------------------- -- entry point ------------------------------------------------------------------------------- local main = function () - local job = arg[1] or "help" + local job = parse_argv (arg) local runner = check_job (job) return runner(arg) end -- cgit v1.2.3 From f385ec0f5919feed2839f6146a6ebbbce5926354 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 20 Nov 2015 00:01:41 +0100 Subject: [chars] allow passing location of char-def.lua on command line --- scripts/mkcharacters | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/scripts/mkcharacters b/scripts/mkcharacters index 9e9fd1a..59582f2 100755 --- a/scripts/mkcharacters +++ b/scripts/mkcharacters @@ -13,7 +13,7 @@ -- config ----------------------------------------------------------------------- local charfile = "./build/luaotfload-characters.lua" -local chardef = "/home/phg/base/char-def.lua" +local chardef = arg[1] --- for every code point char-def.lua provides a set of fields. they --- are: @@ -63,6 +63,11 @@ for _, lib in next, { "lualibs-lua.lua", require(found) end +if not chardef then + chardef = kpse.expand_path("~/context/tex/texmf-context/tex/context/base/") + .. "/char-def.lua" +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 @@ -70,6 +75,9 @@ if not (chardef and lfs.isfile(chardef)) then "Could not find ConTeXt.") end +io.write(string.format("extracting data from char-def.lua at %s\n", + chardef)) + ----------------------------------------------------------------------- -- functionality ----------------------------------------------------------------------- -- cgit v1.2.3 From 3a12cad2b229d501ef6835d27797a1a18fb981ef Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 20 Nov 2015 00:23:45 +0100 Subject: [conf] plug in the correct resolvers (fallout from db reorganization) --- src/luaotfload-configuration.lua | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/luaotfload-configuration.lua b/src/luaotfload-configuration.lua index efed573..57311dc 100644 --- a/src/luaotfload-configuration.lua +++ b/src/luaotfload-configuration.lua @@ -308,9 +308,9 @@ local set_name_resolver = function () --- replace the resolver from luatex-fonts if config.luaotfload.db.resolver == "cached" then logreport ("both", 2, "cache", "Caching of name: lookups active.") - names.resolvespec = names.resolve_cached + names.resolvespec = fonts.names.lookup_font_name_cached else - names.resolvespec = names.resolve_name + names.resolvespec = fonts.names.lookup_font_name end end return true -- cgit v1.2.3 From cf6c8c94cc88db6564ccea266b3c6d8f7a5bb1a1 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 20 Nov 2015 00:43:05 +0100 Subject: [tests] adapt lookup test runner (fallout from db reorganization) --- scripts/mktests | 65 +++++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 59 insertions(+), 6 deletions(-) diff --git a/scripts/mktests b/scripts/mktests index 757e360..ad8c4f5 100755 --- a/scripts/mktests +++ b/scripts/mktests @@ -18,14 +18,68 @@ local tests = { } local lpeg = require "lpeg" local lpegmatch = lpeg.match +config = { luaotfload = { } } +luatexbase = { } + kpse.set_program_name "luatex" require "lualibs" require "luaotfload-basics-gen.lua" require "luaotfload-log.lua" -require "luaotfload-parsers" -require "luaotfload-configuration" -require "luaotfload-database" + +fonts = { names = { } } -- for db; normally provided by the fontloaders + +local require_init = { } + +local loadmodule = function (name) + local v = require ("luaotfload-" .. name) + if v then + local mod = { } + local tv = type (v) + if tv == "table" then + mod.name = name + mod.init = v.init + require_init [#require_init + 1] = mod + elseif tv == "function" then + mod.name = name + mod.init = v + require_init [#require_init + 1] = mod + end + end +end + +require "alt_getopt" + +loadmodule "log.lua" --- this populates the luaotfload.log.* namespace +loadmodule "parsers" --- fonts.conf, configuration, and request syntax +loadmodule "configuration" --- configuration file handling +loadmodule "database" +loadmodule "resolvers" --- Font lookup + +do --- init_modules + --- NB we don’t command the logger at this point. + local todo = #require_init + local ret = true + for i = 1, todo do + local mod = require_init[i] + local name = mod.name + local init = mod.init + if type (init) ~= "function" then + error ("luaotfload broken; module " + .. name .. " missing initializers!") + end + local v = mod.init () + if v == true then + --- evaluated well + elseif type (v) == "table" then + luaotfload[name] = v + else + error ("luaotfload broken; initialization of module " + .. name .. " returned " .. tostring (v) .. ".") + return false + end + end +end local names = fonts.names @@ -234,7 +288,6 @@ local default_spec = { local resolve_font_name = function () local failed, total = 0, 0 - local resolve_name = names.resolve_name for nset = 1, #font_name_tests do local set = font_name_tests[nset] @@ -246,7 +299,7 @@ local resolve_font_name = function () local input_spec = table.copy (default_spec) input_spec.name = input input_spec.specification = input_spec.lookup .. ":" .. input - local result = resolve_name (input_spec) == output + local result = fonts.names.lookup_font_name (input_spec) == output total = total + 1 if not result then failed = failed + 1 @@ -260,7 +313,7 @@ local resolve_font_name = function () .. ":" .. input_spec.name input_spec.optsize = input_spec.optsize or default_spec.optsize input_spec.style = translate_style [input_spec.style] - local result = resolve_name (input_spec) == output + local result = fonts.names.lookup_font_name (input_spec) == output total = total + 1 if not result then failed = failed + 1 -- cgit v1.2.3 From 275d4d635fb09f3f0518b0b85ab4ca2d07004888 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 21 Nov 2015 16:31:35 +0100 Subject: [fontloader] sync with Context as of 2015-11-21 --- src/fontloader/misc/fontloader-font-con.lua | 8 +- src/fontloader/misc/fontloader-font-otf.lua | 28 +++-- src/fontloader/misc/fontloader-font-tfm.lua | 43 ++++++- src/fontloader/misc/fontloader-fonts-demo-vf-1.lua | 8 +- src/fontloader/misc/fontloader-fonts-otn.lua | 76 ------------ src/fontloader/misc/fontloader-plain.tex | 4 + src/fontloader/runtime/fontloader-reference.lua | 130 ++++++++------------- 7 files changed, 122 insertions(+), 175 deletions(-) diff --git a/src/fontloader/misc/fontloader-font-con.lua b/src/fontloader/misc/fontloader-font-con.lua index 383a403..55d7793 100644 --- a/src/fontloader/misc/fontloader-font-con.lua +++ b/src/fontloader/misc/fontloader-font-con.lua @@ -170,8 +170,8 @@ constructors.setfactor() function constructors.scaled(scaledpoints, designsize) -- handles designsize in sp as well if scaledpoints < 0 then + local factor = constructors.factor if designsize then - local factor = constructors.factor if designsize > factor then -- or just 1000 / when? mp? return (- scaledpoints/1000) * designsize -- sp's else @@ -700,6 +700,7 @@ function constructors.scale(tfmdata,specification) end -- if hasmath then + -- -- todo, just operate on descriptions.math local vn = character.next if vn then @@ -736,6 +737,11 @@ function constructors.scale(tfmdata,specification) chr.horiz_variants = t end end + -- todo also check mathitalics (or that one can go away) + end + local vi = character.vert_italic + if vi and vi ~= 0 then + chr.vert_italic = vi*hdelta end local va = character.accent if va then diff --git a/src/fontloader/misc/fontloader-font-otf.lua b/src/fontloader/misc/fontloader-font-otf.lua index 0ca1e98..f709e70 100644 --- a/src/fontloader/misc/fontloader-font-otf.lua +++ b/src/fontloader/misc/fontloader-font-otf.lua @@ -1999,9 +1999,10 @@ actions["merge kern classes"] = function(data,filename,raw) local kernclass = subtable.kernclass -- name is inconsistent with anchor_classes local lookup = subtable.lookup or subtable.name if kernclass then -- the next one is quite slow + -- as fas as i can see the kernclass is a table with one entry and offsets + -- have no [1] so we could remov eon elevel (kernclass) and start offsets + -- at 1 but we're too far down the road now to fix that if #kernclass > 0 then - -- it's a table with one entry .. a future luatex can just - -- omit that level kernclass = kernclass[1] lookup = type(kernclass.lookup) == "string" and kernclass.lookup or lookup report_otf("fixing kernclass table of lookup %a",lookup) @@ -2028,15 +2029,17 @@ actions["merge kern classes"] = function(data,filename,raw) if splt then local extrakerns = { } local baseoffset = (fk-1) * maxseconds - for sk=2,maxseconds do -- will become 1 based in future luatex - local sv = seconds[sk] -- for sk, sv in next, seconds do - local splt = split[sv] - if splt then -- redundant test - local offset = offsets[baseoffset + sk] - if offset then - for i=1,#splt do - extrakerns[splt[i]] = offset + for sk=2,maxseconds do + local sv = seconds[sk] + if sv then + local splt = split[sv] + if splt then -- redundant test + local offset = offsets[baseoffset + sk] + if offset then + for i=1,#splt do + extrakerns[splt[i]] = offset + end end end end @@ -2583,6 +2586,7 @@ local function copytotfm(data,cache_id) -- watch out: luatex uses horiz_variants for the parts -- local italic = m.italic + local vitalic = m.vitalic -- local variants = m.hvariants local parts = m.hparts @@ -2623,12 +2627,14 @@ local function copytotfm(data,cache_id) c.vert_variants = parts elseif parts then character.vert_variants = parts - italic = m.vitalic end -- if italic and italic ~= 0 then character.italic = italic -- overload end + if vitalic and vitalic ~= 0 then + character.vert_italic = vitalic + end -- local accent = m.accent if accent then diff --git a/src/fontloader/misc/fontloader-font-tfm.lua b/src/fontloader/misc/fontloader-font-tfm.lua index 401dc83..2dd5768 100644 --- a/src/fontloader/misc/fontloader-font-tfm.lua +++ b/src/fontloader/misc/fontloader-font-tfm.lua @@ -25,6 +25,8 @@ local encodings = fonts.encodings local tfm = constructors.newhandler("tfm") tfm.version = 1.000 +tfm.maxnestingdepth = 5 +tfm.maxnestingsize = 65536*1024 local tfmfeatures = constructors.newfeatures("tfm") local registertfmfeature = tfmfeatures.register @@ -45,6 +47,18 @@ supplied by .

-- ofm directive blocks local path search unless set; btw, in context we -- don't support ofm files anyway as this format is obsolete +-- we need to deal with nested virtual fonts, but because we load in the +-- frontend we also need to make sure we don't nest too deep (esp when sizes +-- get large) +-- +-- (VTITLE Example of a recursion) +-- (MAPFONT D 0 (FONTNAME recurse)(FONTAT D 2)) +-- (CHARACTER C A (CHARWD D 1)(CHARHT D 1)(MAP (SETRULE D 1 D 1))) +-- (CHARACTER C B (CHARWD D 2)(CHARHT D 2)(MAP (SETCHAR C A))) +-- (CHARACTER C C (CHARWD D 4)(CHARHT D 4)(MAP (SETCHAR C B))) +-- +-- we added the same checks as below to the luatex engine + function tfm.setfeatures(tfmdata,features) local okay = constructors.initializefeatures("tfm",tfmdata,features,trace_features,report_tfm) if okay then @@ -54,9 +68,12 @@ function tfm.setfeatures(tfmdata,features) end end +local depth = { } -- table.setmetatableindex("number") + local function read_from_tfm(specification) - local filename = specification.filename - local size = specification.size + local filename = specification.filename + local size = specification.size + depth[filename] = (depth[filename] or 0) + 1 if trace_defining then report_defining("loading tfm file %a at size %s",filename,size) end @@ -104,6 +121,25 @@ local function read_from_tfm(specification) end properties.virtualized = true tfmdata.fonts = vfdata.fonts + tfmdata.type = "virtual" -- else nested calls with cummulative scaling + local fontlist = vfdata.fonts + local name = file.nameonly(filename) + for i=1,#fontlist do + local n = fontlist[i].name + local s = fontlist[i].size + local d = depth[filename] + s = constructors.scaled(s,vfdata.designsize) + if d > tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i] = { id = 0 } + elseif (d > 1) and (s > tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i] = { id = 0 } + else + local t, id = fonts.constructors.readanddefine(n,s) + fontlist[i] = { id = id } + end + end end end end @@ -122,7 +158,10 @@ local function read_from_tfm(specification) resources.unicodes = { } resources.lookuptags = { } -- + depth[filename] = depth[filename] - 1 return tfmdata + else + depth[filename] = depth[filename] - 1 end end diff --git a/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua b/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua index 3878ae6..13acd16 100644 --- a/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua +++ b/src/fontloader/misc/fontloader-fonts-demo-vf-1.lua @@ -17,6 +17,7 @@ return function(specification) { "special", "pdf:1 0 0 rg" }, { "special", "pdf:0 1 0 rg" }, { "special", "pdf:0 0 1 rg" }, + { "special", "pdf:0 0 1 rg" }, } local chars = { identifiers[id1].characters, @@ -26,7 +27,12 @@ return function(specification) for u, v in next, f1.characters do local n = math.floor(math.random(1,3)+0.5) local c = chars[n][u] or v - v.commands = { color[n], { 'slot', n, u }, color[0] } + v.commands = { + color[n], + { 'slot', n, u }, + color[0], + { 'nop' } + } v.kerns = nil v.width = c.width v.height = c.height diff --git a/src/fontloader/misc/fontloader-fonts-otn.lua b/src/fontloader/misc/fontloader-fonts-otn.lua index 1b99c56..7fafadb 100644 --- a/src/fontloader/misc/fontloader-fonts-otn.lua +++ b/src/fontloader/misc/fontloader-fonts-otn.lua @@ -250,7 +250,6 @@ local disccodes = nodes.disccodes local glyph_code = nodecodes.glyph local glue_code = nodecodes.glue local disc_code = nodecodes.disc -local whatsit_code = nodecodes.whatsit local math_code = nodecodes.math local dir_code = whatcodes.dir @@ -316,8 +315,6 @@ local notmatchpre = { } local notmatchpost = { } local notmatchreplace = { } --- head is always a whatsit so we can safely assume that head is not changed - -- we use this for special testing and documentation local checkstep = (nodes and nodes.tracers and nodes.tracers.steppers.check) or function() end @@ -3320,43 +3317,6 @@ local function featuresprocessor(head,font,attr) comprun(start,c_run) start = getnext(start) end - elseif id == whatsit_code then -- will be function - local subtype = getsubtype(start) - if subtype == dir_code then - local dir = getfield(start,"dir") - if dir == "+TLT" then - topstack = topstack + 1 - dirstack[topstack] = dir - rlmode = 1 - elseif dir == "+TRT" then - topstack = topstack + 1 - dirstack[topstack] = dir - rlmode = -1 - elseif dir == "-TLT" or dir == "-TRT" then - topstack = topstack - 1 - rlmode = dirstack[topstack] == "+TRT" and -1 or 1 - else - rlmode = rlparmode - end - if trace_directions then - report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) - end - elseif subtype == localpar_code then - local dir = getfield(start,"dir") - if dir == "TRT" then - rlparmode = -1 - elseif dir == "TLT" then - rlparmode = 1 - else - rlparmode = 0 - end - -- one might wonder if the par dir should be looked at, so we might as well drop the next line - rlmode = rlparmode - if trace_directions then - report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) - end - end - start = getnext(start) elseif id == math_code then start = getnext(end_of_math(start)) else @@ -3592,42 +3552,6 @@ local function featuresprocessor(head,font,attr) comprun(start,c_run) start = getnext(start) end - elseif id == whatsit_code then - local subtype = getsubtype(start) - if subtype == dir_code then - local dir = getfield(start,"dir") - if dir == "+TLT" then - topstack = topstack + 1 - dirstack[topstack] = dir - rlmode = 1 - elseif dir == "+TRT" then - topstack = topstack + 1 - dirstack[topstack] = dir - rlmode = -1 - elseif dir == "-TLT" or dir == "-TRT" then - topstack = topstack - 1 - rlmode = dirstack[topstack] == "+TRT" and -1 or 1 - else - rlmode = rlparmode - end - if trace_directions then - report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) - end - elseif subtype == localpar_code then - local dir = getfield(start,"dir") - if dir == "TRT" then - rlparmode = -1 - elseif dir == "TLT" then - rlparmode = 1 - else - rlparmode = 0 - end - rlmode = rlparmode - if trace_directions then - report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) - end - end - start = getnext(start) elseif id == math_code then start = getnext(end_of_math(start)) else diff --git a/src/fontloader/misc/fontloader-plain.tex b/src/fontloader/misc/fontloader-plain.tex index 9902c49..99347ed 100644 --- a/src/fontloader/misc/fontloader-plain.tex +++ b/src/fontloader/misc/fontloader-plain.tex @@ -13,6 +13,10 @@ % We assume that pdf is used. +\ifdefined\pdfextension + \input luatex-pdf \relax +\fi + \pdfoutput 1 % We set the page dimensions because otherwise the backend does weird things diff --git a/src/fontloader/runtime/fontloader-reference.lua b/src/fontloader/runtime/fontloader-reference.lua index a2a598b..ae36617 100644 --- a/src/fontloader/runtime/fontloader-reference.lua +++ b/src/fontloader/runtime/fontloader-reference.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 10/09/15 21:28:28 +-- merge date : 11/19/15 19:13:15 do -- begin closure to overcome local limits and interference @@ -4211,8 +4211,8 @@ end constructors.setfactor() function constructors.scaled(scaledpoints,designsize) if scaledpoints<0 then + local factor=constructors.factor if designsize then - local factor=constructors.factor if designsize>factor then return (- scaledpoints/1000)*designsize else @@ -4650,6 +4650,10 @@ function constructors.scale(tfmdata,specification) end end end + local vi=character.vert_italic + if vi and vi~=0 then + chr.vert_italic=vi*hdelta + end local va=character.accent if va then chr.top_accent=vdelta*va @@ -5833,6 +5837,8 @@ local constructors=fonts.constructors local encodings=fonts.encodings local tfm=constructors.newhandler("tfm") tfm.version=1.000 +tfm.maxnestingdepth=5 +tfm.maxnestingsize=65536*1024 local tfmfeatures=constructors.newfeatures("tfm") local registertfmfeature=tfmfeatures.register constructors.resolvevirtualtoo=false @@ -5845,9 +5851,11 @@ function tfm.setfeatures(tfmdata,features) return {} end end +local depth={} local function read_from_tfm(specification) local filename=specification.filename local size=specification.size + depth[filename]=(depth[filename] or 0)+1 if trace_defining then report_defining("loading tfm file %a at size %s",filename,size) end @@ -5891,6 +5899,25 @@ local function read_from_tfm(specification) end properties.virtualized=true tfmdata.fonts=vfdata.fonts + tfmdata.type="virtual" + local fontlist=vfdata.fonts + local name=file.nameonly(filename) + for i=1,#fontlist do + local n=fontlist[i].name + local s=fontlist[i].size + local d=depth[filename] + s=constructors.scaled(s,vfdata.designsize) + if d>tfm.maxnestingdepth then + report_defining("too deeply nested virtual font %a with size %a, max nesting depth %s",n,s,tfm.maxnestingdepth) + fontlist[i]={ id=0 } + elseif (d>1) and (s>tfm.maxnestingsize) then + report_defining("virtual font %a exceeds size %s",n,s) + fontlist[i]={ id=0 } + else + local t,id=fonts.constructors.readanddefine(n,s) + fontlist[i]={ id=id } + end + end end end end @@ -5906,7 +5933,10 @@ local function read_from_tfm(specification) properties.haslogatures=true resources.unicodes={} resources.lookuptags={} + depth[filename]=depth[filename]-1 return tfmdata + else + depth[filename]=depth[filename]-1 end end local function check_tfm(specification,fullname) @@ -8652,7 +8682,7 @@ actions["merge kern classes"]=function(data,filename,raw) local subtable=subtables[s] local kernclass=subtable.kernclass local lookup=subtable.lookup or subtable.name - if kernclass then + if kernclass then if #kernclass>0 then kernclass=kernclass[1] lookup=type(kernclass.lookup)=="string" and kernclass.lookup or lookup @@ -8677,14 +8707,16 @@ actions["merge kern classes"]=function(data,filename,raw) if splt then local extrakerns={} local baseoffset=(fk-1)*maxseconds - for sk=2,maxseconds do + for sk=2,maxseconds do local sv=seconds[sk] - local splt=split[sv] - if splt then - local offset=offsets[baseoffset+sk] - if offset then - for i=1,#splt do - extrakerns[splt[i]]=offset + if sv then + local splt=split[sv] + if splt then + local offset=offsets[baseoffset+sk] + if offset then + for i=1,#splt do + extrakerns[splt[i]]=offset + end end end end @@ -9145,6 +9177,7 @@ local function copytotfm(data,cache_id) local m=d.math if m then local italic=m.italic + local vitalic=m.vitalic local variants=m.hvariants local parts=m.hparts if variants then @@ -9171,11 +9204,13 @@ local function copytotfm(data,cache_id) c.vert_variants=parts elseif parts then character.vert_variants=parts - italic=m.vitalic end if italic and italic~=0 then character.italic=italic end + if vitalic and vitalic~=0 then + character.vert_italic=vitalic + end local accent=m.accent if accent then character.accent=accent @@ -11610,7 +11645,6 @@ local disccodes=nodes.disccodes local glyph_code=nodecodes.glyph local glue_code=nodecodes.glue local disc_code=nodecodes.disc -local whatsit_code=nodecodes.whatsit local math_code=nodecodes.math local dir_code=whatcodes.dir local localpar_code=whatcodes.localpar @@ -14245,42 +14279,6 @@ local function featuresprocessor(head,font,attr) comprun(start,c_run) start=getnext(start) end - elseif id==whatsit_code then - local subtype=getsubtype(start) - if subtype==dir_code then - local dir=getfield(start,"dir") - if dir=="+TLT" then - topstack=topstack+1 - dirstack[topstack]=dir - rlmode=1 - elseif dir=="+TRT" then - topstack=topstack+1 - dirstack[topstack]=dir - rlmode=-1 - elseif dir=="-TLT" or dir=="-TRT" then - topstack=topstack-1 - rlmode=dirstack[topstack]=="+TRT" and -1 or 1 - else - rlmode=rlparmode - end - if trace_directions then - report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) - end - elseif subtype==localpar_code then - local dir=getfield(start,"dir") - if dir=="TRT" then - rlparmode=-1 - elseif dir=="TLT" then - rlparmode=1 - else - rlparmode=0 - end - rlmode=rlparmode - if trace_directions then - report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) - end - end - start=getnext(start) elseif id==math_code then start=getnext(end_of_math(start)) else @@ -14501,42 +14499,6 @@ local function featuresprocessor(head,font,attr) comprun(start,c_run) start=getnext(start) end - elseif id==whatsit_code then - local subtype=getsubtype(start) - if subtype==dir_code then - local dir=getfield(start,"dir") - if dir=="+TLT" then - topstack=topstack+1 - dirstack[topstack]=dir - rlmode=1 - elseif dir=="+TRT" then - topstack=topstack+1 - dirstack[topstack]=dir - rlmode=-1 - elseif dir=="-TLT" or dir=="-TRT" then - topstack=topstack-1 - rlmode=dirstack[topstack]=="+TRT" and -1 or 1 - else - rlmode=rlparmode - end - if trace_directions then - report_process("directions after txtdir %a: parmode %a, txtmode %a, # stack %a, new dir %a",dir,rlparmode,rlmode,topstack,newdir) - end - elseif subtype==localpar_code then - local dir=getfield(start,"dir") - if dir=="TRT" then - rlparmode=-1 - elseif dir=="TLT" then - rlparmode=1 - else - rlparmode=0 - end - rlmode=rlparmode - if trace_directions then - report_process("directions after pardir %a: parmode %a, txtmode %a",dir,rlparmode,rlmode) - end - end - start=getnext(start) elseif id==math_code then start=getnext(end_of_math(start)) else -- cgit v1.2.3 From 0ee06552f8a2c0e29e67754fe0571549ad6855aa Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 21 Nov 2015 17:38:19 +0100 Subject: [letterspace] pull in missing local --- src/luaotfload-letterspace.lua | 1 + 1 file changed, 1 insertion(+) diff --git a/src/luaotfload-letterspace.lua b/src/luaotfload-letterspace.lua index 9a0646b..ab81881 100644 --- a/src/luaotfload-letterspace.lua +++ b/src/luaotfload-letterspace.lua @@ -27,6 +27,7 @@ local getnext = nodedirect.getnext local getprev = nodedirect.getprev local getfield = nodedirect.getfield local setfield = nodedirect.setfield +local getsubtype = nodedirect.getsubtype local find_node_tail = nodedirect.tail local todirect = nodedirect.tonut local tonode = nodedirect.tonode -- cgit v1.2.3