From 539c87e88dbea35170bf5a40957586bc5d9a9270 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Wed, 27 Jan 2016 08:13:45 +0100 Subject: [resolvers] allow arbitrary sequence lookups MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This primarily affects the “anon” lookup. However, since we cannot any longer determine the lookup success by crude means, the resolver signature had to be modified to indicate success or failure via the return value. This does no longer match the resolver implementation of Context but the interface has become much cleaner. --- src/luaotfload-resolvers.lua | 126 ++++++++++++++++++++++++++++--------------- 1 file changed, 84 insertions(+), 42 deletions(-) (limited to 'src') diff --git a/src/luaotfload-resolvers.lua b/src/luaotfload-resolvers.lua index 3d7f6b0..05a0656 100644 --- a/src/luaotfload-resolvers.lua +++ b/src/luaotfload-resolvers.lua @@ -62,14 +62,18 @@ local logreport = luaotfload.log.report local resolve_file resolve_file = function (specification) - local name = fonts.names.lookup_font_file (specification.name) + local name, _format, success = fonts.names.lookup_font_file (specification.name) local suffix = filesuffix (name) if fonts.formats[suffix] then specification.forced = stringlower (suffix) - specification.forcedname = fileremovesuffix(name) + specification.forcedname = fileremovesuffix (name) else specification.name = name end + if success ~= true then + logreport ("log", 1, "resolve", "file lookup of %q unsuccessful", name) + end + return success end --[[doc-- @@ -85,22 +89,22 @@ end local resolve_path resolve_path = function (specification) local name = specification.name - local exists, _ = lfsisfile(name) + local exists, _ = lfsisfile (name) if not exists then -- resort to file: lookup - logreport ("log", 0, "load", + logreport ("log", 1, "resolve", "path lookup of %q unsuccessful, falling back to file:", name) - resolve_file (specification) + return resolve_file (specification) + end + local suffix = filesuffix (name) + if fonts.formats [suffix] then + specification.forced = stringlower (suffix) + specification.name = fileremovesuffix (name) + specification.forcedname = name else - local suffix = filesuffix (name) - if fonts.formats[suffix] then - specification.forced = stringlower (suffix) - specification.name = fileremovesuffix(name) - specification.forcedname = name - else - specification.name = name - end + specification.name = name end + return true end --[[doc-- @@ -120,18 +124,17 @@ resolve_name = function (specification) end local resolved, subfont = resolver (specification) if resolved then - logreport ("log", 0, "load", "Lookup/name: %q -> \"%s%s\"", - specification.name, - resolved, + logreport ("log", 1, "resolve", "name lookup %q -> \"%s%s\"", + specification.name, resolved, subfont and stringformat ("(%d)", subfont) or "") specification.resolved = resolved specification.sub = subfont specification.forced = stringlower (filesuffix (resolved) or "") specification.forcedname = resolved specification.name = fileremovesuffix (resolved) - else - resolve_file (specification) + return true end + return resolve_file (specification) end --[[doc-- @@ -158,36 +161,74 @@ end --doc]]-- -local type1_formats = { "tfm", "ofm", "TFM", "OFM", } +local tex_formats = { "tfm", "ofm", "TFM", "OFM", } -local resolve_anon -resolve_anon = function (specification) +local resolve_tex_format = function (specification) local name = specification.name - for i=1, #type1_formats do - local format = type1_formats[i] + for i=1, #tex_formats do + local format = tex_formats [i] local suffix = filesuffix (name) - if resolvers.findfile(name, format) then + if resolvers.findfile (name, format) then local usename = suffix == format and fileremovesuffix (name) or name specification.forcedname = file.addsuffix (usename, format) specification.forced = format - return + return true end end - --- under some weird circumstances absolute paths get - --- passed to the definer; we have to catch them - --- before the name: resolver misinterprets them. - name = specification.specification - local exists, _ = lfsisfile(name) - if exists then --- garbage; we do this because we are nice, - --- not because it is correct - logreport ("log", 1, "load", "file %q exists", name) - logreport ("log", 1, "load", - "... overriding borked anon: lookup with path: lookup") - specification.name = name - resolve_path (specification) - return + return false +end + +local resolve_path_if_exists = function (specification) + local spec = specification.specification + local exists, _void = lfsisfile (spec) + if exists then + --- If this path is taken a file matching the specification + --- literally was found. In this situation, Luaotfload is + --- expected to load that file directly, even though we provide + --- explicit “file” and “path” lookups to address exactly this + --- situation. + logreport ("log", 1, "resolve", + "file %q exists, performing path lookup", spec) + specification.name = spec + return resolve_path (specification) + end + return false +end + +local resolve_methods = { + tex = resolve_tex_format, + path = resolve_path_if_exists, + name = resolve_name, +} + +local resolve_sequence = function (seq, specification) + for i = 1, #seq do + local id = seq [i] + local mth = resolve_methods [id] + logreport ("both", 0, "resolve", "step %d: apply method %q (%s)", i, id, mth) + if mth (specification) == true then + logreport ("both", 0, "resolve", + "%d: method %q indicated lookup success", i, id) + logreport ("both", 0, "resolve", + "method %q resolved %q -> %s (%s)", + id, specification.specification, + specification.name, + specification.forcedname) + return true + end end - resolve_name (specification) + logreport ("both", 0, "resolve", + "sequence of %d lookups yielded nothing appropriate", #seq) + return false +end + +local default_anon_sequence = { + "tex", "path", "name", +} + +local resolve_anon +resolve_anon = function (specification) + return resolve_sequence (default_anon_sequence, specification) end --[[doc-- @@ -207,16 +248,17 @@ resolve_kpse = function (specification) if resolvers.findfile (name, suffix) then specification.forced = stringlower (suffix) specification.forcedname = name - return + return true end end for t, format in next, fonts.formats do --- brute force if kpsefind_file (name, format) then specification.forced = t specification.name = name - return + return true end end + return false end --[[doc-- @@ -250,5 +292,5 @@ return { end, --- [.init] } ---- vim:ft=lua:ts=8:sw=4:et +--- vim:ft=lua:ts=8:sw=4:et:tw=79 -- cgit v1.2.3 From fdefa722cdbf92c38e02f26a1a7092ef70a14cae Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 12 Feb 2016 00:39:37 +0100 Subject: [fontloader] patch font-otn.lua to skip unusable contextpos features Address issue #322 The annotation says it all; reportedly this is fine with TL 2016, though. --- src/fontloader/misc/fontloader-font-otn.lua | 4 ++-- src/luaotfload-main.lua | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) (limited to 'src') diff --git a/src/fontloader/misc/fontloader-font-otn.lua b/src/fontloader/misc/fontloader-font-otn.lua index 081630a..9cdb79b 100644 --- a/src/fontloader/misc/fontloader-font-otn.lua +++ b/src/fontloader/misc/fontloader-font-otn.lua @@ -3897,9 +3897,9 @@ local function split(replacement,original) end local valid = { -- does contextpos work? - coverage = { chainsub = true, chainpos = true, contextsub = true, contextpos = true }, + coverage = { chainsub = true, chainpos = true, contextsub = true, contextpos = false }, reversecoverage = { reversesub = true }, - glyphs = { chainsub = true, chainpos = true, contextsub = true, contextpos = true }, + glyphs = { chainsub = true, chainpos = true, contextsub = true, contextpos = false }, } local function prepare_contextchains(tfmdata) diff --git a/src/luaotfload-main.lua b/src/luaotfload-main.lua index c843f26..d5fdb9e 100644 --- a/src/luaotfload-main.lua +++ b/src/luaotfload-main.lua @@ -13,7 +13,7 @@ local luaotfload = luaotfload luaotfload.log = luaotfload.log or { } luaotfload.version = "2.6" luaotfload.loaders = { } -luaotfload.min_luatex_version = 80 --- i. e. 0.79 +luaotfload.min_luatex_version = 80 --- i. e. 0.80 luaotfload.fontloader_package = "reference" --- default: from current Context local authors = "\z -- cgit v1.2.3 From 0a1b9b746b5ce4cd740af8948f083685879c4eb9 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 15 Feb 2016 08:26:54 +0100 Subject: [parsers,features] parse combo requests Highly experimental at this point. The font request parser has been extended to handle combinations of already defined fonts. Nothing else has been implemented yet, so the request handler will simply error out with a message. --- src/luaotfload-features.lua | 14 ++++++++++++-- src/luaotfload-parsers.lua | 30 ++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index fd43e58..6df04b2 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -993,7 +993,10 @@ local import_values = { { "mode", true }, } -local lookup_types = { "anon", "file", "kpse", "my", "name", "path" } +local lookup_types = { "anon" , "file", "kpse" + , "my" , "name", "path" + , "combo" + } local select_lookup = function (request) for i=1, #lookup_types do @@ -1049,6 +1052,7 @@ end local handle_request = function (specification) local request = lpegmatch(luaotfload.parsers.font_request, specification.specification) +----inspect(request) if not request then --- happens when called with an absolute path --- in an anonymous lookup; @@ -1077,7 +1081,13 @@ local handle_request = function (specification) specification.lookup = "path" return specification end + local lookup, name = select_lookup(request) + if lookup == "combo" then + report ("both", 0, "load", + "‘combo’ lookup not implemented at this stage.") + os.exit(-42) + end request.features = apply_default_features(request.features) if name then @@ -1749,4 +1759,4 @@ return { end } --- vim:tw=71:sw=4:ts=4:expandtab +-- vim:tw=79:sw=4:ts=4:expandtab diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua index 0349cdc..5ebe8d5 100644 --- a/src/luaotfload-parsers.lua +++ b/src/luaotfload-parsers.lua @@ -45,6 +45,7 @@ local lfsisdir = lfs.isdir --- COMMON PATTERNS ------------------------------------------------------------------------------- +local asterisk = P"*" local dot = P"." local colon = P":" local semicolon = P";" @@ -72,6 +73,8 @@ local digit = R"09" local alpha = R("az", "AZ") local anum = alpha + digit local decimal = digit^1 * (dot * digit^0)^-1 +local hexdigit = R("09", "af", "AF") +local hex = P"0x" * hexdigit^1 ------------------------------------------------------------------------------- --- FONTCONFIG @@ -560,9 +563,35 @@ local modifier = slash * (other_modifier --> ignore + garbage_modifier) --> warn local modifier_list = Cg(Ct(modifier^0), "modifiers") +--- combining --------------------------------------------------------- +--- +--- \font \three = combo:1/42,2/99/0xdeadbeef,3/1/U+2a-U+1337*42 +--- v +~ v +~ +~~~~~~~~~ v v +~~~ +~~~~~ +~ +--- | | | | | | | | | | +--- | | | | | | | | | | +--- idx : --+-÷--+-÷--÷----------+ | +----+ | +--- | | | | | | +--- id : ----+----+--÷------------+ +-----------+ +--- | | +--- chars : ------------+--------------+ +--- +local combohex = hex / tonumber +local combouint = digit^1 / tonumber +local tonumber16 = function (s) return tonumber (s, 16) end +local combouni = P"U+" * (digit^1 / tonumber16) +local combonum = combohex + combouni + combouint +local comborange = Ct(combonum * dash * combonum) + combonum +local combochars = comborange * (asterisk * comborange)^0 +local combodef1 = Ct( Cg(combouint, "idx") --> no chars + * slash * Cg(combouint, "id" )) +local combodef = Ct( Cg(combouint, "idx" ) + * slash * Cg(combouint, "id" ) + * slash * Cg(Ct(combochars^1), "chars")) +local combolist = Ct(combodef1 * (comma * combodef)^1) --- lookups ----------------------------------------------------------- local fontname = C((1-S":(/")^1) --- like luatex-fonts local unsupported = Cmt((1-S":(")^1, check_garbage) +local combo = P"combo:" * ws * Cg(combolist, "combo") local prefixed = P"name:" * ws * Cg(fontname, "name") --- initially we intended file: to emulate the behavior of --- luatex-fonts, i.e. no paths allowed. after all, we do have XeTeX @@ -626,6 +655,7 @@ local specification = (prefixed + unprefixed) * subfont^-1 * modifier_list^-1 local font_request = Ct(path_lookup * (colon^-1 * features)^-1 + + combo --> TODO: feature list needed? + specification * (colon * features)^-1) -- lpeg.print(font_request) -- cgit v1.2.3 From de3abd3209745257c1fbb7bf08be6b189d5e3cdd Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Tue, 16 Feb 2016 08:23:41 +0100 Subject: [features] handle combination definitions --- src/luaotfload-features.lua | 113 +++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 106 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 6df04b2..723fd54 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -19,6 +19,7 @@ local C = lpeg.C local table = table local tabletohash = table.tohash +local tablesort = table.sort local setmetatableindex = table.setmetatableindex local insert = table.insert @@ -28,6 +29,7 @@ local insert = table.insert local fonts = fonts local definers = fonts.definers local handlers = fonts.handlers +local fontidentifiers = fonts.hashes and fonts.hashes.identifiers local as_script, normalize @@ -65,6 +67,104 @@ local stringformat = string.format local stringis_empty = string.is_empty local mathceil = math.ceil +local cmp_by_idx = function (a, b) return a.idx < b.idx end + +local handle_combination = function (combo, spec) + if not combo [1] then + report ("both", 0, "load", "Empty font combination requested.") + return false + end + inspect(combo) + + if not fontidentifiers then + fontidentifiers = fonts.hashes and fonts.hashes.identifiers + end + + local chain = { } + local fontids = { } + local n = #combo + + tablesort (combo, cmp_by_idx) + + --- pass 1: skim combo and resolve fonts + report ("both", 0, "load", "Combining %d fonts.", n) + for i = 1, n do + local cur = combo [i] + local id = cur.id + local idx = cur.idx + local fnt = fontidentifiers [id] + if fnt then + local chars = cur.chars + report ("both", 0, "load", + " *> %.2d: include font %d at rank %d (%d items).", + i, id, idx, (chars and #chars or 0)) + chain [#chain + 1] = { fnt, chars, idx = idx } + fontids [#fontids + 1] = id + else + report ("both", 0, "load", + " *> %.2d: font %d at rank %d unknown, skipping.", + n, id, idx) + --- TODO might instead attempt to define the font at this point + --- but that’d require some modifications to the syntax + end + end + + local nc = #chain + if nc == 0 then + report ("both", 0, "load", + " *> no valid font (of %d) in combination.", n) + return false + end + + local basefnt = chain [1] [1] + if nc == 1 then + report ("both", 0, "load", + " *> combination boils down to a single font (%s) \z + of %d initially specified; not pursuing this any \z + further.", basefnt.fullname, n) + return basefnt + end + + local basechar = basefnt.characters + local baseprop = basefnt.properties + baseprop.name = spec.name + baseprop.virtualized = true + baseprop.fonts = fontids + + for i = 2, nc do + local cur = chain [i] + local fnt = cur [1] + local def = cur [2] + local src = fnt.characters + local cnt = 0 + + local pickchr = function (uc) + local chr = src [uc] + if chr then + chr.commands = { "slot", i, uc } + basechar [uc] = chr + cnt = cnt + 1 + end + end + + for j = 1, #def do + local this = def [j] + if type (this) == "number" then + pickchr (this) + elseif type (this) == "table" then + for uc = this [1], this [2] do pickchr (uc) end + else + report ("both", 0, "load", + " *> item no. %d of combination definition \z + %d not processable.", j, i) + end + end + report ("both", 0, "load", + " *> font %d / %d: imported %d glyphs into combo.", + i, nc, cnt) + end + return basefnt +end ---[[ begin excerpt from font-ott.lua ]] @@ -1082,13 +1182,12 @@ local handle_request = function (specification) return specification end - local lookup, name = select_lookup(request) + local lookup, name = select_lookup (request) if lookup == "combo" then - report ("both", 0, "load", - "‘combo’ lookup not implemented at this stage.") - os.exit(-42) + return handle_combination (request.combo, specification) end - request.features = apply_default_features(request.features) + + request.features = apply_default_features(request.features) if name then specification.name = name @@ -1126,8 +1225,8 @@ if as_script == true then --- skip the remainder of the file return else local registersplit = definers.registersplit - registersplit (":", handle_request, "cryptic") - registersplit ("", handle_request, "more cryptic") -- catches \font\text=[names] + registersplit (":", handle_request, "common") + registersplit ("", handle_request, "xetex path style") -- catches \font\text=[names] end ---[[ end included font-ltx.lua ]] -- cgit v1.2.3 From 1a6a253e85e609d37113585081b6cf9711757208 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 18 Feb 2016 08:35:22 +0100 Subject: [features,loaders] allow for direct injection of tfmdata when defining fonts --- src/luaotfload-features.lua | 17 ++++++++++++++--- src/luaotfload-loaders.lua | 46 +++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 56 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 723fd54..0ca58c1 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -74,7 +74,6 @@ local handle_combination = function (combo, spec) report ("both", 0, "load", "Empty font combination requested.") return false end - inspect(combo) if not fontidentifiers then fontidentifiers = fonts.hashes and fonts.hashes.identifiers @@ -150,9 +149,16 @@ local handle_combination = function (combo, spec) for j = 1, #def do local this = def [j] if type (this) == "number" then + report ("both", 0, "load", + " *> [%d][%d]: import codepoint U+%.4X", + i, j, this) pickchr (this) elseif type (this) == "table" then - for uc = this [1], this [2] do pickchr (uc) end + local lo, hi = unpack (this) + report ("both", 0, "load", + " *> [%d][%d]: import codepoint range U+%.4X--U+%.4X", + i, j, lo, hi) + for uc = lo, hi do pickchr (uc) end else report ("both", 0, "load", " *> item no. %d of combination definition \z @@ -163,7 +169,12 @@ local handle_combination = function (combo, spec) " *> font %d / %d: imported %d glyphs into combo.", i, nc, cnt) end - return basefnt + spec.lookup = nil + spec.method = nil + spec.name = spec.specification + spec.forced = nil + spec.data = function () return basefnt end + return spec end ---[[ begin excerpt from font-ott.lua ]] diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index 0f22f46..8e5248b 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -14,13 +14,43 @@ if not luaotfload then error "this module requires Luaotfload" end local logreport = luaotfload.log and luaotfload.log.report or print +local lua_reader = function (specification) + local fullname = specification.filename or "" + if fullname == "" then + local forced = specification.forced or "" + if forced ~= "" then + fullname = specification.name .. "." .. forced + else + fullname = specification.name + end + end + local fullname = resolvers.findfile (fullname) or "" + if fullname ~= "" then + local loader = loadfile (fullname) + loader = loader and loader () + return loader and loader (specification) + end +end + +local data_reader = function (specification) + local data = specification.data + if data and type (data) == "function" then + logreport ("both", 0, "loaders", + "data: found tfmdata for “%s”, injecting.", + specification.name) + return data () + end +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 + local readers = fonts.readers + local sequence = readers.sequence + local seqset = table.tohash (sequence) + 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) @@ -32,10 +62,18 @@ local install_formats = function () formats [which] = "type1" readers [which] = reader handlers [which] = { } + if not seqset [which] then + logreport ("both", 0, "loaders", + "Extending reader sequence for “%s”.", which) + sequence [#sequence + 1] = which + seqset [which] = true + end return true end - return aux ("pfa", function (spec) return readers.opentype (spec, "pfa", "type1") end) + return aux ("dat", data_reader) + and aux ("lua", lua_reader) + and 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 -- cgit v1.2.3 From 128b29a4260f0454996f5663a02c0f7c575b2d6b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 19 Feb 2016 00:51:24 +0100 Subject: =?UTF-8?q?[features,loaders]=20fix=20lookup=20conflicts=20via=20i?= =?UTF-8?q?ntroduction=20of=20=E2=80=9Cevl=E2=80=9D=20lookup?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This introduces a forced lookup type “evl” that bypasses the other methods. The specification is extended with the correct values including a more meaningful hash string. As a result, the loader no longer attempts to interpret the specification as a “file:” request but the backend can still resolve the necessary files. --- src/luaotfload-database.lua | 4 ++-- src/luaotfload-features.lua | 26 ++++++++++++++++---------- src/luaotfload-loaders.lua | 17 ++++++++--------- 3 files changed, 26 insertions(+), 21 deletions(-) (limited to 'src') diff --git a/src/luaotfload-database.lua b/src/luaotfload-database.lua index 367723b..1d5dfd8 100644 --- a/src/luaotfload-database.lua +++ b/src/luaotfload-database.lua @@ -583,8 +583,6 @@ local style_category = { local type1_metrics = { "tfm", "ofm", } -local dummy_findfile = resolvers.findfile -- from basics-gen - local lookup_filename = function (filename) if not name_index then name_index = load_names () end local files = name_index.files @@ -630,6 +628,8 @@ end --doc]]-- +local dummy_findfile = resolvers.findfile -- from basics-gen + --- string -> string * string * bool local lookup_font_file lookup_font_file = function (filename) diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index 0ca58c1..aeeaea3 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -69,9 +69,14 @@ local mathceil = math.ceil local cmp_by_idx = function (a, b) return a.idx < b.idx end +local defined_combos = 0 + local handle_combination = function (combo, spec) + defined_combos = defined_combos + 1 if not combo [1] then - report ("both", 0, "load", "Empty font combination requested.") + report ("both", 0, "load", + "combo %d: Empty font combination requested.", + defined_combos) return false end @@ -86,7 +91,8 @@ local handle_combination = function (combo, spec) tablesort (combo, cmp_by_idx) --- pass 1: skim combo and resolve fonts - report ("both", 0, "load", "Combining %d fonts.", n) + report ("both", 0, "load", "combo %d: combining %d fonts.", + defined_combos, n) for i = 1, n do local cur = combo [i] local id = cur.id @@ -98,7 +104,7 @@ local handle_combination = function (combo, spec) " *> %.2d: include font %d at rank %d (%d items).", i, id, idx, (chars and #chars or 0)) chain [#chain + 1] = { fnt, chars, idx = idx } - fontids [#fontids + 1] = id + fontids [#fontids + 1] = { id = id } else report ("both", 0, "load", " *> %.2d: font %d at rank %d unknown, skipping.", @@ -128,7 +134,7 @@ local handle_combination = function (combo, spec) local baseprop = basefnt.properties baseprop.name = spec.name baseprop.virtualized = true - baseprop.fonts = fontids + basefnt.fonts = fontids for i = 2, nc do local cur = chain [i] @@ -140,7 +146,7 @@ local handle_combination = function (combo, spec) local pickchr = function (uc) local chr = src [uc] if chr then - chr.commands = { "slot", i, uc } + chr.commands = { { "slot", i, uc } } basechar [uc] = chr cnt = cnt + 1 end @@ -169,11 +175,11 @@ local handle_combination = function (combo, spec) " *> font %d / %d: imported %d glyphs into combo.", i, nc, cnt) end - spec.lookup = nil - spec.method = nil - spec.name = spec.specification - spec.forced = nil - spec.data = function () return basefnt end + spec.file = basefnt.filename + spec.name = stringformat ("luaotfload<%d>", defined_combos) + spec.features = { normal = { spec.specification } } + spec.forced = "evl" + spec.eval = function () return basefnt end return spec end diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index 8e5248b..80ce41a 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -32,14 +32,13 @@ local lua_reader = function (specification) end end -local data_reader = function (specification) - local data = specification.data - if data and type (data) == "function" then - logreport ("both", 0, "loaders", - "data: found tfmdata for “%s”, injecting.", - specification.name) - return data () - end +local eval_reader = function (specification) + local eval = specification.eval + if not eval or type (eval) ~= "function" then return nil end + logreport ("both", 0, "loaders", + "eval: found tfmdata for “%s”, injecting.", + specification.name) + return eval () end local install_formats = function () @@ -71,7 +70,7 @@ local install_formats = function () return true end - return aux ("dat", data_reader) + return aux ("evl", eval_reader) and aux ("lua", lua_reader) and aux ("pfa", function (spec) return readers.opentype (spec, "pfa", "type1") end) and aux ("pfb", function (spec) return readers.opentype (spec, "pfb", "type1") end) -- cgit v1.2.3 From 128b005cd8b44483ce2a58bd0cf078318663c696 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 19 Feb 2016 08:10:26 +0100 Subject: [parsers] allow whitespace around combo elements This gives more leeway to the notation, allowing font definitions to become more readable: \font \f = "combo: 1 / \fontid\one, 2 / \fontid\two / 0x41-0x5a, 3 / \fontid\three / 0x42, 4 / \fontid\three / 0x54 * 69 * U+58" --- src/luaotfload-parsers.lua | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua index 5ebe8d5..0f87256 100644 --- a/src/luaotfload-parsers.lua +++ b/src/luaotfload-parsers.lua @@ -575,19 +575,22 @@ local modifier_list = Cg(Ct(modifier^0), "modifiers") --- | | --- chars : ------------+--------------+ --- +local comborowsep = ws * comma * ws +local combocolsep = ws * slash * ws +local comborangesep = ws * asterisk * ws local combohex = hex / tonumber local combouint = digit^1 / tonumber local tonumber16 = function (s) return tonumber (s, 16) end local combouni = P"U+" * (digit^1 / tonumber16) local combonum = combohex + combouni + combouint local comborange = Ct(combonum * dash * combonum) + combonum -local combochars = comborange * (asterisk * comborange)^0 -local combodef1 = Ct( Cg(combouint, "idx") --> no chars - * slash * Cg(combouint, "id" )) -local combodef = Ct( Cg(combouint, "idx" ) - * slash * Cg(combouint, "id" ) - * slash * Cg(Ct(combochars^1), "chars")) -local combolist = Ct(combodef1 * (comma * combodef)^1) +local combochars = comborange * (comborangesep * comborange)^0 +local combodef1 = Ct( Cg(combouint, "idx") --> no chars + * combocolsep * Cg(combouint, "id" )) +local combodef = Ct( Cg(combouint, "idx" ) + * combocolsep * Cg(combouint, "id" ) + * combocolsep * Cg(Ct(combochars^1), "chars")) +local combolist = Ct(combodef1 * (comborowsep * combodef)^1) --- lookups ----------------------------------------------------------- local fontname = C((1-S":(/")^1) --- like luatex-fonts local unsupported = Cmt((1-S":(")^1, check_garbage) -- cgit v1.2.3 From 9e04cce348b4de350b2e0612698c81311e6e6e9d Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 19 Feb 2016 21:57:24 +0100 Subject: [parsers] rework combo syntax MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use arrows to emphasise what’s mapped. Allow whitespace to visually separate items. Also allow optional grouping with parentheses. Now it’s possible to define a combination as follows: \font \f = "combo: 1 -> 42; 2 -> 1337, U+0042-U+0084; 3 -> (55, 0x54 * 0x45 * 0x58)" --- src/luaotfload-parsers.lua | 44 +++++++++++++++++++++++++++----------------- 1 file changed, 27 insertions(+), 17 deletions(-) (limited to 'src') diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua index 0f87256..71e539d 100644 --- a/src/luaotfload-parsers.lua +++ b/src/luaotfload-parsers.lua @@ -565,19 +565,21 @@ local modifier_list = Cg(Ct(modifier^0), "modifiers") --- combining --------------------------------------------------------- --- ---- \font \three = combo:1/42,2/99/0xdeadbeef,3/1/U+2a-U+1337*42 ---- v +~ v +~ +~~~~~~~~~ v v +~~~ +~~~~~ +~ ---- | | | | | | | | | | ---- | | | | | | | | | | ---- idx : --+-÷--+-÷--÷----------+ | +----+ | ---- | | | | | | ---- id : ----+----+--÷------------+ +-----------+ ---- | | ---- chars : ------------+--------------+ +--- \font \three = combo: 1->42; 2->99,0xdeadbeef; 3->(1,U+2a-U+1337*42) +--- v +~ v +~ +~~~~~~~~~ v v +~~~ +~~~~~ +~ +--- | | | | | | | | | | +--- | | | | | | | | | | +--- idx : ---+--÷---+--÷--÷-----------+ | +----+ | +--- | | | | | | +--- id : ------+------+--÷---------------+ +-----------+ +--- | | +--- chars : ----------------+-----------------+ --- -local comborowsep = ws * comma * ws -local combocolsep = ws * slash * ws -local comborangesep = ws * asterisk * ws +local comborowsep = ws * semicolon * ws +local combomapsep = ws * P"->" * ws +local combodefsep = ws * comma * ws +local comborangesep = ws * asterisk * ws + local combohex = hex / tonumber local combouint = digit^1 / tonumber local tonumber16 = function (s) return tonumber (s, 16) end @@ -585,12 +587,20 @@ local combouni = P"U+" * (digit^1 / tonumber16) local combonum = combohex + combouni + combouint local comborange = Ct(combonum * dash * combonum) + combonum local combochars = comborange * (comborangesep * comborange)^0 -local combodef1 = Ct( Cg(combouint, "idx") --> no chars - * combocolsep * Cg(combouint, "id" )) -local combodef = Ct( Cg(combouint, "idx" ) - * combocolsep * Cg(combouint, "id" ) - * combocolsep * Cg(Ct(combochars^1), "chars")) +local parenthesized = function (p) return P"(" * ws * p * ws * P")" end + +local comboidxpat = Cg(combouint, "idx") +local comboidpat = Cg(combouint, "id" ) +local combocharspat = comboidpat * combodefsep * Cg(Ct(combochars^1), "chars") + +local comboidx = parenthesized (comboidxpat ) + comboidxpat +local comboid = parenthesized (comboidpat ) + comboidpat +local comboidchars = parenthesized (combocharspat) + combocharspat + +local combodef1 = Ct(comboidx * combomapsep * comboid) --> no chars +local combodef = Ct(comboidx * combomapsep * comboidchars) local combolist = Ct(combodef1 * (comborowsep * combodef)^1) + --- lookups ----------------------------------------------------------- local fontname = C((1-S":(/")^1) --- like luatex-fonts local unsupported = Cmt((1-S":(")^1, check_garbage) -- cgit v1.2.3 From 3447815896954281938500d49bedef715078a140 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 19 Feb 2016 22:41:23 +0100 Subject: [features,parsers] implement font fallbacks MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Building on the combination mechanism, this allows defining fallback fonts of which all glyphs are pulled that aren’t currently part of the base font. Example: \input luaotfload.sty \font \lm = file:lmroman10-regular.otf:mode=base \font \cmu = file:cmunrm.otf:mode=base \font \lmu = "combo: 1->\fontid\lm; 2->\fontid\cmu,fallback" \lmu Eh bien, mon prince. Gênes et Lueques ne sont plus que des apanages, des поместья, de la famille Buonaparte. \bye This allows setting Latin Modern text that contains Cyrillic letters. Note that -- as with the other combinations -- only glyphs are considered, no other properties of the fallback font. So besides the occasional letter in a different script this functionality is probably useless. --- src/luaotfload-features.lua | 56 ++++++++++++++++++++++++++++----------------- src/luaotfload-loaders.lua | 1 + src/luaotfload-parsers.lua | 9 ++++---- 3 files changed, 41 insertions(+), 25 deletions(-) (limited to 'src') diff --git a/src/luaotfload-features.lua b/src/luaotfload-features.lua index aeeaea3..4bcfbc3 100644 --- a/src/luaotfload-features.lua +++ b/src/luaotfload-features.lua @@ -100,9 +100,15 @@ local handle_combination = function (combo, spec) local fnt = fontidentifiers [id] if fnt then local chars = cur.chars - report ("both", 0, "load", - " *> %.2d: include font %d at rank %d (%d items).", - i, id, idx, (chars and #chars or 0)) + if chars == true then + report ("both", 0, "load", + " *> %.2d: fallback font %d at rank %d.", + i, id, idx) + else + report ("both", 0, "load", + " *> %.2d: include font %d at rank %d (%d items).", + i, id, idx, (chars and #chars or 0)) + end chain [#chain + 1] = { fnt, chars, idx = idx } fontids [#fontids + 1] = { id = id } else @@ -143,8 +149,12 @@ local handle_combination = function (combo, spec) local src = fnt.characters local cnt = 0 - local pickchr = function (uc) + local pickchr = function (uc, unavailable) local chr = src [uc] + if unavailable == true and basechar [uc] then + --- fallback mode: already known + return + end if chr then chr.commands = { { "slot", i, uc } } basechar [uc] = chr @@ -152,23 +162,27 @@ local handle_combination = function (combo, spec) end end - for j = 1, #def do - local this = def [j] - if type (this) == "number" then - report ("both", 0, "load", - " *> [%d][%d]: import codepoint U+%.4X", - i, j, this) - pickchr (this) - elseif type (this) == "table" then - local lo, hi = unpack (this) - report ("both", 0, "load", - " *> [%d][%d]: import codepoint range U+%.4X--U+%.4X", - i, j, lo, hi) - for uc = lo, hi do pickchr (uc) end - else - report ("both", 0, "load", - " *> item no. %d of combination definition \z - %d not processable.", j, i) + if def == true then --> fallback; grab all currently unavailable + for uc, _chr in next, src do pickchr (uc, true) end + else --> grab only defined range + for j = 1, #def do + local this = def [j] + if type (this) == "number" then + report ("both", 0, "load", + " *> [%d][%d]: import codepoint U+%.4X", + i, j, this) + pickchr (this) + elseif type (this) == "table" then + local lo, hi = unpack (this) + report ("both", 0, "load", + " *> [%d][%d]: import codepoint range U+%.4X--U+%.4X", + i, j, lo, hi) + for uc = lo, hi do pickchr (uc) end + else + report ("both", 0, "load", + " *> item no. %d of combination definition \z + %d not processable.", j, i) + end end end report ("both", 0, "load", diff --git a/src/luaotfload-loaders.lua b/src/luaotfload-loaders.lua index 80ce41a..fb01821 100644 --- a/src/luaotfload-loaders.lua +++ b/src/luaotfload-loaders.lua @@ -123,6 +123,7 @@ do 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 "") + logreport ("both", 0, "loaders", " > type %s", result.type or "") return result end end diff --git a/src/luaotfload-parsers.lua b/src/luaotfload-parsers.lua index 71e539d..b190c2c 100644 --- a/src/luaotfload-parsers.lua +++ b/src/luaotfload-parsers.lua @@ -591,11 +591,12 @@ local parenthesized = function (p) return P"(" * ws * p * ws * P")" end local comboidxpat = Cg(combouint, "idx") local comboidpat = Cg(combouint, "id" ) -local combocharspat = comboidpat * combodefsep * Cg(Ct(combochars^1), "chars") +local combocharspat = Cg(P"fallback" * Cc(true) + Ct(combochars^1), "chars") +local comboidcharspat = comboidpat * combodefsep * combocharspat -local comboidx = parenthesized (comboidxpat ) + comboidxpat -local comboid = parenthesized (comboidpat ) + comboidpat -local comboidchars = parenthesized (combocharspat) + combocharspat +local comboidx = parenthesized (comboidxpat ) + comboidxpat +local comboid = parenthesized (comboidpat ) + comboidpat +local comboidchars = parenthesized (comboidcharspat) + comboidcharspat local combodef1 = Ct(comboidx * combomapsep * comboid) --> no chars local combodef = Ct(comboidx * combomapsep * comboidchars) -- cgit v1.2.3