From c81bffaf9ac987ee48fe06700bf218391a045780 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 25 Apr 2013 11:48:43 +0200 Subject: add test for non-standard fonts --- tests/weirdfonts.tex | 15 +++++++++++++++ 1 file changed, 15 insertions(+) create mode 100644 tests/weirdfonts.tex diff --git a/tests/weirdfonts.tex b/tests/weirdfonts.tex new file mode 100644 index 0000000..9cbf8ac --- /dev/null +++ b/tests/weirdfonts.tex @@ -0,0 +1,15 @@ +%% non-standard fonts deserve an extra test file +\documentclass{scrartcl} +\usepackage{fontspec} +%% ···································································· +%% libertine monospace +%% ------------------- +%% real-world example from: http://tex.stackexchange.com/q/110566 +%% causing database lookups to fail; addressed in luaotfload since +%% https://github.com/phi-gamma/luaotfload/commit/4d0d2c19ab36d4918a72041a087fbcb451ac8c52 +\setmonofont{Linux Libertine Mono O} +%% ···································································· + +\begin{document} + foo {\ttfamily bar} baz +\end{document} -- cgit v1.2.3 From 38c8611e8af03e7da61919b3c723cc34e9a62c27 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 25 Apr 2013 15:26:07 +0200 Subject: [db] map filenames to db indices instead of paths --- luaotfload-database.lua | 137 ++++++++++++++++++++++++++++++++---------------- 1 file changed, 93 insertions(+), 44 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index e8f3d1d..acc351f 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -66,7 +66,7 @@ fonts.names = fonts.names or { } local names = fonts.names -names.version = 2.2 +names.version = 2.201 names.data = nil names.path = { basename = "luaotfload-names.lua", @@ -99,12 +99,15 @@ local sanitize_string = function (str) end --[[doc-- -This is a sketch of the db: +This is a sketch of the luaotfload db: type dbobj = { - mappings : fontentry list; - status : filestatus; - version : float; + mappings : fontentry list; + status : filestatus; + version : float; + // preliminary additions of v2.2: + basenames : (string, int) hash; // where int is the index in mappings + barenames : (string, int) hash; // where int is the index in mappings } and fontentry = { familyname : string; @@ -126,6 +129,40 @@ This is a sketch of the db: beware that this is a reconstruction and may be incomplete. +mtx-fonts has in names.tma: + + type names = { + cache_uuid : uuid; + cache_version : float; + datastate : uuid list; + fallbacks : (filetype, (basename, int) hash) hash; + families : (basename, int list) hash; + files : (filename, fullname) hash; + indices : (fullname, int) hash; + mappings : (filetype, (basename, int) hash) hash; + names : ? (empty hash) ?; + rejected : (basename, int) hash; + specifications: fontentry list; + } + and fontentry = { + designsize : int; + familyname : string; + filename : string; + fontname : string; + format : string; + fullname : string; + maxsize : int; + minsize : int; + modification : int; + rawname : string; + style : string; + subfamily : string; + variant : string; + weight : string; + width : string; + } + + --doc]]-- local fontnames_init = function ( ) @@ -134,10 +171,12 @@ local fontnames_init = function ( ) status = { }, --- adding filename mapping increases the --- size of the serialized db on my system - --- (5840 font files) by a factor of ... - barenames = { },--- incr. by 1.11 - basenames = { },--- incr. by 1.22 --- fullnames = { },--- incr. by 1.48 + --- (5840 font files) by a factor of 1.09 + --- if we store only the indices in the + --- mappings table + barenames = { }, + basenames = { }, +-- fullnames = { }, version = names.version, } end @@ -240,28 +279,38 @@ end local fonts_loaded = false local fonts_reloaded = false +--- chain: barenames -> [fullnames ->] basenames -> findfile local crude_file_lookup_verbose = function (data, filename) - local found = data.barenames[filename] - if found then + local mappings = data.mappings + local found + + --- look up in db first ... + found = data.barenames[filename] + if found and mappings[found] then + found = mappings[found].filename report("info", 0, "db", "crude file lookup: req=%s; hit=bare; ret=%s", filename, found[1]) return found end -- found = data.fullnames[filename] --- if found then --- report("info", 0, "db", +-- if found and mappings[found] then +-- found = mappings[found].filename[1] -- "crude file lookup: req=%s; hit=bare; ret=%s", -- filename, found[1]) -- return found -- end found = data.basenames[filename] - if found then + if found and mappings[found] then + found = mappings[found].filename report("info", 0, "db", "crude file lookup: req=%s; hit=bare; ret=%s", filename, found[1]) return found end + + --- now look for tfm et al.; will be superseded by proper + --- format lookup found = resolvers.findfile(filename, "tfm") if found then report("info", 0, "db", @@ -281,7 +330,10 @@ local crude_file_lookup = function (data, filename) local found = data.barenames[filename] -- or data.fullnames[filename] or data.basenames[filename] - if found then return found end + if found then + found = data.mappings[found] + if found then return found.filename end + end found = resolvers.findfile(filename, "tfm") if found then return { found, false } end found = resolvers.findfile(filename, "ofm") @@ -742,13 +794,14 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) if db_timestamp == timestamp and not newstatus[entryname].index[1] then for _,v in next, status[entryname].index do - local index = #newstatus[entryname].index - local fullinfo = mappings[v] - newmappings[#newmappings+1] = fullinfo --- keep - newstatus[entryname].index[index+1] = #newmappings --- newfullnames[fullname] = fullinfo.filename - newbasenames[basename] = fullinfo.filename - newbarenames[barename] = fullinfo.filename + local index = #newstatus[entryname].index + local fullinfo = mappings[v] + local location = #newmappings + 1 + newmappings[location] = fullinfo --- keep + newstatus[entryname].index[index+1] = location --- is this actually used anywhere? +-- newfullnames[fullname] = location + newbasenames[basename] = location + newbarenames[barename] = location end report("log", 2, "db", "font “%s” already indexed", entryname) return false @@ -757,38 +810,34 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) local info = fontloaderinfo(fullname) if info then if type(info) == "table" and #info > 1 then --- ttc - for i in next, info do - local fullinfo = font_fullinfo(fullname, i-1, texmf) + for n_font = 1, #info do + local fullinfo = font_fullinfo(fullname, n_font-1, texmf) if not fullinfo then return false end - local index = newstatus[entryname].index[i] - if newstatus[entryname].index[i] then - index = newstatus[entryname].index[i] - else - index = #newmappings+1 - end - newmappings[index] = fullinfo --- newfullnames[fullname] = fullinfo.filename - newbasenames[basename] = fullinfo.filename - newbarenames[barename] = fullinfo.filename - newstatus[entryname].index[i] = index + local location = #newmappings+1 + local index = newstatus[entryname].index[n_font] + if not index then index = location end + + newmappings[index] = fullinfo +-- newfullnames[fullname] = location + newbasenames[basename] = location + newbarenames[barename] = location + newstatus[entryname].index[n_font] = index end else local fullinfo = font_fullinfo(fullname, false, texmf) if not fullinfo then return false end - local index - if newstatus[entryname].index[1] then - index = newstatus[entryname].index[1] - else - index = #newmappings+1 - end + local location = #newmappings+1 + local index = newstatus[entryname].index[1] + if not index then index = location end + newmappings[index] = fullinfo --- newfullnames[fullname] = { fullinfo.filename[1], fullinfo.filename[2] } - newbasenames[basename] = { fullinfo.filename[1], fullinfo.filename[2] } - newbarenames[barename] = { fullinfo.filename[1], fullinfo.filename[2] } +-- newfullnames[fullname] = location + newbasenames[basename] = location + newbarenames[barename] = location newstatus[entryname].index[1] = index end -- cgit v1.2.3 From 3a645a338fc4297bc9a61dae1fece13533d2f3ee Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 25 Apr 2013 17:26:16 +0200 Subject: store preprocessed font names with db --- luaotfload-database.lua | 82 ++++++++++++++++++++++++++++--------------------- 1 file changed, 47 insertions(+), 35 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index acc351f..bd664a6 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -436,12 +436,18 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con for _,face in next, data.mappings do --- TODO we really should store those in dedicated --- .sanitized field - local family = sanitize_string(face.names and face.names.family) - local subfamily = sanitize_string(face.names and face.names.subfamily) - local fullname = sanitize_string(face.names and face.names.fullname) - local psname = sanitize_string(face.names and face.names.psname) - local fontname = sanitize_string(face.fontname) - local pfullname = sanitize_string(face.fullname) + local family, subfamily, fullname, psname, fontname, pfullname + + local facenames = face.sanitized + if facenames then + family = facenames.family + subfamily = facenames.subfamily + fullname = facenames.fullname + psname = facenames.psname + end + fontname = facenames.fontname or sanitize_string(face.fontname) + pfullname = facenames.pfullname or sanitize_string(face.fullname) + local optsize, dsnsize, maxsize, minsize if #face.size > 0 then optsize = face.size @@ -483,30 +489,24 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con elseif subfamily == "regular" or synonym_set.regular[subfamily] then found.fallback = face - elseif name == fullname then - --- happens with Libertine Mono which has - --- “mono” as subfamily - found[1] = face - break end + end - else - if name == fullname - or name == pfullname - or name == fontname - or name == psname then - if optsize then - if dsnsize == size - or (size > minsize and size <= maxsize) then - found[1] = face - break - else - found[#found+1] = face - end - else + if name == fullname + or name == pfullname + or name == fontname + or name == psname then + if optsize then + if dsnsize == size + or (size > minsize and size <= maxsize) then found[1] = face break + else + found[#found+1] = face end + else + found[1] = face + break end end end @@ -623,7 +623,7 @@ find_closest = function (name, limit) for n = 1, n_fonts do local current = mappings[n] - local cnames = current.names + local cnames = current.sanitized --[[ This is simplistic but surpisingly fast. Matching is performed against the “family” name @@ -675,6 +675,14 @@ find_closest = function (name, limit) return false end --- find_closest() +local sanitize_names = function (names) + local res = { } + for idx, name in next, names do + res[idx] = sanitize_string(name) + end + return res +end + --[[doc-- The data inside an Opentype font file can be quite heterogeneous. Thus in order to get the relevant information, parts of the original @@ -701,18 +709,22 @@ font_fullinfo = function (filename, subfont, texmf) if metadata.names then for _, namedata in next, metadata.names do if namedata.lang == "English (US)" then - tfmdata.names = { + local names = { --- see --- https://developer.apple.com/fonts/TTRefMan/RM06/Chap6name.html - fullname = namedata.names.compatfull - or namedata.names.fullname, - family = namedata.names.preffamilyname - or namedata.names.family, - subfamily= tfmdata.fontstyle_name - or namedata.names.prefmodifiers - or namedata.names.subfamily, - psname = namedata.names.postscriptname + fullname = namedata.names.compatfull + or namedata.names.fullname, + family = namedata.names.preffamilyname + or namedata.names.family, + subfamily = tfmdata.fontstyle_name + or namedata.names.prefmodifiers + or namedata.names.subfamily, + psname = namedata.names.postscriptname, + pfullname = metadata.fullname, + fontname = metadata.fontname, } + tfmdata.names = names + tfmdata.sanitized = sanitize_names(names) end end else -- cgit v1.2.3 From cd83d13014406c6e6dd8facf325c19bf0b51c432 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Thu, 25 Apr 2013 18:35:50 +0200 Subject: scan fontconfig dirs even though ``$OSFONTDIR`` is set This is essentially what this change to the TL2011 version does: https://github.com/lualatex/luaotfload/commit/31530badb2681ff3423fe31f5eccf3d05fab1956#L2R657 in response to this issue: https://github.com/lualatex/luaotfload/issues/11 --- fontdbutil.lua | 2 +- luaotfload-database.lua | 19 ++++++++----------- 2 files changed, 9 insertions(+), 12 deletions(-) diff --git a/fontdbutil.lua b/fontdbutil.lua index d76678f..3c60eec 100755 --- a/fontdbutil.lua +++ b/fontdbutil.lua @@ -269,7 +269,7 @@ actions.query = function (job) logs.names_report(false, 1, "resolve", "Font “%s” found!", query) logs.names_report(false, 1, - "resolve", "Resolved file name “%s”:", foundname) + "resolve", "Resolved file name “%s”", foundname) if job.show_info then show_font_info(foundname) end diff --git a/luaotfload-database.lua b/luaotfload-database.lua index bd664a6..1b13f69 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -1188,19 +1188,16 @@ update_names = function (fontnames, force) end local newfontnames = fontnames_init() read_blacklist() - --installed_fonts_scanned = false - --scan_installed_fonts(fontnames, newfontnames) --- see fixme above - local scanned, new = scan_texmf_fonts(fontnames, newfontnames) + + local scanned, new + scanned, new = scan_texmf_fonts(fontnames, newfontnames) n_scanned = n_scanned + scanned n_new = n_new + new - --if not installed_fonts_scanned - --and stringis_empty(kpseexpand_path("$OSFONTDIR")) - if stringis_empty(kpseexpand_path("$OSFONTDIR")) - then - local scanned, new = scan_os_fonts(fontnames, newfontnames) - n_scanned = n_scanned + scanned - n_new = n_new + new - end + + scanned, new = scan_os_fonts(fontnames, newfontnames) + n_scanned = n_scanned + scanned + n_new = n_new + new + --- stats: --- before rewrite | after rewrite --- partial: 804 ms | 701 ms -- cgit v1.2.3 From 29620364877381833baaf5c767177413c125d3cd Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Apr 2013 01:15:21 +0200 Subject: import from Context as of 2013-04-26 --- luaotfload-merged.lua | 62 +++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 45 insertions(+), 17 deletions(-) diff --git a/luaotfload-merged.lua b/luaotfload-merged.lua index da5e35a..bb89e39 100644 --- a/luaotfload-merged.lua +++ b/luaotfload-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 04/24/13 13:39:43 +-- merge date : 04/25/13 18:50:39 do -- begin closure to overcome local limits and interference @@ -7412,6 +7412,7 @@ nodes.injections=nodes.injections or {} local injections=nodes.injections local nodecodes=nodes.nodecodes local glyph_code=nodecodes.glyph +local kern_code=nodecodes.kern local nodepool=nodes.pool local newkern=nodepool.kern local traverse_id=node.traverse_id @@ -7505,7 +7506,7 @@ local function trace(head) local cb=n[a_cursbase] local cc=n[a_curscurs] local char=n.char - report_injections("font %s, char %U, glyph %c",char,n.font,char) + report_injections("font %s, char %U, glyph %c",n.font,char,char) if kp then local k=kerns[kp] if k[3] then @@ -7542,6 +7543,24 @@ local function trace(head) end report_injections("end run") end +local function show_result(head) + local current=head + local skipping=false + while current do + local id=current.id + if id==glyph_code then + report_injections("char: %C, width %p, xoffset %p, yoffset %p",current.char,current.width,current.xoffset,current.yoffset) + skipping=false + elseif id==kern_code then + report_injections("kern: %p",current.kern) + skipping=false + elseif not skipping then + report_injections() + skipping=true + end + current=current.next + end +end function injections.handler(head,where,keep) local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns) if has_marks or has_cursives then @@ -7680,17 +7699,26 @@ function injections.handler(head,where,keep) local d=mrks[index] if d then local rlmode=d[3] - if rlmode and rlmode>=0 then - local k=wx[p] - if k then - n.xoffset=p.xoffset-p.width+d[1]-k[2] + local k=wx[p] + if k then + local x=k[2] + local w=k[4] + if w then + if rlmode and rlmode>=0 then + n.xoffset=p.xoffset-p.width+d[1]-x + else + n.xoffset=p.xoffset-d[1]-x + end else - n.xoffset=p.xoffset-p.width+d[1] + if rlmode and rlmode>=0 then + n.xoffset=p.xoffset-p.width+d[1] + else + n.xoffset=p.xoffset-d[1]-x + end end else - local k=wx[p] - if k then - n.xoffset=p.xoffset-d[1]-k[2] + if rlmode and rlmode>=0 then + n.xoffset=p.xoffset-p.width+d[1] else n.xoffset=p.xoffset-d[1] end @@ -7723,21 +7751,21 @@ function injections.handler(head,where,keep) local wx=w-x if rl<0 then if wx~=0 then - insert_node_before(head,n,newkern(wx)) + insert_node_before(head,n,newkern(wx)) end if x~=0 then - insert_node_after (head,n,newkern(x)) + insert_node_after (head,n,newkern(x)) end else if x~=0 then - insert_node_before(head,n,newkern(x)) + insert_node_before(head,n,newkern(x)) end if wx~=0 then - insert_node_after(head,n,newkern(wx)) + insert_node_after (head,n,newkern(wx)) end end elseif x~=0 then - insert_node_before(head,n,newkern(x)) + insert_node_before(head,n,newkern(x)) end end end @@ -7746,9 +7774,9 @@ function injections.handler(head,where,keep) if k~=0 then local rln=rl[n] if rln and rln<0 then - insert_node_before(head,n,newkern(-k)) + insert_node_before(head,n,newkern(-k)) else - insert_node_before(head,n,newkern(k)) + insert_node_before(head,n,newkern(k)) end end end -- cgit v1.2.3 From b2659be825b80de3201a3df17cc1dc2d4bcf296d Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Apr 2013 14:19:00 +0200 Subject: add draft lookup cache --- luaotfload-database.lua | 117 +++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 111 insertions(+), 6 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 1b13f69..55966bf 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -61,8 +61,11 @@ local tableappend = table.append local tabletohash = table.tohash --- the font loader namespace is “fonts”, same as in Context -fonts = fonts or { } -fonts.names = fonts.names or { } +--- 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 @@ -73,6 +76,7 @@ names.path = { dir = "", path = "", } +local lookup_cache = nil --> names.data.cache; populated by load_names -- We use the cache.* of ConTeXt (see luat-basics-gen), we can -- use it safely (all checks and directory creations are already done). It @@ -108,6 +112,7 @@ This is a sketch of the luaotfload db: // preliminary additions of v2.2: basenames : (string, int) hash; // where int is the index in mappings barenames : (string, int) hash; // where int is the index in mappings + caches : lookup_cache; // see below } and fontentry = { familyname : string; @@ -165,7 +170,7 @@ mtx-fonts has in names.tma: --doc]]-- -local fontnames_init = function ( ) +local fontnames_init = function ( ) --- returns clean dbobj return { mappings = { }, status = { }, @@ -178,6 +183,10 @@ local fontnames_init = function ( ) basenames = { }, -- fullnames = { }, version = names.version, + caches = { --- new + file = { }, name = { }, + path = { }, anon = { }, + } } end @@ -242,6 +251,7 @@ load_names = function ( ) "Font names database loaded", "%s", foundname) report("info", 3, "db", "Loading took %0.f ms", 1000*(os.gettimeofday()-starttime)) + lookup_cache = data.caches else report("info", 1, "db", [[Font names database not found, generating new one. @@ -249,6 +259,7 @@ load_names = function ( ) data = update_names(fontnames_init()) save_names(data) end + fonts_loaded = true return data end @@ -341,6 +352,101 @@ local crude_file_lookup = function (data, filename) return false end +--[[doc-- +Lookups can be quite costly, more so the less specific they are. +Even if we find a matching font eventually, the next time the +user compiles Eir document E will have to stand through the delay +again. +Thus, some caching of results -- even between runs -- is in order. +We’ll just store successful lookups in the database in a record of +the respective lookup type. + +type lookup_cache = { + file : lookups; + name : lookups; + path : lookups; + anon : lookups; +} +and lookups = (string, (string * num)) dict + +TODO: + × 1) add cache to dbobj + × 2) wrap lookups in cached versions + 3) make caching optional (via the config table) for debugging + 4) make names_update() cache aware (nil if “force”) + × 5) add logging + 6) add cache control to fontdbutil + 7) incr db version + 8) ??? + n) PROFIT!!! + +--doc]]-- + +--- the resolver is called after the font request is parsed +--- this is where we insert the cache +local normal_resolve = fonts.definers.resolve +local dummyresolver = function (specification) + --- this ensures that the db is always loaded + --- before a lookup occurs + if not fonts_loaded then names.data = load_names() end + inspect(normal_resolve(specification)) + return normal_resolve(specification) +end + +--[[doc-- +The name lookup requires both the “name” and the “style” +key, so we’ll concatenate them. +--doc]]-- +--- string -> spec -> string +local to_hash_field = function (lookup, specification) + if lookup == "name" and specification.style then + return specification.name.."*"..specification.style + end + return specification.name +end + +--[[doc-- +From my reading of font-def.lua, what a resolver does is +basically rewrite the “name” field of the specification record +with the resolution. +Also, the fields “resolved”, “sub”, “force” etc. influence the outcome. + +We’ll just cache a deep copy of the entire spec as it leaves the +resolver, lest we want to worry if we caught all the details. +--doc]]-- + +local cached_resolver = function (specification) + if not lookup_cache then names.data = load_names() end + local lookup = specification.lookup + local field = to_hash_field(lookup, specification) + local cached = lookup_cache[lookup] + report("info", 4, "cache", + "looking up field “%s” in category “%s” ...", + field, lookup) + local hit = cached[field] + if hit then + report("info", 4, "cache", "found!") + return hit + end + report("info", 4, "cache", "not cached; resolving") + + --- here we add to the cache + local resolved_spec = normal_resolve(specification) + cached[field] = tablecopy(resolved_spec) --- slow for the first time + --- obviously, the updated cache needs to be stored. + --- for the moment, we write the entire db to disk + --- whenever the cache is updated. + --- TODO this should trigger a save only once the + --- document is compiled (finish_pdffile callback?) + report("info", 5, "cache", "saving updated cache") + save_names(names.data) + return resolved_spec +end + +--fonts.definers.resolve = dummyresolver +--fonts.definers.resolve = normalresolver +fonts.definers.resolve = cached_resolver + --[[doc-- Luatex-fonts, the font-loader package luaotfload imports, comes with @@ -382,10 +488,11 @@ font database created by the mkluatexfontdb script. resolve = function (_,_,specification) -- the 1st two parameters are used by ConTeXt if not fonts_loaded then names.data = load_names() - fonts_loaded = true end local data = names.data + --inspect(specification) + --os.exit() if specification.lookup == "file" then local found = crude_file_lookup(data, specification.name) --local found = crude_file_lookup_verbose(data, specification.name) @@ -607,7 +714,6 @@ find_closest = function (name, limit) if not fonts_loaded then names.data = load_names() - fonts_loaded = true end local data = names.data @@ -1234,7 +1340,6 @@ scan_external_dir = function (dir) old_names = names.data else old_names = load_names() - fonts_loaded = true end new_names = tablecopy(old_names) local n_scanned, n_new = scan_dir(dir, old_names, new_names) -- cgit v1.2.3 From 5ee12c85b552649909857ec93af8a70d982da687 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Apr 2013 18:00:19 +0200 Subject: improve request caching --- luaotfload-database.lua | 202 +++++++++++++++++++++++++++--------------------- 1 file changed, 115 insertions(+), 87 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 55966bf..0c47bfd 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -76,7 +76,10 @@ names.path = { dir = "", path = "", } -local lookup_cache = nil --> names.data.cache; populated by load_names + +config = config or { } +config.luaotfload = config.luaotfload or { } +config.luaotfload.resolver = config.luaotfload.resolver or "normal" -- We use the cache.* of ConTeXt (see luat-basics-gen), we can -- use it safely (all checks and directory creations are already done). It @@ -85,8 +88,8 @@ local writable_path = caches.getwritablepath("names","") if not writable_path then error("Impossible to find a suitable writeable cache...") end -names.path.dir = writable_path -names.path.path = filejoin(writable_path, names.path.basename) +names.path.dir = writable_path +names.path.path = filejoin(writable_path, names.path.basename) --[[doc-- Auxiliary functions @@ -106,13 +109,13 @@ end This is a sketch of the luaotfload db: type dbobj = { - mappings : fontentry list; - status : filestatus; - version : float; + mappings : fontentry list; + status : filestatus; + version : float; // preliminary additions of v2.2: - basenames : (string, int) hash; // where int is the index in mappings - barenames : (string, int) hash; // where int is the index in mappings - caches : lookup_cache; // see below + basenames : (string, int) hash; // where int is the index in mappings + barenames : (string, int) hash; // where int is the index in mappings + request_cache : lookup_cache; // see below } and fontentry = { familyname : string; @@ -170,23 +173,26 @@ mtx-fonts has in names.tma: --doc]]-- -local fontnames_init = function ( ) --- returns clean dbobj +local fontnames_init = function (keep_cache) --- returns dbobj + local request_cache + if keep_cache and names.data and names.data.request_cache then + request_cache = names.data.request_cache + else + request_cache = { } + end return { - mappings = { }, - status = { }, + mappings = { }, + status = { }, --- adding filename mapping increases the --- size of the serialized db on my system --- (5840 font files) by a factor of 1.09 --- if we store only the indices in the --- mappings table - barenames = { }, - basenames = { }, --- fullnames = { }, - version = names.version, - caches = { --- new - file = { }, name = { }, - path = { }, anon = { }, - } + barenames = { }, + basenames = { }, +-- fullnames = { }, + version = names.version, + request_cache = request_cache, } end @@ -198,13 +204,8 @@ end --- is assumed to be located at an identical path, carrying the suffix --- .luc. -local code_cache = { } - --- string -> (string * table) local load_lua_file = function (path) - local code = code_cache[path] - if code then return path, code() end - local foundname = filereplacesuffix(path, "luc") local fh = ioopen(foundname, "rb") -- try bin first @@ -225,8 +226,6 @@ local load_lua_file = function (path) end if not code then return nil, nil end - - code_cache[path] = code --- insert into memo return foundname, code() end @@ -241,6 +240,10 @@ local save_names local scan_external_dir local update_names +--- state of the database +local fonts_loaded = false +local fonts_reloaded = false + --- unit -> dbobj load_names = function ( ) local starttime = os.gettimeofday() @@ -251,12 +254,11 @@ load_names = function ( ) "Font names database loaded", "%s", foundname) report("info", 3, "db", "Loading took %0.f ms", 1000*(os.gettimeofday()-starttime)) - lookup_cache = data.caches else report("info", 1, "db", [[Font names database not found, generating new one. This can take several minutes; please be patient.]]) - data = update_names(fontnames_init()) + data = update_names(fontnames_init(false)) save_names(data) end fonts_loaded = true @@ -286,10 +288,6 @@ do end end ---- state of the database -local fonts_loaded = false -local fonts_reloaded = false - --- chain: barenames -> [fullnames ->] basenames -> findfile local crude_file_lookup_verbose = function (data, filename) local mappings = data.mappings @@ -361,19 +359,13 @@ Thus, some caching of results -- even between runs -- is in order. We’ll just store successful lookups in the database in a record of the respective lookup type. -type lookup_cache = { - file : lookups; - name : lookups; - path : lookups; - anon : lookups; -} -and lookups = (string, (string * num)) dict +type lookup_cache = (string, (string * num)) dict TODO: × 1) add cache to dbobj × 2) wrap lookups in cached versions - 3) make caching optional (via the config table) for debugging - 4) make names_update() cache aware (nil if “force”) + × 3) make caching optional (via the config table) for debugging + × 4) make names_update() cache aware (nil if “force”) × 5) add logging 6) add cache control to fontdbutil 7) incr db version @@ -384,26 +376,39 @@ TODO: --- the resolver is called after the font request is parsed --- this is where we insert the cache -local normal_resolve = fonts.definers.resolve -local dummyresolver = function (specification) +local normal_resolver = fonts.definers.resolve +local dummy_resolver = function (specification) --- this ensures that the db is always loaded --- before a lookup occurs - if not fonts_loaded then names.data = load_names() end - inspect(normal_resolve(specification)) - return normal_resolve(specification) + if not names.data then names.data = load_names() end + --inspect(specification) + local resolved = normal_resolver(specification) + --inspect(resolved) + return resolved end --[[doc-- -The name lookup requires both the “name” and the “style” -key, so we’ll concatenate them. +The name lookup requires both the “name” and some other +keys, so we’ll concatenate them. +The spec is modified in place (ugh), so we’ll have to catalogue what +fields actually influence its behavior. + +Idk what the “spec” resolver is for. + + lookup inspects modifies + file: name forced, name + name:* name, style, sub, resolved, sub, name, forced + optsize, size + spec: name, sub resolved, sub, name, forced + +* name: contains both the name resolver from luatex-fonts and resolve() + below + +The following fields of a resolved spec need to be cached: --doc]]-- ---- string -> spec -> string -local to_hash_field = function (lookup, specification) - if lookup == "name" and specification.style then - return specification.name.."*"..specification.style - end - return specification.name -end +local cache_fields = { + "forced", "hash", "lookup", "name", "resolved", "sub", +} --[[doc-- From my reading of font-def.lua, what a resolver does is @@ -415,37 +420,54 @@ We’ll just cache a deep copy of the entire spec as it leaves the resolver, lest we want to worry if we caught all the details. --doc]]-- +--- spec -> spec local cached_resolver = function (specification) - if not lookup_cache then names.data = load_names() end - local lookup = specification.lookup - local field = to_hash_field(lookup, specification) - local cached = lookup_cache[lookup] + if not names.data then names.data = load_names() end + local request_cache = names.data.request_cache + local request = specification.specification report("info", 4, "cache", - "looking up field “%s” in category “%s” ...", - field, lookup) - local hit = cached[field] - if hit then + "looking for “%s” in cache ...", + request) + local found = names.data.request_cache[request] + if found then --- replay fields from cache hit report("info", 4, "cache", "found!") - return hit + for i=1, #cache_fields do + local f = cache_fields[i] + if found[f] then specification[f] = found[f] end + end + return specification end report("info", 4, "cache", "not cached; resolving") - --- here we add to the cache - local resolved_spec = normal_resolve(specification) - cached[field] = tablecopy(resolved_spec) --- slow for the first time + --- first we resolve normally ... + local resolved_spec = normal_resolver(specification) + --- ... then we add the fields to the cache + local entry = { } + for i=1, #cache_fields do + local f = cache_fields[i] + entry[f] = resolved_spec[f] + end + report("info", 4, "cache", "new entry: %s", request) + names.data.request_cache[request] = entry + --- obviously, the updated cache needs to be stored. --- for the moment, we write the entire db to disk --- whenever the cache is updated. --- TODO this should trigger a save only once the --- document is compiled (finish_pdffile callback?) report("info", 5, "cache", "saving updated cache") - save_names(names.data) + save_names() return resolved_spec end ---fonts.definers.resolve = dummyresolver ---fonts.definers.resolve = normalresolver -fonts.definers.resolve = cached_resolver +local resolvers = { + dummy = dummy_resolver, + normal = normal_resolver, + cached = cached_resolver, +} + +fonts.definers.resolve = resolvers[config.luaotfload.resolver] +--fonts.definers.resolve = resolvers.cached --[[doc-- @@ -484,15 +506,16 @@ font database created by the mkluatexfontdb script. --- successful lookup as this cannot be inferred from the other --- values. --- ---- + resolve = function (_,_,specification) -- the 1st two parameters are used by ConTeXt if not fonts_loaded then + print("=============") + print(names.data) names.data = load_names() + --os.exit() end local data = names.data - --inspect(specification) - --os.exit() if specification.lookup == "file" then local found = crude_file_lookup(data, specification.name) --local found = crude_file_lookup_verbose(data, specification.name) @@ -1281,18 +1304,18 @@ update_names = function (fontnames, force) .. (force and " forcefully" or "")) if force then - fontnames = fontnames_init() + fontnames = fontnames_init(false) else if not fontnames then fontnames = load_names() end if fontnames.version ~= names.version then - fontnames = fontnames_init() + fontnames = fontnames_init(true) report("log", 1, "db", "No font names database or old " .. "one found; generating new one") end end - local newfontnames = fontnames_init() + local newfontnames = fontnames_init(true) read_blacklist() local scanned, new @@ -1317,21 +1340,26 @@ end --- dbobj -> unit save_names = function (fontnames) + if not fontnames then fontnames = names.data end local path = names.path.dir if not lfs.isdir(path) then dirmkdirs(path) end - path = filejoin(path, names.path.basename) if fileiswritable(path) then - local luaname, lucname = make_name(path) - tabletofile(luaname, fontnames, true) - caches.compile(fontnames,luaname,lucname) - report("info", 0, "db", "Font names database saved") - return path - else - report("info", 0, "db", "Failed to save names database") - return nil + local luaname, lucname = make_name(names.path.path) + if luaname then + --tabletofile(luaname, data, true, { reduce=true }) + table.tofile(luaname, fontnames, true) + if lucname and type(caches.compile) == "function" then + os.remove(lucname) + caches.compile(fontnames, luaname, lucname) + report("info", 0, "db", "Font names database saved") + return names.path.path + end + end end + report("info", 0, "db", "Failed to save names database") + return nil end scan_external_dir = function (dir) -- cgit v1.2.3 From 05e014ba69d57c18c460e0d0e12a7802d9c58225 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Apr 2013 18:21:06 +0200 Subject: add ``flush-cache`` option to fontdbutil --- fontdbutil.lua | 21 +++++++++++++++++++-- luaotfload-database.lua | 33 +++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 16 deletions(-) diff --git a/fontdbutil.lua b/fontdbutil.lua index 3c60eec..1aa99d0 100755 --- a/fontdbutil.lua +++ b/fontdbutil.lua @@ -126,6 +126,7 @@ This tool is part of the luaotfload package. Valid options are: -u --update update the database -f --force force re-indexing all fonts + -c --flush-cache empty cache of font requests --find="font name" query the database for a font name -F --fuzzy look for approximate matches if --find fails @@ -214,7 +215,7 @@ set. --]]-- local action_sequence = { - "loglevel", "help", "version", "generate", "query" + "loglevel", "help", "version", "flush", "generate", "query" } local action_pending = table.tohash(action_sequence, false) @@ -252,6 +253,19 @@ actions.generate = function (job) return false, false end +actions.flush = function (job) + local success, fontnames = names.flush_cache() + if success then + local savedname = names.save(fontnames) + logs.names_report("info", 2, "cache", + "Cache emptied", #fontnames.mappings) + if savedname then + return true, true + end + end + return false, false +end + actions.query = function (job) local query = job.query @@ -304,6 +318,7 @@ local process_cmdline = function ( ) -- unit -> jobspec local long_options = { alias = 1, + ["flush-cache"] = "c", find = 1, force = "f", fuzzy = "F", @@ -317,7 +332,7 @@ local process_cmdline = function ( ) -- unit -> jobspec version = "V", } - local short_options = "fFiquvVh" + local short_options = "cfFiquvVh" local options, _, optarg = alt_getopt.get_ordered_opts (arg, short_options, long_options) @@ -366,6 +381,8 @@ local process_cmdline = function ( ) -- unit -> jobspec result.show_info = true elseif v == "alias" then config.luaotfload.self = optarg[n] + elseif v == "c" then + action_pending["flush"] = true end end diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 0c47bfd..7c6e657 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -69,7 +69,7 @@ fonts.definers = fonts.definers or { } local names = fonts.names -names.version = 2.201 +names.version = 2.202 names.data = nil names.path = { basename = "luaotfload-names.lua", @@ -231,6 +231,7 @@ end --- define locals in scope local find_closest +local flush_cache local font_fullinfo local load_names local read_fonts_conf @@ -367,9 +368,10 @@ TODO: × 3) make caching optional (via the config table) for debugging × 4) make names_update() cache aware (nil if “force”) × 5) add logging - 6) add cache control to fontdbutil - 7) incr db version - 8) ??? + × 6) add cache control to fontdbutil + × 7) incr db version + 8) wishlist: save cache only at the end of a run + 9) ??? n) PROFIT!!! --doc]]-- @@ -508,12 +510,7 @@ font database created by the mkluatexfontdb script. --- resolve = function (_,_,specification) -- the 1st two parameters are used by ConTeXt - if not fonts_loaded then - print("=============") - print(names.data) - names.data = load_names() - --os.exit() - end + if not fonts_loaded then names.data = load_names() end local data = names.data if specification.lookup == "file" then @@ -1291,6 +1288,13 @@ local function scan_os_fonts(fontnames, newfontnames) return n_scanned, n_new end +flush_cache = function (fontnames) + if not fontnames then fontnames = load_names() end + fontnames.request_cache = { } + collectgarbage"collect" + return true, fontnames +end + --- dbobj -> bool -> dbobj update_names = function (fontnames, force) local starttime = os.gettimeofday() @@ -1376,10 +1380,11 @@ scan_external_dir = function (dir) end --- export functionality to the namespace “fonts.names” -names.scan = scan_external_dir -names.load = load_names -names.update = update_names -names.save = save_names +names.flush_cache = flush_cache +names.load = load_names +names.save = save_names +names.scan = scan_external_dir +names.update = update_names names.resolve = resolve --- replace the resolver from luatex-fonts names.resolvespec = resolve -- cgit v1.2.3 From 7c283ff361da9c8477e4f1af3798d54371f81100 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Apr 2013 18:48:32 +0200 Subject: have flush_cache operate on names.data --- luaotfload-database.lua | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 7c6e657..4980766 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -1288,11 +1288,11 @@ local function scan_os_fonts(fontnames, newfontnames) return n_scanned, n_new end -flush_cache = function (fontnames) - if not fontnames then fontnames = load_names() end - fontnames.request_cache = { } +flush_cache = function () + if not names.data then names.data = load_names() end + names.data.request_cache = { } collectgarbage"collect" - return true, fontnames + return true, names.data end --- dbobj -> bool -> dbobj @@ -1352,8 +1352,8 @@ save_names = function (fontnames) if fileiswritable(path) then local luaname, lucname = make_name(names.path.path) if luaname then - --tabletofile(luaname, data, true, { reduce=true }) - table.tofile(luaname, fontnames, true) + --tabletofile(luaname, fontnames, true, { reduce=true }) + tabletofile(luaname, fontnames, true) if lucname and type(caches.compile) == "function" then os.remove(lucname) caches.compile(fontnames, luaname, lucname) -- cgit v1.2.3 From 76569528866a34fb649611997792d936a283190b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Apr 2013 19:08:30 +0200 Subject: import from Context as of 2013-04-26 --- luaotfload-merged.lua | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/luaotfload-merged.lua b/luaotfload-merged.lua index bb89e39..0cf2ce4 100644 --- a/luaotfload-merged.lua +++ b/luaotfload-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 04/25/13 18:50:39 +-- merge date : 04/26/13 15:13:48 do -- begin closure to overcome local limits and interference @@ -7705,7 +7705,7 @@ function injections.handler(head,where,keep) local w=k[4] if w then if rlmode and rlmode>=0 then - n.xoffset=p.xoffset-p.width+d[1]-x + n.xoffset=p.xoffset-p.width+d[1]-(w-x) else n.xoffset=p.xoffset-d[1]-x end @@ -7745,7 +7745,8 @@ function injections.handler(head,where,keep) end if next(wx) then for n,k in next,wx do - local x,w=k[2] or 0,k[4] + local x=k[2] + local w=k[4] if w then local rl=k[1] local wx=w-x -- cgit v1.2.3 From d16a93579dfec03a0dab4281b45f63d877fc4c88 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Fri, 26 Apr 2013 22:33:37 +0200 Subject: install the new file: lookup in luaotfload.lua --- luaotfload-database.lua | 35 +++++++++++++++++++++-------------- luaotfload-features.lua | 17 +++++++++++------ luaotfload.dtx | 15 +++++++++++++-- 3 files changed, 45 insertions(+), 22 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 4980766..576971e 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -230,6 +230,8 @@ local load_lua_file = function (path) end --- define locals in scope +local crude_file_lookup +local crude_file_lookup_verbose local find_closest local flush_cache local font_fullinfo @@ -290,8 +292,12 @@ do end --- chain: barenames -> [fullnames ->] basenames -> findfile -local crude_file_lookup_verbose = function (data, filename) - local mappings = data.mappings + +--- string -> (string * bool | int) +crude_file_lookup_verbose = function (filename) + if not names.data then names.data = names_reload() end + local data = names.data + local mappings = data.mappings local found --- look up in db first ... @@ -336,7 +342,11 @@ local crude_file_lookup_verbose = function (data, filename) return false end -local crude_file_lookup = function (data, filename) +--- string -> (string * bool | int) +crude_file_lookup = function (filename) + if not names.data then names.data = names_reload() end + local data = names.data + local mappings = data.mappings local found = data.barenames[filename] -- or data.fullnames[filename] or data.basenames[filename] @@ -470,6 +480,7 @@ local resolvers = { fonts.definers.resolve = resolvers[config.luaotfload.resolver] --fonts.definers.resolve = resolvers.cached +fonts.definers.resolve = resolvers.dummy --[[doc-- @@ -513,12 +524,6 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con if not fonts_loaded then names.data = load_names() end local data = names.data - if specification.lookup == "file" then - local found = crude_file_lookup(data, specification.name) - --local found = crude_file_lookup_verbose(data, specification.name) - if found then return found[1], found[2], true end - end - local name = sanitize_string(specification.name) local style = sanitize_string(specification.style) or "regular" @@ -1380,11 +1385,13 @@ scan_external_dir = function (dir) end --- export functionality to the namespace “fonts.names” -names.flush_cache = flush_cache -names.load = load_names -names.save = save_names -names.scan = scan_external_dir -names.update = update_names +names.flush_cache = flush_cache +names.load = load_names +names.save = save_names +names.scan = scan_external_dir +names.update = update_names +names.crude_file_lookup = crude_file_lookup +names.crude_file_lookup_verbose = crude_file_lookup_verbose names.resolve = resolve --- replace the resolver from luatex-fonts names.resolvespec = resolve diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 78f8256..0171dba 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -163,7 +163,7 @@ local set_default_features = function (speclist) return speclist end -local function issome () feature_list.lookup = 'name' end +local function issome () feature_list.lookup = 'file' end local function isfile () feature_list.lookup = 'file' end local function isname () feature_list.lookup = 'name' end local function thename(s) feature_list.name = s end @@ -180,7 +180,8 @@ local spaces = P(" ")^0 local namespec = (1-S("/:("))^1 local filespec = (R("az", "AZ") * P(":"))^-1 * (1-S(":("))^1 local stylespec = spaces * P("/") * (((1-P(":"))^0)/isstyle) * spaces -local filename = (P("file:")/isfile * (filespec/thename)) + (P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]")) +local filename = (P("file:")/isfile * (filespec/thename)) + + (P("[") * P(true)/isname * (((1-P("]"))^0)/thename) * P("]")) local fontname = (P("name:")/isname * (namespec/thename)) + P(true)/issome * (namespec/thename) local sometext = (R("az","AZ","09") + S("+-.,"))^1 local truevalue = P("+") * spaces * (sometext/istrue) @@ -216,10 +217,12 @@ local function colonized(specification) -- xetex mode specification.name = feature_list.name feature_list.name = nil end - if feature_list.lookup then - specification.lookup = feature_list.lookup - feature_list.lookup = nil - end + --- this test overwrites valid file: requests for xetex bracket + --- syntax +-- if feature_list.lookup then +-- specification.lookup = feature_list.lookup +-- feature_list.lookup = nil +-- end if feature_list.sub then specification.sub = feature_list.sub feature_list.sub = nil @@ -229,6 +232,8 @@ local function colonized(specification) -- xetex mode feature_list.mode = fonts.mode end specification.features.normal = fonts.handlers.otf.features.normalize(feature_list) + --inspect(specification) + --os.exit() return specification end diff --git a/luaotfload.dtx b/luaotfload.dtx index 18e01d8..8b3616a 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1328,7 +1328,7 @@ add_to_callback("find_vf_file", loadmodule"lib-dir.lua" --- required by luaofload-database.lua loadmodule"override.lua" --- “luat-ovr” -logs.set_loglevel(0) +logs.set_loglevel(config.luaotfload.loglevel or 2) % \end{macrocode} % \CONTEXT does not support ofm, these lines were added in order to make it @@ -1365,8 +1365,19 @@ loadmodule"colors.lua" --- “font-clr” % % \begin{macrocode} +--- below lines already (2013-04-25) lead to warnings by +--- the font loader +--fonts.definers.resolvers.file = function (specification) +-- specification.name = fonts.names.resolve('', '', specification) +--end + fonts.definers.resolvers.file = function (specification) - specification.name = fonts.names.resolve('', '', specification) + --inspect(specification) + if specification.lookup == "file" then + local found = fonts.names.crude_file_lookup(specification.name) + --local found = fonts.names.crude_file_lookup_verbose(specification.name) + specification.name = found[1] + end end % \end{macrocode} -- cgit v1.2.3 From 8331000eb1d76381fe5f03fa6c090ae936a110b6 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 27 Apr 2013 02:31:08 +0200 Subject: drop scanning fonts.conf in favor of `fc-cat` --- luaotfload-database.lua | 140 ++++++++++++++++-------------------------------- 1 file changed, 45 insertions(+), 95 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 4980766..e23902a 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -21,6 +21,7 @@ local tonumber = tonumber local fontloaderinfo = fontloader.info local iolines = io.lines local ioopen = io.open +local iopopen = io.popen local kpseexpand_path = kpse.expand_path local kpseexpand_var = kpse.expand_var local kpselookup = kpse.lookup @@ -234,7 +235,6 @@ local find_closest local flush_cache local font_fullinfo local load_names -local read_fonts_conf local reload_db local resolve local save_names @@ -1141,6 +1141,29 @@ local function scan_texmf_fonts(fontnames, newfontnames) return n_scanned, n_new end +--- fc-cat outputs every directory it finds fonts in, +--- so we have to remove all subdirectories from the +--- list. + +--- dir list -> dir list +local collapse_paths = function (dir_lst) + tablesort(dir_lst) + local last = dir_lst[1] + local res = { last } + local ndirs = #dir_lst + if ndirs > 1 then + for i=2, ndirs do + local dir = dir_lst[i] + if stringsub(dir, 1, #last) ~= last then + --- new prefix + res[#res+1] = dir + last = dir + end + end + end + return res +end + --[[ For the OS fonts, there are several options: - if OSFONTDIR is set (which is the case under windows by default but @@ -1148,99 +1171,32 @@ end in the scan_texmf_fonts. - if not: - under Windows and Mac OSX, we take a look at some hardcoded directories - - under Unix, we read /etc/fonts/fonts.conf and read the directories in it + - under Unix, we parse the output of “fc-cat -v” This means that if you have fonts in fancy directories, you need to set them in OSFONTDIR. ]] ---- (string -> tab -> tab -> tab) -read_fonts_conf = function (path, results, passed_paths) - --[[ - This function parses /etc/fonts/fonts.conf and returns all the dir - it finds. The code is minimal, please report any error it may - generate. - - TODO fonts.conf are some kind of XML so in theory the following - is totally inappropriate. Maybe a future version of the - lualibs will include the lxml-* files from Context so we - can write something presentable instead. - ]] - local fh = ioopen(path) - passed_paths[#passed_paths+1] = path - passed_paths_set = tabletohash(passed_paths, true) - if not fh then - report("log", 2, "db", "cannot open file %s", path) - return results - end - local incomments = false - for line in fh:lines() do - while line and line ~= "" do - -- spaghetti code... hmmm... - if incomments then - local tmp = stringfind(line, '-->') --- wtf? - if tmp then - incomments = false - line = stringsub(line, tmp+3) - else - line = nil - end - else - local tmp = stringfind(line, '') --- wtf? + if tmp then + incomments = false + line = stringsub(line, tmp+3) + else + line = nil + end + else + local tmp = stringfind(line, '" + + ---> header specifica + local xml_declaration = P"")^0 * P"?>" + local xml_doctype = P"")^0 * P">" + local header = xml_declaration^-1 + * (xml_doctype + comment + ws)^0 + + ---> enforce root node + local root_start = P"<" * ws^-1 * P"fontconfig" * ws^-1 * P">" + local root_stop = P"" + + local dquote, squote = P[["]], P"'" + local xml_namestartchar = S":_" + alpha --- ascii only, funk the rest + local xml_namechar = S":._" + alpha + digit + local xml_name = ws^-1 + * C(xml_namestartchar * xml_namechar^0) + local xml_attvalue = dquote * C((1 - S[[%&"]])^1) * dquote * ws^-1 + + squote * C((1 - S[[%&']])^1) * squote * ws^-1 + local xml_attr = Cg(xml_name * P"=" * xml_attvalue) + local xml_attr_list = Cf(Ct"" * xml_attr^1, rawset) + + --[[doc-- + scan_node creates a parser for a given xml tag. + --doc]]-- + --- string -> bool -> lpeg_t + local scan_node = function (tag) + --- Node attributes go into a table with the index “attributes” + --- (relevant for “prefix="xdg"” and the likes). + local p_tag = P(tag) + local with_attributes = P"<" * p_tag + * Cg(xml_attr_list, "attributes")^-1 + * ws^-1 + * P">" + local plain = P"<" * p_tag * ws^-1 * P">" + local node_start = plain + with_attributes + local node_stop = P"" + --- there is no nesting, the earth is flat ... + local node = node_start + * Cc(tag) * C(comment + (1 - node_stop)^1) + * node_stop + return Ct(node) -- returns {string, string [, attributes = { key = val }] } end - local incomments = false - for line in fh:lines() do - while line and line ~= "" do - -- spaghetti code... hmmm... - if incomments then - local tmp = stringfind(line, '-->') --- wtf? - if tmp then - incomments = false - line = stringsub(line, tmp+3) - else - line = nil + + --[[doc-- + At the moment, the interesting tags are “dir” for + directory declarations, and “include” for including + further configuration files. + + spec: http://freedesktop.org/software/fontconfig/fontconfig-user.html + --doc]]-- + local include_node = scan_node"include" + local dir_node = scan_node"dir" + + local element = dir_node + + include_node + + comment --> ignore + + P(1-root_stop) --> skip byte + + local root = root_start * Ct(element^0) * root_stop + local p_cheapxml = header * root + + --lpeg.print(p_cheapxml) ---> 757 rules with v0.10 + + --[[doc-- + fonts_conf_scanner() handles configuration files. + It is called on an abolute path to a config file (e.g. + /home/luser/.config/fontconfig/fonts.conf) and returns a list + of the nodes it managed to extract from the file. + --doc]]-- + --- string -> path list + local fonts_conf_scanner = function (path) + local fh = ioopen(path, "r") + if not fh then + report("both", 3, "db", "cannot open fontconfig file %s", path) + return + end + local raw = fh:read"*all" + fh:close() + + local confdata = lpegmatch(p_cheapxml, raw) + if not confdata then + report("both", 3, "db", "cannot scan fontconfig file %s", path) + return + end + return confdata + end + + --[[doc-- + read_fonts_conf_indeed() is called with six arguments; the + latter three are tables that represent the state and are + always returned. + The first three are + · the path to the file + · the expanded $HOME + · the expanded $XDG_CONFIG_DIR + --doc]]-- + --- string -> string -> string -> tab -> tab -> (tab * tab * tab) + local read_fonts_conf_indeed + read_fonts_conf_indeed = function (start, home, xdg_home, + acc, done, dirs_done) + + local paths = fonts_conf_scanner(start) + if not paths then --- nothing to do + return acc, done, dirs_done + end + + for i=1, #paths do + local pathobj = paths[i] + local kind, path = pathobj[1], pathobj[2] + local attributes = pathobj.attributes + if attributes and attributes.prefix == "xdg" then + --- this prepends the xdg root (usually ~/.config) + path = filejoin(xdg_home, path) + end + + if kind == "dir" then + if stringsub(path, 1, 1) == "~" then + path = filejoin(home, stringsub(path, 2)) end - else - local tmp = stringfind(line, ' list: paths collected + local done = { } ---> set: files inspected + local dirs_done = { } ---> set: dirs in list + for i=1, #path_list do --- we keep the state between files + acc, done, dirs_done = read_fonts_conf_indeed( + path_list[i], home, xdg_home, + acc, done, dirs_done) + end + return acc + end +end --- read_fonts_conf closure --- TODO stuff those paths into some writable table local function get_os_dirs() @@ -1258,14 +1380,12 @@ local function get_os_dirs() elseif os.type == "windows" or os.type == "msdos" or os.name == "cygwin" then local windir = os.getenv("WINDIR") return { filejoin(windir, 'Fonts') } - else - local passed_paths = {} - local os_dirs = {} - for _,p in next, {"/usr/local/etc/fonts/fonts.conf", "/etc/fonts/fonts.conf"} do - if lfs.isfile(p) then - read_fonts_conf(p, os_dirs, passed_paths) - end - end + else + local fonts_conves = { --- plural, much? + "/usr/local/etc/fonts/fonts.conf", + "/etc/fonts/fonts.conf", + } + local os_dirs = read_fonts_conf(fonts_conves) return os_dirs end return {} @@ -1275,7 +1395,8 @@ local function scan_os_fonts(fontnames, newfontnames) local n_scanned, n_new = 0, 0 --[[ This function scans the OS fonts through - - fontcache for Unix (reads the fonts.conf file and scans the directories) + - fontcache for Unix (reads the fonts.conf file and scans the + directories) - a static set of directories for Windows and MacOSX ]] report("info", 2, "db", "Scanning OS fonts...") @@ -1390,6 +1511,9 @@ names.resolve = resolve --- replace the resolver from luatex-fonts names.resolvespec = resolve names.find_closest = find_closest +-- for testing purpose +names.read_fonts_conf = read_fonts_conf + --- dummy required by luatex-fonts (cf. luatex-fonts-syn.lua) fonts.names.getfilename = function (askedname,suffix) return "" end -- cgit v1.2.3 From 9fceb52298c05c31666521b4226362322b18c178 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sat, 27 Apr 2013 18:26:21 +0200 Subject: update fontconfig test --- luaotfload-database.lua | 17 ++++++++++----- tests/fontconfig_conf_reading.tex | 8 ++++--- tests/fonts.conf.test | 44 ++++++++++++++++++++++----------------- 3 files changed, 42 insertions(+), 27 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index edc3a5b..3085b63 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -86,12 +86,19 @@ config.luaotfload.resolver = config.luaotfload.resolver or "normal" -- We use the cache.* of ConTeXt (see luat-basics-gen), we can -- use it safely (all checks and directory creations are already done). It -- uses TEXMFCACHE or TEXMFVAR as starting points. -local writable_path = caches.getwritablepath("names","") -if not writable_path then - error("Impossible to find a suitable writeable cache...") +local writable_path +if caches then + writable_path = caches.getwritablepath("names","") + if not writable_path then + error("Impossible to find a suitable writeable cache...") + end + names.path.dir = writable_path + names.path.path = filejoin(writable_path, names.path.basename) +else --- running as script, inject some dummies + caches = { } + logs = { report = function () end } end -names.path.dir = writable_path -names.path.path = filejoin(writable_path, names.path.basename) + --[[doc-- Auxiliary functions diff --git a/tests/fontconfig_conf_reading.tex b/tests/fontconfig_conf_reading.tex index dbbbc3c..66ab377 100644 --- a/tests/fontconfig_conf_reading.tex +++ b/tests/fontconfig_conf_reading.tex @@ -1,6 +1,8 @@ \directlua{ -require("lualibs") -require("otfl-font-nms.lua") -texio.write_nl(table.serialize(fonts.names.read_fonts_conf("fonts.conf.test", {}))) + config = { lualibs = { load_extended = false } } + require"lualibs" + require"luaotfload-database" + local results = fonts.names.read_fonts_conf{"fonts.conf.test"} + inspect(results) } \bye diff --git a/tests/fonts.conf.test b/tests/fonts.conf.test index 0e5b961..3c3e132 100644 --- a/tests/fonts.conf.test +++ b/tests/fonts.conf.test @@ -1,19 +1,25 @@ - - - - - - -test 1 ok -test 2 oktest 3 ok -test 4 oktest 5 ok - -/etc/fonts/conf.d -/etc/fonts/fonts.conf -/etc/fonts/conf.d/69-unifont.conf + + + + + + + + + + + fontconfig/fonts.conf + test 1 ok + test 2 oktest 3 ok + test 4 oktest 5 ok + + /etc/fonts/conf.d + /etc/fonts/fonts.conf + /etc/fonts/conf.d/69-unifont.conf + -- cgit v1.2.3 From 4821fad2ff58fa8c4fbee58cbb6fe5353e047613 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 01:45:34 +0200 Subject: Import new font request parser addressing https://github.com/phi-gamma/luaotfload/issues/4 incomplete for now, only handles file: and name: requests --- luaotfload-features.lua | 327 ++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 274 insertions(+), 53 deletions(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 0171dba..cd639b6 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -26,7 +26,7 @@ function fonts.definers.getspecification(str) return "", str, "", ":", str end -local feature_list = { } +local old_feature_list = { } local report = logs.names_report @@ -64,20 +64,23 @@ local isstyle = function (request) for _,v in next, request do local stylename = supported[v] if stylename then - feature_list.style = stylename + old_feature_list.style = stylename elseif stringfind(v, "^s=") then --- after all, we want everything after the second byte ... local val = stringsub(v, 3) - feature_list.optsize = val + old_feature_list.optsize = val elseif stylename == false then report("log", 0, - "load font", "unsupported font option: %s", v) + "load", "unsupported font option: %s", v) elseif not stringis_empty(v) then - feature_list.style = stringgsub(v, "[^%a%d]", "") + old_feature_list.style = stringgsub(v, "[^%a%d]", "") end end end +--- TODO an option to dump the default features for a script would make +--- a nice addition to luaotfload-tool + local defaults = { dflt = { "ccmp", "locl", "rlig", "liga", "clig", @@ -131,17 +134,22 @@ defaults.tibt = defaults.khmr defaults.lao = defaults.thai +--[[doc-- +Which features are active by default depends on the script requested. +--doc]]-- + --- (string, string) dict -> (string, string) dict local set_default_features = function (speclist) + speclist = speclist or { } local script = speclist.script or "dflt" - report("log", 0, "load font", + report("log", 0, "load", "auto-selecting default features for script: %s", script) local requested = defaults[script] if not requested then - report("log", 0, "load font", + report("log", 0, "load", "no defaults for script “%s”, falling back to “dflt”", script) requested = defaults.dflt @@ -149,9 +157,7 @@ local set_default_features = function (speclist) for i=1, #requested do local feat = requested[i] - if speclist[feat] ~= false then - speclist[feat] = true - end + if speclist[feat] ~= false then speclist[feat] = true end end for feat, state in next, global_defaults do @@ -163,14 +169,15 @@ local set_default_features = function (speclist) return speclist end -local function issome () feature_list.lookup = 'file' end -local function isfile () feature_list.lookup = 'file' end -local function isname () feature_list.lookup = 'name' end -local function thename(s) feature_list.name = s end -local function issub (v) feature_list.sub = v end -local function istrue (s) feature_list[s] = true end -local function isfalse(s) feature_list[s] = false end -local function iskey (k,v) feature_list[k] = v end +-- --[==[obsolete-- +local function issome () old_feature_list.lookup = 'name' end +local function isfile () old_feature_list.lookup = 'file' end +local function isname () old_feature_list.lookup = 'name' end +local function thename(s) old_feature_list.name = s end +local function issub (v) old_feature_list.sub = v end +local function istrue (s) old_feature_list[s] = true end +local function isfalse(s) old_feature_list[s] = false end +local function iskey (k,v) old_feature_list[k] = v end local P, S, R, C = lpeg.P, lpeg.S, lpeg.R, lpeg.C @@ -191,54 +198,268 @@ local somevalue = sometext/istrue local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim local option = spaces * (keyvalue + falsevalue + truevalue + somevalue) * spaces local options = P(":") * spaces * (P(";")^0 * option)^0 -local pattern = (filename + fontname) * subvalue^0 * stylespec^0 * options^0 - -local function colonized(specification) -- xetex mode - feature_list = { } - lpeg.match(pattern,specification.specification) - feature_list = set_default_features(feature_list) - if feature_list.style then - specification.style = feature_list.style - feature_list.style = nil +local oldsyntax = (filename + fontname) * subvalue^0 * stylespec^0 * options^0 + +--- to be annihilated +local function old_behavior (specification) -- xetex mode + old_feature_list = { } + lpeg.match(oldsyntax,specification.specification) + old_feature_list = set_default_features(old_feature_list) + if old_feature_list.style then + specification.style = old_feature_list.style + old_feature_list.style = nil end - if feature_list.optsize then - specification.optsize = feature_list.optsize - feature_list.optsize = nil + if old_feature_list.optsize then + specification.optsize = old_feature_list.optsize + old_feature_list.optsize = nil end - if feature_list.name then - if resolvers.findfile(feature_list.name, "tfm") then - feature_list.lookup = "file" - feature_list.name = file.addsuffix(feature_list.name, "tfm") - elseif resolvers.findfile(feature_list.name, "ofm") then - feature_list.lookup = "file" - feature_list.name = file.addsuffix(feature_list.name, "ofm") + if old_feature_list.name then + if resolvers.findfile(old_feature_list.name, "tfm") then + old_feature_list.lookup = "file" + old_feature_list.name = file.addsuffix(old_feature_list.name, "tfm") + elseif resolvers.findfile(old_feature_list.name, "ofm") then + old_feature_list.lookup = "file" + old_feature_list.name = file.addsuffix(old_feature_list.name, "ofm") end - specification.name = feature_list.name - feature_list.name = nil + specification.name = old_feature_list.name + old_feature_list.name = nil end --- this test overwrites valid file: requests for xetex bracket --- syntax --- if feature_list.lookup then --- specification.lookup = feature_list.lookup --- feature_list.lookup = nil --- end - if feature_list.sub then - specification.sub = feature_list.sub - feature_list.sub = nil + if old_feature_list.lookup then + specification.lookup = old_feature_list.lookup + old_feature_list.lookup = nil end - if not feature_list.mode then + if old_feature_list.sub then + specification.sub = old_feature_list.sub + old_feature_list.sub = nil + end + if not old_feature_list.mode then -- if no mode is set, use our default - feature_list.mode = fonts.mode + old_feature_list.mode = fonts.mode end - specification.features.normal = fonts.handlers.otf.features.normalize(feature_list) - --inspect(specification) - --os.exit() + specification.features.normal = fonts.handlers.otf.features.normalize(old_feature_list) return specification end -fonts.definers.registersplit(":",colonized,"cryptic") -fonts.definers.registersplit("", colonized,"more cryptic") -- catches \font\text=[names] +--fonts.definers.registersplit(":",old_behavior,"cryptic") +--fonts.definers.registersplit("", old_behavior,"more cryptic") -- catches \font\text=[names] +--obsolete]==]-- + +----------------------------------------------------------------------- +--- request syntax parser 2.2 +----------------------------------------------------------------------- +--- the luaotfload font request syntax (see manual) +--- has a canonical form: +--- +--- \font=:: +--- +--- where +--- is the control sequence that activates the font +--- is either “file” or “name”, determining the lookup +--- is either a file name (no path) or a font +--- name, depending on the lookup +--- is a list of switches or options, separated by +--- semicolons or commas; a switch is of the form “+” foo +--- or “-” foo, options are of the form lhs “=” rhs +--- +--- however, to ensure backward compatibility we also have +--- support for Xetex-style requests. +--- +--- for the Xetex emulation see: +--- · The XeTeX Reference Guide by Will Robertson, 2011 +--- · The XeTeX Companion by Michel Goosens, 2010 +--- · About XeTeX by Jonathan Kew, 2005 +--- +--- +--- caueat emptor. +--- the request is parsed into one of **four** different +--- lookup categories: the regular ones, file and name, +--- as well as the Xetex compatibility ones, path and anon. +--- (maybe a better choice of identifier would be “ambig”.) +--- +--- according to my reconstruction, the correct chaining +--- of the lookups for each category is as follows: +--- +--- | File -> ( db/filename lookup; +--- db/basename lookup; +--- kpse.find_file() ) +--- | Name -> ( names.resolve() ) +--- | Path -> ( db/filename lookup; +--- db/basename lookup; +--- kpse.find_file(); +--- fullpath lookup ) +--- | Anon -> ( names.resolve(); (* most general *) +--- db/filename lookup; +--- db/basename lookup; +--- kpse.find_file(); +--- fullpath lookup ) +--- +--- the database should be generated only if the chain has +--- been completed, and then only once. +--- +--- caching of successful lookups is essential. we need +--- an additional subtable "cached" in the database. it +--- should be nil’able by issuing fontdbutil --flush or +--- something. if a cache miss is followed by a successful +--- lookup, then it will be counted as new addition to the +--- cache. we also need a config option to ignore caching. +--- +--- also everything has to be finished by tomorrow at noon. +--- +----------------------------------------------------------------------- + + +local stringlower = string.lower + +local toboolean = function (s) + if s == "true" then return true end + if s == "false" then return false end +--if s == "yes" then return true end --- Context style +--if s == "no" then return false end + return s +end + +local lpegmatch = lpeg.match +local P, S, R = lpeg.P, lpeg.S, lpeg.R +local C, Cc, Cf, Cg, Cs, Ct + = lpeg.C, lpeg.Cc, lpeg.Cf, lpeg.Cg, lpeg.Cs, lpeg.Ct + +--- terminals and low-level classes ----------------------------------- +--- note we could use the predefined ones from lpeg.patterns +local dot = P"." +local colon = P":" +local featuresep = S",;" +local slash = P"/" +local equals = P"=" +local lbrk, rbrk = P"[", P"]" + +local spacing = S" \t\v" +local ws = spacing^0 + +local digit = R"09" +local alpha = R("az", "AZ") +local anum = alpha + digit +local decimal = digit^1 * (dot * digit^0)^-1 + +--- modifiers --------------------------------------------------------- +--[[doc-- + The slash notation: called “modifiers” (Kew) or “font options” + (Robertson, Goosens) + we only support the shorthands for italic / bold / bold italic + shapes, the rest is ignored. +--doc]]-- +local style_modifier = (P"BI" + P"IB" + P"bi" + P"ib" + S"biBI") + / stringlower +local other_modifier = P"S=" * decimal --- optical size; unsupported + + P"AAT" + P"aat" --- apple stuff; unsupported + + P"ICU" + P"icu" --- not applicable + + P"GR" + P"gr" --- sil stuff; unsupported +local garbage_modifier = ((1 - colon - slash)^0 * Cc(false)) +local modifier = slash * (other_modifier --> ignore + + Cs(style_modifier) --> collect + + garbage_modifier) --> warn +local modifier_list = Cg(Ct(modifier^0), "modifiers") + +--- lookups ----------------------------------------------------------- +local fontname = C((1-S"/:(")^1) --- like luatex-fonts +local prefixed = P"name:" * ws * Cg(fontname, "name") + + P"file:" * ws * Cg(fontname, "file") +local unprefixed = Cg(fontname, "anon") +local path_lookup = lbrk * Cg(C((1-rbrk)^1), "path") * rbrk + +--- features ---------------------------------------------------------- +local field = (anum + S"+-.")^1 --- sic! +--- assignments are “lhs=rhs” +--- switches are “+key” | “-key” +local assignment = C(field) * ws * equals * ws * (field / toboolean) +local switch = P"+" * ws * C(field) * Cc(true) + + P"-" * ws * C(field) * Cc(false) + + C(field) * Cc(true) -- catch crap +local feature_expr = ws * Cg(assignment + switch) * ws +local feature_list = Cf(Ct"" + * feature_expr + * (featuresep * feature_expr)^0 + , rawset) + * featuresep^-1 + +--- top-level rules --------------------------------------------------- +--- \font\foo=: +local features = Cg(feature_list, "features") +local specification = (prefixed + unprefixed) * modifier_list^-1 +local font_request = Ct(path_lookup * (colon^-1 * features)^-1 + + specification * (colon * features)^-1) + +-- lpeg.print(font_request) +--- new parser: 632 rules +--- old parser: 230 rules + +local import_values = { + --- That’s what the 1.x parser did, not quite as graciously, + --- with an array of branch expressions. + "style", "optsize", "lookup", "sub" --[[‽]], "mode", +} + +local handle_name = function (specification, raw) + --- FIXME only file: and name: atm + local name = raw.file or raw.name + local lookup + --- why is this here? + --- TODO should we keep this, check if it applies only to tfm and + --- ofm, and test formats by a defined list! + if resolvers.findfile(name, "tfm") then + lookup = "file" + name = file.addsuffix(name, "tfm") + elseif resolvers.findfile(name, "ofm") then + lookup = "file" + name = file.addsuffix(name, "ofm") + end + return name, lookup +end + +--- spec -> spec +local handle_request = function (specification) + local request = lpegmatch(font_request, + specification.specification) + request.features = set_default_features(request.features) + + local name, lookup = handle_name(specification, request) + if name then + specification.name = name + specification.lookup = lookup or specification.lookup + end + + for n=1, #import_values do + local feat = import_values[n] + local newvalue = request.features[feat] + if newvalue then + specification[feat] = request.features[feat] + request.features[feat] = nil + end + end + --- The next line sets the “rand” feature to “random”; I haven’t + --- investigated it any further (luatex-fonts-ext), so it will + --- just stay here. + specification.features.normal + = fonts.handlers.otf.features.normalize(request.features) + return specification +end + +local compare_requests = function (spec) + local old = old_behavior(spec) + local new = handle_request(spec) + return new +end + +fonts.definers.registersplit(":", compare_requests, "cryptic") +fonts.definers.registersplit("", compare_requests, "more cryptic") -- catches \font\text=[names] + +--fonts.definers.registersplit(":", handle_request, "cryptic") +--fonts.definers.registersplit("", handle_request, "more cryptic") -- catches \font\text=[names] + +--fonts.definers.registersplit(":",old_behavior,"cryptic") +--fonts.definers.registersplit("", old_behavior,"more cryptic") -- catches \font\text=[names] --- TODO below section is literally the same in luatex-fonts-def --- why is it here? -- cgit v1.2.3 From eeb0aff3db719c6257311a0217ede37b8629e33a Mon Sep 17 00:00:00 2001 From: Elie Roux Date: Sat, 27 Apr 2013 12:13:37 +0200 Subject: Updating NEWS --- NEWS | 1 + luaotfload-blacklist.cnf | 2 ++ 2 files changed, 3 insertions(+) diff --git a/NEWS b/NEWS index 754cbcd..aac957d 100644 --- a/NEWS +++ b/NEWS @@ -9,6 +9,7 @@ Change History updating otfl-fonts-merged.lua (available in ConTeXt) * Improve documentation * renaming mkluatexfontdb into fontdbutil, with more search functionalities + * blacklisting font lingoes.ttf 2013/04/11, luaotfload v1.28: * Adapting to LuaTeX 0.75, keeping backward-compatibility diff --git a/luaotfload-blacklist.cnf b/luaotfload-blacklist.cnf index 771649b..36a29df 100644 --- a/luaotfload-blacklist.cnf +++ b/luaotfload-blacklist.cnf @@ -1,5 +1,7 @@ % Takes ages to load LastResort.ttf % a MacOSX font, but also available for free from unicode.org +% Segfaults under LuaTeX 0.76 +lingoes.ttf % Mac OS X TTC fonts, this list need to be filtered out % luatex bug fixed? -- cgit v1.2.3 From 84eec2bb9d4e33f5ceacd33ee38a7d686b9134eb Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 10:12:18 +0200 Subject: unblacklist Apple TTC files http://tug.org/pipermail/lualatex-dev/2013-April/001498.html --- luaotfload-blacklist.cnf | 20 -------------------- 1 file changed, 20 deletions(-) diff --git a/luaotfload-blacklist.cnf b/luaotfload-blacklist.cnf index 36a29df..943d347 100644 --- a/luaotfload-blacklist.cnf +++ b/luaotfload-blacklist.cnf @@ -3,23 +3,3 @@ LastResort.ttf % a MacOSX font, but also available for free from unicode.org % Segfaults under LuaTeX 0.76 lingoes.ttf -% Mac OS X TTC fonts, this list need to be filtered out -% luatex bug fixed? -% /Library/Fonts/AmericanTypewriter.ttc -% /Library/Fonts/Baskerville.ttc -% /Library/Fonts/Chalkboard.ttc -% /Library/Fonts/Cochin.ttc -% /Library/Fonts/Copperplate.ttc -% /Library/Fonts/Didot.ttc -% /Library/Fonts/Futura.ttc -% /Library/Fonts/GillSans.ttc -% /Library/Fonts/Hoefler Text.ttc -% /Library/Fonts/MarkerFelt.ttc -% /Library/Fonts/Optima.ttc -% /Library/Fonts/Papyrus.ttc -% /Library/Fonts/STHeiti Medium.ttc -% /System/Library/Fonts/AquaKana.ttc -% /System/Library/Fonts/HelveticaNeue.ttc -% /System/Library/Fonts/LucidaGrande.ttc -% /System/Library/Fonts/Menlo.ttc -% /System/Library/Fonts/STHeiti Light.ttc -- cgit v1.2.3 From 9c16f2f73eed3946020b0197d9fe97034c4f9f24 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 10:17:50 +0200 Subject: workaround for non-ascii cache file names --- luaotfload-override.lua | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/luaotfload-override.lua b/luaotfload-override.lua index 726000d..7ee9730 100644 --- a/luaotfload-override.lua +++ b/luaotfload-override.lua @@ -81,4 +81,10 @@ logs.names_report = function (mode, lvl, ...) end end +--- This will vanish as soon as Hans fixes it in data-con +--- https://github.com/lualatex/luaotfload/issues/17 + +containers.cleanname = function (name) + return (string.gsub(string.lower(name),"[^%w%d\128\255]+","-")) +end -- vim:tw=71:sw=4:ts=4:expandtab -- cgit v1.2.3 From a1ab3fe5a146cf741d517be62985b97268de624b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 12:59:51 +0200 Subject: add fallback for specification name --- luaotfload-database.lua | 12 ++++++------ luaotfload-features.lua | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 576971e..b678f51 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -437,7 +437,7 @@ local cached_resolver = function (specification) if not names.data then names.data = load_names() end local request_cache = names.data.request_cache local request = specification.specification - report("info", 4, "cache", + report("log", 4, "cache", "looking for “%s” in cache ...", request) local found = names.data.request_cache[request] @@ -449,7 +449,7 @@ local cached_resolver = function (specification) end return specification end - report("info", 4, "cache", "not cached; resolving") + report("log", 4, "cache", "not cached; resolving") --- first we resolve normally ... local resolved_spec = normal_resolver(specification) @@ -459,7 +459,7 @@ local cached_resolver = function (specification) local f = cache_fields[i] entry[f] = resolved_spec[f] end - report("info", 4, "cache", "new entry: %s", request) + report("log", 4, "cache", "new entry: %s", request) names.data.request_cache[request] = entry --- obviously, the updated cache needs to be stored. @@ -467,7 +467,7 @@ local cached_resolver = function (specification) --- whenever the cache is updated. --- TODO this should trigger a save only once the --- document is compiled (finish_pdffile callback?) - report("info", 5, "cache", "saving updated cache") + report("log", 5, "cache", "saving updated cache") save_names() return resolved_spec end @@ -480,7 +480,7 @@ local resolvers = { fonts.definers.resolve = resolvers[config.luaotfload.resolver] --fonts.definers.resolve = resolvers.cached -fonts.definers.resolve = resolvers.dummy +--fonts.definers.resolve = resolvers.dummy --[[doc-- @@ -1268,7 +1268,7 @@ local function get_os_dirs() local os_dirs = {} for _,p in next, {"/usr/local/etc/fonts/fonts.conf", "/etc/fonts/fonts.conf"} do if lfs.isfile(p) then - read_fonts_conf(p, os_dirs, passed_paths) + paths = read_fonts_conf(p, os_dirs, passed_paths) end end return os_dirs diff --git a/luaotfload-features.lua b/luaotfload-features.lua index cd639b6..f3d9158 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -401,9 +401,9 @@ local import_values = { "style", "optsize", "lookup", "sub" --[[‽]], "mode", } -local handle_name = function (specification, raw) +local handle_name = function (specname, raw) --- FIXME only file: and name: atm - local name = raw.file or raw.name + local name = raw.file or raw.name or specname local lookup --- why is this here? --- TODO should we keep this, check if it applies only to tfm and @@ -424,7 +424,7 @@ local handle_request = function (specification) specification.specification) request.features = set_default_features(request.features) - local name, lookup = handle_name(specification, request) + local name, lookup = handle_name(specification.name, request) if name then specification.name = name specification.lookup = lookup or specification.lookup -- cgit v1.2.3 From 996ba6a5014fc546c8e8c769a259b9adaf2090dc Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 13:34:58 +0200 Subject: add prelimiary anon: and path: resolvers --- luaotfload-features.lua | 23 +++++++++++++++++++---- luaotfload.dtx | 30 ++++++++++++++++++++++++++++-- 2 files changed, 47 insertions(+), 6 deletions(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index f3d9158..c939a3f 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -401,7 +401,7 @@ local import_values = { "style", "optsize", "lookup", "sub" --[[‽]], "mode", } -local handle_name = function (specname, raw) +local handle_tfmofm = function (specname, raw) --- FIXME only file: and name: atm local name = raw.file or raw.name or specname local lookup @@ -418,13 +418,28 @@ local handle_name = function (specname, raw) return name, lookup end +local lookup_types = { "anon", "file", "name", "path" } + +local select_lookup = function (request) + for i=1, #lookup_types do + local lookup = lookup_types[i] + local value = request[lookup] + if value then + return lookup, value + end + end +end + --- spec -> spec local handle_request = function (specification) - local request = lpegmatch(font_request, - specification.specification) + local request = lpegmatch(font_request, + specification.specification) + local lookup, name = select_lookup(request) request.features = set_default_features(request.features) - local name, lookup = handle_name(specification.name, request) + --- FIXME what to do about tfm/ofm?? + --local name, lookup = handle_tfmofm(specification.name, request) + if name then specification.name = name specification.lookup = lookup or specification.lookup diff --git a/luaotfload.dtx b/luaotfload.dtx index 8b3616a..ead0773 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1371,8 +1371,10 @@ loadmodule"colors.lua" --- “font-clr” -- specification.name = fonts.names.resolve('', '', specification) --end -fonts.definers.resolvers.file = function (specification) - --inspect(specification) +local resolvers = fonts.definers.resolvers +local formats = fonts.formats + +resolvers.file = function (specification) if specification.lookup == "file" then local found = fonts.names.crude_file_lookup(specification.name) --local found = fonts.names.crude_file_lookup_verbose(specification.name) @@ -1380,6 +1382,30 @@ fonts.definers.resolvers.file = function (specification) end end +--- TODO rewrite this according to the syntax spec +resolvers.anon = function (specification) + local resolved, subfontno = fonts.names.resolve(nil, nil, specification) + if resolved then --- we follow fonts-def to some extent + specification.resolved = resolved + specification.sub = subfontno + local suffix = file.suffix(resolved) + if formats[suffix] then + specification.forced = suffix + specification.name = file.removesuffix(resolved) + else + specification.name = resolved + end + else + resolvers.file(specification) + end +end + +--- TODO rewrite this according to the syntax spec +resolvers.path = function (specification) + local found = fonts.names.crude_file_lookup(specification.name) + specification.name = found[1] +end + % \end{macrocode} % We create a callback for patching fonts on the fly, to be used by other % packages. -- cgit v1.2.3 From 2a4159410151fa9c99adaf56071a370bcb261ac1 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 16:03:16 +0200 Subject: add test for ttc subfont loading --- tests/pln-subfont-1.tex | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 tests/pln-subfont-1.tex diff --git a/tests/pln-subfont-1.tex b/tests/pln-subfont-1.tex new file mode 100644 index 0000000..4877682 --- /dev/null +++ b/tests/pln-subfont-1.tex @@ -0,0 +1,12 @@ +\ifdefined\directlua\input luaotfload.sty\fi + +\directlua{ + inspect(fontloader.info"cambria.ttc") +} + +\font\subfontone="file:cambria.ttc(0)" at 42pt +\font\subfonttwo="file:cambria.ttc(1)" at 42pt + +\subfontone foo bar baz \endgraf +\subfonttwo foo bar baz \endgraf +\bye -- cgit v1.2.3 From 98147cdc664312aa287a46a6d64c0e8fa86ebdbc Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 16:04:05 +0200 Subject: add the subfont selector patter into new syntax (hidden goodie?) --- luaotfload-features.lua | 29 ++++++++++++++++++++++++----- 1 file changed, 24 insertions(+), 5 deletions(-) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index c939a3f..08414f6 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -384,10 +384,28 @@ local feature_list = Cf(Ct"" , rawset) * featuresep^-1 +--- other ------------------------------------------------------------- +--- This rule is present in the original parser. It sets the “sub” +--- field of the specification which allows addressing a specific +--- font inside a TTC container. Neither in Luatex-Fonts nor in +--- Luaotfload is this documented, so we might as well silently drop +--- it. However, as backward compatibility is one of our prime goals we +--- just insert it here and leave it undocumented until someone cares +--- to ask. (Note: afair subfonts are numbered, but this rule matches a +--- string; I won’t mess with it though until someone reports a +--- problem.) +--- local subvalue = P("(") * (C(P(1-S("()"))^1)/issub) * P(")") -- for Kim +--- Who’s Kim? +--- Note to self: subfonts apparently start at index 0. Tested with +--- Cambria.ttc that includes “Cambria Math” at 0 and “Cambria” at 1. +--- Other values cause luatex to segfault. +local subfont = P"(" * Cg((1 - S"()")^1, "sub") * P")" --- top-level rules --------------------------------------------------- --- \font\foo=: local features = Cg(feature_list, "features") -local specification = (prefixed + unprefixed) * modifier_list^-1 +local specification = (prefixed + unprefixed) + * subfont^-1 + * modifier_list^-1 local font_request = Ct(path_lookup * (colon^-1 * features)^-1 + specification * (colon * features)^-1) @@ -449,6 +467,7 @@ local handle_request = function (specification) local feat = import_values[n] local newvalue = request.features[feat] if newvalue then + print(feat, newvalue) specification[feat] = request.features[feat] request.features[feat] = nil end @@ -467,11 +486,11 @@ local compare_requests = function (spec) return new end -fonts.definers.registersplit(":", compare_requests, "cryptic") -fonts.definers.registersplit("", compare_requests, "more cryptic") -- catches \font\text=[names] +--fonts.definers.registersplit(":", compare_requests, "cryptic") +--fonts.definers.registersplit("", compare_requests, "more cryptic") -- catches \font\text=[names] ---fonts.definers.registersplit(":", handle_request, "cryptic") ---fonts.definers.registersplit("", handle_request, "more cryptic") -- catches \font\text=[names] +fonts.definers.registersplit(":", handle_request, "cryptic") +fonts.definers.registersplit("", handle_request, "more cryptic") -- catches \font\text=[names] --fonts.definers.registersplit(":",old_behavior,"cryptic") --fonts.definers.registersplit("", old_behavior,"more cryptic") -- catches \font\text=[names] -- cgit v1.2.3 From 74ebd14b94432c9de82614627454dfa3bfcb9de0 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 16:39:26 +0200 Subject: add lookups ``file:``, ``path:``, ``name:``, and ``anon:`` --- fontdbutil.lua | 2 +- luaotfload-database.lua | 4 +-- luaotfload.dtx | 86 ++++++++++++++++++++++++++++++++----------------- 3 files changed, 60 insertions(+), 32 deletions(-) diff --git a/fontdbutil.lua b/fontdbutil.lua index 1aa99d0..af9e23c 100755 --- a/fontdbutil.lua +++ b/fontdbutil.lua @@ -28,7 +28,7 @@ string.quoted = string.quoted or function (str) return string.format("%q",str) end -dofile(loader_path) +require(loader_path) --[[doc-- Depending on how the script is called we change its behavior. diff --git a/luaotfload-database.lua b/luaotfload-database.lua index b678f51..eb8271d 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -295,7 +295,7 @@ end --- string -> (string * bool | int) crude_file_lookup_verbose = function (filename) - if not names.data then names.data = names_reload() end + if not names.data then names.data = load_names() end local data = names.data local mappings = data.mappings local found @@ -344,7 +344,7 @@ end --- string -> (string * bool | int) crude_file_lookup = function (filename) - if not names.data then names.data = names_reload() end + if not names.data then names.data = load_names() end local data = names.data local mappings = data.mappings local found = data.barenames[filename] diff --git a/luaotfload.dtx b/luaotfload.dtx index ead0773..0584f07 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1014,11 +1014,12 @@ local luatexbase = luatexbase local type, next = type, next local setmetatable = setmetatable +local find_file = kpse.find_file +local lfsisfile = lfs.isfile local stringfind = string.find -local stringsub = string.sub -local stringmatch = string.match local stringformat = string.format -local find_file = kpse.find_file +local stringmatch = string.match +local stringsub = string.sub local add_to_callback, create_callback = luatexbase.add_to_callback, luatexbase.create_callback @@ -1363,47 +1364,74 @@ loadmodule"colors.lua" --- “font-clr” % is understood. % Until then it is considered a kludge, like the hack below. % +% Relying on the \verb|name:| resolver for everything has been the source +% of permanent trouble with the database. +% With the introduction of the new syntax parser we now have enough +% granularity to distinguish between the \XETEX emulation layer and the +% genuine \verb|name:| and \verb|file:| lookups of \LUATEX-Fonts. +% Another benefit is that we can now easily plug in or replace new lookup +% behaviors if necessary. +% +% The name resolver remains untouched, but it calls +% \luafunction{fonts.names.resolve()} internally anyways (see +% \fileent{luaotfload-database.lua}). +% % \begin{macrocode} ---- below lines already (2013-04-25) lead to warnings by ---- the font loader ---fonts.definers.resolvers.file = function (specification) --- specification.name = fonts.names.resolve('', '', specification) ---end - local resolvers = fonts.definers.resolvers local formats = fonts.formats +% \end{macrocode} +% \identifier{luaotfload} promises easy access to system fonts. +% Without additional precautions, this cannot be achieved by +% \identifier{kpathsea} alone, because it searches only the +% \fileent{texmf} directories by default. +% Although it is possible for \identifier{kpathsea} to include extra +% paths by adding them to the \verb|OSFONTDIR| environment variable, +% this is still short of the goal »\emphasis{it just works!}«. +% When building the font database \identifier{luaotfload} scans +% system font directories anyways, so we already have all the +% information for looking sytem fonts. +% With the release version 2.2 the file names are indexed in the database +% as well and we are ready to resolve \verb|file:| lookups this way. +% Thus we no longer need to call the \identifier{kpathsea} library in +% most cases when looking up font files, only when generating the database. +% +% \begin{macrocode} resolvers.file = function (specification) + --- how would we go about allowing subfonts (ttc)? if specification.lookup == "file" then local found = fonts.names.crude_file_lookup(specification.name) - --local found = fonts.names.crude_file_lookup_verbose(specification.name) specification.name = found[1] end end --- TODO rewrite this according to the syntax spec -resolvers.anon = function (specification) - local resolved, subfontno = fonts.names.resolve(nil, nil, specification) - if resolved then --- we follow fonts-def to some extent - specification.resolved = resolved - specification.sub = subfontno - local suffix = file.suffix(resolved) - if formats[suffix] then - specification.forced = suffix - specification.name = file.removesuffix(resolved) - else - specification.name = resolved - end - else - resolvers.file(specification) - end -end +% \end{macrocode} +% We classify as \verb|anon:| those requests that have neither a +% prefix nor brackets. According to Khaled\footnote{% +% \url{https://github.com/phi-gamma/luaotfload/issues/4#issuecomment-17090553}. +% } +% they are the \XETEX equivalent of a \verb|name:| request, so we will be +% treating them as such. +% +% \begin{macrocode} ---- TODO rewrite this according to the syntax spec +resolvers.anon = resolvers.name + +% \end{macrocode} +% Prior to version 2.2, \identifier{luaotfload} did not distinguish +% \verb|file:| and \verb|path:| lookups, causing complications with the +% resolver. +% Now we test if the requested name is an absolute path in the file +% system, otherwise we fall back to the \verb|file:| lookup. +% +% \begin{macrocode} resolvers.path = function (specification) - local found = fonts.names.crude_file_lookup(specification.name) - specification.name = found[1] + local exists, _ = lfsisfile(specification.name) + if not exists then -- resort to file: lookup + resolvers.file(specification) + end end % \end{macrocode} -- cgit v1.2.3 From 189085f9a7212320183d5fed0c4aa31df1602d5f Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 19:08:11 +0200 Subject: catch tfm/ofm before db update; remove ``kpse.lookup()`` as criterion for resolved font --- fontdbutil.lua | 12 +++++-- luaotfload-database.lua | 84 ++++++++++++++++++++++--------------------------- luaotfload-features.lua | 37 ---------------------- luaotfload.dtx | 51 +++++++++++++++++++++++------- 4 files changed, 86 insertions(+), 98 deletions(-) diff --git a/fontdbutil.lua b/fontdbutil.lua index af9e23c..470d282 100755 --- a/fontdbutil.lua +++ b/fontdbutil.lua @@ -276,14 +276,20 @@ actions.query = function (job) optsize = 0, } - local foundname, _whatever, success = + local foundname, subfont, success = fonts.names.resolve(nil, nil, tmpspec) if success then logs.names_report(false, 1, "resolve", "Font “%s” found!", query) - logs.names_report(false, 1, - "resolve", "Resolved file name “%s”", foundname) + if subfont then + logs.names_report(false, 1, "resolve", + "Resolved file name “%s”, subfont nr. “%s”", + foundname, subfont) + else + logs.names_report(false, 1, + "resolve", "Resolved file name “%s”", foundname) + end if job.show_info then show_font_info(foundname) end diff --git a/luaotfload-database.lua b/luaotfload-database.lua index eb8271d..e5065bd 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -291,7 +291,7 @@ do end end ---- chain: barenames -> [fullnames ->] basenames -> findfile +local type1_formats = { "tfm", "ofm", } --- string -> (string * bool | int) crude_file_lookup_verbose = function (filename) @@ -320,26 +320,19 @@ crude_file_lookup_verbose = function (filename) if found and mappings[found] then found = mappings[found].filename report("info", 0, "db", - "crude file lookup: req=%s; hit=bare; ret=%s", + "crude file lookup: req=%s; hit=base; ret=%s", filename, found[1]) return found end - --- now look for tfm et al.; will be superseded by proper - --- format lookup - found = resolvers.findfile(filename, "tfm") - if found then - report("info", 0, "db", - "crude file lookup: req=tfm; hit=bare; ret=%s", found) - return { found, false } - end - found = resolvers.findfile(filename, "ofm") - if found then - report("info", 0, "db", - "crude file lookup: req=ofm; hit=bare; ret=%s", found) - return { found, false } + --- ofm and tfm + for i=1, #type1_formats do + local format = type1_formats[i] + if resolvers.findfile(filename, format) then + return { file.addsuffix(filename, format), false }, format + end end - return false + return { filename, false }, nil end --- string -> (string * bool | int) @@ -354,11 +347,13 @@ crude_file_lookup = function (filename) found = data.mappings[found] if found then return found.filename end end - found = resolvers.findfile(filename, "tfm") - if found then return { found, false } end - found = resolvers.findfile(filename, "ofm") - if found then return { found, false } end - return false + for i=1, #type1_formats do + local format = type1_formats[i] + if resolvers.findfile(filename, format) then + return { file.addsuffix(filename, format), false }, format + end + end + return { filename, false }, nil end --[[doc-- @@ -644,13 +639,14 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con end if #found == 1 then - if kpselookup(found[1].filename[1]) then - report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", - name, style, found[1].filename[1] - ) - return found[1].filename[1], found[1].filename[2], true - end + --- Since we do the file resolving ourselves, we don’t need the + --- kpathsea lookup here any longer. + --- “found” is really synonymous with “registered in the db”. + report("log", 0, "resolve", + "font family='%s', subfamily='%s' found: %s", + name, style, found[1].filename[1] + ) + return found[1].filename[1], found[1].filename[2], true elseif #found > 1 then -- we found matching font(s) but not in the requested optical -- sizes, so we loop through the matches to find the one with @@ -665,13 +661,11 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con least = difference end end - if kpselookup(closest.filename[1]) then - report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", - name, style, closest.filename[1] - ) - return closest.filename[1], closest.filename[2], true - end + report("log", 0, "resolve", + "font family='%s', subfamily='%s' found: %s", + name, style, closest.filename[1] + ) + return closest.filename[1], closest.filename[2], true elseif found.fallback then return found.fallback.filename[1], found.fallback.filename[2], true end @@ -680,7 +674,7 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con if not fonts_reloaded then --- last straw: try reloading the database return reload_db( - "unresoled font name: “" .. name .. "”", + "unresolved font name: “" .. name .. "”", resolve, nil, nil, specification ) end @@ -737,9 +731,7 @@ find_closest = function (name, limit) local name = sanitize_string(name) limit = limit or fuzzy_limit - if not fonts_loaded then - names.data = load_names() - end + if not fonts_loaded then names.data = load_names() end local data = names.data @@ -866,10 +858,10 @@ font_fullinfo = function (filename, subfont, texmf) tfmdata.fontname = metadata.fontname tfmdata.fullname = metadata.fullname tfmdata.familyname = metadata.familyname - tfmdata.filename = { - texmf and filebasename(filename) or filename, - subfont - } + if texmf then + filename = filebasename(filename) + end + tfmdata.filename = { filename, subfont } tfmdata.weight = metadata.pfminfo.weight tfmdata.width = metadata.pfminfo.width tfmdata.slant = metadata.italicangle @@ -1328,9 +1320,9 @@ update_names = function (fontnames, force) read_blacklist() local scanned, new - scanned, new = scan_texmf_fonts(fontnames, newfontnames) - n_scanned = n_scanned + scanned - n_new = n_new + new +-- scanned, new = scan_texmf_fonts(fontnames, newfontnames) +-- n_scanned = n_scanned + scanned +-- n_new = n_new + new scanned, new = scan_os_fonts(fontnames, newfontnames) n_scanned = n_scanned + scanned diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 08414f6..de7ff3f 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -419,23 +419,6 @@ local import_values = { "style", "optsize", "lookup", "sub" --[[‽]], "mode", } -local handle_tfmofm = function (specname, raw) - --- FIXME only file: and name: atm - local name = raw.file or raw.name or specname - local lookup - --- why is this here? - --- TODO should we keep this, check if it applies only to tfm and - --- ofm, and test formats by a defined list! - if resolvers.findfile(name, "tfm") then - lookup = "file" - name = file.addsuffix(name, "tfm") - elseif resolvers.findfile(name, "ofm") then - lookup = "file" - name = file.addsuffix(name, "ofm") - end - return name, lookup -end - local lookup_types = { "anon", "file", "name", "path" } local select_lookup = function (request) @@ -455,9 +438,6 @@ local handle_request = function (specification) local lookup, name = select_lookup(request) request.features = set_default_features(request.features) - --- FIXME what to do about tfm/ofm?? - --local name, lookup = handle_tfmofm(specification.name, request) - if name then specification.name = name specification.lookup = lookup or specification.lookup @@ -467,7 +447,6 @@ local handle_request = function (specification) local feat = import_values[n] local newvalue = request.features[feat] if newvalue then - print(feat, newvalue) specification[feat] = request.features[feat] request.features[feat] = nil end @@ -495,22 +474,6 @@ fonts.definers.registersplit("", handle_request, "more cryptic") -- catches \fo --fonts.definers.registersplit(":",old_behavior,"cryptic") --fonts.definers.registersplit("", old_behavior,"more cryptic") -- catches \font\text=[names] ---- TODO below section is literally the same in luatex-fonts-def ---- why is it here? ---function fonts.definers.applypostprocessors(tfmdata) --- local postprocessors = tfmdata.postprocessors --- if postprocessors then --- for i=1,#postprocessors do --- local extrahash = postprocessors[i](tfmdata) -- after scaling etc --- if type(extrahash) == "string" and extrahash ~= "" then --- -- e.g. a reencoding needs this --- extrahash = string.gsub(lower(extrahash),"[^a-z]","-") --- tfmdata.properties.fullname = format("%s-%s",tfmdata.properties.fullname,extrahash) --- end --- end --- end --- return tfmdata ---end ---[[ end included font-ltx.lua ]] --[[doc-- diff --git a/luaotfload.dtx b/luaotfload.dtx index 0584f07..722a8d2 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1378,8 +1378,9 @@ loadmodule"colors.lua" --- “font-clr” % % \begin{macrocode} -local resolvers = fonts.definers.resolvers -local formats = fonts.formats +local request_resolvers = fonts.definers.resolvers +local formats = fonts.formats +formats.ofm = "type1" % \end{macrocode} % \identifier{luaotfload} promises easy access to system fonts. @@ -1398,15 +1399,13 @@ local formats = fonts.formats % most cases when looking up font files, only when generating the database. % % \begin{macrocode} -resolvers.file = function (specification) - --- how would we go about allowing subfonts (ttc)? - if specification.lookup == "file" then - local found = fonts.names.crude_file_lookup(specification.name) - specification.name = found[1] - end +request_resolvers.file = function (specification) + --local found = fonts.names.crude_file_lookup(specification.name) + local found = fonts.names.crude_file_lookup_verbose(specification.name) + specification.name = found[1] + --if format then specification.forced = format end end ---- TODO rewrite this according to the syntax spec % \end{macrocode} % We classify as \verb|anon:| those requests that have neither a % prefix nor brackets. According to Khaled\footnote{% @@ -1417,7 +1416,35 @@ end % % \begin{macrocode} -resolvers.anon = resolvers.name +--request_resolvers.anon = request_resolvers.name + +% \end{macrocode} +% There is one drawback, though. +% This syntax is also used for requesting fonts in \identifier{Type1} +% (\abbrev{tfm}, \abbrev{ofm}) format. +% These are essentially \verb|file:| lookups and must be caught before +% the \verb|name:| resolver kicks in, lest they cause the database to +% update. +% Even if we were to require the \verb|file:| prefix for all +% \identifier{Type1} requests, tests have shown that certain fonts still +% include further fonts (e.~g. \fileent{omlgcb.ofm} will ask for +% \fileent{omsecob.tfm}) \emphasis{using the old syntax}. +% For this reason, we introduce an extra check with an early return. +% +% \begin{macrocode} +local type1_formats = { "tfm", "ofm", } + +request_resolvers.anon = function (specification) + local name = specification.name + for i=1, #type1_formats do + local format = type1_formats[i] + if resolvers.findfile(name, format) then + specification.name = file.addsuffix(name, format) + return + end + end + request_resolvers.name(specification) +end % \end{macrocode} % Prior to version 2.2, \identifier{luaotfload} did not distinguish @@ -1427,10 +1454,10 @@ resolvers.anon = resolvers.name % system, otherwise we fall back to the \verb|file:| lookup. % % \begin{macrocode} -resolvers.path = function (specification) +request_resolvers.path = function (specification) local exists, _ = lfsisfile(specification.name) if not exists then -- resort to file: lookup - resolvers.file(specification) + request_resolvers.file(specification) end end -- cgit v1.2.3 From 1c8a1d0a59de24f0d1f456c4fad29024e00ef23b Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 28 Apr 2013 19:13:56 +0200 Subject: test for file existence again, but try with ``lfs.isfile()`` first --- luaotfload-database.lua | 33 ++++++++++++++++++++------------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index e5065bd..8caa35b 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -25,6 +25,7 @@ local kpseexpand_path = kpse.expand_path local kpseexpand_var = kpse.expand_var local kpselookup = kpse.lookup local kpsereadable_file = kpse.readable_file +local lfsisfile = lfs.isfile local mathabs = math.abs local mathmin = math.min local stringfind = string.find @@ -639,14 +640,15 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con end if #found == 1 then - --- Since we do the file resolving ourselves, we don’t need the - --- kpathsea lookup here any longer. --- “found” is really synonymous with “registered in the db”. - report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", - name, style, found[1].filename[1] - ) - return found[1].filename[1], found[1].filename[2], true + local filename = found[1].filename[1] + if lfsisfile(filename) or kpselookup(filename) then + report("log", 0, "resolve", + "font family='%s', subfamily='%s' found: %s", + name, style, filename + ) + return filename, found[1].filename[2], true + end elseif #found > 1 then -- we found matching font(s) but not in the requested optical -- sizes, so we loop through the matches to find the one with @@ -661,13 +663,18 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con least = difference end end - report("log", 0, "resolve", - "font family='%s', subfamily='%s' found: %s", - name, style, closest.filename[1] - ) - return closest.filename[1], closest.filename[2], true + local filename = closest.filename[1] + if lfsisfile(filename) or kpselookup(filename) then + report("log", 0, "resolve", + "font family='%s', subfamily='%s' found: %s", + name, style, filename + ) + return filename, closest.filename[2], true + end elseif found.fallback then - return found.fallback.filename[1], found.fallback.filename[2], true + return found.fallback.filename[1], + found.fallback.filename[2], + true end --- no font found so far -- cgit v1.2.3 From 09765c22460ee4aa3e2fbe5cf1af54aa3106e6a5 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 10:55:49 +0200 Subject: [doc] add font request syntax description MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit For convenience it’s a notational bastard of BNF and ISO EBNF. I couldn’t find a package for typesetting the latter, and with my limited understanding of LaTeX I couldn’t have written one within an acceptable time. Anyways, I don’t think anybody will be confused by this. --- luaotfload.dtx | 79 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 77 insertions(+), 2 deletions(-) diff --git a/luaotfload.dtx b/luaotfload.dtx index 722a8d2..957dea1 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -160,6 +160,8 @@ and the derived files \renewcommand\partname{Part}%% gets rid of the stupid “file” heading +\usepackage{syntax}%% bnf for font request syntax + \VerbatimFootnotes \begin{document} \DocInput{luaotfload.dtx}% @@ -256,8 +258,81 @@ and the derived files % % \noindent % The curly brackets are optional and escape the spaces in the enclosed -% font name (alternatively, double quotes serve the same purpose). -% The individual parts of the syntax are: +% font name. +% Alternatively, double quotes serve the same purpose. +% A selection of individual parts of the syntax are discussed below; +% for a more formal description see figure \ref{font-syntax}. +% +% \begin{figure}[b] +% \setlength\grammarparsep{12pt plus 2pt minus 2pt} +% \setlength\grammarindent{5cm} +% \begingroup +% \small +% \begin{grammar} +% ::= `\\font', {\sc csname}, `=', , [ ] ; +% +% ::= `at', {\sc dimension} ; +% +% ::= `"', `"' +% \alt `{', `}' +% \alt ; +% +% ::= , [`:', ] +% \alt `[', `]', [ [`:'], ] ; +% +% ::= , [ ], \{ \} +% \alt , \{ \} ; +% +% ::= `file:', +% \alt `name:', ; +% +% ::= \{ \} ; +% +% ::= \{ \} ; +% +% ::= {\sc tfmname} | ; +% +% ::= \{ {\sc all_characters} - `]' \} ; +% +% ::= `/', (`i' | `b' | `bi' | `ib') ; +% +% ::= `(', \{ {\sc digit} \}, `)' ; +% +% ::= , \{ `;', \} ; +% +% ::= {\sc feature_id}, `=', {\sc feature_value} +% \alt , {\sc feature_id} ; +% +% ::= `+' | `-' ; +% +% ::= {\sc all_characters} - ( `(' | `/' | `:' ) ; +% \end{grammar} +% \endgroup +% \caption{Font request syntax. +% Braces or double quotes around the +% \emphasis{specification} rule will +% preserve whitespace in file names. +% In addition to the font style modifiers +% (\emphasis{slash-notation}) given above, there +% are others that are recognized but will be silently +% ignored: {\ttfamily aat}, +% {\ttfamily icu}, and +% {\ttfamily gr}. +% The special terminals are: +% {\sc feature\textunderscore id} for a valid font +% feature name and +% {\sc feature\textunderscore value} for the corresponding +% value. +% {\sc tfmname} is the name of a \abbrev{tfm} file. +% {\sc digit} again refers to bytes 48--57, and +% {\sc all\textunderscore characters} to all byte values. +% {\sc csname} and {\sc dimension} are the \TEX concepts.} +% \label{font-syntax} +% \end{figure} +% +% %(* braces around the specification will preserve whitespace *) +% %(* file lookups do not allow paths *) +% %(* others like `aat', `icu', and `gr' are silently ignored *) % % \paragraph{Prefix} % -- cgit v1.2.3 From 2adc02056a47717a8f9fee7a48e62ab5cf50c9c8 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 12:07:37 +0200 Subject: add test file for tfm --- tests/pln-tfm.tex | 8 ++++++++ 1 file changed, 8 insertions(+) create mode 100644 tests/pln-tfm.tex diff --git a/tests/pln-tfm.tex b/tests/pln-tfm.tex new file mode 100644 index 0000000..26fa738 --- /dev/null +++ b/tests/pln-tfm.tex @@ -0,0 +1,8 @@ +\ifdefined\directlua\input luaotfload.sty \fi +%% TFM’s can be loaded with a file: request ... +\font\antykwatorunska="file:rm-anttr" +%% or with an anonymous request, like in þe olde TeX: +\font\antykwatorunskabcap=ec-anttbcap +\antykwatorunska foo bar +\antykwatorunskabcap baz xyzzy +\bye -- cgit v1.2.3 From be7d5713a125033d686d97a38910cb5af62f9093 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 12:51:52 +0200 Subject: [doc] describe the various font requests --- luaotfload.dtx | 184 +++++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 145 insertions(+), 39 deletions(-) diff --git a/luaotfload.dtx b/luaotfload.dtx index 957dea1..abc737c 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -130,6 +130,8 @@ and the derived files \setsansfont[Ligatures=TeX,Scale=MatchLowercase]{Iwona Medium} %setmathfont{XITS Math} +\usepackage{hologo} + \newcommand\TEX {\TeX\xspace} \newcommand\LUA {Lua\xspace} \newcommand\PDFTEX {pdf\TeX\xspace} @@ -246,15 +248,15 @@ and the derived files % % \section{Loading Fonts} % -% \identifier{luaotfload} supports an extended font loading syntax: +% \identifier{luaotfload} supports an extended font request syntax: % -% \begin{center} +% \begin{quote} % |\font\foo={|% % \meta{prefix}|:|% % \meta{font name}|:|% % \meta{font features}|}|% % \meta{\TEX font features} -% \end{center} +% \end{quote} % % \noindent % The curly brackets are optional and escape the spaces in the enclosed @@ -330,45 +332,93 @@ and the derived files % \label{font-syntax} % \end{figure} % -% %(* braces around the specification will preserve whitespace *) -% %(* file lookups do not allow paths *) -% %(* others like `aat', `icu', and `gr' are silently ignored *) -% -% \paragraph{Prefix} -% -% The \meta{prefix} is either |file:| or |name:|. -% It determines whether the font loader should interpret the request as a -% file name or font name, respectively, which again influences how it -% will attempt to locate the font. -% The prefix can be omitted, in which case |name:| is assumed. -% -%% \iffalse%% how am i supposed to friggin comment stuff in a dtx??? -%% TODO -%% it would appear that the next paragraph is incorrect; I get -%% name: lookups regardless unless the font file is actually -%% in CWD -%% \fi -%% For compatibility with \XETEX, surrounding the \meta{font name} with -%% square brackets is synonymous to using the |file:| prefix. +% \subsection{Prefix -- the \identifier{luaotfload}\space Way} % +% In \identifier{luaotfload}, the canonical syntax for font requests +% requires a \emphasis{prefix}: +% \begin{quote} +% |\font\fontname=|\meta{prefix}|:|\meta{fontname}\dots +% \end{quote} +% where \meta{prefix} is either \verb|file:| or \verb|name:|. +% It determines whether the font loader should interpret the request as +% a \emphasis{file name} or +% \emphasis{font name}, respectively, +% which again influences how it will attempt to locate the font. +% Examples for font names are +% “Latin Modern Italic”, +% “GFS Bodoni Rg”, and +% “PT Serif Caption” +% -- they are the human readable identifiers +% usually listed in drop-down menus and the like. % In order for fonts installed both in system locations and in your % \fileent{texmf} to be accessible by font name, \identifier{luaotfload} must % first collect the metadata included in the files. -% Please refer to section ~\ref{sec:fontdb} below for instructions on how to +% Please refer to section~\ref{sec:fontdb} below for instructions on how to % create the database. % -% \paragraph{Font name} +% File names are whatever your file system allows them to be, except +% that that they may not contain the characters +% \verb|(|, +% \verb|:|, and +% \verb|/|. +% As obvious from the last exception, the \verb|file:| lookup will +% not process paths to the font location -- only those +% files found when generating the database are addressable this way. +% Continue below in the \XETEX section if you need to load your fonts +% by path. +% The file names corresponding to the example font names above are +% \fileent{lmroman12-italic.otf}, +% \fileent{GFSBodoni.otf}, and +% \fileent{PTZ56F.ttf}. +% +% \subsection{\hologo{XeTeX} Compatibility Layer} +% +% In addition to the regular prefixed requests, \identifier{luaotfload} +% accepts loading fonts the \XETEX way. +% There are again two modes: bracketed and unbracketed. +% A bracketed request looks as follows. % -% The \meta{font name} can be either a font filename or actual font -% name based on the \meta{prefix} as mentioned above. +% \begin{quote} +% |\font\fontname=[|\meta{path to file}|]| +% \end{quote} % -% A filename request may optionally include the absolute path to the font file, -% allowing for fonts outside the standard locations to be loaded as well. -% If no path is specified, then \identifier{kpathsea} is used to locate the -% font (which will typically be in the \fileent{texmf} tree or the -% current directory). +% \noindent +% Inside the square brackets, every character except for a closing +% bracket is permitted, allowing for specifying paths to a font file. +% Naturally, path-less file names are equally valid and processed the +% same way as an ordinary \verb|file:| lookup. % -% \subparagraph{Examples for loading by file name} +% \begin{quote} +% |\font\fontname=|\meta{font name} \dots +% \end{quote} +% +% Unbracketed (or, for lack of a better word: \emphasis{anonymous}) +% font requests resemble the conventional \TEX syntax. +% However, they have a broader spectrum of possible interpretations: +% before anything else, \identifier{luaotfload} attempts to load a +% traditional \TEX Font Metric (\abbrev{tfm} or \abbrev{ofm}). +% If this fails, it performs a \verb|name:| lookup, which itself will +% fall back to a \verb|file:| lookup if no database entry matches +% \meta{font name}. +% +% Furthermore, \identifier{luaotfload} supports the slashed (shorthand) +% font style notation from \XETEX. +% +% \begin{quote} +% |\font\fontname=|\meta{font name}|/|\meta{modifier}\dots +% \end{quote} +% +% \noindent +% Currently, four style modifiers are supported: +% \verb|i| for italic shape, +% \verb|b| for bold weight, +% \verb|bi| or \verb|ib| for the combination of both. +% Other “slashed” modifiers are too specific to the \XETEX engine and +% have no meaning in \LUATEX. +% +% \subsection{Examples} +% +% \subsubsection{Loading by File Name} % % For example, conventional \abbrev{type1} font can be loaded with a \verb|file:| % request like so: @@ -380,8 +430,11 @@ and the derived files % \end{quote} % % The \OpenType version of Janusz Nowacki’s font \emphasis{Antykwa -% Półtawskiego} (in \TEX Live) in its condensed variant can be loaded as -% follows: +% Półtawskiego}\footnote{% +% \url{http://jmn.pl/antykwa-poltawskiego/}, also available in +% in \TEX Live. +% } +% in its condensed variant can be loaded as follows: % % \begin{quote} % \begin{verbatim} @@ -399,7 +452,7 @@ and the derived files % \end{verbatim} % \end{quote} % -% \subparagraph{Examples for loading by font name} +% \subsubsection{Loading by Font Name} % % The \verb|name:| lookup does not depend on cryptic filenames: % @@ -435,9 +488,62 @@ and the derived files % \end{verbatim} % \end{quote} % -% \paragraph{Font features} +% \subsubsection{Modifiers} +% +% If the entire \emphasis{Iwona} family\footnote{% +% \url{http://jmn.pl/kurier-i-iwona/}, +% also in \TEX Live. +% } +% is installed in some location accessible by \identifier{luaotfload}, +% the regular shape can be loaded as follows: +% +% \begin{quote} +% \begin{verbatim} +% \font\iwona=Iwona at 20pt +% \end{verbatim} +% \end{quote} +% +% \noindent +% To load the most common of the other styles, the slash notation can +% be employed as shorthand: +% +% \begin{quote} +% \begin{verbatim} +% \font\iwonaitalic =Iwona/i at 20pt +% \font\iwonabold =Iwona/b at 20pt +% \font\iwonabolditalic=Iwona/bi at 20pt +% \end{verbatim} +% \end{quote} +% +% \noindent +% which is equivalent to these full names: +% +% \begin{quote} +% \begin{verbatim} +% \font\iwonaitalic ="Iwona Italic" at 20pt +% \font\iwonabold ="Iwona Bold" at 20pt +% \font\iwonabolditalic="Iwona BoldItalic" at 20pt +% \end{verbatim} +% \end{quote} +% +% \section{Font features} +% +% \emphasis{Font features} are the second to last component in the +% general scheme for font requests: +% +% \begin{quote} +% |\font\foo={|% +% \meta{prefix}|:|% +% \meta{font name}|:|% +% \meta{font features}|}|% +% \meta{\TEX font features} +% \end{quote} +% +% \noindent +% If style modifiers are present (\XETEX style), they must precede \meta{font +% features}. % -% \meta{font features} is semicolon-separated list of feature +% The element \meta{font features} is a semicolon-separated list of feature % tags\footnote{% % Cf. \url{http://www.microsoft.com/typography/otspec/featurelist.htm}. % } @@ -1078,7 +1184,7 @@ luaotfload.prefer_merge = config.luaotfload.prefer_merge or true luaotfload.module = { name = "luaotfload", version = 2.2, - date = "2013/04/15", + date = "2013/04/29", description = "OpenType layout system.", author = "Elie Roux & Hans Hagen", copyright = "Elie Roux", -- cgit v1.2.3 From 1a76cea6357f50d7dae752765173af335ba95beb Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 13:57:35 +0200 Subject: add handler for XeTeX slashed notation --- luaotfload-database.lua | 2 -- luaotfload-features.lua | 35 +++++++++++++++++++++++++++++++++++ tests/pln-subfont-1.tex | 6 +++--- 3 files changed, 38 insertions(+), 5 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 8caa35b..4aa966a 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -562,8 +562,6 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con local found = { } local synonym_set = style_synonyms.set for _,face in next, data.mappings do - --- TODO we really should store those in dedicated - --- .sanitized field local family, subfamily, fullname, psname, fontname, pfullname local facenames = face.sanitized diff --git a/luaotfload-features.lua b/luaotfload-features.lua index de7ff3f..b11bf22 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -431,6 +431,35 @@ local select_lookup = function (request) end end +local supported = { + b = "bold", + i = "italic", + bi = "bolditalic", + aat = false, + icu = false, + gr = false, +} + +local handle_slashed = function (modifiers) + local style, optsize + for i=1, #modifiers do + local mod = modifiers[i] + if supported[mod] then + style = supported[mod] + --elseif stringfind(v, "^s=") then + elseif stringsub(v, 1, 2) == "s=" then + local val = stringsub(v, 3) + optsize = val + elseif stylename == false then + report("log", 0, + "load", "unsupported font option: %s", v) + elseif not stringis_empty(v) then + style = stringgsub(v, "[^%a%d]", "") + end + end + return style, optsize +end + --- spec -> spec local handle_request = function (specification) local request = lpegmatch(font_request, @@ -443,6 +472,11 @@ local handle_request = function (specification) specification.lookup = lookup or specification.lookup end + if request.modifiers then + local style, optsize = handle_slashed(request.modifiers) + specification.style, specification.optsize = style, optsize + end + for n=1, #import_values do local feat = import_values[n] local newvalue = request.features[feat] @@ -451,6 +485,7 @@ local handle_request = function (specification) request.features[feat] = nil end end + --- The next line sets the “rand” feature to “random”; I haven’t --- investigated it any further (luatex-fonts-ext), so it will --- just stay here. diff --git a/tests/pln-subfont-1.tex b/tests/pln-subfont-1.tex index 4877682..fb8e1e7 100644 --- a/tests/pln-subfont-1.tex +++ b/tests/pln-subfont-1.tex @@ -1,12 +1,12 @@ \ifdefined\directlua\input luaotfload.sty\fi - +%% This requires the Cambria fonts from MS. \directlua{ inspect(fontloader.info"cambria.ttc") } - +%% Here we load both subfonts in the collection +%% with the not-quite documented subfont syntax. \font\subfontone="file:cambria.ttc(0)" at 42pt \font\subfonttwo="file:cambria.ttc(1)" at 42pt - \subfontone foo bar baz \endgraf \subfonttwo foo bar baz \endgraf \bye -- cgit v1.2.3 From 19164c39c9f98d9e51a13d5d698f575879f3dfee Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 14:48:12 +0200 Subject: add examples for XeTeX notation and lookup caching --- tests/pln-request-4-slashed.tex | 12 ++++++++++++ tests/pln-request-5-cached.tex | 17 +++++++++++++++++ 2 files changed, 29 insertions(+) create mode 100644 tests/pln-request-4-slashed.tex create mode 100644 tests/pln-request-5-cached.tex diff --git a/tests/pln-request-4-slashed.tex b/tests/pln-request-4-slashed.tex new file mode 100644 index 0000000..5e7d99e --- /dev/null +++ b/tests/pln-request-4-slashed.tex @@ -0,0 +1,12 @@ +\ifdefined\directlua\input luaotfload.sty\fi +\font\iwona =iwona at 20pt +\font\iwonabold =iwona/b at 20pt +\font\iwonaitalic =iwona/i at 20pt +\font\iwonabolditalic =iwona/bi at 20pt + +\def\test{foo bar baz \endgraf} +{\iwona \test} +{\iwonabold \test} +{\iwonaitalic \test} +{\iwonabolditalic \test} +\bye diff --git a/tests/pln-request-5-cached.tex b/tests/pln-request-5-cached.tex new file mode 100644 index 0000000..437b20d --- /dev/null +++ b/tests/pln-request-5-cached.tex @@ -0,0 +1,17 @@ +\ifdefined\directlua + \directlua{config = config or { luaotfload = { } } + config.luaotfload.resolver = "cached" } + \input luaotfload.sty +\fi + +\font\iwona =name:iwona at 20pt +\font\iwonabold =name:iwona/b at 20pt +\font\iwonaitalic =name:iwona/i at 20pt +\font\iwonabolditalic =name:iwona/bi at 20pt + +\def\test{foo bar baz \endgraf} +{\iwona \test} +{\iwonabold \test} +{\iwonaitalic \test} +{\iwonabolditalic \test} +\bye -- cgit v1.2.3 From e79f34d859d48be485589f19fc6905afa5872a53 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 14:52:53 +0200 Subject: only cache ``name:`` lookups --- luaotfload-database.lua | 72 +++++++++++++++--------------------------- luaotfload-features.lua | 3 +- luaotfload.dtx | 18 ++--------- tests/pln-request-5-cached.tex | 3 +- 4 files changed, 32 insertions(+), 64 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index 4aa966a..abf06a2 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -240,6 +240,7 @@ local load_names local read_fonts_conf local reload_db local resolve +local resolve_cached local save_names local scan_external_dir local update_names @@ -380,22 +381,6 @@ TODO: 9) ??? n) PROFIT!!! ---doc]]-- - ---- the resolver is called after the font request is parsed ---- this is where we insert the cache -local normal_resolver = fonts.definers.resolve -local dummy_resolver = function (specification) - --- this ensures that the db is always loaded - --- before a lookup occurs - if not names.data then names.data = load_names() end - --inspect(specification) - local resolved = normal_resolver(specification) - --inspect(resolved) - return resolved -end - ---[[doc-- The name lookup requires both the “name” and some other keys, so we’ll concatenate them. The spec is modified in place (ugh), so we’ll have to catalogue what @@ -428,33 +413,29 @@ We’ll just cache a deep copy of the entire spec as it leaves the resolver, lest we want to worry if we caught all the details. --doc]]-- ---- spec -> spec -local cached_resolver = function (specification) +--- 'a -> 'a -> table -> (string * int|boolean * boolean) +resolve_cached = function (_, _, specification) if not names.data then names.data = load_names() end local request_cache = names.data.request_cache local request = specification.specification - report("log", 4, "cache", - "looking for “%s” in cache ...", + report("log", 4, "cache", "looking for “%s” in cache ...", request) + local found = names.data.request_cache[request] + + --- case 1) cache positive ---------------------------------------- if found then --- replay fields from cache hit report("info", 4, "cache", "found!") - for i=1, #cache_fields do - local f = cache_fields[i] - if found[f] then specification[f] = found[f] end - end - return specification + return found[1], found[2], true end report("log", 4, "cache", "not cached; resolving") + --- case 2) cache negative ---------------------------------------- --- first we resolve normally ... - local resolved_spec = normal_resolver(specification) - --- ... then we add the fields to the cache - local entry = { } - for i=1, #cache_fields do - local f = cache_fields[i] - entry[f] = resolved_spec[f] - end + local filename, subfont, success = resolve(nil, nil, specification) + if not success then return filename, subfont, false end + --- ... then we add the fields to the cache ... ... + local entry = { filename, subfont } report("log", 4, "cache", "new entry: %s", request) names.data.request_cache[request] = entry @@ -463,21 +444,13 @@ local cached_resolver = function (specification) --- whenever the cache is updated. --- TODO this should trigger a save only once the --- document is compiled (finish_pdffile callback?) + --- TODO we should speed up writing by separating + --- the cache from the db report("log", 5, "cache", "saving updated cache") save_names() - return resolved_spec + return filename, subfont, true end -local resolvers = { - dummy = dummy_resolver, - normal = normal_resolver, - cached = cached_resolver, -} - -fonts.definers.resolve = resolvers[config.luaotfload.resolver] ---fonts.definers.resolve = resolvers.cached ---fonts.definers.resolve = resolvers.dummy - --[[doc-- Luatex-fonts, the font-loader package luaotfload imports, comes with @@ -1390,9 +1363,16 @@ names.update = update_names names.crude_file_lookup = crude_file_lookup names.crude_file_lookup_verbose = crude_file_lookup_verbose -names.resolve = resolve --- replace the resolver from luatex-fonts -names.resolvespec = resolve -names.find_closest = find_closest +--- replace the resolver from luatex-fonts +if config.luaotfload.resolver == "cached" then + report("info", 0, "cache", "caching of name: lookups active") + names.resolve = resolve_cached + names.resolvespec = resolve_cached +else + names.resolve = resolve + names.resolvespec = resolve +end +names.find_closest = find_closest --- dummy required by luatex-fonts (cf. luatex-fonts-syn.lua) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index b11bf22..6cbfdf4 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -416,7 +416,8 @@ local font_request = Ct(path_lookup * (colon^-1 * features)^-1 local import_values = { --- That’s what the 1.x parser did, not quite as graciously, --- with an array of branch expressions. - "style", "optsize", "lookup", "sub" --[[‽]], "mode", + -- "style", "optsize",--> from slashed notation; handled otherwise + "lookup", "sub" --[[‽]], "mode", } local lookup_types = { "anon", "file", "name", "path" } diff --git a/luaotfload.dtx b/luaotfload.dtx index abc737c..6392c64 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -540,8 +540,8 @@ and the derived files % \end{quote} % % \noindent -% If style modifiers are present (\XETEX style), they must precede \meta{font -% features}. +% If style modifiers are present (\XETEX style), they must precede +% \meta{font features}. % % The element \meta{font features} is a semicolon-separated list of feature % tags\footnote{% @@ -1532,19 +1532,6 @@ loadmodule"database.lua" --- “font-nms” loadmodule"colors.lua" --- “font-clr” % \end{macrocode} -% This hack makes fonts called with file method found by fonts.names.resolve -% instead of just trying to find them with \identifier{kpse}. -% It is necessary in cases when font files are not reachable by -% \identifier{kpse} but present in the database, a quite common case -% under Linux. -% -% As of 2013-04-24 we have a workaround in the resolver that handles -% \verb|file:| lookups diverted this way. -% It requires some overhead due to additional extra data saved in the -% names database, and might vanish entirely once the font request syntax -% is understood. -% Until then it is considered a kludge, like the hack below. -% % Relying on the \verb|name:| resolver for everything has been the source % of permanent trouble with the database. % With the introduction of the new syntax parser we now have enough @@ -1715,7 +1702,6 @@ local patch_defined_font = function (specification, size, id) if type(tfmdata) == "table" then call_callback("luaotfload.patch_font", tfmdata) end - -- inspect(table.keys(tfmdata)) return tfmdata end diff --git a/tests/pln-request-5-cached.tex b/tests/pln-request-5-cached.tex index 437b20d..8ba4a5e 100644 --- a/tests/pln-request-5-cached.tex +++ b/tests/pln-request-5-cached.tex @@ -1,6 +1,7 @@ \ifdefined\directlua \directlua{config = config or { luaotfload = { } } - config.luaotfload.resolver = "cached" } + config.luaotfload.resolver = "cached" + config.luaotfload.loglevel = 5 } \input luaotfload.sty \fi -- cgit v1.2.3 From a57dc29a2723f46dd9bf721469744a44284a61bb Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 15:04:25 +0200 Subject: make cache filename hotfix not break fontdbutil --- luaotfload-override.lua | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/luaotfload-override.lua b/luaotfload-override.lua index 7ee9730..2b9ef8b 100644 --- a/luaotfload-override.lua +++ b/luaotfload-override.lua @@ -81,10 +81,12 @@ logs.names_report = function (mode, lvl, ...) end end ---- This will vanish as soon as Hans fixes it in data-con ---- https://github.com/lualatex/luaotfload/issues/17 +if containers then + --- This will vanish as soon as Hans fixes it in data-con + --- https://github.com/lualatex/luaotfload/issues/17 -containers.cleanname = function (name) - return (string.gsub(string.lower(name),"[^%w%d\128\255]+","-")) + containers.cleanname = function (name) + return (string.gsub(string.lower(name),"[^%w%d\128\255]+","-")) + end end -- vim:tw=71:sw=4:ts=4:expandtab -- cgit v1.2.3 From 57fab947bfac698ff9f5aada24c0704e7068e224 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 15:38:24 +0200 Subject: remove exceptional handling of texmf fonts (``name:`` always resolves to absolute paths) --- luaotfload-database.lua | 33 +++++++++++++-------------------- 1 file changed, 13 insertions(+), 20 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index d4613ba..a750804 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -542,7 +542,7 @@ resolve = function (_,_,specification) -- the 1st two parameters are used by Con local found = { } local synonym_set = style_synonyms.set - for _,face in next, data.mappings do + for _, face in next, data.mappings do local family, subfamily, fullname, psname, fontname, pfullname local facenames = face.sanitized @@ -797,7 +797,7 @@ The data inside an Opentype font file can be quite heterogeneous. Thus in order to get the relevant information, parts of the original table as returned by the font file reader need to be relocated. --doc]]-- -font_fullinfo = function (filename, subfont, texmf) +font_fullinfo = function (filename, subfont) local tfmdata = { } local rawfont = fontloader.open(filename, subfont) if not rawfont then @@ -844,10 +844,7 @@ font_fullinfo = function (filename, subfont, texmf) tfmdata.fontname = metadata.fontname tfmdata.fullname = metadata.fullname tfmdata.familyname = metadata.familyname - if texmf then - filename = filebasename(filename) - end - tfmdata.filename = { filename, subfont } + tfmdata.filename = { filename, subfont } -- always store full path tfmdata.weight = metadata.pfminfo.weight tfmdata.width = metadata.pfminfo.width tfmdata.slant = metadata.italicangle @@ -862,7 +859,7 @@ end --- we return true if the fond is new or re-indexed --- string -> dbobj -> dbobj -> bool -> bool -local load_font = function (fullname, fontnames, newfontnames, texmf) +local load_font = function (fullname, fontnames, newfontnames) local newmappings = newfontnames.mappings local newstatus = newfontnames.status @@ -879,11 +876,7 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) local basename = filebasename(fullname) local barename = filenameonly(fullname) - --- entryname is apparently the identifier a font is - --- loaded by; it is different for files in the texmf - --- (due to kpse? idk.) - --- entryname = texmf : true -> basename | false -> fullname - local entryname = texmf and basename or fullname + local entryname = basename if not fullname then return false end @@ -899,8 +892,7 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) and status[entryname].timestamp timestamp = lfs.attributes(fullname, "modification") - local index_status = newstatus[entryname] - or (not texmf and newstatus[basename]) + local index_status = newstatus[entryname] or newstatus[basename] local teststat = newstatus[entryname] --- index_status: nil | false | table if index_status and index_status.timestamp == timestamp then @@ -932,7 +924,7 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) if info then if type(info) == "table" and #info > 1 then --- ttc for n_font = 1, #info do - local fullinfo = font_fullinfo(fullname, n_font-1, texmf) + local fullinfo = font_fullinfo(fullname, n_font-1) if not fullinfo then return false end @@ -947,7 +939,7 @@ local load_font = function (fullname, fontnames, newfontnames, texmf) newstatus[entryname].index[n_font] = index end else - local fullinfo = font_fullinfo(fullname, false, texmf) + local fullinfo = font_fullinfo(fullname, false) if not fullinfo then return false end @@ -1070,13 +1062,13 @@ for key, value in next, font_extensions do end --- string -> dbobj -> dbobj -> bool -> (int * int) -local scan_dir = function (dirname, fontnames, newfontnames, texmf) +local scan_dir = function (dirname, fontnames, newfontnames) --[[ This function scans a directory and populates the list of fonts with all the fonts it finds. - dirname is the name of the directory to scan - names is the font database to fill -> no such term!!! - - texmf is a boolean saying if we are scanning a texmf directory + - texmf used to be a boolean saying if we are scanning a texmf directory ]] local n_scanned, n_new = 0, 0 --- total of fonts collected report("log", 2, "db", "scanning", "%s", dirname) @@ -1092,7 +1084,7 @@ local scan_dir = function (dirname, fontnames, newfontnames, texmf) local fullname = found[j] fullname = path_normalize(fullname) report("log", 2, "db", "loading font “%s”", fullname) - local new = load_font(fullname, fontnames, newfontnames, texmf) + local new = load_font(fullname, fontnames, newfontnames) if new then n_new = n_new + 1 end end end @@ -1382,8 +1374,9 @@ local function scan_os_fonts(fontnames, newfontnames) ]] report("info", 2, "db", "Scanning OS fonts...") report("info", 3, "db", "Searching in static system directories...") + print"~~~~" for _,d in next, get_os_dirs() do - local found, new = scan_dir(d, fontnames, newfontnames, false) + local found, new = scan_dir(d, fontnames, newfontnames) n_scanned = n_scanned + found n_new = n_new + new end -- cgit v1.2.3 From 39bfa54bb32955f36f473abfa01dc43c73ad3efe Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 15:44:16 +0200 Subject: rename fontdbutil -> luaotfload-tool --- fontdbutil.lua | 444 ---------------------------------------------------- luaotfload-tool.lua | 444 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 444 insertions(+), 444 deletions(-) delete mode 100755 fontdbutil.lua create mode 100755 luaotfload-tool.lua diff --git a/fontdbutil.lua b/fontdbutil.lua deleted file mode 100755 index 470d282..0000000 --- a/fontdbutil.lua +++ /dev/null @@ -1,444 +0,0 @@ -#!/usr/bin/env texlua - ---[[doc-- -This file was originally written by Elie Roux and Khaled Hosny and is under CC0 -license (see http://creativecommons.org/publicdomain/zero/1.0/legalcode). - -This file is a wrapper for the luaotfload font names module -(luaotfload-database.lua). It is part of the luaotfload bundle, please -see the luaotfload documentation for more info. Report bugs to -\url{https://github.com/lualatex/luaotfload/issues}. - ---doc]]-- - -kpse.set_program_name"luatex" - -local stringformat = string.format -local texiowrite_nl = texio.write_nl -local stringfind = string.find -local stringlower = string.lower - - -local loader_file = "luatexbase.loader.lua" -local loader_path = assert(kpse.find_file(loader_file, "lua"), - "File '"..loader_file.."' not found") - - -string.quoted = string.quoted or function (str) - return string.format("%q",str) -end - -require(loader_path) - ---[[doc-- -Depending on how the script is called we change its behavior. -For backwards compatibility, moving or symlinking the script to a -file name starting with \fileent{mkluatexfontdb} will cause it to -trigger a database update on every run. -Running as \fileent{fontdbutil} -- the new name -- will do this upon -request only. - -There are two naming conventions followed here: firstly that of -utilities such as \fileent{mktexpk}, \fileent{mktexlsr} and the likes, -and secondly that of \fileent{fmtutil}. -After support for querying the database was added, the latter appeared -to be the more appropriate. ---doc]]-- - -config = config or { } -local config = config -config.luaotfload = config.luaotfload or { } - -do -- we don’t have file.basename and the likes yet, so inline parser ftw - local C, P = lpeg.C, lpeg.P - local lpegmatch = lpeg.match - local slash = P"/" - local dot = P"." - local noslash = 1 - slash - local slashes = slash^1 - local path = slashes^-1 * (noslash^1 * slashes)^1 - local thename = (1 - slash - dot)^1 - local extension = dot * (1 - slash - dot)^1 - local p_basename = path^-1 * C(thename) * extension^-1 * P(-1) - - -- if stringfind(stringlower(arg[0]), "^fontdbutil") then - local self = lpegmatch(p_basename, stringlower(arg[0])) - if self == "fontdbutil" then - config.luaotfload.self = "fontdbutil" - else - config.luaotfload.self = "mkluatexfontdb" - end -end - -config.lualibs = config.lualibs or { } -config.lualibs.verbose = false -config.lualibs.prefer_merged = true -config.lualibs.load_extended = false - -require"lualibs" - ---[[doc-- -\fileent{luatex-basics-gen.lua} calls functions from the -\luafunction{texio.*} library; too much for our taste. -We intercept them with dummies. ---doc]]-- - -local dummy_function = function ( ) end -local backup_write, backup_write_nl = texio.write, texio.write_nl - -texio.write, texio.write_nl = dummy_function, dummy_function -require"luaotfload-basics-gen.lua" -texio.write, texio.write_nl = backup_write, backup_write_nl - -require"luaotfload-override.lua" --- this populates the logs.* namespace -require"luaotfload-database" -require"alt_getopt" - -local version = "2.2" -- same version number as luaotfload -local names = fonts.names - -local db_src_out = names.path.dir.."/"..names.path.basename -local db_bin_out = file.replacesuffix(db_src_out, "luc") - -local help_messages = { - fontdbutil = [[ - -Usage: %s [OPTION]... - -Operations on the LuaTeX font database. - -This tool is part of the luaotfload package. Valid options are: - -------------------------------------------------------------------------------- - VERBOSITY AND LOGGING - - -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 --version print version and exit - -h --help print this message - - --alias= force behavior of “fontdbutil” or legacy - “mkluatexfontdb” -------------------------------------------------------------------------------- - DATABASE - - -u --update update the database - -f --force force re-indexing all fonts - -c --flush-cache empty cache of font requests - - --find="font name" query the database for a font name - -F --fuzzy look for approximate matches if --find fails - --limit=n limit display of fuzzy matches to - (default: n = 1) - -i --info display font metadata - - --log=stdout redirect log output to stdout - -The font database will be saved to - %s - %s - -]], - mkluatexfontdb = [[ - -Usage: %s [OPTION]... - -Rebuild the LuaTeX font database. - -Valid options: - -f --force force re-indexing all fonts - -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 --version print version and exit - -h --help print this message - --alias= force behavior of “fontdbutil” or legacy - “mkluatexfontdb” - -The font database will be saved to - %s - %s - -]], -} - -local help_msg = function ( ) - local template = help_messages[config.luaotfload.self] - or help.messages.fontdbutil - texiowrite_nl(stringformat(template, config.luaotfload.self, db_src_out, db_bin_out)) -end - -local version_msg = function ( ) - texiowrite_nl(stringformat( - "%s version %s, database version %s.\n", - config.luaotfload.self, version, names.version)) -end - -local show_info_items = function (fontinfo) - local items = table.sortedkeys(fontinfo) - for n = 1, #items do - local item = items[n] - texiowrite_nl(stringformat( - [[ %11s: %s]], item, fontinfo[item])) - end -end - -local show_font_info = function (filename) - local fullname = resolvers.findfile(filename) - if fullname then - local fontinfo = fontloader.info(fullname) - local nfonts = #fontinfo - if nfonts > 0 then -- true type collection - logs.names_report(true, 1, "resolve", - [[%s is a font collection]], filename) - for n = 1, nfonts do - logs.names_report(true, 1, "resolve", - [[showing info for font no. %d]], n) - show_info_items(fontinfo[n]) - end - else - show_info_items(fontinfo) - end - else - logs.names_report(true, 1, "resolve", - "font %s not found", filename) - end -end - ---[[-- -Running the scripts triggers one or more actions that have to be -executed in the correct order. To avoid duplication we track them in a -set. ---]]-- - -local action_sequence = { - "loglevel", "help", "version", "flush", "generate", "query" -} -local action_pending = table.tohash(action_sequence, false) - -action_pending.loglevel = true --- always set the loglevel -action_pending.generate = false --- this is the default action - -local actions = { } --- (jobspec -> (bool * bool)) list - -actions.loglevel = function (job) - logs.set_loglevel(job.log_level) - logs.names_report("info", 3, "util", - "setting log level", "%d", job.log_level) - return true, true -end - -actions.version = function (job) - version_msg() - return true, false -end - -actions.help = function (job) - help_msg() - return true, false -end - -actions.generate = function (job) - local fontnames, savedname - fontnames = names.update(fontnames, job.force_reload) - logs.names_report("info", 2, "db", - "Fonts in the database: %i", #fontnames.mappings) - savedname = names.save(fontnames) - if savedname then --- FIXME have names.save return bool - return true, true - end - return false, false -end - -actions.flush = function (job) - local success, fontnames = names.flush_cache() - if success then - local savedname = names.save(fontnames) - logs.names_report("info", 2, "cache", - "Cache emptied", #fontnames.mappings) - if savedname then - return true, true - end - end - return false, false -end - -actions.query = function (job) - - local query = job.query - local tmpspec = { - name = query, - lookup = "name", - specification = "name:" .. query, - optsize = 0, - } - - local foundname, subfont, success = - fonts.names.resolve(nil, nil, tmpspec) - - if success then - logs.names_report(false, 1, - "resolve", "Font “%s” found!", query) - if subfont then - logs.names_report(false, 1, "resolve", - "Resolved file name “%s”, subfont nr. “%s”", - foundname, subfont) - else - logs.names_report(false, 1, - "resolve", "Resolved file name “%s”", foundname) - end - if job.show_info then - show_font_info(foundname) - end - else - logs.names_report(false, 1, - "resolve", "Cannot find “%s”.", query) - if job.fuzzy == true then - logs.names_report(false, 1, - "resolve", "Looking for close matches, this may take a while ...") - local success = fonts.names.find_closest(query, job.fuzzy_limit) - end - end - return true, true -end - ---[[-- -Command-line processing. -mkluatexfontdb.lua relies on the script alt_getopt to process argv and -analyzes its output. - -TODO with extended lualibs we have the functionality from the -environment.* namespace that could eliminate the dependency on -alt_getopt. ---]]-- - -local process_cmdline = function ( ) -- unit -> jobspec - local result = { -- jobspec - force_reload = nil, - query = "", - log_level = 1, --- 2 is approx. the old behavior - } - - local long_options = { - alias = 1, - ["flush-cache"] = "c", - find = 1, - force = "f", - fuzzy = "F", - help = "h", - info = "i", - limit = 1, - log = 1, - quiet = "q", - update = "u", - verbose = 1 , - version = "V", - } - - local short_options = "cfFiquvVh" - - local options, _, optarg = - alt_getopt.get_ordered_opts (arg, short_options, long_options) - - local nopts = #options - for n=1, nopts do - local v = options[n] - if v == "q" then - result.log_level = 0 - elseif v == "u" then - action_pending["generate"] = true - elseif v == "v" then - if result.log_level > 0 then - result.log_level = result.log_level + 1 - else - result.log_level = 2 - end - elseif v == "V" then - action_pending["version"] = true - elseif v == "h" then - action_pending["help"] = true - elseif v == "f" then - result.update = true - result.force_reload = 1 - elseif v == "verbose" then - local lvl = optarg[n] - if lvl then - result.log_level = tonumber(lvl) - end - elseif v == "log" then - local str = optarg[n] - if str then - logs.set_logout(str) - end - elseif v == "find" then - action_pending["query"] = true - result.query = optarg[n] - elseif v == "F" then - result.fuzzy = true - elseif v == "limit" then - local lim = optarg[n] - if lim then - result.fuzzy_limit = tonumber(lim) - end - elseif v == "i" then - result.show_info = true - elseif v == "alias" then - config.luaotfload.self = optarg[n] - elseif v == "c" then - action_pending["flush"] = true - end - end - - if config.luaotfload.self == "mkluatexfontdb" then - action_pending["generate"] = true - print(result.log_level) - result.log_level = math.max(2, result.log_level) - print(result.log_level) - end - return result -end - -local main = function ( ) -- unit -> int - local retval = 0 - local job = process_cmdline() - --- inspect(action_pending) --- inspect(job) - - for i=1, #action_sequence do - local actionname = action_sequence[i] - local exit = false - if action_pending[actionname] then - logs.names_report("log", 3, "util", "preparing for task", - "%s", actionname) - - local action = actions[actionname] - local success, continue = action(job) - - if not success then - logs.names_report(false, 0, "util", - "could not finish task", "%s", actionname) - retval = -1 - exit = true - elseif not continue then - logs.names_report(false, 3, "util", - "task completed, exiting", "%s", actionname) - exit = true - else - logs.names_report(false, 3, "util", - "task completed successfully", "%s", actionname) - end - end - if exit then break end - end - - texiowrite_nl"" - return retval -end - -return main() - --- vim:tw=71:sw=4:ts=4:expandtab diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua new file mode 100755 index 0000000..470d282 --- /dev/null +++ b/luaotfload-tool.lua @@ -0,0 +1,444 @@ +#!/usr/bin/env texlua + +--[[doc-- +This file was originally written by Elie Roux and Khaled Hosny and is under CC0 +license (see http://creativecommons.org/publicdomain/zero/1.0/legalcode). + +This file is a wrapper for the luaotfload font names module +(luaotfload-database.lua). It is part of the luaotfload bundle, please +see the luaotfload documentation for more info. Report bugs to +\url{https://github.com/lualatex/luaotfload/issues}. + +--doc]]-- + +kpse.set_program_name"luatex" + +local stringformat = string.format +local texiowrite_nl = texio.write_nl +local stringfind = string.find +local stringlower = string.lower + + +local loader_file = "luatexbase.loader.lua" +local loader_path = assert(kpse.find_file(loader_file, "lua"), + "File '"..loader_file.."' not found") + + +string.quoted = string.quoted or function (str) + return string.format("%q",str) +end + +require(loader_path) + +--[[doc-- +Depending on how the script is called we change its behavior. +For backwards compatibility, moving or symlinking the script to a +file name starting with \fileent{mkluatexfontdb} will cause it to +trigger a database update on every run. +Running as \fileent{fontdbutil} -- the new name -- will do this upon +request only. + +There are two naming conventions followed here: firstly that of +utilities such as \fileent{mktexpk}, \fileent{mktexlsr} and the likes, +and secondly that of \fileent{fmtutil}. +After support for querying the database was added, the latter appeared +to be the more appropriate. +--doc]]-- + +config = config or { } +local config = config +config.luaotfload = config.luaotfload or { } + +do -- we don’t have file.basename and the likes yet, so inline parser ftw + local C, P = lpeg.C, lpeg.P + local lpegmatch = lpeg.match + local slash = P"/" + local dot = P"." + local noslash = 1 - slash + local slashes = slash^1 + local path = slashes^-1 * (noslash^1 * slashes)^1 + local thename = (1 - slash - dot)^1 + local extension = dot * (1 - slash - dot)^1 + local p_basename = path^-1 * C(thename) * extension^-1 * P(-1) + + -- if stringfind(stringlower(arg[0]), "^fontdbutil") then + local self = lpegmatch(p_basename, stringlower(arg[0])) + if self == "fontdbutil" then + config.luaotfload.self = "fontdbutil" + else + config.luaotfload.self = "mkluatexfontdb" + end +end + +config.lualibs = config.lualibs or { } +config.lualibs.verbose = false +config.lualibs.prefer_merged = true +config.lualibs.load_extended = false + +require"lualibs" + +--[[doc-- +\fileent{luatex-basics-gen.lua} calls functions from the +\luafunction{texio.*} library; too much for our taste. +We intercept them with dummies. +--doc]]-- + +local dummy_function = function ( ) end +local backup_write, backup_write_nl = texio.write, texio.write_nl + +texio.write, texio.write_nl = dummy_function, dummy_function +require"luaotfload-basics-gen.lua" +texio.write, texio.write_nl = backup_write, backup_write_nl + +require"luaotfload-override.lua" --- this populates the logs.* namespace +require"luaotfload-database" +require"alt_getopt" + +local version = "2.2" -- same version number as luaotfload +local names = fonts.names + +local db_src_out = names.path.dir.."/"..names.path.basename +local db_bin_out = file.replacesuffix(db_src_out, "luc") + +local help_messages = { + fontdbutil = [[ + +Usage: %s [OPTION]... + +Operations on the LuaTeX font database. + +This tool is part of the luaotfload package. Valid options are: + +------------------------------------------------------------------------------- + VERBOSITY AND LOGGING + + -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 --version print version and exit + -h --help print this message + + --alias= force behavior of “fontdbutil” or legacy + “mkluatexfontdb” +------------------------------------------------------------------------------- + DATABASE + + -u --update update the database + -f --force force re-indexing all fonts + -c --flush-cache empty cache of font requests + + --find="font name" query the database for a font name + -F --fuzzy look for approximate matches if --find fails + --limit=n limit display of fuzzy matches to + (default: n = 1) + -i --info display font metadata + + --log=stdout redirect log output to stdout + +The font database will be saved to + %s + %s + +]], + mkluatexfontdb = [[ + +Usage: %s [OPTION]... + +Rebuild the LuaTeX font database. + +Valid options: + -f --force force re-indexing all fonts + -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 --version print version and exit + -h --help print this message + --alias= force behavior of “fontdbutil” or legacy + “mkluatexfontdb” + +The font database will be saved to + %s + %s + +]], +} + +local help_msg = function ( ) + local template = help_messages[config.luaotfload.self] + or help.messages.fontdbutil + texiowrite_nl(stringformat(template, config.luaotfload.self, db_src_out, db_bin_out)) +end + +local version_msg = function ( ) + texiowrite_nl(stringformat( + "%s version %s, database version %s.\n", + config.luaotfload.self, version, names.version)) +end + +local show_info_items = function (fontinfo) + local items = table.sortedkeys(fontinfo) + for n = 1, #items do + local item = items[n] + texiowrite_nl(stringformat( + [[ %11s: %s]], item, fontinfo[item])) + end +end + +local show_font_info = function (filename) + local fullname = resolvers.findfile(filename) + if fullname then + local fontinfo = fontloader.info(fullname) + local nfonts = #fontinfo + if nfonts > 0 then -- true type collection + logs.names_report(true, 1, "resolve", + [[%s is a font collection]], filename) + for n = 1, nfonts do + logs.names_report(true, 1, "resolve", + [[showing info for font no. %d]], n) + show_info_items(fontinfo[n]) + end + else + show_info_items(fontinfo) + end + else + logs.names_report(true, 1, "resolve", + "font %s not found", filename) + end +end + +--[[-- +Running the scripts triggers one or more actions that have to be +executed in the correct order. To avoid duplication we track them in a +set. +--]]-- + +local action_sequence = { + "loglevel", "help", "version", "flush", "generate", "query" +} +local action_pending = table.tohash(action_sequence, false) + +action_pending.loglevel = true --- always set the loglevel +action_pending.generate = false --- this is the default action + +local actions = { } --- (jobspec -> (bool * bool)) list + +actions.loglevel = function (job) + logs.set_loglevel(job.log_level) + logs.names_report("info", 3, "util", + "setting log level", "%d", job.log_level) + return true, true +end + +actions.version = function (job) + version_msg() + return true, false +end + +actions.help = function (job) + help_msg() + return true, false +end + +actions.generate = function (job) + local fontnames, savedname + fontnames = names.update(fontnames, job.force_reload) + logs.names_report("info", 2, "db", + "Fonts in the database: %i", #fontnames.mappings) + savedname = names.save(fontnames) + if savedname then --- FIXME have names.save return bool + return true, true + end + return false, false +end + +actions.flush = function (job) + local success, fontnames = names.flush_cache() + if success then + local savedname = names.save(fontnames) + logs.names_report("info", 2, "cache", + "Cache emptied", #fontnames.mappings) + if savedname then + return true, true + end + end + return false, false +end + +actions.query = function (job) + + local query = job.query + local tmpspec = { + name = query, + lookup = "name", + specification = "name:" .. query, + optsize = 0, + } + + local foundname, subfont, success = + fonts.names.resolve(nil, nil, tmpspec) + + if success then + logs.names_report(false, 1, + "resolve", "Font “%s” found!", query) + if subfont then + logs.names_report(false, 1, "resolve", + "Resolved file name “%s”, subfont nr. “%s”", + foundname, subfont) + else + logs.names_report(false, 1, + "resolve", "Resolved file name “%s”", foundname) + end + if job.show_info then + show_font_info(foundname) + end + else + logs.names_report(false, 1, + "resolve", "Cannot find “%s”.", query) + if job.fuzzy == true then + logs.names_report(false, 1, + "resolve", "Looking for close matches, this may take a while ...") + local success = fonts.names.find_closest(query, job.fuzzy_limit) + end + end + return true, true +end + +--[[-- +Command-line processing. +mkluatexfontdb.lua relies on the script alt_getopt to process argv and +analyzes its output. + +TODO with extended lualibs we have the functionality from the +environment.* namespace that could eliminate the dependency on +alt_getopt. +--]]-- + +local process_cmdline = function ( ) -- unit -> jobspec + local result = { -- jobspec + force_reload = nil, + query = "", + log_level = 1, --- 2 is approx. the old behavior + } + + local long_options = { + alias = 1, + ["flush-cache"] = "c", + find = 1, + force = "f", + fuzzy = "F", + help = "h", + info = "i", + limit = 1, + log = 1, + quiet = "q", + update = "u", + verbose = 1 , + version = "V", + } + + local short_options = "cfFiquvVh" + + local options, _, optarg = + alt_getopt.get_ordered_opts (arg, short_options, long_options) + + local nopts = #options + for n=1, nopts do + local v = options[n] + if v == "q" then + result.log_level = 0 + elseif v == "u" then + action_pending["generate"] = true + elseif v == "v" then + if result.log_level > 0 then + result.log_level = result.log_level + 1 + else + result.log_level = 2 + end + elseif v == "V" then + action_pending["version"] = true + elseif v == "h" then + action_pending["help"] = true + elseif v == "f" then + result.update = true + result.force_reload = 1 + elseif v == "verbose" then + local lvl = optarg[n] + if lvl then + result.log_level = tonumber(lvl) + end + elseif v == "log" then + local str = optarg[n] + if str then + logs.set_logout(str) + end + elseif v == "find" then + action_pending["query"] = true + result.query = optarg[n] + elseif v == "F" then + result.fuzzy = true + elseif v == "limit" then + local lim = optarg[n] + if lim then + result.fuzzy_limit = tonumber(lim) + end + elseif v == "i" then + result.show_info = true + elseif v == "alias" then + config.luaotfload.self = optarg[n] + elseif v == "c" then + action_pending["flush"] = true + end + end + + if config.luaotfload.self == "mkluatexfontdb" then + action_pending["generate"] = true + print(result.log_level) + result.log_level = math.max(2, result.log_level) + print(result.log_level) + end + return result +end + +local main = function ( ) -- unit -> int + local retval = 0 + local job = process_cmdline() + +-- inspect(action_pending) +-- inspect(job) + + for i=1, #action_sequence do + local actionname = action_sequence[i] + local exit = false + if action_pending[actionname] then + logs.names_report("log", 3, "util", "preparing for task", + "%s", actionname) + + local action = actions[actionname] + local success, continue = action(job) + + if not success then + logs.names_report(false, 0, "util", + "could not finish task", "%s", actionname) + retval = -1 + exit = true + elseif not continue then + logs.names_report(false, 3, "util", + "task completed, exiting", "%s", actionname) + exit = true + else + logs.names_report(false, 3, "util", + "task completed successfully", "%s", actionname) + end + end + if exit then break end + end + + texiowrite_nl"" + return retval +end + +return main() + +-- vim:tw=71:sw=4:ts=4:expandtab -- cgit v1.2.3 From dae29b04d0bb7e21bb4d3d19b9781b59e44ec5cb Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 16:26:45 +0200 Subject: use ``fullname`` in status entries This suppresses redundand database updates in the case where a font is found in multiple directories with different timestamps. Also removed references to ``fontdbutil``. --- luaotfload-database.lua | 48 ++++++++++++++++++++++++------------------------ luaotfload-features.lua | 2 +- luaotfload-tool.lua | 17 +++++++---------- luaotfload.dtx | 30 +++++++++++++++--------------- 4 files changed, 47 insertions(+), 50 deletions(-) diff --git a/luaotfload-database.lua b/luaotfload-database.lua index a750804..037ca07 100644 --- a/luaotfload-database.lua +++ b/luaotfload-database.lua @@ -383,7 +383,7 @@ TODO: × 3) make caching optional (via the config table) for debugging × 4) make names_update() cache aware (nil if “force”) × 5) add logging - × 6) add cache control to fontdbutil + × 6) add cache control to luaotfload-tool × 7) incr db version 8) wishlist: save cache only at the end of a run 9) ??? @@ -858,8 +858,10 @@ font_fullinfo = function (filename, subfont) end --- we return true if the fond is new or re-indexed ---- string -> dbobj -> dbobj -> bool -> bool +--- string -> dbobj -> dbobj -> bool local load_font = function (fullname, fontnames, newfontnames) + if not fullname then return false end + local newmappings = newfontnames.mappings local newstatus = newfontnames.status @@ -878,40 +880,39 @@ local load_font = function (fullname, fontnames, newfontnames) local entryname = basename - if not fullname then return false end - - if names.blacklist[fullname] - or names.blacklist[basename] + if names.blacklist[fullname] or names.blacklist[basename] then report("log", 2, "db", "ignoring blacklisted font “%s”", fullname) return false end + local timestamp, db_timestamp - db_timestamp = status[entryname] - and status[entryname].timestamp + db_timestamp = status[fullname] + and status[fullname].timestamp timestamp = lfs.attributes(fullname, "modification") - local index_status = newstatus[entryname] or newstatus[basename] - local teststat = newstatus[entryname] + local index_status = newstatus[fullname] --- index_status: nil | false | table if index_status and index_status.timestamp == timestamp then -- already indexed this run return false end - newstatus[entryname] = newstatus[entryname] or { } - newstatus[entryname].timestamp = timestamp - newstatus[entryname].index = newstatus[entryname].index or { } + newstatus[fullname] = newstatus[fullname] or { } + newstatus[fullname].timestamp = timestamp + newstatus[fullname].index = newstatus[fullname].index or { } + --- this test compares the modification data registered + --- in the database with the current one if db_timestamp == timestamp - and not newstatus[entryname].index[1] then - for _,v in next, status[entryname].index do - local index = #newstatus[entryname].index + and not newstatus[fullname].index[1] then + for _,v in next, status[fullname].index do + local index = #newstatus[fullname].index local fullinfo = mappings[v] local location = #newmappings + 1 newmappings[location] = fullinfo --- keep - newstatus[entryname].index[index+1] = location --- is this actually used anywhere? + newstatus[fullname].index[index+1] = location --- is this actually used anywhere? -- newfullnames[fullname] = location newbasenames[basename] = location newbarenames[barename] = location @@ -929,14 +930,14 @@ local load_font = function (fullname, fontnames, newfontnames) return false end local location = #newmappings+1 - local index = newstatus[entryname].index[n_font] + local index = newstatus[fullname].index[n_font] if not index then index = location end newmappings[index] = fullinfo -- newfullnames[fullname] = location newbasenames[basename] = location newbarenames[barename] = location - newstatus[entryname].index[n_font] = index + newstatus[fullname].index[n_font] = index end else local fullinfo = font_fullinfo(fullname, false) @@ -944,14 +945,14 @@ local load_font = function (fullname, fontnames, newfontnames) return false end local location = #newmappings+1 - local index = newstatus[entryname].index[1] + local index = newstatus[fullname].index[1] if not index then index = location end newmappings[index] = fullinfo -- newfullnames[fullname] = location newbasenames[basename] = location newbarenames[barename] = location - newstatus[entryname].index[1] = index + newstatus[fullname].index[1] = index end else --- missing info @@ -1108,7 +1109,7 @@ local function scan_texmf_fonts(fontnames, newfontnames) fontdirs = fontdirs .. stringgsub(kpseexpand_path("$TTFONTS"), "^%.", "") if not stringis_empty(fontdirs) then for _,d in next, filesplitpath(fontdirs) do - local found, new = scan_dir(d, fontnames, newfontnames, true) + local found, new = scan_dir(d, fontnames, newfontnames) n_scanned = n_scanned + found n_new = n_new + new end @@ -1374,7 +1375,6 @@ local function scan_os_fonts(fontnames, newfontnames) ]] report("info", 2, "db", "Scanning OS fonts...") report("info", 3, "db", "Searching in static system directories...") - print"~~~~" for _,d in next, get_os_dirs() do local found, new = scan_dir(d, fontnames, newfontnames) n_scanned = n_scanned + found @@ -1409,9 +1409,9 @@ update_names = function (fontnames, force) fontnames = load_names() end if fontnames.version ~= names.version then - fontnames = fontnames_init(true) report("log", 1, "db", "No font names database or old " .. "one found; generating new one") + fontnames = fontnames_init(true) end end local newfontnames = fontnames_init(true) diff --git a/luaotfload-features.lua b/luaotfload-features.lua index 6cbfdf4..494d02d 100644 --- a/luaotfload-features.lua +++ b/luaotfload-features.lua @@ -301,7 +301,7 @@ end --- --- caching of successful lookups is essential. we need --- an additional subtable "cached" in the database. it ---- should be nil’able by issuing fontdbutil --flush or +--- should be nil’able by issuing luaotfload-tool --flush or --- something. if a cache miss is followed by a successful --- lookup, then it will be counted as new addition to the --- cache. we also need a config option to ignore caching. diff --git a/luaotfload-tool.lua b/luaotfload-tool.lua index 470d282..bb935cf 100755 --- a/luaotfload-tool.lua +++ b/luaotfload-tool.lua @@ -35,7 +35,7 @@ Depending on how the script is called we change its behavior. For backwards compatibility, moving or symlinking the script to a file name starting with \fileent{mkluatexfontdb} will cause it to trigger a database update on every run. -Running as \fileent{fontdbutil} -- the new name -- will do this upon +Running as \fileent{luaotfload-tool} -- the new name -- will do this upon request only. There are two naming conventions followed here: firstly that of @@ -61,10 +61,9 @@ do -- we don’t have file.basename and the likes yet, so inline parser ftw local extension = dot * (1 - slash - dot)^1 local p_basename = path^-1 * C(thename) * extension^-1 * P(-1) - -- if stringfind(stringlower(arg[0]), "^fontdbutil") then local self = lpegmatch(p_basename, stringlower(arg[0])) - if self == "fontdbutil" then - config.luaotfload.self = "fontdbutil" + if self == "luaotfload-tool" then + config.luaotfload.self = "luaotfload-tool" else config.luaotfload.self = "mkluatexfontdb" end @@ -101,7 +100,7 @@ local db_src_out = names.path.dir.."/"..names.path.basename local db_bin_out = file.replacesuffix(db_src_out, "luc") local help_messages = { - fontdbutil = [[ + ["luaotfload-tool"] = [[ Usage: %s [OPTION]... @@ -119,7 +118,7 @@ This tool is part of the luaotfload package. Valid options are: -V --version print version and exit -h --help print this message - --alias= force behavior of “fontdbutil” or legacy + --alias= force behavior of “luaotfload-tool” or legacy “mkluatexfontdb” ------------------------------------------------------------------------------- DATABASE @@ -155,7 +154,7 @@ Valid options: -vvv print all steps of directory searching -V --version print version and exit -h --help print this message - --alias= force behavior of “fontdbutil” or legacy + --alias= force behavior of “luaotfload-tool” or legacy “mkluatexfontdb” The font database will be saved to @@ -167,7 +166,7 @@ The font database will be saved to local help_msg = function ( ) local template = help_messages[config.luaotfload.self] - or help.messages.fontdbutil + or help_messages["luaotfload-tool"] texiowrite_nl(stringformat(template, config.luaotfload.self, db_src_out, db_bin_out)) end @@ -394,9 +393,7 @@ local process_cmdline = function ( ) -- unit -> jobspec if config.luaotfload.self == "mkluatexfontdb" then action_pending["generate"] = true - print(result.log_level) result.log_level = math.max(2, result.log_level) - print(result.log_level) end return result end diff --git a/luaotfload.dtx b/luaotfload.dtx index 6392c64..9c5d600 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -768,8 +768,8 @@ and the derived files % This is particularly noticeable if it occurs during a typesetting run. % In any case, subsequent updates to the database will be quite fast. % -% \subsection[fontdbutil / mkluatexfontdb.lua]% -% {\fileent{fontdbutil} / +% \subsection[luaotfload-tool / mkluatexfontdb.lua]% +% {\fileent{luaotfload-tool} / % \fileent{mkluatexfontdb.lua}\footnote{% % The script may be named just \fileent{mkluatexfontdb} in your % distribution. @@ -778,7 +778,7 @@ and the derived files % It can still be desirable at times to do some of these steps % manually, and without having to compile a document. % To this end, \identifier{luaotfload} comes with the utility -% \fileent{fontdbutil} that offers an interface to the database +% \fileent{luaotfload-tool} that offers an interface to the database % functionality. % Being a \LUA script, there are two ways to run it: % either make it executable (\verb|chmod +x| on unixoid systems) or @@ -793,15 +793,15 @@ and the derived files % \emphasis{Note}: % On \abbrev{MS} \identifier{Windows} systems, the script can be run % either by calling the wrapper application -% \fileent{fontdbutil.exe} or as -% \verb|texlua.exe fontdbutil|. +% \fileent{luaotfload-tool.exe} or as +% \verb|texlua.exe luaotfload-tool.lua|. % } % Invoked with the argument \verb|--update| it will perform a database % update, scanning for fonts not indexed. % % \begin{quote} % \begin{verbatim} -% fontdbutil --update +% luaotfload-tool --update % \end{verbatim} % \end{quote} % @@ -810,11 +810,11 @@ and the derived files % % \begin{quote} % \begin{verbatim} -% fontdbutil --update --force +% luaotfload-tool --update --force % \end{verbatim} % \end{quote} % -% For sake of backwards compatibility, \fileent{fontdbutil} may be +% For sake of backwards compatibility, \fileent{luaotfload-tool} may be % renamed or symlinked to \fileent{mkluatexfontdb}. % Whenever it is run under this name, it will update the database % first, mimicking the behavior of earlier versions of @@ -862,7 +862,7 @@ and the derived files % % \subsection{Querying from Outside} % -% \fileent{fontdbutil} also provides rudimentary means of +% \fileent{luaotfload-tool} also provides rudimentary means of % accessing the information collected in the font database. % If the option \verb|--find=|\emphasis{name} is given, the script will % try and search the fonts indexed by \identifier{luaotfload} for a @@ -871,7 +871,7 @@ and the derived files % % \begin{quote} % \begin{verbatim} -% fontdbutil --find="Iwona Regular" +% luaotfload-tool --find="Iwona Regular" % \end{verbatim} % \end{quote} % @@ -888,7 +888,7 @@ and the derived files % % \begin{quote} % \begin{verbatim} -% fontdbutil -F --find="Iwona Bright" +% luaotfload-tool -F --find="Iwona Bright" % \end{verbatim} % \end{quote} % @@ -899,7 +899,7 @@ and the derived files % using the \verb|-i| option (\verb|--info|). % \begin{quote} % \begin{verbatim} -% fontdbutil -F --find="Iwona Light Italic" +% luaotfload-tool -F --find="Iwona Light Italic" % \end{verbatim} % \end{quote} % \noindent @@ -908,7 +908,7 @@ and the derived files % In \TEX Live: \fileent{texmf-dist/doc/luatex/base/luatexref-t.pdf}. % } % -% \verb|fontdbutil --help| will list the available command line +% \verb|luaotfload-tool --help| will list the available command line % switches, including some not discussed in detail here. % % \subsection{Blacklisting Fonts} @@ -917,7 +917,7 @@ and the derived files % Some fonts are problematic in general, or just in \LUATEX. % If you find that compiling your document takes far too long or eats % away all your system’s memory, you can track down the culprit by -% running \verb|fontdbutil -v| to increase verbosity. +% running \verb|luaotfload-tool -v| to increase verbosity. % Take a note of the \emphasis{filename} of the font that database % creation fails with and append it to the file % \fileent{luaotfload-blacklist.cnf}. @@ -1126,7 +1126,7 @@ and the derived files % verbosity levels and redirecting log output to \fileent{stdout}: % % \begin{verbatim} -% fontdbutil -fuvvv --log=stdout +% luaotfload-tool -fuvvv --log=stdout % \end{verbatim} % % If this fails, the font last printed to the terminal is likely to be -- cgit v1.2.3 From bcf92b745cc583119367810b4a97d4fc91e63fdb Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 16:31:19 +0200 Subject: install uncached name: resolver as default --- luaotfload.dtx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/luaotfload.dtx b/luaotfload.dtx index 9c5d600..2c9fa77 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -1179,7 +1179,8 @@ local luaotfload = luaotfload config = config or { } config.luaotfload = config.luaotfload or { } -luaotfload.prefer_merge = config.luaotfload.prefer_merge or true +config.luaotfload.resolver = config.luaotfload.resolver or "normal" +--luaotfload.prefer_merge = config.luaotfload.prefer_merge or true luaotfload.module = { name = "luaotfload", -- cgit v1.2.3 From ed0cde735cc25079df9600a43b09ed8163ac1d3f Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 22:26:13 +0200 Subject: sync fontloader code with Context as of 2013-04-29 --- luaotfload-merged.lua | 45 +++++++++++++++++++++++++++++++-------------- 1 file changed, 31 insertions(+), 14 deletions(-) diff --git a/luaotfload-merged.lua b/luaotfload-merged.lua index 0cf2ce4..bf22bac 100644 --- a/luaotfload-merged.lua +++ b/luaotfload-merged.lua @@ -1,6 +1,6 @@ -- merged file : luatex-fonts-merged.lua -- parent file : luatex-fonts.lua --- merge date : 04/26/13 15:13:48 +-- merge date : 04/29/13 20:30:03 do -- begin closure to overcome local limits and interference @@ -3039,7 +3039,6 @@ function caches.getreadablepaths(category,subcategory) end local function makefullname(path,name) if path and path~="" then - name="temp-"..name return file.addsuffix(file.join(path,name),"lua"),file.addsuffix(file.join(path,name),usingjit and "lub" or "luc") end end @@ -3093,7 +3092,7 @@ function caches.compile(data,luaname,lucname) d=table.serialize(data,true) end if d and d~="" then - local f=io.open(lucname,'w') + local f=io.open(lucname,'wb') if f then local s=loadstring(d) if s then @@ -3218,7 +3217,7 @@ function containers.content(container,name) return container.storage[name] end function containers.cleanname(name) - return (gsub(lower(name),"[^%w%d]+","-")) + return (gsub(lower(name),"[^%w\128-\255]+","-")) end end -- closure @@ -4829,22 +4828,35 @@ end local fonts=fonts fonts.names=fonts.names or {} fonts.names.version=1.001 -fonts.names.basename="luatex-fonts-names.lua" +fonts.names.basename="luatex-fonts-names" fonts.names.new_to_old={} fonts.names.old_to_new={} +fonts.names.cache=containers.define("fonts","data",fonts.names.version,true) local data,loaded=nil,false local fileformats={ "lua","tex","other text files" } +function fonts.names.reportmissingbase() + texio.write("") + fonts.names.reportmissingbase=nil +end +function fonts.names.reportmissingname() + texio.write("") + fonts.names.reportmissingname=nil +end function fonts.names.resolve(name,sub) if not loaded then local basename=fonts.names.basename if basename and basename~="" then - for i=1,#fileformats do - local format=fileformats[i] - local foundname=resolvers.findfile(basename,format) or "" - if foundname~="" then - data=dofile(foundname) - texio.write("") - break + data=containers.read(fonts.names.cache,basename) + if not data then + basename=file.addsuffix(basename,"lua") + for i=1,#fileformats do + local format=fileformats[i] + local foundname=resolvers.findfile(basename,format) or "" + if foundname~="" then + data=dofile(foundname) + texio.write("") + break + end end end end @@ -4860,9 +4872,12 @@ function fonts.names.resolve(name,sub) else return filename,false end - else + elseif fonts.names.reportmissingname then + fonts.names.reportmissingname() return name,false end + elseif fonts.names.reportmissingbase then + fonts.names.reportmissingbase() end end fonts.names.resolvespec=fonts.names.resolve @@ -7713,7 +7728,7 @@ function injections.handler(head,where,keep) if rlmode and rlmode>=0 then n.xoffset=p.xoffset-p.width+d[1] else - n.xoffset=p.xoffset-d[1]-x + n.xoffset=p.xoffset-d[1]-x end end else @@ -10054,6 +10069,8 @@ for s=1,#datasets do if ok then success=true break + elseif not start then + break end end else -- cgit v1.2.3 From 572c0e2de196d2d9551cd205b7f0c69800fb7516 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Mon, 29 Apr 2013 22:57:12 +0200 Subject: update NEWS --- Makefile | 2 +- NEWS | 25 +++++++++++++++++++++---- filegraph.dot | 2 +- luaotfload.dtx | 2 +- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Makefile b/Makefile index 4821619..bdc2d35 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ NAME = luaotfload DOC = $(NAME).pdf DTX = $(NAME).dtx OTFL = $(wildcard otfl-*.lua) otfl-blacklist.cnf font-age.lua -SCRIPT = fontdbutil +SCRIPT = luaotfload-tool.lua GLYPHSCRIPT = mkglyphlist GLYPHSOURCE = glyphlist.txt diff --git a/NEWS b/NEWS index aac957d..16fd387 100644 --- a/NEWS +++ b/NEWS @@ -6,10 +6,27 @@ Change History backward-incompatible changes in the font structure (fontspec and unicode-math must be updated) * Synchronisation with ConTeXt is now easier and can be done by just - updating otfl-fonts-merged.lua (available in ConTeXt) - * Improve documentation - * renaming mkluatexfontdb into fontdbutil, with more search functionalities - * blacklisting font lingoes.ttf + updating luaotfload-merged.lua (<= luatex-fonts-merged.lua from + the LuaTeX-Plain format) + * Improved and extended documentation + * Blacklisting font lingoes.ttf while removing several TrueType collections + from the blacklist + * Font filenames are stored in the database (file: lookups more efficient) + * Optional caching of name: lookups + * Increased fidelity of XeTeX emulation + * Renaming mkluatexfontdb into luaotfload-tool, with more search + functionalities (the old behavior is kept if the script is symlinked/ + renamed mkluatexfontdb) + * Added options to luaotfload-tool for simple database queries + * Logging facilities have been rewritten and allow for more granularity + * All files have been renamed, abandoning cryptic acronyms; also + the new prefix is »luaotfload« (<= »otfl«) + * The Adobe Glyph List (font-age.lua) is now built via script (mkglyphlist) + * Hans adapted the font loader to several of our requests (attribute + allocation, custom merged package name, non-ascii names in font cache + etc.) + * There is now a central, non-personal dev repo on github: + https://github.com/lualatex/luaotfload 2013/04/11, luaotfload v1.28: * Adapting to LuaTeX 0.75, keeping backward-compatibility diff --git a/filegraph.dot b/filegraph.dot index a0eadec..d69937b 100644 --- a/filegraph.dot +++ b/filegraph.dot @@ -62,7 +62,7 @@ strict digraph luaotfload_files { //looks weird with circo ... * main files * ································································· */ - fontdbutil [label = "fontdbutil\nmkluatexfontdb.lua", + fontdbutil [label = "luaotfload-util\nmkluatexfontdb.lua", shape = rect, width = "3.2cm", height = "1.2cm", diff --git a/luaotfload.dtx b/luaotfload.dtx index 2c9fa77..5b454bc 100644 --- a/luaotfload.dtx +++ b/luaotfload.dtx @@ -332,7 +332,7 @@ and the derived files % \label{font-syntax} % \end{figure} % -% \subsection{Prefix -- the \identifier{luaotfload}\space Way} +% \subsection{Prefix -- the \identifier{luaotfload}{ }Way} % % In \identifier{luaotfload}, the canonical syntax for font requests % requires a \emphasis{prefix}: -- cgit v1.2.3