summaryrefslogtreecommitdiff
path: root/otfl-node-inj.lua
diff options
context:
space:
mode:
Diffstat (limited to 'otfl-node-inj.lua')
-rw-r--r--otfl-node-inj.lua606
1 files changed, 606 insertions, 0 deletions
diff --git a/otfl-node-inj.lua b/otfl-node-inj.lua
new file mode 100644
index 0000000..6fd93fa
--- /dev/null
+++ b/otfl-node-inj.lua
@@ -0,0 +1,606 @@
+if not modules then modules = { } end modules ['node-inj'] = {
+ version = 1.001,
+ comment = "companion to node-ini.tex",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- tricky ... fonts.ids is not yet defined .. to be solved (maybe general tex ini)
+
+-- This is very experimental (this will change when we have luatex > .50 and
+-- a few pending thingies are available. Also, Idris needs to make a few more
+-- test fonts.
+
+local next = next
+
+local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
+
+fonts = fonts or { }
+fonts.tfm = fonts.tfm or { }
+fonts.ids = fonts.ids or { }
+
+local fontdata = fonts.ids
+
+local glyph = node.id('glyph')
+local kern = node.id('kern')
+
+local traverse_id = node.traverse_id
+local has_attribute = node.has_attribute
+local set_attribute = node.set_attribute
+local insert_node_before = node.insert_before
+local insert_node_after = node.insert_after
+
+local newkern = nodes.kern
+
+local markbase = attributes.private('markbase')
+local markmark = attributes.private('markmark')
+local markdone = attributes.private('markdone')
+local cursbase = attributes.private('cursbase')
+local curscurs = attributes.private('curscurs')
+local cursdone = attributes.private('cursdone')
+local kernpair = attributes.private('kernpair')
+
+local cursives = { }
+local marks = { }
+local kerns = { }
+
+-- currently we do gpos/kern in a bit inofficial way but when we
+-- have the extra fields in glyphnodes to manipulate ht/dp/wd
+-- explicitly i will provide an alternative; also, we can share
+-- tables
+
+function nodes.set_cursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+ local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
+ local ws, wn = tfmstart.width, tfmnext.width
+ local bound = #cursives + 1
+ set_attribute(start,cursbase,bound)
+ set_attribute(nxt,curscurs,bound)
+ cursives[bound] = { rlmode, dx, dy, ws, wn }
+ return dx, dy, bound
+end
+
+function nodes.set_pair(current,factor,rlmode,spec,tfmchr)
+ local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
+ -- dy = y - h
+ if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
+ local bound = has_attribute(current,kernpair)
+ if bound then
+ local kb = kerns[bound]
+ kb[2], kb[3], kb[4], kb[5] = kb[2] + x, kb[3] + y, kb[4] + w, kb[5] + h
+ else
+ bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, x, y, w, h }
+ end
+ return x, y, w, h, bound
+ end
+ return x, y, w, h -- no bound
+end
+
+function nodes.set_kern(current,factor,rlmode,x,tfmchr)
+ local dx = factor*x
+ if dx ~= 0 then
+ local bound = #kerns + 1
+ set_attribute(current,kernpair,bound)
+ kerns[bound] = { rlmode, dx }
+ end
+ return dx, bound
+end
+
+function nodes.set_mark(start,base,factor,rlmode,ba,ma,index) --ba=baseanchor, ma=markanchor
+ local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
+ local bound = has_attribute(base,markbase)
+ if bound then
+ local mb = marks[bound]
+ if mb then
+ if not index then index = #mb + 1 end
+ mb[index] = { dx, dy }
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ return dx, dy, bound
+ else
+ logs.report("nodes mark", "possible problem, U+%04X is base without data (id: %s)",base.char,bound)
+ end
+ end
+ index = index or 1
+ bound = #marks + 1
+ set_attribute(base,markbase,bound)
+ set_attribute(start,markmark,bound)
+ set_attribute(start,markdone,index)
+ marks[bound] = { [index] = { dx, dy } }
+ return dx, dy, bound
+end
+
+function nodes.trace_injection(head)
+ local function dir(n)
+ return (n<0 and "r-to-l") or (n>0 and "l-to-r") or ("unset")
+ end
+ local function report(...)
+ logs.report("nodes finisher",...)
+ end
+ report("begin run")
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ local kp = has_attribute(n,kernpair)
+ local mb = has_attribute(n,markbase)
+ local mm = has_attribute(n,markmark)
+ local md = has_attribute(n,markdone)
+ local cb = has_attribute(n,cursbase)
+ local cc = has_attribute(n,curscurs)
+ report("char U+%05X, font=%s",n.char,n.font)
+ if kp then
+ local k = kerns[kp]
+ if k[3] then
+ report(" pairkern: dir=%s, x=%s, y=%s, w=%s, h=%s",dir(k[1]),k[2],k[3],k[4],k[5])
+ else
+ report(" kern: dir=%s, dx=%s",dir(k[1]),k[2])
+ end
+ end
+ if mb then
+ report(" markbase: bound=%s",mb)
+ end
+ if mm then
+ local m = marks[mm]
+ if mb then
+ local m = m[mb]
+ if m then
+ report(" markmark: bound=%s, index=%s, dx=%s, dy=%s",mm,j,m[1],m[2])
+ else
+ report(" markmark: bound=%s, missing index",mm)
+ end
+ else
+ m = m[1]
+ report(" markmark: bound=%s, dx=%s, dy=%s",mm,m[1],m[2])
+ end
+ end
+ if cb then
+ report(" cursbase: bound=%s",cb)
+ end
+ if cc then
+ local c = cursives[cc]
+ report(" curscurs: bound=%s, dir=%s, dx=%s, dy=%s",cc,dir(c[1]),c[2],c[3])
+ end
+ end
+ end
+ report("end run")
+end
+
+function nodes.inject_kerns(head,tail,keep)
+ if trace_injections then
+ nodes.trace_injection(head)
+ end
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, rl, valid, cx, wx = false, { }, { }, { }, { }, { }
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ valid[#valid+1] = n
+ if has_kerns then -- move outside loop
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2], kk[3], kk[4], kk[5]
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
+ end
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
+ end
+ rl[n] = kk[1] -- could move in test
+ end
+ end
+ end
+ end
+ end
+ if #valid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,#valid do -- valid == glyphs
+ n = valid[i]
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].marks
+ -- maybe flush
+ maxt = 0
+ end
+ if not tm[n.char] then
+ n_cursbase = has_attribute(n,cursbase)
+ n_curscurs = has_attribute(n,curscurs)
+ if p_cursbase then
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+ cx[n] = dx
+ rl[n] = rlmode
+ end
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
+ end
+ end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = t[i].yoffset + ny
+ end
+ maxt = 0
+ end
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ p_cursbase, p = n_cursbase, n
+ end
+ end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
+ end
+ end
+ if has_marks then
+ local p_markbase, n_markmark = nil, nil
+ for i=1,#valid do
+ local p = valid[i]
+ p_markbase = has_attribute(p,markbase)
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ for n in traverse_id(glyph,p.next) do
+ n_markmark = has_attribute(n,markmark)
+ if p_markbase == n_markmark then
+ local index = has_attribute(n,markdone) or 1
+ local d = mrks[index]
+ if d then
+ -- local rlmode = d[3] -- not used
+ -- if rlmode and rlmode < 0 then
+ -- n.xoffset = p.xoffset + d[1]
+ -- else
+ n.xoffset = p.xoffset - d[1]
+ -- end
+ n.yoffset = p.yoffset + d[2]
+ end
+ else
+ break
+ end
+ end
+ end
+ end
+ if not keep then
+ marks = { }
+ end
+ end
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, w = k[1], k[2] or 0, k[4] or 0
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ if next(cx) then
+ for n, k in next, cx do
+ if k ~= 0 then
+ local rln = rl[n]
+ if rln and rln < 0 then
+ insert_node_before(head,n,newkern(-k))
+ else
+ insert_node_before(head,n,newkern(k))
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
+ end
+ elseif has_kerns then
+ -- we assume done is true because there are kerns
+ for n in traverse_id(glyph,head) do
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3] or 0, kk[4] or 0
+ if y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ end
+ return head, false
+end
+
+-- -- -- KEEP OLD ONE, THE NEXT IS JUST OPTIMIZED -- -- --
+
+function nodes.XXXXXXXxinject_kerns(head,tail,keep)
+ if trace_injections then
+ nodes.trace_injection(head)
+ end
+ local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
+ if has_marks or has_cursives then
+ -- in the future variant we will not copy items but refs to tables
+ local done, ky, valid, cx, wx = false, { }, { }, { }, { }
+ for n in traverse_id(glyph,head) do
+ if n.subtype < 256 then
+ valid[#valid+1] = n
+ if has_kerns then -- move outside loop
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ local x, y, w, h = kk[2], kk[3], kk[4], kk[5]
+ local dy = y - h
+ if dy ~= 0 then
+ ky[n] = dy
+ end
+ if w ~= 0 or x ~= 0 then
+ wx[n] = kk
+ end
+ end
+ end
+ end
+ end
+ end
+ if #valid > 0 then
+ -- we can assume done == true because we have cursives and marks
+ local cx = { }
+ if has_kerns and next(ky) then
+ for n, k in next, ky do
+ n.yoffset = k
+ end
+ end
+ -- todo: reuse t and use maxt
+ if has_cursives then
+ local n_cursbase, n_curscurs, p_cursbase, n, p, nf, tm = nil, nil, nil, nil, nil, nil, nil
+ -- since we need valid[n+1] we can also use a "while true do"
+ local t, d, maxt = { }, { }, 0
+ for i=1,#valid do -- valid == glyphs
+ n = valid[i]
+ if n.font ~= nf then
+ nf = n.font
+ tm = fontdata[nf].marks
+ -- maybe flush
+ maxt = 0
+ end
+ if not tm[n.char] then
+ n_cursbase = has_attribute(n,cursbase)
+ n_curscurs = has_attribute(n,curscurs)
+ if p_cursbase then
+ if p_cursbase == n_curscurs then
+ local c = cursives[n_curscurs]
+ if c then
+ local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
+ if rlmode >= 0 then
+ dx = dx - ws
+ else
+ dx = dx + wn
+ end
+ if dx ~= 0 then
+if rlmode < 0 then
+ cx[n] = -dx
+else
+ cx[n] = dx
+end
+ end
+ -- if rlmode and rlmode < 0 then
+ dy = -dy
+ -- end
+ maxt = maxt + 1
+ t[maxt] = p
+ d[maxt] = dy
+ else
+ maxt = 0
+ end
+ end
+ elseif maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = t[i].yoffset + ny
+ end
+ maxt = 0
+ end
+ if not n_cursbase and maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ p_cursbase, p = n_cursbase, n
+ end
+ end
+ if maxt > 0 then
+ local ny = n.yoffset
+ for i=maxt,1,-1 do
+ ny = ny + d[i]
+ t[i].yoffset = ny
+ end
+ maxt = 0
+ end
+ if not keep then
+ cursives = { }
+ end
+ end
+ if has_marks then
+ local p_markbase, n_markmark = nil, nil
+ for i=1,#valid do
+ local p = valid[i]
+ p_markbase = has_attribute(p,markbase)
+ if p_markbase then
+ local mrks = marks[p_markbase]
+ for n in traverse_id(glyph,p.next) do
+ n_markmark = has_attribute(n,markmark)
+ if p_markbase == n_markmark then
+ local index = has_attribute(n,markdone) or 1
+ local d = mrks[index]
+ if d then
+ local d1, d2 = d[1], d[2]
+ if d1 ~= 0 then
+ n.xoffset = p.xoffset - d[1]
+ end
+ if d2 ~= 0 then
+ n.yoffset = p.yoffset + d[2]
+ end
+ end
+ else
+ break
+ end
+ end
+ end
+ end
+ if not keep then
+ marks = { }
+ end
+ end
+ -- todo : combine
+ if next(wx) then
+ for n, k in next, wx do
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, w = k[1], k[2] or 0, k[4] or 0
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ if next(cx) then
+ for n, k in next, cx do
+ insert_node_before(head,n,newkern(k))
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ elseif not keep then
+ kerns, cursives, marks = { }, { }, { }
+ end
+ elseif has_kerns then
+ -- we assume done is true because there are kerns
+ for n in traverse_id(glyph,head) do
+ local k = has_attribute(n,kernpair)
+ if k then
+ local kk = kerns[k]
+ if kk then
+ -- only w can be nil, can be sped up when w == nil
+ local rl, x, y, w = kk[1], kk[2] or 0, kk[3] or 0, kk[4] or 0
+ if y ~= 0 then
+ n.yoffset = y -- todo: h ?
+ end
+ local wx = w - x
+ if rl < 0 then
+ if wx ~= 0 then
+ insert_node_before(head,n,newkern(wx))
+ end
+ if x ~= 0 then
+ insert_node_after (head,n,newkern(x))
+ end
+ else
+ -- if wx ~= 0 then
+ -- insert_node_after(head,n,newkern(wx))
+ -- end
+ if x ~= 0 then
+ insert_node_before(head,n,newkern(x))
+ end
+ end
+ end
+ end
+ end
+ if not keep then
+ kerns = { }
+ end
+ return head, true
+ end
+ return head, false
+end