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 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-- 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-- 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