From b80b94ca5aedf47f75ed6052985d4c1f167d6a89 Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Sun, 28 Feb 2010 18:54:38 +0200 Subject: Prepare for merging luaotfload-fonts in luaotfload --- luaotfload-fonts.lua | 375 --------------------------------------------------- otfl-font-nms.lua | 375 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 375 insertions(+), 375 deletions(-) delete mode 100644 luaotfload-fonts.lua create mode 100644 otfl-font-nms.lua diff --git a/luaotfload-fonts.lua b/luaotfload-fonts.lua deleted file mode 100644 index aeba0f1..0000000 --- a/luaotfload-fonts.lua +++ /dev/null @@ -1,375 +0,0 @@ --- This lua script is made to generate the font database for LuaTeX, in order --- for it to be able to load a font according to its name, like XeTeX does. --- --- It is part of the luaotfload bundle, see luaotfload's README for legal --- notice. - --- some usual initializations -luaotfload = luaotfload or { } -luaotfload.fonts = { } - -luaotfload.fonts.module = { - name = "luaotfload.fonts", - version = 1.001, - date = "2010/01/12", - description = "luaotfload font database.", - author = "Khaled Hosny and Elie Roux", - copyright = "Luaotfload Development Team", - license = "CC0" -} - -kpse.set_program_name("luatex") - -local luaextra_file = kpse.find_file("luaextra.lua") -if not luaextra_file then - texio.write_nl("Error: cannot find 'luaextra.lua', exiting.") - os.exit(1) -end -dofile(luaextra_file) - -local splitpath, expandpath, glob, basename = file.split_path, kpse.expand_path, dir.glob, file.basename -local upper, format, rep = string.upper, string.format, string.rep - -function kpse.do_file(name) - return dofile(kpse.find_file(name)) -end - --- the file name of the font database -luaotfload.fonts.basename = "otfl-names.lua" - --- the path to add to TEXMFVAR or TEXMFSYSVAR to get the final directory in --- normal cases -luaotfload.fonts.subtexmfvardir = "/tex/" - --- the directory in which the database will be saved, can be overwritten -luaotfload.fonts.directory = kpse.expand_var("$TEXMFVAR") .. luaotfload.fonts.subtexmfvardir - --- the version of the database, to be checked by the lookup function of --- luaotfload -luaotfload.fonts.version = 2.004 - --- Log facilities: --- - level 0 is quiet --- - level 1 is the progress bar --- - level 2 prints the searched directories --- - level 3 prints all the loaded fonts --- - level 4 prints all informations when searching directories (debug only) -luaotfload.fonts.log_level = 1 - -local lastislog = 0 - -function luaotfload.fonts.log(lvl, fmt, ...) - if lvl <= luaotfload.fonts.log_level then - lastislog = 1 - texio.write_nl(format("luaotfload | %s", format(fmt,...))) - end -end - -local log = luaotfload.fonts.log - --- The progress bar -local function progress(current, total) - if luaotfload.fonts.log_level == 1 then --- local width = os.getenv("COLUMNS") -2 --doesn't work - local width = 78 - local percent = current/total - local gauge = format("[%s]", string.rpadd(" ", width, " ")) - if percent > 0 then - local done = string.rpadd("=", (width * percent) - 1, "=") .. ">" - gauge = format("[%s]", string.rpadd(done, width, " ") ) - end - if lastislog == 1 then - texio.write_nl("") - lastislog = 0 - end - io.stderr:write("\r"..gauge) - io.stderr:flush() - end -end - -function fontloader.fullinfo(...) - local t = { } - local f = fontloader.open(...) - local m = f and fontloader.to_table(f) - fontloader.close(f) - -- see http://www.microsoft.com/typography/OTSPEC/features_pt.htm#size - if m.fontstyle_name then - for _,v in pairs(m.fontstyle_name) do - if v.lang == 1033 then - t.fontstyle_name = v.name - end - end - end - if m.names then - for _,v in pairs(m.names) do - if v.lang == "English (US)" then - t.names = { - -- see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html - fullname = v.names.compatfull or v.names.fullname, -- 18, 4 - family = v.names.preffamilyname or v.names.family, -- 17, 1 - subfamily = t.fontstyle_name or v.names.prefmodifiers or v.names.subfamily, -- opt. style, 16, 2 - psname = v.names.postscriptname --or t.fontname - } - end - end - end - t.fontname = m.fontname - t.fullname = m.fullname - t.familyname = m.familyname - t.filename = m.origname - t.weight = m.pfminfo.weight - t.width = m.pfminfo.width - t.slant = m.italicangle - -- don't waste the space with zero values - t.size = { - m.design_size ~= 0 and m.design_size or nil, - m.design_range_top ~= 0 and m.design_range_top or nil, - m.design_range_bottom ~= 0 and m.design_range_bottom or nil, - } - return t -end - -local function load_font(filename, names, texmf) - log(3, "Loading font: %s", filename) - local mappings = names.mappings or { } - local families = names.families or { } - local checksums = names.checksums or { } - if filename then - local checksum = file.checksum(filename) - if checksums[checksum] and checksums[checksum] == filename then - log(3, "Font already indexed: %s", filename) - return - end - checksums[checksum] = filename - local info = fontloader.info(filename) - if info then - if type(info) == "table" and #info > 1 then - for index,_ in ipairs(info) do - local fullinfo = fontloader.fullinfo(filename, index-1) - if texmf then - fullinfo.filename = basename(filename) - end - mappings[#mappings+1] = fullinfo - if fullinfo.names.family then - if not families[fullinfo.names.family] then - families[fullinfo.names.family] = { } - end - table.insert(families[fullinfo.names.family], #mappings) - else - log(3, "Warning: font with broken names table: %s, ignored", filename) - end - end - else - local fullinfo = fontloader.fullinfo(filename) - if texmf then - fullinfo.filename = basename(filename) - end - mappings[#mappings+1] = fullinfo - if fullinfo.names.family then - if not families[fullinfo.names.family] then - families[fullinfo.names.family] = { } - end - table.insert(families[fullinfo.names.family], #mappings) - else - log(3, "Warning: font with broken names table: %s, ignored", filename) - end - end - else - log(1, "Failed to load %s", filename) - end - names.mappings = names.mappings or mappings - names.families = names.families or families - names.checksums = names.checksums or checksums - end -end - --- We need to detect the OS (especially cygwin) to convert paths. -local system = LUAROCKS_UNAME_S or io.popen("uname -s"):read("*l") -if system then - if system:match("^CYGWIN") then - system = 'cygwin' - elseif system:match("^Windows") then - system = 'windows' - else - system = 'unix' - end -else - system = 'unix' -- ? -end -log(2, "Detecting system: %s", system) - --- path normalization: --- - a\b\c -> a/b/c --- - a/../b -> b --- - /cygdrive/a/b -> a:/b -local function path_normalize(path) - if system ~= 'unix' then - path = path:gsub('\\', '/') - path = path:lower() - end - path = file.collapse_path(path) - if system == "cygwin" then - path = path:gsub('^/cygdrive/(%a)/', '%1:/') - end - return path -end - --- 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 --- - recursive is whether we scan all directories recursively (always false --- in this script) --- - texmf is a boolean saying if we are scanning a texmf directory (always --- true in this script) --- - scanned_fonts contains the list of alread scanned fonts, in order for them --- not to be scanned twice. The function populates this list with the --- fonts it scans. -local function scan_dir(dirname, names, recursive, texmf, scanned_fonts) - local list, found = { }, { } - local nbfound = 0 - for _,ext in ipairs { "otf", "ttf", "ttc", "dfont" } do - if recursive then pat = "/**." else pat = "/*." end - log(4, "Scanning '%s' for '%s' fonts", dirname, ext) - found = glob(dirname .. pat .. ext) - -- note that glob fails silently on broken symlinks, which happens - -- sometimes in TeX Live. - log(4, "%s fonts found", #found) - nbfound = nbfound + #found - table.append(list, found) - log(4, "Scanning '%s' for '%s' fonts", dirname, upper(ext)) - found = glob(dirname .. pat .. upper(ext)) - table.append(list, found) - nbfound = nbfound + #found - end - log(2, "%d fonts found in '%s'", nbfound, dirname) - for _,fnt in ipairs(list) do - fnt = path_normalize(fnt) - if not scanned_fonts[fnt] then - load_font(fnt, names, texmf) - scanned_fonts[fnt] = true - end - end -end - --- The function that scans all fonts in the texmf tree, through kpathsea --- variables OPENTYPEFONTS and TTFONTS of texmf.cnf -local function scan_texmf_tree(names) - if expandpath("$OSFONTDIR"):is_empty() then - log(1, "Scanning TEXMF fonts:") - else - log(1, "Scanning TEXMF and OS fonts:") - end - local scanned_fonts = {} - local fontdirs = expandpath("$OPENTYPEFONTS") - fontdirs = fontdirs .. string.gsub(expandpath("$TTFONTS"), "^\.", "") - if not fontdirs:is_empty() then - local explored_dirs = {} - fontdirs = splitpath(fontdirs) - -- hack, don't scan current dir - table.remove(fontdirs, 1) - count = 0 - for _,d in ipairs(fontdirs) do - if not explored_dirs[d] then - count = count + 1 - progress(count, #fontdirs) - scan_dir(d, names, false, true, scanned_fonts) - explored_dirs[d] = true - end - end - end - return scanned_fonts -end - --- this function takes raw data returned by fc-list, parses it, normalizes the --- paths and makes a list out of it. -local function read_fcdata(data) - local list = { } - for line in data:lines() do - line = line:gsub(": ", "") - local ext = string.lower(string.match(line,"^.+%.([^/\\]-)$")) - if ext == "otf" or ext == "ttf" or ext == "ttc" or ext == "dfont" then - list[#list+1] = path_normalize(line:gsub(": ", "")) - end - end - return list -end - --- This function scans the OS fonts through fontcache (fc-list), it executes --- only if OSFONTDIR is empty (which is the case under most Unix by default). --- If OSFONTDIR is non-empty, this means that the system fonts it contains have --- already been scanned, and thus we don't scan them again. -local function scan_os_fonts(names, scanned_fonts) - if expandpath("$OSFONTDIR"):is_empty() then - log(1, "Scanning system fonts:") - log(2, "Executing 'fc-list : file'") - local data = io.popen("fc-list : file", 'r') - log(2, "Parsing the result...") - local list = read_fcdata(data) - data:close() - log(2, "%d fonts found", #list) - log(2, "Scanning...", #list) - count = 0 - for _,fnt in ipairs(list) do - count = count + 1 - progress(count, #list) - if not scanned_fonts[fnt] then - load_font(fnt, names, false) - scanned_fonts[fnt] = true - end - end - end -end - -local function fontnames_init() - return { - mappings = { }, - families = { }, - checksums = { }, - version = luaotfload.fonts.version, - } -end - --- The main function, scans everything and writes the file. -local function reload(force) - texio.write("luaotfload | Generating font names database.") - local fnames - if force then - fnames = fontnames_init() - else - fnames = kpse.do_file(luaotfload.fonts.basename) - if fnames and fnames.version and fnames.version == luaotfload.fonts.version then - else - log(2, "Old font names database version, generating new one") - fnames = fontnames_init() - end - end - local savepath = luaotfload.fonts.directory - savepath = path_normalize(savepath) - if not lfs.isdir(savepath) then - log(1, "Creating directory %s", savepath) - lfs.mkdir(savepath) - if not lfs.isdir(savepath) then - texio.write_nl(string.format("Error: cannot create directory '%s', exiting.\n", savepath)) - os.exit(1) - end - end - savepath = savepath .. '/' .. luaotfload.fonts.basename - local fh = io.open(savepath, 'a+') - if not fh then - texio.write_nl(string.format("Error: cannot write file '%s', exiting.\n", savepath)) - os.exit(1) - end - fh:close() - -- we save the scanned fonts in a variable in order for scan_os_fonts - -- not to rescan them - local scanned_fonts = scan_texmf_tree(fnames) - scan_os_fonts (fnames, scanned_fonts) - log(1, "%s fonts in %s families saved in the database", - #fnames.mappings, #table.keys(fnames.families)) - io.savedata(savepath, table.serialize(fnames, true)) - log(1, "Saved font names database in %s\n", savepath) -end - -luaotfload.fonts.scan = scan_dir -luaotfload.fonts.reload = reload diff --git a/otfl-font-nms.lua b/otfl-font-nms.lua new file mode 100644 index 0000000..aeba0f1 --- /dev/null +++ b/otfl-font-nms.lua @@ -0,0 +1,375 @@ +-- This lua script is made to generate the font database for LuaTeX, in order +-- for it to be able to load a font according to its name, like XeTeX does. +-- +-- It is part of the luaotfload bundle, see luaotfload's README for legal +-- notice. + +-- some usual initializations +luaotfload = luaotfload or { } +luaotfload.fonts = { } + +luaotfload.fonts.module = { + name = "luaotfload.fonts", + version = 1.001, + date = "2010/01/12", + description = "luaotfload font database.", + author = "Khaled Hosny and Elie Roux", + copyright = "Luaotfload Development Team", + license = "CC0" +} + +kpse.set_program_name("luatex") + +local luaextra_file = kpse.find_file("luaextra.lua") +if not luaextra_file then + texio.write_nl("Error: cannot find 'luaextra.lua', exiting.") + os.exit(1) +end +dofile(luaextra_file) + +local splitpath, expandpath, glob, basename = file.split_path, kpse.expand_path, dir.glob, file.basename +local upper, format, rep = string.upper, string.format, string.rep + +function kpse.do_file(name) + return dofile(kpse.find_file(name)) +end + +-- the file name of the font database +luaotfload.fonts.basename = "otfl-names.lua" + +-- the path to add to TEXMFVAR or TEXMFSYSVAR to get the final directory in +-- normal cases +luaotfload.fonts.subtexmfvardir = "/tex/" + +-- the directory in which the database will be saved, can be overwritten +luaotfload.fonts.directory = kpse.expand_var("$TEXMFVAR") .. luaotfload.fonts.subtexmfvardir + +-- the version of the database, to be checked by the lookup function of +-- luaotfload +luaotfload.fonts.version = 2.004 + +-- Log facilities: +-- - level 0 is quiet +-- - level 1 is the progress bar +-- - level 2 prints the searched directories +-- - level 3 prints all the loaded fonts +-- - level 4 prints all informations when searching directories (debug only) +luaotfload.fonts.log_level = 1 + +local lastislog = 0 + +function luaotfload.fonts.log(lvl, fmt, ...) + if lvl <= luaotfload.fonts.log_level then + lastislog = 1 + texio.write_nl(format("luaotfload | %s", format(fmt,...))) + end +end + +local log = luaotfload.fonts.log + +-- The progress bar +local function progress(current, total) + if luaotfload.fonts.log_level == 1 then +-- local width = os.getenv("COLUMNS") -2 --doesn't work + local width = 78 + local percent = current/total + local gauge = format("[%s]", string.rpadd(" ", width, " ")) + if percent > 0 then + local done = string.rpadd("=", (width * percent) - 1, "=") .. ">" + gauge = format("[%s]", string.rpadd(done, width, " ") ) + end + if lastislog == 1 then + texio.write_nl("") + lastislog = 0 + end + io.stderr:write("\r"..gauge) + io.stderr:flush() + end +end + +function fontloader.fullinfo(...) + local t = { } + local f = fontloader.open(...) + local m = f and fontloader.to_table(f) + fontloader.close(f) + -- see http://www.microsoft.com/typography/OTSPEC/features_pt.htm#size + if m.fontstyle_name then + for _,v in pairs(m.fontstyle_name) do + if v.lang == 1033 then + t.fontstyle_name = v.name + end + end + end + if m.names then + for _,v in pairs(m.names) do + if v.lang == "English (US)" then + t.names = { + -- see http://developer.apple.com/textfonts/TTRefMan/RM06/Chap6name.html + fullname = v.names.compatfull or v.names.fullname, -- 18, 4 + family = v.names.preffamilyname or v.names.family, -- 17, 1 + subfamily = t.fontstyle_name or v.names.prefmodifiers or v.names.subfamily, -- opt. style, 16, 2 + psname = v.names.postscriptname --or t.fontname + } + end + end + end + t.fontname = m.fontname + t.fullname = m.fullname + t.familyname = m.familyname + t.filename = m.origname + t.weight = m.pfminfo.weight + t.width = m.pfminfo.width + t.slant = m.italicangle + -- don't waste the space with zero values + t.size = { + m.design_size ~= 0 and m.design_size or nil, + m.design_range_top ~= 0 and m.design_range_top or nil, + m.design_range_bottom ~= 0 and m.design_range_bottom or nil, + } + return t +end + +local function load_font(filename, names, texmf) + log(3, "Loading font: %s", filename) + local mappings = names.mappings or { } + local families = names.families or { } + local checksums = names.checksums or { } + if filename then + local checksum = file.checksum(filename) + if checksums[checksum] and checksums[checksum] == filename then + log(3, "Font already indexed: %s", filename) + return + end + checksums[checksum] = filename + local info = fontloader.info(filename) + if info then + if type(info) == "table" and #info > 1 then + for index,_ in ipairs(info) do + local fullinfo = fontloader.fullinfo(filename, index-1) + if texmf then + fullinfo.filename = basename(filename) + end + mappings[#mappings+1] = fullinfo + if fullinfo.names.family then + if not families[fullinfo.names.family] then + families[fullinfo.names.family] = { } + end + table.insert(families[fullinfo.names.family], #mappings) + else + log(3, "Warning: font with broken names table: %s, ignored", filename) + end + end + else + local fullinfo = fontloader.fullinfo(filename) + if texmf then + fullinfo.filename = basename(filename) + end + mappings[#mappings+1] = fullinfo + if fullinfo.names.family then + if not families[fullinfo.names.family] then + families[fullinfo.names.family] = { } + end + table.insert(families[fullinfo.names.family], #mappings) + else + log(3, "Warning: font with broken names table: %s, ignored", filename) + end + end + else + log(1, "Failed to load %s", filename) + end + names.mappings = names.mappings or mappings + names.families = names.families or families + names.checksums = names.checksums or checksums + end +end + +-- We need to detect the OS (especially cygwin) to convert paths. +local system = LUAROCKS_UNAME_S or io.popen("uname -s"):read("*l") +if system then + if system:match("^CYGWIN") then + system = 'cygwin' + elseif system:match("^Windows") then + system = 'windows' + else + system = 'unix' + end +else + system = 'unix' -- ? +end +log(2, "Detecting system: %s", system) + +-- path normalization: +-- - a\b\c -> a/b/c +-- - a/../b -> b +-- - /cygdrive/a/b -> a:/b +local function path_normalize(path) + if system ~= 'unix' then + path = path:gsub('\\', '/') + path = path:lower() + end + path = file.collapse_path(path) + if system == "cygwin" then + path = path:gsub('^/cygdrive/(%a)/', '%1:/') + end + return path +end + +-- 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 +-- - recursive is whether we scan all directories recursively (always false +-- in this script) +-- - texmf is a boolean saying if we are scanning a texmf directory (always +-- true in this script) +-- - scanned_fonts contains the list of alread scanned fonts, in order for them +-- not to be scanned twice. The function populates this list with the +-- fonts it scans. +local function scan_dir(dirname, names, recursive, texmf, scanned_fonts) + local list, found = { }, { } + local nbfound = 0 + for _,ext in ipairs { "otf", "ttf", "ttc", "dfont" } do + if recursive then pat = "/**." else pat = "/*." end + log(4, "Scanning '%s' for '%s' fonts", dirname, ext) + found = glob(dirname .. pat .. ext) + -- note that glob fails silently on broken symlinks, which happens + -- sometimes in TeX Live. + log(4, "%s fonts found", #found) + nbfound = nbfound + #found + table.append(list, found) + log(4, "Scanning '%s' for '%s' fonts", dirname, upper(ext)) + found = glob(dirname .. pat .. upper(ext)) + table.append(list, found) + nbfound = nbfound + #found + end + log(2, "%d fonts found in '%s'", nbfound, dirname) + for _,fnt in ipairs(list) do + fnt = path_normalize(fnt) + if not scanned_fonts[fnt] then + load_font(fnt, names, texmf) + scanned_fonts[fnt] = true + end + end +end + +-- The function that scans all fonts in the texmf tree, through kpathsea +-- variables OPENTYPEFONTS and TTFONTS of texmf.cnf +local function scan_texmf_tree(names) + if expandpath("$OSFONTDIR"):is_empty() then + log(1, "Scanning TEXMF fonts:") + else + log(1, "Scanning TEXMF and OS fonts:") + end + local scanned_fonts = {} + local fontdirs = expandpath("$OPENTYPEFONTS") + fontdirs = fontdirs .. string.gsub(expandpath("$TTFONTS"), "^\.", "") + if not fontdirs:is_empty() then + local explored_dirs = {} + fontdirs = splitpath(fontdirs) + -- hack, don't scan current dir + table.remove(fontdirs, 1) + count = 0 + for _,d in ipairs(fontdirs) do + if not explored_dirs[d] then + count = count + 1 + progress(count, #fontdirs) + scan_dir(d, names, false, true, scanned_fonts) + explored_dirs[d] = true + end + end + end + return scanned_fonts +end + +-- this function takes raw data returned by fc-list, parses it, normalizes the +-- paths and makes a list out of it. +local function read_fcdata(data) + local list = { } + for line in data:lines() do + line = line:gsub(": ", "") + local ext = string.lower(string.match(line,"^.+%.([^/\\]-)$")) + if ext == "otf" or ext == "ttf" or ext == "ttc" or ext == "dfont" then + list[#list+1] = path_normalize(line:gsub(": ", "")) + end + end + return list +end + +-- This function scans the OS fonts through fontcache (fc-list), it executes +-- only if OSFONTDIR is empty (which is the case under most Unix by default). +-- If OSFONTDIR is non-empty, this means that the system fonts it contains have +-- already been scanned, and thus we don't scan them again. +local function scan_os_fonts(names, scanned_fonts) + if expandpath("$OSFONTDIR"):is_empty() then + log(1, "Scanning system fonts:") + log(2, "Executing 'fc-list : file'") + local data = io.popen("fc-list : file", 'r') + log(2, "Parsing the result...") + local list = read_fcdata(data) + data:close() + log(2, "%d fonts found", #list) + log(2, "Scanning...", #list) + count = 0 + for _,fnt in ipairs(list) do + count = count + 1 + progress(count, #list) + if not scanned_fonts[fnt] then + load_font(fnt, names, false) + scanned_fonts[fnt] = true + end + end + end +end + +local function fontnames_init() + return { + mappings = { }, + families = { }, + checksums = { }, + version = luaotfload.fonts.version, + } +end + +-- The main function, scans everything and writes the file. +local function reload(force) + texio.write("luaotfload | Generating font names database.") + local fnames + if force then + fnames = fontnames_init() + else + fnames = kpse.do_file(luaotfload.fonts.basename) + if fnames and fnames.version and fnames.version == luaotfload.fonts.version then + else + log(2, "Old font names database version, generating new one") + fnames = fontnames_init() + end + end + local savepath = luaotfload.fonts.directory + savepath = path_normalize(savepath) + if not lfs.isdir(savepath) then + log(1, "Creating directory %s", savepath) + lfs.mkdir(savepath) + if not lfs.isdir(savepath) then + texio.write_nl(string.format("Error: cannot create directory '%s', exiting.\n", savepath)) + os.exit(1) + end + end + savepath = savepath .. '/' .. luaotfload.fonts.basename + local fh = io.open(savepath, 'a+') + if not fh then + texio.write_nl(string.format("Error: cannot write file '%s', exiting.\n", savepath)) + os.exit(1) + end + fh:close() + -- we save the scanned fonts in a variable in order for scan_os_fonts + -- not to rescan them + local scanned_fonts = scan_texmf_tree(fnames) + scan_os_fonts (fnames, scanned_fonts) + log(1, "%s fonts in %s families saved in the database", + #fnames.mappings, #table.keys(fnames.families)) + io.savedata(savepath, table.serialize(fnames, true)) + log(1, "Saved font names database in %s\n", savepath) +end + +luaotfload.fonts.scan = scan_dir +luaotfload.fonts.reload = reload -- cgit v1.2.3