summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/mkxl/font-otj.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/mkxl/font-otj.lmt')
-rw-r--r--Master/texmf-dist/tex/context/base/mkxl/font-otj.lmt2556
1 files changed, 2556 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/mkxl/font-otj.lmt b/Master/texmf-dist/tex/context/base/mkxl/font-otj.lmt
new file mode 100644
index 00000000000..e9e9d524e4f
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/mkxl/font-otj.lmt
@@ -0,0 +1,2556 @@
+if not modules then modules = { } end modules ['font-otj'] = {
+ version = 1.001,
+ optimize = true,
+ comment = "companion to font-lib.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files",
+}
+
+-- This property based variant is not faster but looks nicer than the attribute one. We
+-- need to use rawget (which is about 4 times slower than a direct access but we cannot
+-- get/set that one for our purpose! This version does a bit more with discretionaries
+-- (and Kai has tested it with his collection of weird fonts.)
+
+-- There is some duplicate code here (especially in the the pre/post/replace branches) but
+-- we go for speed. We could store a list of glyph and mark nodes when registering but it's
+-- cleaner to have an identification pass here. Also, I need to keep tracing in mind so
+-- being too clever here is dangerous.
+
+-- As we have a rawget on properties we don't need one on injections.
+
+-- The use_advance code was just a test and is meant for testing and manuals. There is no
+-- performance (or whatever) gain and using kerns is somewhat cleaner (at least for now).
+
+-- An alternative is to have a list per base of all marks and then do a run over the node
+-- list that resolves the accumulated l/r/x/y and then do an inject pass.
+
+-- The thing with these positioning options is that it is not clear what Uniscribe does with
+-- the 2rl flag and we keep oscillating a between experiments.
+
+-- Beware: combining advance with cursive and marks can be a problem because marks have no
+-- dimensions .. maybe we need a special field for that ... the advance also sets the apply
+-- x offset flag!
+
+if not nodes.properties then return end
+
+local next, rawget, tonumber = next, rawget, tonumber
+local fastcopy = table.fastcopy
+
+local registertracker = trackers.register
+local registerdirective = directives.register
+
+local trace_injections = false registertracker("fonts.injections", function(v) trace_injections = v end)
+local trace_marks = false registertracker("fonts.injections.marks", function(v) trace_marks = v end)
+local trace_cursive = false registertracker("fonts.injections.cursive", function(v) trace_cursive = v end)
+local trace_spaces = false registertracker("fonts.injections.spaces", function(v) trace_spaces = v end)
+
+-- local fix_cursive_marks = false
+--
+-- registerdirective("fonts.injections.fixcursivemarks", function(v)
+-- fix_cursive_marks = v
+-- end)
+
+local report_injections = logs.reporter("fonts","injections")
+local report_spaces = logs.reporter("fonts","spaces")
+
+local attributes, nodes, node = attributes, nodes, node
+
+fonts = fonts
+local hashes = fonts.hashes
+local fontdata = hashes.identifiers
+local fontmarks = hashes.marks
+local parameters = fonts.hashes.parameters -- not in generic
+----- resources = fonts.hashes.resources -- not in generic
+
+nodes.injections = nodes.injections or { }
+local injections = nodes.injections
+
+local tracers = nodes.tracers
+local setcolor = tracers and tracers.colors.set
+local resetcolor = tracers and tracers.colors.reset
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+local tonode = nuts.tonode
+local tonut = nuts.tonut
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local setchar = nuts.setchar
+----- getxoffset = nuts.getxoffset
+----- getyoffset = nuts.getyoffset
+local getoffsets = nuts.getoffsets
+local getxscale = nuts.getxscale
+local getyscale = nuts.getyscale
+local getxyscales = nuts.getxyscales
+local xscaled = nuts.xscaled
+local yscaled = nuts.yscaled
+local getboth = nuts.getboth
+local getdisc = nuts.getdisc
+local setdisc = nuts.setdisc
+local setoffsets = nuts.setoffsets
+local addxoffset = nuts.addxoffset
+local addyoffset = nuts.addyoffset
+local ischar = nuts.ischar
+local isnextchar = nuts.isnextchar
+local getkern = nuts.getkern
+local setkern = nuts.setkern
+local setlink = nuts.setlink
+local setwidth = nuts.setwidth
+local getwidth = nuts.getwidth
+local addxymargins = nuts.addxymargins -- we delegate scaling
+local copynode = nuts.copy
+
+local nextchar = nuts.traversers.char
+local nextglue = nuts.traversers.glue
+
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+
+local properties = nodes.properties.data
+
+local fontkern = nuts.pool and nuts.pool.fontkern
+local italickern = nuts.pool and nuts.pool.italickern
+
+local useitalickerns = false
+local useadvance = false
+local usezwjkerns = true -- when useadvance
+
+directives.register("fonts.injections.useitalics", function(v)
+ if v then
+ report_injections("using italics for space kerns (tracing only)")
+ end
+ useitalickerns = v
+end)
+
+registerdirective("fonts.injections.method", function(v)
+ useadvance = v == "advance"
+end)
+
+function injections.installnewkern() end -- obsolete
+
+local nofregisteredkerns = 0
+local nofregisteredpositions = 0
+local nofregisteredmarks = 0
+local nofregisteredcursives = 0
+local keepregisteredcounts = false
+
+function injections.keepcounts()
+ keepregisteredcounts = true
+end
+
+function injections.resetcounts()
+ nofregisteredkerns = 0
+ nofregisteredpositions = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ keepregisteredcounts = false
+end
+
+-- We need to make sure that a possible metatable will not kick in unexpectedly.
+
+function injections.reset(n)
+ local p = rawget(properties,n)
+ if p then
+ p.injections = false -- { } -- nil should work too as we use rawget
+ else
+ properties[n] = false -- { injections = { } } -- nil should work too as we use rawget
+ end
+end
+
+function injections.copy(target,source)
+ local sp = rawget(properties,source)
+ if sp then
+ local tp = rawget(properties,target)
+ local si = sp.injections
+ if si then
+ si = fastcopy(si)
+ if tp then
+ tp.injections = si
+ else
+ properties[target] = {
+ injections = si,
+ }
+ end
+ elseif tp then
+ tp.injections = false -- { }
+ else
+ properties[target] = { injections = { } }
+ end
+ else
+ local tp = rawget(properties,target)
+ if tp then
+ tp.injections = false -- { }
+ else
+ properties[target] = false -- { injections = { } }
+ end
+ end
+end
+
+function injections.setligaindex(n,index) -- todo: don't set when 0
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections
+ if i then
+ i.ligaindex = index
+ else
+ p.injections = {
+ ligaindex = index
+ }
+ end
+ else
+ properties[n] = {
+ injections = {
+ ligaindex = index
+ }
+ }
+ end
+end
+
+function injections.getligaindex(n,default)
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections
+ if i then
+ return i.ligaindex or default
+ end
+ end
+ return default
+end
+
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext,r2lflag)
+
+ -- The standard says something about the r2lflag related to the first in a series:
+ --
+ -- When this bit is set, the last glyph in a given sequence to which the cursive
+ -- attachment lookup is applied, will be positioned on the baseline.
+ --
+ -- But it looks like we don't need to consider it.
+
+ local dx = factor*(exit[1]-entry[1])
+ local dy = -factor*(exit[2]-entry[2])
+ local ws = tfmstart.width
+ local wn = tfmnext.width
+ nofregisteredcursives = nofregisteredcursives + 1
+ if rlmode < 0 then
+ dx = -(dx + wn)
+ else
+ dx = dx - ws
+ end
+ if dx == 0 then
+ -- get rid of funny -0
+ dx = 0
+ end
+ --
+ local p = rawget(properties,start)
+ if p then
+ local i = p.injections
+ if i then
+ i.cursiveanchor = true
+ else
+ p.injections = {
+ cursiveanchor = true,
+ }
+ end
+ else
+ properties[start] = {
+ injections = {
+ cursiveanchor = true,
+ },
+ }
+ end
+ local p = rawget(properties,nxt)
+ if p then
+ local i = p.injections
+ if i then
+ i.cursivex = dx
+ i.cursivey = dy
+ else
+ p.injections = {
+ cursivex = dx,
+ cursivey = dy,
+ }
+ end
+ else
+ properties[nxt] = {
+ injections = {
+ cursivex = dx,
+ cursivey = dy,
+ },
+ }
+ end
+ return dx, dy, nofregisteredcursives
+end
+
+-- kind: 0=single 1=first of pair, 2=second of pair
+
+function injections.setposition(kind,current,factor,rlmode,spec,injection)
+ local x = factor * (spec[1] or 0)
+ local y = factor * (spec[2] or 0)
+ local w = factor * (spec[3] or 0)
+ local h = factor * (spec[4] or 0)
+ if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay?
+ local yoffset = y - h
+ local leftkern = x -- both kerns are set in a pair kern compared
+ local rightkern = w - x -- to normal kerns where we set only leftkern
+ if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
+ nofregisteredpositions = nofregisteredpositions + 1
+ if rlmode and rlmode < 0 then
+ leftkern, rightkern = rightkern, leftkern
+ end
+ if not injection then
+ injection = "injections"
+ end
+ local p = rawget(properties,current)
+ if p then
+ local i = p[injection]
+ if i then
+ if leftkern ~= 0 then
+ i.leftkern = (i.leftkern or 0) + leftkern
+ end
+ if rightkern ~= 0 then
+ i.rightkern = (i.rightkern or 0) + rightkern
+ end
+ if yoffset ~= 0 then
+ i.yoffset = (i.yoffset or 0) + yoffset
+ end
+ elseif leftkern ~= 0 or rightkern ~= 0 then
+ p[injection] = {
+ leftkern = leftkern,
+ rightkern = rightkern,
+ yoffset = yoffset,
+ }
+ else
+ p[injection] = {
+ yoffset = yoffset,
+ }
+ end
+ elseif leftkern ~= 0 or rightkern ~= 0 then
+ properties[current] = {
+ [injection] = {
+ leftkern = leftkern,
+ rightkern = rightkern,
+ yoffset = yoffset,
+ },
+ }
+ else
+ properties[current] = {
+ [injection] = {
+ yoffset = yoffset,
+ },
+ }
+ end
+ return x, y, w, h, nofregisteredpositions
+ end
+ end
+ return x, y, w, h -- no bound
+end
+
+-- The next one is used for simple kerns coming from a truetype kern table. The r2l
+-- variant variant needs checking but it is unlikely that a r2l script uses thsi
+-- feature.
+
+function injections.setkern(current,factor,rlmode,x,injection)
+ local dx = factor * x
+ if dx ~= 0 then
+ nofregisteredkerns = nofregisteredkerns + 1
+ local p = rawget(properties,current)
+ if not injection then
+ injection = "injections"
+ end
+ if p then
+ local i = p[injection]
+ if i then
+ i.leftkern = dx + (i.leftkern or 0)
+ else
+ p[injection] = {
+ leftkern = dx,
+ }
+ end
+ else
+ properties[current] = {
+ [injection] = {
+ leftkern = dx,
+ },
+ }
+ end
+ return dx, nofregisteredkerns
+ else
+ return 0, 0
+ end
+end
+
+-- This one is an optimization of pairs where we have only a "w" entry. This one is
+-- potentially different from the previous one wrt r2l. It needs checking. The
+-- optimization relates to smaller tma files.
+
+function injections.setmove(current,factor,rlmode,x,injection)
+ local dx = factor * x
+ if dx ~= 0 then
+ nofregisteredkerns = nofregisteredkerns + 1
+ local p = rawget(properties,current)
+ if not injection then
+ injection = "injections"
+ end
+ if rlmode and rlmode < 0 then
+ -- we need to swap with a single so then we also need to to it here
+ -- as move is just a simple single
+ if p then
+ local i = p[injection]
+ if i then
+ i.rightkern = dx + (i.rightkern or 0)
+ else
+ p[injection] = {
+ rightkern = dx,
+ }
+ end
+ else
+ properties[current] = {
+ [injection] = {
+ rightkern = dx,
+ },
+ }
+ end
+ else
+ if p then
+ local i = p[injection]
+ if i then
+ i.leftkern = dx + (i.leftkern or 0)
+ else
+ p[injection] = {
+ leftkern = dx,
+ }
+ end
+ else
+ properties[current] = {
+ [injection] = {
+ leftkern = dx,
+ },
+ }
+ end
+ end
+ return dx, nofregisteredkerns
+ else
+ return 0, 0
+ end
+end
+
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase,mkmk,checkmark) -- ba=baseanchor, ma=markanchor
+ local dx = factor*(ba[1]-ma[1])
+ local dy = factor*(ba[2]-ma[2])
+ nofregisteredmarks = nofregisteredmarks + 1
+ if rlmode >= 0 then
+ dx = tfmbase.width - dx -- see later commented ox
+ end
+ local p = rawget(properties,start)
+ -- hm, dejavu serif does a sloppy mark2mark before mark2base
+ if p then
+ local i = p.injections
+ if i then
+ if i.markmark then
+ -- out of order mkmk: yes or no or option
+ else
+ -- if dx ~= 0 then
+ -- i.markx = dx
+ -- end
+ -- if y ~= 0 then
+ -- i.marky = dy
+ -- end
+ -- if rlmode then
+ -- i.markdir = rlmode
+ -- end
+ i.markx = dx
+ i.marky = dy
+ i.markdir = rlmode or 0
+ i.markbase = nofregisteredmarks
+ i.markbasenode = base
+ i.markmark = mkmk
+ i.checkmark = checkmark
+ end
+ else
+ p.injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ markmark = mkmk,
+ checkmark = checkmark,
+ }
+ end
+ else
+ properties[start] = {
+ injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ markmark = mkmk,
+ checkmark = checkmark,
+ },
+ }
+ end
+ return dx, dy, nofregisteredmarks
+end
+
+local function dir(n)
+ return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
+end
+
+local function showchar(n,nested)
+ local char = getchar(n)
+ report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char)
+end
+
+local function show(n,what,nested,symbol)
+ if n then
+ local p = rawget(properties,n)
+ if p then
+ local i = p[what]
+ if i then
+ local leftkern = i.leftkern or 0
+ local rightkern = i.rightkern or 0
+ local yoffset = i.yoffset or 0
+ local markx = i.markx or 0
+ local marky = i.marky or 0
+ local markdir = i.markdir or 0
+ local markbase = i.markbase or 0
+ local cursivex = i.cursivex or 0
+ local cursivey = i.cursivey or 0
+ local ligaindex = i.ligaindex or 0
+ local cursbase = i.cursiveanchor
+ local margin = nested and 4 or 2
+ --
+ if rightkern ~= 0 or yoffset ~= 0 then
+ report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset)
+ elseif leftkern ~= 0 then
+ report_injections("%w%s kern: dx %p",margin,symbol,leftkern)
+ end
+ if markx ~= 0 or marky ~= 0 or markbase ~= 0 then
+ report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase ~= 0 and "yes" or "no")
+ end
+ if cursivex ~= 0 or cursivey ~= 0 then
+ if cursbase then
+ report_injections("%w%s curs: base dx %p, dy %p",margin,symbol,cursivex,cursivey)
+ else
+ report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
+ end
+ elseif cursbase then
+ report_injections("%w%s curs: base",margin,symbol)
+ end
+ if ligaindex ~= 0 then
+ report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
+ end
+ end
+ end
+ end
+end
+
+local function showsub(n,what,where)
+ report_injections("begin subrun: %s",where)
+ for n in nextchar, n do
+ showchar(n,where)
+ show(n,what,where," ")
+ end
+ report_injections("end subrun")
+end
+
+local function trace(head,where)
+ report_injections()
+ report_injections("begin run %s: %s kerns, %s positions, %s marks and %s cursives registered",
+ where or "",nofregisteredkerns,nofregisteredpositions,nofregisteredmarks,nofregisteredcursives)
+ local n = head
+ while n do
+ local id = getid(n)
+ if id == glyph_code then
+ showchar(n)
+ show(n,"injections",false," ")
+ show(n,"preinjections",false,"<")
+ show(n,"postinjections",false,">")
+ show(n,"replaceinjections",false,"=")
+ show(n,"emptyinjections",false,"*")
+ elseif id == disc_code then
+ local pre, post, replace = getdisc(n)
+ if pre then
+ showsub(pre,"preinjections","pre")
+ end
+ if post then
+ showsub(post,"postinjections","post")
+ end
+ if replace then
+ showsub(replace,"replaceinjections","replace")
+ end
+ show(n,"emptyinjections",false,"*")
+ end
+ n = getnext(n)
+ end
+ report_injections("end run")
+end
+
+local function show_result(head)
+ local current = head
+ local skipping = false
+ while current do
+ local id = getid(current)
+ if id == glyph_code then
+ local w = getwidth(current)
+ local x, y = getoffsets(current)
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",getchar(current),w,x,y)
+ skipping = false
+ elseif id == kern_code then
+ report_injections("kern: %p",getkern(current))
+ skipping = false
+ elseif not skipping then
+ report_injections()
+ skipping = true
+ end
+ current = getnext(current)
+ end
+ report_injections()
+end
+
+-- G +D-pre G
+-- D-post+
+-- +D-replace+
+--
+-- G +D-pre +D-pre
+-- D-post +D-post
+-- +D-replace +D-replace
+
+-- Beware! pre/post/replace can have non glyphs too
+
+-- local function inject_kerns_only(head,where)
+-- if trace_injections then
+-- trace(head,"kerns")
+-- end
+-- local current = head
+-- local prev -- = nil
+-- local prevdisc -- = nil
+-- local pre -- = nil -- saves a lookup
+-- local post -- = nil -- saves a lookup
+-- local replace -- = nil -- saves a lookup
+-- local pretail -- = nil -- saves a lookup
+-- local posttail -- = nil -- saves a lookup
+-- local replacetail -- = nil -- saves a lookup
+-- while current do
+-- local next, char, id = isnextchar(current)
+-- if char then
+-- local p = rawget(properties,current)
+-- if p then
+-- local i = p.injections
+-- if i then
+-- -- left|glyph|right
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(current,leftkern)
+-- if useadvance then
+-- addmargins(current,-leftkern)
+-- elseif prev and getid(prev) == glue_code then
+-- if useitalickerns then
+-- head = insert_node_before(head,current,italickern(leftkern))
+-- else
+-- setwidth(prev, getwidth(prev) + leftkern)
+-- end
+-- else
+-- head = insert_node_before(head,current,fontkern(leftkern))
+-- end
+-- end
+-- end
+-- if prevdisc then
+-- local done = false
+-- if post then
+-- local i = p.postinjections
+-- if i then
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(current,leftkern)
+-- if useadvance then
+-- addmargins(posttail,false,-leftkern)
+-- else
+-- setlink(posttail,fontkern(leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- if replace then
+-- local i = p.replaceinjections
+-- if i then
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(current,leftkern)
+-- if useadvance then
+-- addmargins(replacetail,false,-leftkern)
+-- else
+-- setlink(replacetail,fontkern(leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- else
+-- local i = p.emptyinjections
+-- if i then
+-- -- glyph|disc|glyph (special case)
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(current,leftkern)
+-- -- if useadvance then
+-- -- add zwj with offset
+-- -- else
+-- replace = fontkern(leftkern)
+-- done = true
+-- -- end
+-- end
+-- end
+-- end
+-- if done then
+-- setdisc(prevdisc,pre,post,replace)
+-- end
+-- end
+-- end
+-- prevdisc = nil
+-- -- prevglyph = current
+-- elseif char == false then
+-- -- other font
+-- prevdisc = nil
+-- -- prevglyph = current
+-- elseif id == disc_code then
+-- pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
+-- local done = false
+-- if pre then
+-- -- left|pre glyphs|right
+-- for n in nextchar, pre do
+-- local p = rawget(properties,n)
+-- if p then
+-- local i = p.injections or p.preinjections
+-- if i then
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(n,leftkern)
+-- if useadvance then
+-- addmargins(n,-leftkern)
+-- else
+-- pre = insert_node_before(pre,n,fontkern(leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if post then
+-- -- left|post glyphs|right
+-- for n in nextchar, post do
+-- local p = rawget(properties,n)
+-- if p then
+-- local i = p.injections or p.postinjections
+-- if i then
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(n,leftkern)
+-- if useadvance then
+-- addmargins(n,-leftkern)
+-- else
+-- post = insert_node_before(post,n,fontkern(leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if replace then
+-- -- left|replace glyphs|right
+-- for n in nextchar, replace do
+-- local p = rawget(properties,n)
+-- if p then
+-- local i = p.injections or p.replaceinjections
+-- if i then
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(n,leftkern)
+-- if useadvance then
+-- addmargins(n,-leftkern)
+-- else
+-- replace = insert_node_before(replace,n,fontkern(leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if done then
+-- setdisc(current,pre,post,replace)
+-- end
+-- -- prevglyph = nil
+-- prevdisc = current
+-- else
+-- -- prevglyph = nil
+-- prevdisc = nil
+-- end
+-- prev = current
+-- current = next
+-- end
+-- --
+-- if keepregisteredcounts then
+-- keepregisteredcounts = false
+-- else
+-- nofregisteredkerns = 0
+-- end
+-- if trace_injections then
+-- show_result(head)
+-- end
+-- return head
+-- end
+
+local function inject_kerns_only_kerns(head,where)
+ if trace_injections then
+ trace(head,"kerns")
+ end
+ local current = head
+ local prev -- = nil
+ local prevdisc -- = nil
+ local pre -- = nil -- saves a lookup
+ local post -- = nil -- saves a lookup
+ local replace -- = nil -- saves a lookup
+ local pretail -- = nil -- saves a lookup
+ local posttail -- = nil -- saves a lookup
+ local replacetail -- = nil -- saves a lookup
+ while current do
+ local next, char, id = isnextchar(current)
+ if char then
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ -- left|glyph|right
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ leftkern = xscaled(current,leftkern)
+ if prev and getid(prev) == glue_code then
+ if useitalickerns then
+ head = insert_node_before(head,current,italickern(leftkern))
+ else
+ setwidth(prev,getwidth(prev) + leftkern)
+ end
+ else
+ head = insert_node_before(head,current,fontkern(leftkern))
+ end
+ end
+ end
+ if prevdisc then
+ local done = false
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(posttail,fontkern(xscaled(current,leftkern)))
+ done = true
+ end
+ end
+ end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(replacetail,fontkern(xscaled(current,leftkern)))
+ done = true
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- glyph|disc|glyph (special case)
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ replace = fontkern(xscaled(current,leftkern))
+ done = true
+ end
+ end
+ end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
+ end
+ end
+ end
+ prevdisc = nil
+ -- prevglyph = current
+ elseif char == false then
+ -- other font
+ prevdisc = nil
+ -- prevglyph = current
+ elseif id == disc_code then
+ pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
+ local done = false
+ if pre then
+ -- left|pre glyphs|right
+ for n in nextchar, pre do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.preinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ pre = insert_node_before(pre,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if post then
+ -- left|post glyphs|right
+ for n in nextchar, post do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ post = insert_node_before(post,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ -- left|replace glyphs|right
+ for n in nextchar, replace do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ replace = insert_node_before(replace,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if done then
+ setdisc(current,pre,post,replace)
+ end
+ -- prevglyph = nil
+ prevdisc = current
+ else
+ -- prevglyph = nil
+ prevdisc = nil
+ end
+ prev = current
+ current = next
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ end
+ if trace_injections then
+ show_result(head)
+ end
+ return head
+end
+
+local function inject_kerns_only_margins(head,where)
+ if trace_injections then
+ trace(head,"kerns")
+ end
+ local current = head
+ local prevdisc -- = nil
+ local pre -- = nil -- saves a lookup
+ local post -- = nil -- saves a lookup
+ local replace -- = nil -- saves a lookup
+ local pretail -- = nil -- saves a lookup
+ local posttail -- = nil -- saves a lookup
+ local replacetail -- = nil -- saves a lookup
+ while current do
+ local next, char, id = isnextchar(current)
+ if char then
+ local p = rawget(properties,current)
+ if p then
+ if prevdisc then
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(posttail,false,-leftkern)
+ end
+ end
+ end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(replacetail,false,-leftkern)
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ if usezwjkerns then
+ replace = copynode(current)
+ setchar(replace,0x200D) -- zwj
+ addxymargins(replace,-leftkern)
+ else
+ replace = fontkern(xscaled(current,leftkern))
+ end
+ setdisc(prevdisc,pre,post,replace) -- setreplace
+ end
+ end
+ end
+ end
+ -- moved down so we can copy zwj
+ local i = p.injections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(current,-leftkern)
+ end
+ end
+ end
+ prevdisc = nil
+ elseif char == false then
+ prevdisc = nil
+ elseif id == disc_code then
+ pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
+ if pre then
+ for n in nextchar, pre do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.preinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(n,-leftkern)
+ end
+ end
+ end
+ end
+ end
+ if post then
+ for n in nextchar, post do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(n,-leftkern)
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ for n in nextchar, replace do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(n,-leftkern)
+ end
+ end
+ end
+ end
+ end
+ prevdisc = current
+ else
+ prevdisc = nil
+ end
+ current = next
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ end
+ if trace_injections then
+ show_result(head)
+ end
+ return head
+end
+
+-- local function inject_positions_only(head,where)
+-- if trace_injections then
+-- trace(head,"positions")
+-- end
+-- local current = head
+-- local prev = nil
+-- local next = nil
+-- local prevdisc = nil
+-- local prevglyph = nil
+-- local pre = nil -- saves a lookup
+-- local post = nil -- saves a lookup
+-- local replace = nil -- saves a lookup
+-- local pretail = nil -- saves a lookup
+-- local posttail = nil -- saves a lookup
+-- local replacetail = nil -- saves a lookup
+-- while current do
+-- local next, char, id = isnextchar(current)
+-- if char then
+-- local p = rawget(properties,current)
+-- if p then
+-- local i = p.injections
+-- if i then
+-- -- left|glyph|right
+-- local yoffset = i.yoffset
+-- if yoffset and yoffset ~= 0 then
+-- -- use raise when advance
+-- addyoffset(current,yscaled(current,yoffset))
+-- end
+-- local leftkern = i.leftkern or 0
+-- local rightkern = i.rightkern or 0
+-- if leftkern ~= 0 then
+-- leftkern = xscaled(current,leftkern)
+-- end
+-- if rightkern ~= 0 then
+-- rightkern = xscaled(current,rightkern)
+-- end
+-- if useadvance then
+-- if leftkern ~= 0 or rightkern ~= 0 then
+-- addmargins(current,-leftkern,-rightkern)
+-- end
+-- else
+-- if leftkern ~= 0 then
+-- if leftkern == -rightkern then
+-- addxoffset(current,leftkern)
+-- rightkern = 0
+-- elseif prev and getid(prev) == glue_code then
+-- if useitalickerns then
+-- head = insert_node_before(head,current,italickern(leftkern))
+-- else
+-- setwidth(prev,getwidth(prev)+leftkern)
+-- end
+-- else
+-- head = insert_node_before(head,current,fontkern(leftkern))
+-- end
+-- end
+-- if rightkern ~= 0 then
+-- if next and getid(next) == glue_code then
+-- if useitalickerns then
+-- insert_node_after(head,current,italickern(rightkern))
+-- else
+-- setwidth(next, getwidth(next)+rightkern)
+-- end
+-- else
+-- insert_node_after(head,current,fontkern(rightkern))
+-- end
+-- end
+-- end
+-- else
+-- local i = p.emptyinjections
+-- if i then
+-- -- glyph|disc|glyph (special case)
+-- local rightkern = i.rightkern
+-- if rightkern and rightkern ~= 0 then
+-- if next and getid(next) == disc_code then
+-- if replace then
+-- -- error, we expect an empty one
+-- else
+-- rightkern = xscaled(current,rightkern)
+-- replace = fontkern(rightkern) -- maybe also leftkern
+-- done = true --KE
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if prevdisc then
+-- local done = false
+-- if post then
+-- local i = p.postinjections
+-- if i then
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(current,leftkern)
+-- if useadvance then
+-- addmargins(posttail,-leftkern)
+-- else
+-- setlink(posttail,fontkern(leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- if replace then
+-- local i = p.replaceinjections
+-- if i then
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- leftkern = xscaled(current,leftkern)
+-- if useadvance then
+-- addmargins(replacetail,-leftkern)
+-- else
+-- setlink(replacetail,fontkern(leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- else
+-- local i = p.emptyinjections
+-- if i then
+-- -- new .. okay?
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- replace = fontkern(xscaled(current,leftkern))
+-- done = true
+-- end
+-- end
+-- end
+-- if done then
+-- setdisc(prevdisc,pre,post,replace)
+-- end
+-- end
+-- end
+-- prevdisc = nil
+-- prevglyph = current
+-- elseif char == false then
+-- prevdisc = nil
+-- prevglyph = current
+-- elseif id == disc_code then
+-- pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
+-- local done = false
+-- if pre then
+-- -- left|pre glyphs|right
+-- for n in nextchar, pre do
+-- local p = rawget(properties,n)
+-- if p then
+-- local i = p.injections or p.preinjections
+-- if i then
+-- local yoffset = i.yoffset
+-- local leftkern = i.leftkern or 0
+-- local rightkern = i.rightkern or 0
+-- if yoffset and yoffset ~= 0 then
+-- -- use raise when advance
+-- addyoffset(n,yscaled(n,yoffset))
+-- end
+-- if leftkern ~= 0 then
+-- leftkern = xscaled(n,leftkern)
+-- end
+-- if rightkern ~= 0 then
+-- rightkern = xscaled(n,rightkern)
+-- end
+-- if useadvance then
+-- if leftkern ~= 0 or rightkern ~= 0 then
+-- addmargins(pre,-leftkern,-rightkern)
+-- end
+-- else
+-- if leftkern ~= 0 then
+-- pre = insert_node_before(pre,n,fontkern(leftkern))
+-- done = true
+-- end
+-- if rightkern ~= 0 then
+-- insert_node_after(pre,n,fontkern(rightkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if post then
+-- -- left|post glyphs|right
+-- for n in nextchar, post do
+-- local p = rawget(properties,n)
+-- if p then
+-- local i = p.injections or p.postinjections
+-- if i then
+-- local yoffset = i.yoffset
+-- local leftkern = i.leftkern or 0
+-- local rightkern = i.rightkern or 0
+-- if yoffset and yoffset ~= 0 then
+-- -- use raise when advance
+-- addyoffset(n,yscaled(n,yoffset))
+-- end
+-- if leftkern ~= 0 then
+-- leftkern = xscaled(n,leftkern)
+-- end
+-- if rightkern ~= 0 then
+-- rightkern = xscaled(n,rightkern)
+-- end
+-- if useadvance then
+-- if leftkern ~= 0 or rightkern ~= 0 then
+-- addmargins(post,-leftkern,-rightkern)
+-- end
+-- else
+-- if leftkern ~= 0 then
+-- post = insert_node_before(post,n,fontkern(leftkern))
+-- done = true
+-- end
+-- if rightkern ~= 0 then
+-- insert_node_after(post,n,fontkern(rightkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if replace then
+-- -- left|replace glyphs|right
+-- for n in nextchar, replace do
+-- local p = rawget(properties,n)
+-- if p then
+-- local i = p.injections or p.replaceinjections
+-- if i then
+-- local yoffset = i.yoffset
+-- local leftkern = i.leftkern or 0
+-- local rightkern = i.rightkern or 0
+-- if yoffset and yoffset ~= 0 then
+-- -- use raise when advance
+-- addyoffset(n,yscaled(n,yoffset))
+-- end
+-- if leftkern ~= 0 then
+-- leftkern = xscaled(n,leftkern)
+-- end
+-- if rightkern ~= 0 then
+-- rightkern = xscaled(n,rightkern)
+-- end
+-- if useadvance then
+-- if leftkern ~= 0 or rightkern ~= 0 then
+-- addmargins(replace,-leftkern,-rightkern)
+-- end
+-- else
+-- if leftkern ~= 0 then
+-- replace = insert_node_before(replace,n,fontkern(leftkern))
+-- done = true
+-- end
+-- if rightkern ~= 0 then
+-- insert_node_after(replace,n,fontkern(rightkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if prevglyph then
+-- if pre then
+-- local p = rawget(properties,prevglyph)
+-- if p then
+-- local i = p.preinjections
+-- if i then
+-- -- glyph|pre glyphs
+-- local rightkern = i.rightkern
+-- if rightkern and rightkern ~= 0 then
+-- rightkern = xscaled(prevglyph,rightkern)
+-- if useadvance then
+-- addmargins(pre,-rightkern)
+-- else
+-- pre = insert_node_before(pre,pre,fontkern(rightkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if replace then
+-- local p = rawget(properties,prevglyph)
+-- if p then
+-- local i = p.replaceinjections
+-- if i then
+-- -- glyph|replace glyphs
+-- local rightkern = i.rightkern
+-- if rightkern and rightkern ~= 0 then
+-- rightkern = xscaled(prevglyph,rightkern)
+-- if useadvance then
+-- addmargins(replace,-rightkern)
+-- else
+-- replace = insert_node_before(replace,replace,fontkern(rightkern))
+-- done = true
+-- end
+-- end
+-- end
+-- end
+-- end
+-- end
+-- if done then
+-- setdisc(current,pre,post,replace)
+-- end
+-- prevglyph = nil
+-- prevdisc = current
+-- else
+-- prevglyph = nil
+-- prevdisc = nil
+-- end
+-- prev = current
+-- current = next
+-- end
+-- --
+-- if keepregisteredcounts then
+-- keepregisteredcounts = false
+-- else
+-- nofregisteredpositions = 0
+-- end
+-- if trace_injections then
+-- show_result(head)
+-- end
+-- return head
+-- end
+
+local function inject_positions_only_kerns(head,where)
+ if trace_injections then
+ trace(head,"positions")
+ end
+ local current = head
+ local prev = nil
+ local next = nil
+ local prevdisc = nil
+ local prevglyph = nil
+ local pre = nil -- saves a lookup
+ local post = nil -- saves a lookup
+ local replace = nil -- saves a lookup
+ local pretail = nil -- saves a lookup
+ local posttail = nil -- saves a lookup
+ local replacetail = nil -- saves a lookup
+ while current do
+ local next, char, id = isnextchar(current)
+ if char then
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ -- left|glyph|right
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ -- use raise when advance
+ addyoffset(current,yscaled(current,yoffset))
+ end
+ local leftkern = i.leftkern or 0
+ local rightkern = i.rightkern or 0
+ if leftkern ~= 0 then
+ leftkern = xscaled(current,leftkern)
+ end
+ if rightkern ~= 0 then
+ rightkern = xscaled(current,rightkern)
+ end
+ if leftkern ~= 0 then
+ if leftkern == -rightkern then
+ addxoffset(current,leftkern)
+ rightkern = 0
+ elseif prev and getid(prev) == glue_code then
+ if useitalickerns then
+ head = insert_node_before(head,current,italickern(leftkern))
+ else
+ setwidth(prev,getwidth(prev)+leftkern)
+ end
+ else
+ head = insert_node_before(head,current,fontkern(leftkern))
+ end
+ end
+ if rightkern ~= 0 then
+ if next and getid(next) == glue_code then
+ if useitalickerns then
+ insert_node_after(head,current,italickern(rightkern))
+ else
+ setwidth(next, getwidth(next)+rightkern)
+ end
+ else
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- glyph|disc|glyph (special case)
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ if next and getid(next) == disc_code then
+ if replace then
+ -- error, we expect an empty one
+ else
+ replace = fontkern(xscaled(current,rightkern)) -- maybe also leftkern
+ done = true --KE
+ end
+ end
+ end
+ end
+ end
+ if prevdisc then
+ local done = false
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(posttail,fontkern(xscaled(current,leftkern)))
+ done = true
+ end
+ end
+ end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(replacetail,fontkern(xscaled(current,leftkern)))
+ done = true
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- new .. okay?
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ replace = fontkern(xscaled(current,leftkern))
+ done = true
+ end
+ end
+ end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
+ end
+ end
+ end
+ prevdisc = nil
+ prevglyph = current
+ elseif char == false then
+ prevdisc = nil
+ prevglyph = current
+ elseif id == disc_code then
+ pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
+ local done = false
+ if pre then
+ -- left|pre glyphs|right
+ for n in nextchar, pre do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.preinjections
+ if i then
+ local yoffset = i.yoffset
+ local leftkern = i.leftkern
+ local rightkern = i.rightkern
+ if yoffset and yoffset ~= 0 then
+ addyoffset(n,yscaled(n,yoffset))
+ end
+ if leftkern and leftkern ~= 0 then
+ pre = insert_node_before(pre,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(pre,n,fontkern(xscaled(n,rightkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if post then
+ -- left|post glyphs|right
+ for n in nextchar, post do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.postinjections
+ if i then
+ local yoffset = i.yoffset
+ local leftkern = i.leftkern
+ local rightkern = i.rightkern
+ if yoffset and yoffset ~= 0 then
+ addyoffset(n,yscaled(n,yoffset))
+ end
+ if leftkern and leftkern ~= 0 then
+ post = insert_node_before(post,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(post,n,fontkern(xscaled(n,rightkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ -- left|replace glyphs|right
+ for n in nextchar, replace do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.replaceinjections
+ if i then
+ local yoffset = i.yoffset
+ local leftkern = i.leftkern
+ local rightkern = i.rightkern
+ if yoffset and yoffset ~= 0 then
+ addyoffset(n,yscaled(n,yoffset))
+ end
+ if leftkern and leftkern ~= 0 then
+ replace = insert_node_before(replace,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(replace,n,fontkern(xscaled(n,rightkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if prevglyph then
+ -- there can only be useful properties when pre/replace start with a glyph
+ if pre then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = p.preinjections
+ if i then
+ -- glyph|pre glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ pre = insert_node_before(pre,pre,fontkern(xscaled(prevglyph,rightkern)))
+ done = true
+ end
+ end
+ end
+ end
+ if replace then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = p.replaceinjections
+ if i then
+ -- glyph|replace glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ replace = insert_node_before(replace,replace,fontkern(xscaled(prevglyph,rightkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if done then
+ setdisc(current,pre,post,replace)
+ end
+ prevglyph = nil
+ prevdisc = current
+ else
+ prevglyph = nil
+ prevdisc = nil
+ end
+ prev = current
+ current = next
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredpositions = 0
+ end
+ if trace_injections then
+ show_result(head)
+ end
+ return head
+end
+
+local function inject_positions_only_margins(head,where)
+ if trace_injections then
+ trace(head,"positions")
+ end
+ local current = head
+ local prev = nil
+ local next = nil
+ local prevdisc = nil
+ local prevglyph = nil
+ local pre = nil -- saves a lookup
+ local post = nil -- saves a lookup
+ local replace = nil -- saves a lookup
+ local pretail = nil -- saves a lookup
+ local posttail = nil -- saves a lookup
+ local replacetail = nil -- saves a lookup
+ while current do
+ local next, char, id = isnextchar(current)
+ if char then
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ -- left|glyph|right
+ local yoffset = i.yoffset or 0
+ local leftkern = i.leftkern or 0
+ local rightkern = i.rightkern or 0
+ if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
+ addxymargins(n,-leftkern,-rightkern,yoffset) -- also scales
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- glyph|disc|glyph (special case)
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ if next and getid(next) == disc_code then
+ if replace then
+ -- error, we expect an empty one
+ else
+ if usezwjkerns then
+ replace = copynode(current)
+ setchar(replace,0x200D) -- zwj
+ addxymargins(replace,false,-rightkern)
+ else
+ replace = fontkern(xscaled(current,rightkern)) -- maybe also leftkern
+ end
+ done = true --KE
+ end
+ end
+ end
+ end
+ end
+ if prevdisc then
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(posttail,-leftkern)
+ end
+ end
+ end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ addxymargins(replacetail,-leftkern)
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- new .. okay?
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ if usezwjkerns then
+ replace = copynode(current)
+ setchar(replace,0x200D) -- zwj
+ addxymargins(replace,-leftkern)
+ else
+ replace = fontkern(xscaled(current,leftkern))
+ end
+ setdisc(prevdisc,pre,post,replace)
+ end
+ end
+ end
+ end
+ end
+ prevdisc = nil
+ prevglyph = current
+ elseif char == false then
+ prevdisc = nil
+ prevglyph = current
+ elseif id == disc_code then
+ pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
+ if pre then
+ -- left|pre glyphs|right
+ for n in nextchar, pre do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.preinjections
+ if i then
+ local yoffset = i.yoffset or 0
+ local leftkern = i.leftkern or 0
+ local rightkern = i.rightkern or 0
+ if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
+ addxymargins(n,-leftkern,-rightkern,yoffset) -- also scales
+ end
+ end
+ end
+ end
+ end
+ if post then
+ -- left|post glyphs|right
+ for n in nextchar, post do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.postinjections
+ if i then
+ local yoffset = i.yoffset or 0
+ local leftkern = i.leftkern or 0
+ local rightkern = i.rightkern or 0
+ if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
+ addxymargins(n,-leftkern,-rightkern,yoffset) -- also scales
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ -- left|replace glyphs|right
+ for n in nextchar, replace do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.replaceinjections
+ if i then
+ local yoffset = i.yoffset or 0
+ local leftkern = i.leftkern or 0
+ local rightkern = i.rightkern or 0
+ if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
+ addxymargins(n,-leftkern,-rightkern,yoffset) -- also scales
+ end
+ end
+ end
+ end
+ end
+ if prevglyph then
+ if pre then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = p.preinjections
+ if i then
+ -- glyph|pre glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ addxymargins(pre,-rightkern,0,0)
+ end
+ end
+ end
+ end
+ if replace then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = p.replaceinjections
+ if i then
+ -- glyph|replace glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ addxymargins(replace,-rightkern,0,0)
+ end
+ end
+ end
+ end
+ end
+ prevglyph = nil
+ prevdisc = current
+ else
+ prevglyph = nil
+ prevdisc = nil
+ end
+ prev = current
+ current = next
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredpositions = 0
+ end
+ if trace_injections then
+ show_result(head)
+ end
+ return head
+end
+
+local function showoffset(n,flag)
+ local x, y = getoffsets(n)
+ if x ~= 0 or y ~= 0 then
+ setcolor(n,"darkgray")
+ end
+end
+
+local function processmark(p,n,pn) -- p = basenode
+ local px, py = getoffsets(p)
+ local nx, ny = getoffsets(n)
+ local sx, sy = getxyscales(n) -- we assume n and p to have equal scales
+ local ox = 0
+ local rightkern = nil
+ local pp = rawget(properties,p)
+ if pp then
+ pp = pp.injections
+ if pp then
+ rightkern = pp.rightkern
+ end
+ end
+ local markdir = pn.markdir
+ if rightkern then -- x and w ~= 0
+ ox = px - sx * (pn.markx or 0) - rightkern
+ if markdir and markdir < 0 then
+ -- kern(w-x) glyph(p) kern(x) mark(n)
+ if not pn.markmark then
+ ox = ox + sx * (pn.leftkern or 0)
+ end
+ else
+ -- kern(x) glyph(p) kern(w-x) mark(n)
+ --
+ -- According to Kai we don't need to handle leftkern here but I'm
+ -- pretty sure I've run into a case where it was needed so maybe
+ -- some day we need something more clever here.
+ --
+ -- maybe we need to apply both then
+ --
+ if false then
+ -- a mark with kerning (maybe husayni needs it )
+ local leftkern = pp.leftkern
+ if leftkern then
+ ox = ox - sx * leftkern
+ end
+ end
+ end
+ else
+ ox = px - sx * (pn.markx or 0)
+ if markdir and markdir < 0 then
+ if not pn.markmark then
+ local leftkern = pn.leftkern
+ if leftkern then
+ ox = ox + sx * leftkern -- husayni needs it
+ end
+ end
+ end
+ if pn.checkmark then
+ local wn = getwidth(n) -- in arial marks have widths
+ if wn and wn ~= 0 then
+ wn = wn/2
+ if trace_injections then
+ report_injections("correcting non zero width mark %C",getchar(n))
+ end
+ -- -- bad: we should center
+ --
+ -- pn.leftkern = -wn
+ -- pn.rightkern = -wn
+ --
+ -- -- we're too late anyway as kerns are already injected so we do it the
+ -- -- ugly way (no checking if the previous is already a kern) .. maybe we
+ -- -- should fix the font instead
+ --
+ -- todo: head and check for prev / next kern
+ --
+ insert_node_before(n,n,fontkern(-wn))
+ insert_node_after(n,n,fontkern(-wn))
+ end
+ end
+ end
+ local oy = ny + py + sy * (pn.marky or 0)
+ if not pn.markmark then
+ local yoffset = pn.yoffset
+ if yoffset then
+ oy = oy + sy * yoffset -- husayni needs it
+ end
+ end
+ setoffsets(n,ox,oy)
+ if trace_marks then
+ showoffset(n,true)
+ end
+end
+
+local function inject_everything(head,where)
+ if trace_injections then
+ trace(head,"everything")
+ end
+ local hascursives = nofregisteredcursives > 0
+ local hasmarks = nofregisteredmarks > 0
+ --
+ local current = head
+ local last = nil
+ local prev = nil
+ local next = nil
+ local prevdisc = nil
+ local prevglyph = nil
+ local pre = nil -- saves a lookup
+ local post = nil -- saves a lookup
+ local replace = nil -- saves a lookup
+ local pretail = nil -- saves a lookup
+ local posttail = nil -- saves a lookup
+ local replacetail = nil -- saves a lookup
+ --
+ local cursiveanchor = nil
+ local minc = 0
+ local maxc = 0
+ local glyphs = { }
+ local marks = { }
+ local nofmarks = 0
+ --
+ while current do
+ local next, char, id = isnextchar(current)
+ if char then
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ local pm = i.markbasenode
+ if pm then
+ nofmarks = nofmarks + 1
+ marks[nofmarks] = current
+ else
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ addyoffset(current,yscaled(current,yoffset)) -- or just * sy
+ end
+ if hascursives then
+ local cursivex = i.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex ~= 0 then
+ i.leftkern = (i.leftkern or 0) + cursivex
+ end
+ if maxc == 0 then
+ minc = 1
+ maxc = 1
+ glyphs[1] = cursiveanchor
+ else
+ maxc = maxc + 1
+ glyphs[maxc] = cursiveanchor
+ end
+ properties[cursiveanchor].cursivedy = i.cursivey -- cursiveprops
+ last = current
+ else
+ maxc = 0
+ end
+ elseif maxc > 0 then
+ local nx, ny = getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + yscaled(current,properties[ti].cursivedy) -- stepwise increment
+ setoffsets(ti,false,ny)
+ if trace_cursive then
+ showoffset(ti)
+ end
+ end
+ maxc = 0
+ cursiveanchor = nil
+ end
+ if i.cursiveanchor then
+ cursiveanchor = current -- no need for both now
+ else
+ if maxc > 0 then
+ local nx, ny = getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + yscaled(current,properties[ti].cursivedy) -- stepwise increment
+ setoffsets(ti,false,ny)
+ if trace_cursive then
+ showoffset(ti)
+ end
+ end
+ maxc = 0
+ end
+ cursiveanchor = nil
+ end
+ end
+ -- left|glyph|right
+ local leftkern = i.leftkern
+ local rightkern = i.rightkern
+ if leftkern and leftkern ~= 0 then
+ local opposite = rightkern and leftkern == -rightkern
+ leftkern = xscaled(current,leftkern)
+ if opposite then
+ addxoffset(current,leftkern)
+ rightkern = 0
+ elseif prev and getid(prev) == glue_code then
+ if useitalickerns then
+ head = insert_node_before(head,current,italickern(leftkern))
+ else
+ setwidth(prev, getwidth(prev) + leftkern)
+ end
+ else
+ head = insert_node_before(head,current,fontkern(leftkern))
+ end
+ end
+ if rightkern and rightkern ~= 0 then
+ rightkern = xscaled(current,rightkern)
+ if next and getid(next) == glue_code then
+ if useitalickerns then
+ insert_node_after(head,current,italickern(rightkern))
+ else
+ setwidth(next, getwidth(next) + rightkern)
+ end
+ else
+ insert_node_after(head,current,fontkern(rightkern))
+ end
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ -- glyph|disc|glyph (special case)
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ if next and getid(next) == disc_code then
+ if replace then
+ -- error, we expect an empty one
+ else
+ replace = fontkern(xscaled(current,rightkern))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if prevdisc then
+ if p then
+ local done = false
+ if post then
+ local i = p.postinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(posttail,fontkern(xscaled(current,leftkern)))
+ done = true
+ end
+ end
+ end
+ if replace then
+ local i = p.replaceinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ setlink(replacetail,fontkern(xscaled(current,leftkern)))
+ done = true
+ end
+ end
+ else
+ local i = p.emptyinjections
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ replace = fontkern(xscaled(current,leftkern))
+ done = true
+ end
+ end
+ end
+ if done then
+ setdisc(prevdisc,pre,post,replace)
+ end
+ end
+ end
+ else
+ -- cursive
+ if hascursives and maxc > 0 then
+ local nx, ny = getoffsets(current)
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + yscaled(current,properties[ti].cursivedy)
+ setoffsets(ti,false,ny) -- can be mark, we could use properties
+ end
+ maxc = 0
+ cursiveanchor = nil
+ end
+ end
+ prevdisc = nil
+ prevglyph = current
+ elseif char == false then
+ -- base = nil
+ prevdisc = nil
+ prevglyph = current
+ elseif id == disc_code then
+ -- base = nil
+ pre, post, replace, pretail, posttail, replacetail = getdisc(current,true)
+ local done = false
+ if pre then
+ -- left|pre glyphs|right
+ for n in nextchar, pre do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.preinjections
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ addyoffset(n,yscaled(n,yoffset))
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ pre = insert_node_before(pre,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(pre,n,fontkern(xscaled(n,rightkern)))
+ done = true
+ end
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,n,i)
+ end
+ end
+ end
+ end
+ end
+ end
+ if post then
+ -- left|post glyphs|right
+ for n in nextchar, post do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.postinjections
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ addyoffset(n,yscaled(n,yoffset))
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ post = insert_node_before(post,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ done = true
+ insert_node_after(post,n,fontkern(xscaled(n,rightkern)))
+ end
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,n,i)
+ end
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ -- left|replace glyphs|right
+ for n in nextchar, replace do
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections or p.replaceinjections
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ addyoffset(n,yscaled(n,yoffset))
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ replace = insert_node_before(replace,n,fontkern(xscaled(n,leftkern)))
+ done = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(replace,n,fontkern(xscaled(n,rightkern)))
+ done = true
+ end
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,n,i)
+ end
+ end
+ end
+ end
+ end
+ end
+ if prevglyph then
+ if pre then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = p.preinjections
+ if i then
+ -- glyph|pre glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ pre = insert_node_before(pre,pre,fontkern(xscaled(prevglyph,rightkern)))
+ done = true
+ end
+ end
+ end
+ end
+ if replace then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = p.replaceinjections
+ if i then
+ -- glyph|replace glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ replace = insert_node_before(replace,replace,fontkern(xscaled(prevglyph,rightkern)))
+ done = true
+ end
+ end
+ end
+ end
+ end
+ if done then
+ setdisc(current,pre,post,replace)
+ end
+ prevglyph = nil
+ prevdisc = current
+ else
+ -- base = nil
+ prevglyph = nil
+ prevdisc = nil
+ end
+ prev = current
+ current = next
+ end
+ -- cursive
+ if hascursives and maxc > 0 then
+ local nx, ny = getoffsets(last)
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + yscaled(properties[ti].cursivedy)
+ setoffsets(ti,false,ny)
+ if trace_cursive then
+ showoffset(ti)
+ end
+ end
+ end
+ --
+ if nofmarks > 0 then
+ for i=1,nofmarks do
+ local m = marks[i]
+ local p = rawget(properties,m)
+ local i = p.injections
+ local b = i.markbasenode
+ processmark(b,m,i)
+ end
+ elseif hasmarks then
+ -- sometyhing bad happened
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ nofregisteredpositions = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ end
+ if trace_injections then
+ show_result(head)
+ end
+ return head
+end
+
+-- space triggers
+
+local triggers = false
+
+function nodes.injections.setspacekerns(font,sequence)
+ if triggers then
+ triggers[font] = sequence
+ else
+ triggers = { [font] = sequence }
+ end
+end
+
+local threshold = 1 -- todo: add a few methods for context
+
+directives.register("otf.threshold", function(v) threshold = tonumber(v) or 1 end)
+
+local getthreshold = function(font)
+ local p = parameters[font]
+ local f = p.factor
+ local s = p.spacing
+ local t = threshold * (s and s.width or p.space or 0) - 2
+ return t > 0 and t or 0, f
+end
+
+injections.getthreshold = getthreshold
+
+function injections.isspace(n,threshold,id)
+ if (id or getid(n)) == glue_code then
+ local w = getwidth(n)
+ if threshold and w > threshold then -- was >=
+ return 32
+ end
+ end
+end
+
+-- We have a plugin so that Kai can use the next in plain. Such a plugin is rather application
+-- specific.
+--
+-- local getboth = nodes.direct.getboth
+-- local getid = nodes.direct.getid
+-- local getprev = nodes.direct.getprev
+-- local getnext = nodes.direct.getnext
+--
+-- local whatsit_code = nodes.nodecodes.whatsit
+-- local glyph_code = nodes.nodecodes.glyph
+--
+-- local function getspaceboth(n) -- fragile: what it prev/next has no width field
+-- local prev, next = getboth(n)
+-- while prev and (getid(prev) == whatsit_code or (getwidth(prev) == 0 and getid(prev) ~= glyph_code)) do
+-- prev = getprev(prev)
+-- end
+-- while next and (getid(next) == whatsit_code or (getwidth(next) == 0 and getid(next) ~= glyph_code)) do
+-- next = getnext(next)
+-- end
+-- end
+--
+-- injections.installgetspaceboth(getspaceboth)
+
+local getspaceboth = getboth
+
+function injections.installgetspaceboth(gb)
+ getspaceboth = gb or getboth
+end
+
+local function injectspaces(head)
+
+ if not triggers then
+ return head
+ end
+ local lastfont = nil
+ local spacekerns = nil
+ local leftkerns = nil
+ local rightkerns = nil
+ local factor = 0
+ local threshold = 0
+ local leftkern = false
+ local rightkern = false
+ local xscale = 1
+
+ local function updatefont(font,trig)
+ leftkerns = trig.left
+ rightkerns = trig.right
+ lastfont = font
+ threshold,
+ factor = getthreshold(font)
+ end
+
+ for n in nextglue, head do
+ local prev, next = getspaceboth(n)
+ local prevchar = prev and ischar(prev)
+ local nextchar = next and ischar(next)
+ if nextchar then
+ local font = getfont(next)
+ local trig = triggers[font]
+ if trig then
+ if lastfont ~= font then
+ updatefont(font,trig)
+ end
+ if rightkerns then
+ rightkern = rightkerns[nextchar]
+ end
+ xscale = getxscale(next)
+ end
+ end
+ if prevchar then
+ local font = getfont(prev)
+ local trig = triggers[font]
+ if trig then
+ if lastfont ~= font then
+ updatefont(font,trig)
+ end
+ if leftkerns then
+ leftkern = leftkerns[prevchar]
+ end
+ xscale = getxscale(prev)
+ end
+ end
+ if leftkern then
+ local old = getwidth(n)
+ if old > threshold then
+ if rightkern then
+ if useitalickerns then
+ local lnew = leftkern * factor
+ local rnew = rightkern * factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p + %p] %C",prevchar,lnew,old,rnew,nextchar)
+ end
+ lnew = lnew * xscale
+ rnew = rnew * xscale
+ head = insert_node_before(head,n,italickern(lnew))
+ insert_node_after(head,n,italickern(rnew))
+ else
+ local new = old + (leftkern + rightkern) * factor
+ if trace_spaces then
+ report_spaces("%C [%p -> %p] %C",prevchar,old,new,nextchar)
+ end
+ setwidth(n,new)
+ end
+ rightkern = false
+ else
+ if useitalickerns then
+ local new = leftkern * factor
+ if trace_spaces then
+ report_spaces("%C [%p + %p]",prevchar,old,new)
+ end
+ new = new * xscale
+ insert_node_after(head,n,italickern(new)) -- tricky with traverse but ok
+ else
+ local new = old + leftkern * factor * xscale
+ if trace_spaces then
+ report_spaces("%C [%p -> %p]",prevchar,old,new)
+ end
+ setwidth(n,new)
+ end
+ end
+ end
+ leftkern = false
+ elseif rightkern then
+ local old = getwidth(n)
+ if old > threshold then
+ local new = rightkern * factor * xscale
+ if useitalickerns then
+ if trace_spaces then
+ report_spaces("[%p + %p] %C",old,new,nextchar)
+ end
+ insert_node_after(head,n,italickern(new))
+ else
+ new = old + new
+ if trace_spaces then
+ report_spaces("[%p -> %p] %C",old,new,nextchar)
+ end
+ setwidth(n,new)
+ end
+ else
+ -- message
+ end
+ rightkern = false
+ end
+ end
+
+ triggers = false
+
+ return head
+end
+
+-- When advance is found to be okay there will be split functions (which is abit
+-- more efficient) but first we need to have scales done (we can also have addoffset
+-- and alike then)
+
+function injections.handler(head,where)
+ if triggers then
+ head = injectspaces(head)
+ end
+ if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
+ if trace_injections then
+ report_injections("injection variant %a (%s)","everything","kerns")
+ end
+ -- I will do useadvance here when I am playing with fonts that follow this
+ -- injection routem, which is seldom.
+ return inject_everything(head,where)
+ elseif nofregisteredpositions > 0 then
+ if trace_injections then
+ report_injections("injection variant %a (%s)","positions",useadvance and "margins" or "kerns")
+ end
+ if useadvance then
+ return inject_positions_only_margins(head,where)
+ else
+ return inject_positions_only_kerns(head,where)
+ end
+ elseif nofregisteredkerns > 0 then
+ if trace_injections then
+ report_injections("injection variant %a (%s)","kerns",useadvance and "margins" or "kerns")
+ end
+ if useadvance then
+ return inject_kerns_only_margins(head,where)
+-- return inject_positions_only_margins(head,where)
+ else
+ return inject_kerns_only_kerns(head,where)
+ end
+ else
+ return head
+ end
+end
+