diff options
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.lmt | 2556 |
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 + |