From 5b773f9c6d94616316734a0070cae68ce6a67523 Mon Sep 17 00:00:00 2001 From: Philipp Gesang Date: Sun, 14 Dec 2014 12:14:51 +0100 Subject: [letterspace] convert to node.direct MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is an experiment: The character kerning callback has been converted in its entirety to utilize the not-so-new direct node API. Since the translation was mechanical only to a certain extent, this may have introduced errors. On the other hand, the revised code resembles its distant ancestor in Context’s ``typo-krn.lua`` much more closely again, which may come in handy in the future. --- src/luaotfload-letterspace.lua | 217 ++++++++++++++++++++++++----------------- 1 file changed, 127 insertions(+), 90 deletions(-) (limited to 'src/luaotfload-letterspace.lua') diff --git a/src/luaotfload-letterspace.lua b/src/luaotfload-letterspace.lua index f1fb234..8956f82 100644 --- a/src/luaotfload-letterspace.lua +++ b/src/luaotfload-letterspace.lua @@ -7,7 +7,7 @@ if not modules then modules = { } end modules ['letterspace'] = { } local log = luaotfload.log -local report = log.report +local logreport = log.report local getmetatable = getmetatable local require = require @@ -17,14 +17,26 @@ local tonumber = tonumber local next = next local nodes, node, fonts = nodes, node, fonts -local find_node_tail = node.tail or node.slide -local free_node = node.free -local copy_node = node.copy -local new_node = node.new -local insert_node_before = node.insert_before - -local nodepool = nodes.pool - +--- As of December 2014 the faster ``node.direct.*`` interface is +--- preferred. +local nodedirect = nodes.nuts +local getchar = nodedirect.getchar +local getfont = nodedirect.getfont +local getid = nodedirect.getid +local getnext = nodedirect.getnext +local getprev = nodedirect.getprev +local getfield = nodedirect.getfield +local setfield = nodedirect.setfield +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 +local copy_node = nodedirect.copy +local new_node = nodedirect.new + +local nodepool = nodedirect.pool local new_kern = nodepool.kern local new_glue = nodepool.glue @@ -78,34 +90,24 @@ local userkern_code = kerncodes.userkern --- node-res ----------------------------------------------------------------------- -nodes.pool = nodes.pool or { } -local pool = nodes.pool - -local kern = new_node ("kern", kerncodes.userkern) local glue_spec = new_node "glue_spec" -pool.kern = function (k) - local n = copy_node (kern) - n.kern = k - return n -end - -pool.glue = function (width, stretch, shrink, - stretch_order, shrink_order) - local n = new_node"glue" +nodepool.glue = function (width, stretch, shrink, + stretch_order, shrink_order) + local n = new_node "glue" if not width then -- no spec elseif width == false or tonumber(width) then local s = copy_node(glue_spec) - if width then s.width = width end - if stretch then s.stretch = stretch end - if shrink then s.shrink = shrink end - if stretch_order then s.stretch_order = stretch_order end - if shrink_order then s.shrink_order = shrink_order end - n.spec = s + if width then setfield(s, "width" , width ) end + if stretch then setfield(s, "stretch" , stretch ) end + if shrink then setfield(s, "shrink" , shrink ) end + if stretch_order then setfield(s, "stretch_order", stretch_order) end + if shrink_order then setfield(s, "shrink_order" , shrink_order ) end + setfield(n, "spec", s) else -- shared - n.spec = copy_node(width) + setfield(n, "spec", copy_node(width)) end return n end @@ -187,13 +189,12 @@ end local kern_injector = function (fillup, kern) if fillup then local g = new_glue(kern) - local s = g.spec - s.stretch = kern - s.stretch_order = 1 + local s = getfield(g, "spec") + setfield(s, "stretch", kern) + setfield(s, "stretch_order", 1) return g - else - return new_kern(kern) end + return new_kern(kern) end --[[doc-- @@ -223,12 +224,12 @@ kerncharacters = function (head) local firstkern = true while start do - local id = start.id + local id = getid(start) if id == glyph_code then --- 1) look up kern factor (slow, but cached rudimentarily) local krn - local fontid = start.font + local fontid = getfont(start) do krn = kernfactors[fontid] if not krn then @@ -249,7 +250,7 @@ kerncharacters = function (head) goto nextnode elseif firstkern then firstkern = false - if (id ~= disc_code) and (not start.components) then + if (id ~= disc_code) and (not getfield(start, "components")) then --- not a ligature, skip node goto nextnode end @@ -266,7 +267,7 @@ kerncharacters = function (head) lastfont = fontid --- 2) resolve ligatures - local c = start.components + local c = getfield(start, "components") if c then if keepligature and keepligature(start) then @@ -274,20 +275,20 @@ kerncharacters = function (head) else --- c = kerncharacters (c) --> taken care of after replacing local s = start - local p, n = s.prev, s.next + local p, n = getprev(s), s.next local tail = find_node_tail(c) if p then - p.next = c - c.prev = p + setfield(p, "next", c) + p = getprev(c) else head = c end if n then - n.prev = tail + tail = getprev(n) end - tail.next = n + setnext(tail, "next", n) start = c - s.components = nil + setfield(s, "components", nil) -- we now leak nodes ! -- free_node(s) done = true @@ -295,30 +296,40 @@ kerncharacters = function (head) end -- kern ligature --- 3) apply the extra kerning - local prev = start.prev + local prev = getprev(start) if prev then - local pid = prev.id + local pid = getid(prev) if not pid then -- nothing elseif pid == kern_code then - if prev.subtype == kerning_code --- context does this by means of an - or prev.subtype == userkern_code --- attribute; we may need a test + 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 - if keeptogether and prev.prev.id == glyph_code and keeptogether(prev.prev,start) then + + local pprev = getprev(prev) + local pprev_id = getid(pprev) + + if keeptogether + and pprev_id == glyph_code + and keeptogether(pprev, start) + then -- keep else - prev.subtype = userkern_code - prev.kern = prev.kern + quaddata[lastfont]*krn -- here + prev_subtype = userkern_code + local prev_kern = getfield(prev, "kern") + prev_kern = prev_kern + quaddata[lastfont] * krn done = true end end elseif pid == glyph_code then - if prev.font == lastfont then - local prevchar, lastchar = prev.char, start.char - if keeptogether and keeptogether(prev,start) 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 kerns = chardata[lastfont] and chardata[lastfont][prevchar].kerns @@ -337,31 +348,34 @@ kerncharacters = function (head) -- a bit too complicated, we can best not copy and just calculate -- but we could have multiple glyphs involved so ... local disc = prev -- disc - local pre, post, replace = disc.pre, disc.post, disc.replace - local prv, nxt = disc.prev, disc.next + local pre = getfield(disc, "pre") + local post = getfield(disc, "post") + local replace = getfield(disc, "replace") + 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) - pre.prev = before - before.next = pre - before.prev = nil + setfield(pre, "prev", before) + setfield(before, "next", pre) + setfield(before, "prev", nil) pre = kerncharacters (before) - pre = pre.next - pre.prev = nil - disc.pre = pre + pre = getnext(pre) + setfield(pre, "prev", 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) - tail.next = after - after.prev = tail - after.next = nil + setfield(tail, "next", after) + setfield(after, "prev", tail) + setfield(after, "next", nil) post = kerncharacters (post) - tail.next = nil - disc.post = post + setfield(tail, "next", nil) + setfield(disc, "post", post) free_node(after) end @@ -369,29 +383,34 @@ kerncharacters = function (head) local before = copy_node(prv) local after = copy_node(nxt) local tail = find_node_tail(replace) - replace.prev = before - before.next = replace - before.prev = nil - tail.next = after - after.prev = tail - after.next = nil + setfield(replace, "prev", before) + setfield(before, "next", replace) + setfield(before, "prev", nil) + setfield(tail, "next", after) + setfield(after, "prev", tail) + setfield(after, "next", nil) replace = kerncharacters (before) - replace = replace.next - replace.prev = nil - after.prev.next = nil - disc.replace = replace + replace = getnext(replace) + setfield(replace, "prev", nil) + setfield(after, "prev.next", nil) + setfield(disc, "replace", replace) free_node(after) free_node(before) + elseif identifiers[lastfont] then - if prv and prv.id == glyph_code and prv.font == lastfont then - local prevchar, lastchar = prv.char, start.char + if prv + and getid(prv) == glyph_code + and getfont(prv) == lastfont + then + local prevchar = getchar(prv) + local lastchar = getchar(start) local kerns = chardata[lastfont] and chardata[lastfont][prevchar].kerns local kern = kerns and kerns[lastchar] or 0 krn = kern + quaddata[lastfont]*krn -- here else krn = quaddata[lastfont]*krn -- here end - disc.replace = kern_injector(false,krn) -- only kerns permitted, no glue + setfield(disc, "replace", kern_injector(false, krn)) end end @@ -400,7 +419,7 @@ kerncharacters = function (head) ::nextnode:: if start then - start = start.next + start = getnext(start) end end return head, done @@ -439,19 +458,37 @@ local remove_processor = function (name) return false --> unregistered end ---- now for the simplistic variant +--- 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 ( ) - return add_processor( kerncharacters + + local handler = function (hd) + local direct_hd = todirect (hd) + local hd, _done = kerncharacters (hd) + if not hd then --- bad + logreport ("both", 0, "letterspace", + "kerncharacters() failed to return a valid new head") + end + return tonode (hd) + end + + return add_processor( handler , "luaotfload.letterspace" , "pre_linebreak_filter" , "hpack_filter") end --- unit -> bool -local disablefontkerning = function ( ) - return remove_processor "luaotfload.letterspace" -end +---al disablefontkerning = function ( ) +---eturn remove_processor "luaotfload.letterspace" +--- --[[doc-- @@ -515,10 +552,10 @@ otffeatures.register { local initializecompatfontkerning = function (tfmdata, percentage) local factor = tonumber (percentage) if not factor then - report ("both", 0, "letterspace", - "Invalid argument to letterspace: %s (type %q), " .. - "was expecting percentage as Lua number instead.", - percentage, type (percentage)) + 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) -- cgit v1.2.3