module("luaotfload", package.seeall) luaotfload.module = { name = "luaotfload", version = 2.2, date = "2013/04/15", description = "OpenType layout system.", author = "Elie Roux & Hans Hagen", copyright = "Elie Roux", license = "CC0" } local luatexbase = luatexbase local type, next = type, next local stringfind = string.find local stringsub = string.sub local stringmatch = string.match local stringformat = string.format local find_file = kpse.find_file local add_to_callback, create_callback = luatexbase.add_to_callback, luatexbase.create_callback local reset_callback, call_callback = luatexbase.reset_callback, luatexbase.call_callback local dummy_function = function () end _G.luaotfload = _G.luaotfload or { } local luaotfload = _G.luaotfload --[[doc-- No final decision has been made on how to handle font definition. At the moment, there are three candidates: The \identifier{generic} callback as hard-coded in the font loader, the \identifier{old} wrapper, and a simplified version of the latter (\identifier{patch}) that does nothing besides applying font patches. --doc]]-- luaotfload.font_definer = "patch" --- | “generic” | “old” local error, warning, info, log = luatexbase.provides_module(luaotfload.module) --[[doc-- This is a necessary initalization in order not to rebuild an existing font. Maybe 600 should be replaced by \texmacro{pdfpkresolution} %% (why?) or \luafunction{texconfig.pk_dpi} (and it should be replaced dynamically), but we don't have access (yet) to the \identifier{texconfig} table, so we let it be 600. Anyway, it does still work fine even if \texmacro{pdfpkresolution} is changed. --doc]]-- kpse.init_prog("", 600, "/") --[[doc-- We set the minimum version requirement for \LUATEX to v0.74, as it was the first version to include version 5.2 of the \LUA interpreter. --doc]]-- local luatex_version = 74 if tex.luatexversion < luatex_version then warning("LuaTeX v%.2f is old, v%.2f is recommended.", tex.luatexversion/100, luatex_version /100) end --[[doc-- \subsection{Module loading} We load the files imported from \CONTEXT with this function. It automatically prepends the prefix \fileent{otfl-} to its argument, so we can refer to the files with their actual \CONTEXT name. --doc]]-- local fl_prefix = "otfl" -- “luatex” for luatex-plain local loadmodule = function (name) local tofind = fl_prefix .."-"..name local found = find_file(tofind,"tex") if found then log("loading file %s.", found) dofile(found) else error("file %s not found.", tofind) end end --[[doc-- Virtual fonts are resolved via a callback. \luafunction{find_vf_file} derives the name of the virtual font file from the filename. (NB: \CONTEXT handles this likewise in \fileent{font-vf.lua}.) --doc]]-- local Cs, P, lpegmatch = lpeg.Cs, lpeg.P, lpeg.match local p_dot, p_slash = P".", P"/" local p_suffix = (p_dot * (1 - p_dot - p_slash)^1 * P(-1)) / "" local p_removesuffix = Cs((p_suffix + 1)^1) local find_vf_file = function (name) local fullname = find_file(name, "ovf") if not fullname then --fullname = find_file(file.removesuffix(name), "ovf") fullname = find_file(lpegmatch(p_removesuffix, name), "ovf") end if fullname then log("loading virtual font file %s.", fullname) end return fullname end --[[doc-- \subsection{Preparing the Font Loader} We treat the fontloader as a black box so behavior is consistent between formats. The wrapper file is \fileent{otfl-fonts.lua} which we imported from \href{http://standalone.contextgarden.net/current/context/experimental/tex/generic/context/luatex/}{\LUATEX-Plain}. It has roughly two purposes: \begin{enumerate} \item insert the functionality required for fontloader; and \item put it in place via the respective callbacks. \end{enumerate} How the first step is executed depends on the presence on the \emphasis{merged font loader code}. In \identifier{luaotfload} this is contained in the file \fileent{otfl-fonts-merged.lua}. If this file cannot be found, the original libraries from \CONTEXT of which the merged code was composed are loaded instead. Hans provides two global tables to control the font loader: \begin{itemize} \item \luafunction{generic_context}: encapsulation mechanism, callback functions \item \luafunction{non generic_context}: customized code insertion \end{itemize} With \luafunction{non_generic_context} we can tailor the font loader insertion to our file naming habits (key \luafunction{load_before}). Additionally, \luafunction{skip_loading} can be unset to force loading of the original libraries as though the merged code was absent. Another key, \luafunction{load_after} is called at the time when the font loader is actually inserted. In combination with the option \luafunction{no_callbacks_yet} in \luafunction{generic_context}, we can insert our own, \identifier{luatexbase}-style callback handling here. --doc]]-- if not _G. generic_context then _G. generic_context = { } end if not _G.non_generic_context then _G.non_generic_context = { } end local generic_context = generic_context local non_generic_context =non_generic_context generic_context.no_callbacks_yet = true _G.non_generic_context = { luatex_fonts = { load_before = "otfl-fonts-merged.lua", -- load_after = nil, --- TODO, this is meant for callbacks skip_loading = true, }} --[[doc-- In its raw form, the font loader will write to the terminal quite liberally, not using the proper channels (loggers) even of \CONTEXT. To make it behave we temporarily replace two functions from the \luafunction{texio} library with wrappers that redirect output to the log. Just in case Hans decides to call \luafunction{texio.write*} with the optional target parameter (which he doesn’t at the moment), we catch the first argument and skip it where appropriate. The originals are backed up and restored after loading \fileent{otfl-fonts.lua}. Should we decide to do our own packaging (we’re capable of that anyways), this will most likely become unnecessary. --doc]]-- local normal_write, normal_write_nl = texio.write, texio.write_nl local log_template = "luaotfload: %s" local fake_write = function (first, rest) if first == "log" or first == "term" then -- ignore normal_write("log", stringformat(log_template, rest)) else normal_write("log", stringformat(log_template, first)) end end local fake_write_nl = function (first, rest) if first == "log" or first == "term" then -- ignore normal_write_nl("log", stringformat(log_template, rest)) else normal_write_nl("log", stringformat(log_template, first, rest)) end end texio.write, texio.write_nl = fake_write, fake_write_nl --[[doc-- The imported font loader will call \luafunction{callback.register} once while reading \fileent{font-def.lua}. This is unavoidable unless we modify the imported files, but harmless if we make it call a dummy instead. --doc]]-- local trapped_register = callback.register callback.register = dummy_function --[[doc-- Now that things are sorted out we can finally load the fontloader. --doc]]-- loadmodule"fonts.lua" --[[doc-- Here we restore the original \luafunction{texio} functions. --doc]]-- texio.write, texio.write_nl = normal_write, normal_write_nl --[[doc-- By default, the fontloader requires a number of \emphasis{private attributes} for internal use. These must be kept consistent with the attribute handling methods as provided by \identifier{luatexbase}. Our strategy is to override the function that allocates new attributes before we initialize the font loader, making it a wrapper around \luafunction{luatexbase.new_attribute}.\footnote{% Many thanks, again, to Hans Hagen for making this part configurable! } The attribute identifiers are prefixed “\fileent{otfl@}” to avoid name clashes. --doc]]-- do local new_attribute = luatexbase.new_attribute local the_attributes = luatexbase.attributes _G.attributes = _G.attributes or { } _G.attributes.private = function (name) local attr = "otfl@" .. name local number = the_attributes[attr] if not number then number = new_attribute(attr) end return number end end --[[doc-- \subsection{Callbacks} After the fontloader is ready we can restore the callback trap from \identifier{luatexbase}. --doc]]-- callback.register = trapped_register --[[doc-- We do our own callback handling with the means provided by luatexbase. Note: \luafunction{pre_linebreak_filter} and \luafunction{hpack_filter} are coupled in \CONTEXT in the concept of \emphasis{node processor}. --doc]]-- add_to_callback("pre_linebreak_filter", generic_context.callback_pre_linebreak_filter, "luaotfload.node_processor", 1) add_to_callback("hpack_filter", generic_context.callback_hpack_filter, "luaotfload.node_processor", 1) add_to_callback("find_vf_file", find_vf_file, "luaotfload.find_vf_file") loadmodule"font-otc.lua" -- TODO check what we can drop from otfl-features loadmodule"lib-dir.lua" -- required by font-nms loadmodule"luat-ovr.lua" if fonts and fonts.readers.tfm then -------------------------------------------------------------------- --- OFM; read this first -------------------------------------------------------------------- --- I can’t quite make out whether this is still relevant --- as those ofm fonts always fail, even in the 2011 version --- (mktexpk: don't know how to create bitmap font for omarabb.ofm) --- the font loader appears to read ofm like tfm so if this --- hack was supposed achieve that, we should excise it anyways fonts.readers.ofm = fonts.readers.tfm fonts.handlers.ofm = fonts.handlers.tfm --- empty anyways fonts.formats.ofm = fonts.formats.tfm --- “type1” --- fonts.readers.sequence[#fonts.readers.sequence+1] = "ofm" -------------------------------------------------------------------- end --[[doc-- Now we load the modules written for \identifier{luaotfload}. --doc]]-- loadmodule"font-pfb.lua" --- new in 2.0, added 2011 loadmodule"font-nms.lua" loadmodule"font-clr.lua" loadmodule"font-ltx.lua" --- new in 2.0, added 2011 --[[doc-- We create a callback for patching fonts on the fly, to be used by other packages. It initially contains the empty function that we are going to override below. --doc]]-- create_callback("luaotfload.patch_font", "simple", dummy_function) --[[doc-- This is a wrapper for the imported font loader. As of 2013, everything it does appear to be redundand, so we won’t use it unless somebody points out a cogent reason. Nevertheless, it has been adapted to work with the current structure of font data objects and will stay here for reference / until breakage is reported. \emphasis{TODO} This one also enables patching fonts. The current fontloader apparently comes with a dedicated mechanism for that already: enhancers. How those work remains to be figured out. --doc]]-- local define_font_wrapper = function (...) --- we use “tfmdata” (not “fontdata”) for consistency with the --- font loader local tfmdata = fonts.definers.read(...) if type(tfmdata) == "table" and tfmdata.shared then local metadata = tfmdata.shared.rawdata.metadata local mathdata = metadata.math --- do all fonts have this field? if mathdata then local mathconstants = { } --- why new hash, not modify in place? local units_per_em = metadata.units_per_em local size = tfmdata.size for k,v in next, mathdata do --- afaics this is alread taken care of by --- definers.read if stringfind(k, "Percent") then -- keep percent values as is print(k,v) mathconstants[k] = v else mathconstants[k] = v / units_per_em * size end end --- for \overwithdelims --- done by definers.read as well mathconstants.FractionDelimiterSize = 1.01 * size --- fontloader has 2.4 × size mathconstants.FractionDelimiterDisplayStyleSize = 2.39 * size tfmdata.MathConstants = mathconstants end call_callback("luaotfload.patch_font", tfmdata) end return tfmdata end --[[doc-- \subsection{\CONTEXT override} We provide a simplified version of the original font definition callback. --doc]]-- local read_font_file = fonts.definers.read local patch_defined_font = function (...) local tfmdata = read_font_file(...)-- spec -> size -> id -> tmfdata if type(tfmdata) == "table" then call_callback("luaotfload.patch_font", tfmdata) end -- inspect(table.keys(tfmdata)) return tfmdata end caches.compilemethod = "both" reset_callback("define_font") --[[doc-- Finally we register the callbacks --doc]]-- if luaotfload.font_definer == "old" then add_to_callback("define_font", define_font_wrapper, "luaotfload.define_font", 1) elseif luaotfload.font_definer == "generic" then add_to_callback("define_font", generic_context.callback_define_font, "luaotfload.define_font", 1) elseif luaotfload.font_definer == "patch" then add_to_callback("define_font", patch_defined_font, "luaotfload.define_font", 1) end --[[todo-- --- The manual promises coercion of the file: lookup if --- the asked name is enclosed in brackets. --- A couple things make me doubt that this is the case: --- --- 1) there doesn’t appear to be code for these cases --- 2) the brackets remain part of the file name --- 3) we still get calls to names.resolve which --- ignores the “lookup” field of the spec it gets --- --- For this reason here is some code that a) coerces --- file: lookups in these cases and b) strips the brackets --- from the file name. As we *still* get name: lookups even --- though this code is active I’ll just leave it here --- for reference, ineffective as it is. do local getspecification, makespecification = fonts.definers.getspecification, fonts.definers.makespecification local analyze = function (specification, size) local lookup, name, sub, method, detail = getspecification(specification or "") local filename = stringmatch(name, "^%[(.*)%]$") if filename then lookup = "file" --> coerce file: name = filename --> remove brackets end return makespecification(specification, lookup, name, sub, method, detail, size) end fonts.definers.analyze = analyze end --]]-- loadmodule"features.lua" -- vim:tw=71:sw=4:ts=4:expandtab