diff options
Diffstat (limited to 'Master/texmf-dist/doc/luatex/fontloader-luaotfload/luaotfload-letterspace.luax')
-rw-r--r-- | Master/texmf-dist/doc/luatex/fontloader-luaotfload/luaotfload-letterspace.luax | 683 |
1 files changed, 0 insertions, 683 deletions
diff --git a/Master/texmf-dist/doc/luatex/fontloader-luaotfload/luaotfload-letterspace.luax b/Master/texmf-dist/doc/luatex/fontloader-luaotfload/luaotfload-letterspace.luax deleted file mode 100644 index df93dbe1b70..00000000000 --- a/Master/texmf-dist/doc/luatex/fontloader-luaotfload/luaotfload-letterspace.luax +++ /dev/null @@ -1,683 +0,0 @@ -if not modules then modules = { } end modules ['letterspace'] = { - version = "2.8", - comment = "companion to luaotfload-main.lua", - author = "Hans Hagen, PRAGMA-ADE, Hasselt NL; adapted by Philipp Gesang", - copyright = "PRAGMA ADE / ConTeXt Development Team", - license = "see context related readme files" -} - ---- This code diverged quite a bit from its origin in Context. Please ---- do *not* report bugs on the Context list. - -local log = luaotfload.log -local logreport = log.report - --- UF -texio.write_nl ("------------------") -texio.write_nl ("!!!!! UF: Using CHANGED luaotfload-letterspace 2017-07-14 !!!!!") -texio.write_nl ("------------------") --- /UF - -local getmetatable = getmetatable -local require = require -local setmetatable = setmetatable -local tonumber = tonumber - -local next = next -local nodes, node, fonts = nodes, node, fonts - -local nodedirect = nodes.nuts - -local getfield = nodedirect.getfield -local setfield = nodedirect.setfield - -local field_setter = function (name) return function (n, ...) setfield (n, name, ...) end end -local field_getter = function (name) return function (n, ...) getfield (n, name, ...) end end - -local getfont = nodedirect.getfont -local getid = nodedirect.getid - -local getnext = nodedirect.getnext or field_getter "next" -local setnext = nodedirect.setnext or field_setter "next" - -local getprev = nodedirect.getprev or field_getter "prev" -local setprev = nodedirect.setprev or field_setter "prev" - ---- since r5336 -local getboth = nodedirect.getboth or function (n) - return getprev (n), getnext (n) -end - -local setlink = nodedirect.setlink or function (a, b) - setnext (a, b) - setprev (b, a) -end - -local getdisc = nodedirect.getdisc or field_getter "disc" -local setdisc = nodedirect.setdisc or field_setter "disc" - -local getsubtype = nodedirect.getsubtype or field_getter "subtype" -local setsubtype = nodedirect.setsubtype or field_setter "subtype" - -local getchar = nodedirect.getchar or field_getter "subtype" -local setchar = nodedirect.setchar or field_setter "subtype" - -local find_node_tail = nodedirect.tail -local todirect = nodedirect.tonut -local tonode = nodedirect.tonode - -local insert_node_before = nodedirect.insert_before -local free_node = nodedirect.free -- may cause double free -local free_node = function (n) - logreport ("term", 5, "letterspace", "not calling free_node(%d)", n) - -- free_node (n) -end -local copy_node = nodedirect.copy -local new_node = nodedirect.new - -local nodepool = nodedirect.pool --- local new_kern = nodepool.kern -- UF removed 2017-07-14 - -local nodecodes = nodes.nodecodes - -local glyph_code = nodecodes.glyph -local kern_code = nodecodes.kern -local disc_code = nodecodes.disc -local math_code = nodecodes.math -local glue_code = nodecodes.glue - -local fonthashes = fonts.hashes -local chardata = fonthashes.characters -local quaddata = fonthashes.quads -local otffeatures = fonts.constructors.newfeatures "otf" - ---[[doc-- - - Since the letterspacing method was derived initially from Context’s - typo-krn.lua we keep the sub-namespace “letterspace” inside the - “luaotfload” table. - ---doc]]-- - -luaotfload.letterspace = luaotfload.letterspace or { } -local letterspace = luaotfload.letterspace - -letterspace.keepligature = false -letterspace.keeptogether = false - ----=================================================================--- ---- preliminary definitions ----=================================================================--- --- We set up a layer emulating some Context internals that are needed --- for the letterspacing callback. ------------------------------------------------------------------------ ---- node-ini ------------------------------------------------------------------------ - -local bothways = function (t) return table.swapped (t, t) end -local kerncodes = bothways { [0] = "fontkern" - , [1] = "userkern" - , [2] = "accentkern" - } -local skipcodes = bothways { [0] = "userskip" - , [13] = "spaceskip" - , [14] = "xspaceskip" - } - -kerncodes.kerning = kerncodes.fontkern --- idiosyncrasy -local kerning_code = kerncodes.kerning -local userkern_code = kerncodes.userkern -local userskip_code = skipcodes.userskip -local spaceskip_code = skipcodes.spaceskip -local xspaceskip_code = skipcodes.xspaceskip - ------------------------------------------------------------------------ ---- node-res ------------------------------------------------------------------------ - -local glue_spec = new_node "glue_spec" - -local new_gluespec = function (width, - stretch, shrink, - stretch_order, shrink_order) - local spec = copy_node(glue_spec) - if width then setfield(spec, "width" , width ) end - if stretch then setfield(spec, "stretch" , stretch ) end - if shrink then setfield(spec, "shrink" , shrink ) end - if stretch_order then setfield(spec, "stretch_order", stretch_order) end - if shrink_order then setfield(spec, "shrink_order" , shrink_order ) end - return spec -end - -local new_glue = function (width, stretch, shrink, - stretch_order, shrink_order) - local n = new_node "glue" - if not width then return n end - -- no spec - if width == false then - local width = tonumber(width) - if width then - setfield(n, "spec", - new_gluespec(width, stretch, shrink, - stretch_order, shrink_order)) - end - else - -- shared - setfield(n, "spec", copy_node(width)) - end - return n -end - ------------------------------------------------------------------------ ---- font-hsh ------------------------------------------------------------------------ ---- some initialization resembling font-hsh -local fonthashes = fonts.hashes -local identifiers = fonthashes.identifiers --- was: fontdata -local chardata = fonthashes.characters -local quaddata = fonthashes.quads -local parameters = fonthashes.parameters - ---- ('a, 'a) hash -> (('a, 'a) hash -> 'a -> 'a) -> ('a, 'a) hash -local setmetatableindex = function (t, f) - local mt = getmetatable(t) - if mt then - mt.__index = f - else - setmetatable(t, { __index = f }) - end - return t -end - -if not parameters then - parameters = { } - setmetatableindex(parameters, function(t, k) - if k == true then - return parameters[currentfont()] - else - local parameters = identifiers[k].parameters - t[k] = parameters - return parameters - end - end) - --fonthashes.parameters = parameters -end - -if not chardata then - chardata = { } - setmetatableindex(chardata, function(t, k) - if k == true then - return chardata[currentfont()] - else - local tfmdata = identifiers[k] - if not tfmdata then --- unsafe - tfmdata = font.fonts[k] - end - if tfmdata then - local characters = tfmdata.characters - t[k] = characters - return characters - end - end - end) - fonthashes.characters = chardata -end - -if not quaddata then - quaddata = { } - setmetatableindex(quaddata, function(t, k) - if k == true then - return quads[currentfont()] - else - local parameters = parameters[k] - local quad = parameters and parameters.quad or 0 - t[k] = quad - return quad - end - end) - --fonthashes.quads = quaddata -end - ----=================================================================--- ---- character kerning functionality ----=================================================================--- - --- UF changed 2017-07-14 -local newUF = node.direct.new - -local kern_injector = function (fillup, kern) - if fillup then - local g = newUF("glue") - setfield(g, "stretch", kern) - setfield(g, "stretch_order", 1) - return g - end - local g = newUF("kern") - setfield(g,"kern",kern) - return g -end --- /UF - -local kernable_skip = function (n) - local st = getsubtype (n) - return st == userskip_code - or st == spaceskip_code - or st == xspaceskip_code -end - -local function spec_injector (fillup, width, stretch, shrink) - if fillup then - local spec = new_gluespec(width, 2 * stretch, 2 * shrink) - setfield(spec, "stretch_order", 1) - return spec - end - return new_gluespec(width,stretch,shrink) -end - ---[[doc-- - - Caveat lector. - This is an adaptation of the Context character kerning mechanism - that emulates XeTeX-style fontwise letterspacing. Note that in its - present state it is far inferior to the original, which is - attribute-based and ignores font-boundaries. Nevertheless, due to - popular demand the following callback has been added. - ---doc]]-- - -local kernfactors = { } --- fontid -> factor - -local kerncharacters -kerncharacters = function (head) - local start = head - local lastfont = nil - local keepligature = letterspace.keepligature --- function - local keeptogether = letterspace.keeptogether --- function - local fillup = false - - local identifiers = fonthashes.identifiers - local kernfactors = kernfactors - local firstkern = true - - while start do - local id = getid(start) - if id == glyph_code then - --- 1) look up kern factor (slow, but cached rudimentarily) - local krn - local fontid = getfont(start) - do - krn = kernfactors[fontid] - if not krn then - local tfmdata = identifiers[fontid] - if not tfmdata then -- unsafe - tfmdata = font.fonts[fontid] - end - if tfmdata then - fontproperties = tfmdata.properties - if fontproperties then - krn = fontproperties.kerncharacters - end - end - kernfactors[fontid] = krn - end - if not krn or krn == 0 then - firstkern = true - goto nextnode - elseif firstkern then - firstkern = false - if (id ~= disc_code) and (not getfield(start, "components")) then - --- not a ligature, skip node - goto nextnode - end - end - end - - if krn == "max" then - krn = .25 - fillup = true - else - fillup = false - end - - lastfont = fontid - - --- 2) resolve ligatures - local c = getfield(start, "components") - - if c then - if keepligature and keepligature(start) then - -- keep 'm - c = nil - else - while c do - local s = start - local p, n = getboth (s) - if p then - setlink (p, c) - else - head = c - end - if n then - local tail = find_node_tail(c) - setlink (tail, n) - end - start = c - setfield(s, "components", nil) - free_node(s) --> double free with multipart components - c = getfield (start, "components") - end - end - end -- kern ligature - - --- 3) apply the extra kerning - local prev = getprev(start) - if prev then - local pid = getid(prev) - - if not pid then - -- nothing - - elseif pid == glue_code and kernable_skip(prev) then - local spec = getfield(prev, "spec") - local wd = getfield(spec, "width") - if wd > 0 then - --- formula taken from Context - --- existing_width extended by four times the - --- width times the font’s kernfactor - local newwd = wd + --[[two en to a quad]] 4 * wd * krn - local stretched = (getfield(spec,"stretch") * newwd) / wd - local shrunk = (getfield(spec,"shrink") * newwd) / wd - setfield(prev, "spec", - spec_injector(fillup, newwd, stretched, shrunk)) - end - - elseif pid == kern_code then - local prev_subtype = getsubtype(prev) - if prev_subtype == kerning_code --- context does this by means of an - or prev_subtype == userkern_code --- attribute; we may need a test - then - - local pprev = getprev(prev) - local pprev_id = getid(pprev) - - if keeptogether - and pprev_id == glyph_code - and keeptogether(pprev, start) - then - -- keep - else - setsubtype (prev, userkern_code) - local prev_kern = getfield(prev, "kern") - prev_kern = prev_kern + quaddata[lastfont] * krn - setfield (prev, "kern", prev_kern) - end - end - - elseif pid == glyph_code then - if getfont(prev) == lastfont then - local prevchar = getchar(prev) - local lastchar = getchar(start) - if keeptogether and keeptogether(prev, start) then - -- keep 'm - elseif identifiers[lastfont] then - local lastfontchars = chardata[lastfont] - if lastfontchars then - local prevchardata = lastfontchars[prevchar] - if not prevchardata then - --- font doesn’t contain the glyph - else - local kern = 0 - local kerns = prevchardata.kerns - if kerns then kern = kerns[lastchar] or kern end - krn = kern + quaddata[lastfont]*krn -- here - insert_node_before(head,start,kern_injector(fillup,krn)) - end - end - end - else - krn = quaddata[lastfont]*krn -- here - insert_node_before(head,start,kern_injector(fillup,krn)) - end - - elseif pid == disc_code then - local disc = prev -- disc - local pre, post, replace = getdisc (disc) - local prv = getprev(disc) - local nxt = getnext(disc) - - if pre and prv then -- must pair with start.prev - -- this one happens in most cases - local before = copy_node(prv) - setprev(pre, before) - setnext(before, pre) - setprev(before, nil) - pre = kerncharacters (before) - pre = getnext(pre) - setprev(pre, nil) - setfield(disc, "pre", pre) - free_node(before) - end - - if post and nxt then -- must pair with start - local after = copy_node(nxt) - local tail = find_node_tail(post) - setnext(tail, after) - setprev(after, tail) - setnext(after, nil) - post = kerncharacters (post) - setnext(tail, nil) - setfield(disc, "post", post) - free_node(after) - end - - if replace and prv and nxt then -- must pair with start and start.prev - local before = copy_node(prv) - local after = copy_node(nxt) - local tail = find_node_tail(replace) - setprev(replace, before) - setnext(before, replace) - setprev(before, nil) - setnext(tail, after) - setprev(after, tail) - setnext(after, nil) - replace = kerncharacters (before) - replace = getnext(replace) - setprev(replace, nil) - setnext(getprev(after), nil) - setfield(disc, "replace", replace) - free_node(after) - free_node(before) - - elseif identifiers[lastfont] then - if prv - and getid(prv) == glyph_code - and getfont(prv) == lastfont - then - local kern = 0 - local prevchar = getchar(prv) - local lastchar = getchar(start) - local lastfontchars = chardata[lastfont] - if lastfontchars then - local prevchardata = lastfontchars[prevchar] - if not prevchardata then - --- font doesn’t contain the glyph - else - local kerns = prevchardata.kerns - if kerns then kern = kerns[lastchar] or kern end - end - end - krn = kern + quaddata[lastfont]*krn -- here - else - krn = quaddata[lastfont]*krn -- here - end - setfield(disc, "replace", kern_injector(false, krn)) - end --[[if replace and prv and nxt]] - end --[[if not pid]] - end --[[if prev]] - end --[[if id == glyph_code]] - - ::nextnode:: - if start then - start = getnext(start) - end - end - return head -end - ----=================================================================--- ---- integration ----=================================================================--- - ---- · callback: kerncharacters ---- · enabler: enablefontkerning ---- · disabler: disablefontkerning - ---- callback wrappers - ---- (node_t -> node_t) -> string -> string list -> bool -local registered_as = { } --- procname -> callbacks -local add_processor = function (processor, name, ...) - local callbacks = { ... } - for i=1, #callbacks do - luatexbase.add_to_callback(callbacks[i], processor, name) - end - registered_as[name] = callbacks --- for removal - return true -end - ---- string -> bool -local remove_processor = function (name) - local callbacks = registered_as[name] - if callbacks then - for i=1, #callbacks do - luatexbase.remove_from_callback(callbacks[i], name) - end - return true - end - return false --> unregistered -end - ---- When font kerning is requested, usually by defining a font with the ---- ``letterspace`` parameter, we inject a wrapper for the ---- ``kerncharacters()`` node processor in the relevant callbacks. This ---- wrapper initially converts the received head node into its “direct” ---- counterpart. Likewise, the callback result is converted back to an ---- ordinary node prior to returning. Internally, ``kerncharacters()`` ---- performs all node operations on direct nodes. - ---- unit -> bool -local enablefontkerning = function ( ) - - local handler = function (hd) - local direct_hd = todirect (hd) - logreport ("term", 5, "letterspace", - "kerncharacters() invoked with node.direct interface \z - (``%s`` -> ``%s``)", tostring (hd), tostring (direct_hd)) - local direct_hd = kerncharacters (direct_hd) - if not direct_hd then --- bad - logreport ("both", 0, "letterspace", - "kerncharacters() failed to return a valid new head") - end - return tonode (direct_hd) - end - - return add_processor( handler - , "luaotfload.letterspace" - , "pre_linebreak_filter" - , "hpack_filter") -end - ---- unit -> bool ----al disablefontkerning = function ( ) ----eturn remove_processor "luaotfload.letterspace" ---- - ---[[doc-- - - Fontwise kerning is enabled via the “kernfactor” option at font - definition time. Unlike the Context implementation which relies on - Luatex attributes, it uses a font property for passing along the - letterspacing factor of a node. - - The callback is activated the first time a letterspaced font is - requested and stays active until the end of the run. Since the font - is a property of individual glyphs, every glyph in the entire - document must be checked for the kern property. This is quite - inefficient compared to Context’s attribute based approach, but Xetex - compatibility reduces our options significantly. - ---doc]]-- - - -local fontkerning_enabled = false --- callback state - ---- fontobj -> float -> unit -local initializefontkerning = function (tfmdata, factor) - if factor ~= "max" then - factor = tonumber (factor) or 0 - end - if factor == "max" or factor ~= 0 then - local fontproperties = tfmdata.properties - if fontproperties then - --- hopefully this field stays unused otherwise - fontproperties.kerncharacters = factor - end - if not fontkerning_enabled then - fontkerning_enabled = enablefontkerning () - end - end -end - ---- like the font colorization, fontwise kerning is hooked into the ---- feature mechanism - -otffeatures.register { - name = "kernfactor", - description = "kernfactor", - initializers = { - base = initializefontkerning, - node = initializefontkerning, - } -} - ---[[doc-- - - The “letterspace” feature is essentially identical with the above - “kernfactor” method, but scales the factor to percentages to match - Xetex’s behavior. (See the Xetex reference, page 5, section 1.2.2.) - - Since Xetex doesn’t appear to have a (documented) “max” keyword, we - assume all input values are numeric. - ---doc]]-- - -local initializecompatfontkerning = function (tfmdata, percentage) - local factor = tonumber (percentage) - if not factor then - logreport ("both", 0, "letterspace", - "Invalid argument to letterspace: %s (type %q), " .. - "was expecting percentage as Lua number instead.", - percentage, type (percentage)) - return - end - return initializefontkerning (tfmdata, factor * 0.01) -end - -otffeatures.register { - name = "letterspace", - description = "letterspace", - initializers = { - base = initializecompatfontkerning, - node = initializecompatfontkerning, - } -} - ---[[example-- - -See https://bitbucket.org/phg/lua-la-tex-tests/src/tip/pln-letterspace-8-compare.tex -for an example. - ---example]]-- - ---- vim:sw=2:ts=2:expandtab:tw=71 - |