summaryrefslogtreecommitdiff
path: root/src/fontloader
diff options
context:
space:
mode:
Diffstat (limited to 'src/fontloader')
-rw-r--r--src/fontloader/misc/fontloader-basics-nod.lua8
-rw-r--r--src/fontloader/misc/fontloader-font-otf.lua33
-rw-r--r--src/fontloader/misc/fontloader-fonts-cbk.lua44
-rw-r--r--src/fontloader/misc/fontloader-fonts-inj.lua1286
-rw-r--r--src/fontloader/misc/fontloader-fonts.lua9
-rw-r--r--src/fontloader/misc/fontloader-test.tex14
-rw-r--r--src/fontloader/runtime/fontloader-fontloader.lua1204
7 files changed, 1775 insertions, 823 deletions
diff --git a/src/fontloader/misc/fontloader-basics-nod.lua b/src/fontloader/misc/fontloader-basics-nod.lua
index ea539f3..1ec2895 100644
--- a/src/fontloader/misc/fontloader-basics-nod.lua
+++ b/src/fontloader/misc/fontloader-basics-nod.lua
@@ -154,8 +154,8 @@ nodes.unset_attribute = node.unset_attribute
nodes.protect_glyphs = node.protect_glyphs
nodes.unprotect_glyphs = node.unprotect_glyphs
-nodes.kerning = node.kerning
-nodes.ligaturing = node.ligaturing
+-----.kerning = node.kerning
+-----.ligaturing = node.ligaturing
nodes.mlist_to_hlist = node.mlist_to_hlist
-- in generic code, at least for some time, we stay nodes, while in context
@@ -194,8 +194,12 @@ nuts.insert_before = direct.insert_before
nuts.insert_after = direct.insert_after
nuts.delete = direct.delete
nuts.copy = direct.copy
+nuts.copy_list = direct.copy_list
nuts.tail = direct.tail
nuts.flush_list = direct.flush_list
+nuts.free = direct.free
+nuts.remove = direct.remove
+nuts.is_node = direct.is_node
nuts.end_of_math = direct.end_of_math
nuts.traverse = direct.traverse
nuts.traverse_id = direct.traverse_id
diff --git a/src/fontloader/misc/fontloader-font-otf.lua b/src/fontloader/misc/fontloader-font-otf.lua
index 302d8ea..1bb608f 100644
--- a/src/fontloader/misc/fontloader-font-otf.lua
+++ b/src/fontloader/misc/fontloader-font-otf.lua
@@ -2000,6 +2000,8 @@ actions["reorganize glyph lookups"] = function(data,filename,raw)
end
+local zero = { 0, 0 }
+
actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we replace inplace we safe entries
local descriptions = data.descriptions
for unicode, description in next, descriptions do
@@ -2008,14 +2010,37 @@ actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we rep
for class, data in next, anchors do
if class == "baselig" then
for tag, specification in next, data do
- for i=1,#specification do
- local si = specification[i]
- specification[i] = { si.x or 0, si.y or 0 }
+ -- for i=1,#specification do
+ -- local si = specification[i]
+ -- specification[i] = { si.x or 0, si.y or 0 }
+ -- end
+ -- can be sparse so we need to fill the holes
+ local n = 0
+ for k, v in next, specification do
+ if k > n then
+ n = k
+ end
+ local x, y = v.x, v.y
+ if x or y then
+ specification[k] = { x or 0, y or 0 }
+ else
+ specification[k] = zero
+ end
end
+ local t = { }
+ for i=1,n do
+ t[i] = specification[i] or zero
+ end
+ data[tag] = t -- so # is okay (nicer for packer)
end
else
for tag, specification in next, data do
- data[tag] = { specification.x or 0, specification.y or 0 }
+ local x, y = specification.x, specification.y
+ if x or y then
+ data[tag] = { x or 0, y or 0 }
+ else
+ data[tag] = zero
+ end
end
end
end
diff --git a/src/fontloader/misc/fontloader-fonts-cbk.lua b/src/fontloader/misc/fontloader-fonts-cbk.lua
index 965b968..414cafb 100644
--- a/src/fontloader/misc/fontloader-fonts-cbk.lua
+++ b/src/fontloader/misc/fontloader-fonts-cbk.lua
@@ -29,11 +29,28 @@ local kerning = node.kerning
local basepass = true
+local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning = nil end
+local function k_warning() texio.write_nl("warning: node.kerning called directly") k_warning = nil end
+
+function node.ligaturing(...)
+ if basepass and l_warning then
+ l_warning()
+ end
+ return ligaturing(...)
+end
+
+function node.kerning(...)
+ if basepass and k_warning then
+ k_warning()
+ end
+ return kerning(...)
+end
+
function nodes.handlers.setbasepass(v)
basepass = v
end
-function nodes.handlers.characters(head)
+function nodes.handlers.nodepass(head)
local fontdata = fonts.hashes.identifiers
if fontdata then
local usedfonts = { }
@@ -115,14 +132,27 @@ function nodes.handlers.characters(head)
end
end
-function nodes.simple_font_handler(head)
- -- lang.hyphenate(head)
- head = nodes.handlers.characters(head)
- nodes.injections.handler(head)
+function nodes.handlers.basepass(head)
if not basepass then
head = ligaturing(head)
head = kerning(head)
end
- nodes.handlers.protectglyphs(head)
- return head
+ return head, true
+end
+
+local nodepass = nodes.handlers.nodepass
+local basepass = nodes.handlers.basepass
+local injectpass = nodes.injections.handler
+local protectpass = nodes.handlers.protectglyphs
+
+function nodes.simple_font_handler(head)
+ if head then
+ head = nodepass(head)
+ head = injectpass(head)
+ head = basepass(head)
+ protectpass(head)
+ return head, true
+ else
+ return head, false
+ end
end
diff --git a/src/fontloader/misc/fontloader-fonts-inj.lua b/src/fontloader/misc/fontloader-fonts-inj.lua
index 4024035..3b93382 100644
--- a/src/fontloader/misc/fontloader-fonts-inj.lua
+++ b/src/fontloader/misc/fontloader-fonts-inj.lua
@@ -1,23 +1,25 @@
-if not modules then modules = { } end modules ['node-inj'] = {
+if not modules then modules = { } end modules ['font-inj'] = {
version = 1.001,
- comment = "companion to node-ini.mkiv",
+ 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 is very experimental (this will change when we have luatex > .50 and
--- a few pending thingies are available. Also, Idris needs to make a few more
--- test fonts. Some optimizations can go away when we have faster machines.
+-- This property based variant is not faster but looks nicer than the attribute one. We
+-- need to use rawget (which is apbout 4 times slower than a direct access but we cannot
+-- get/set that one for our purpose!
--- todo: ignore kerns between disc and glyph
+if not nodes.properties then return end
-local next = next
+local next, rawget = next, rawget
local utfchar = utf.char
-local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
+local trace_injections = false trackers.register("fonts.injections", function(v) trace_injections = v end)
-local report_injections = logs.reporter("nodes","injections")
+local report_injections = logs.reporter("fonts","injections")
+
+report_injections("using experimental injector")
local attributes, nodes, node = attributes, nodes, node
@@ -29,6 +31,7 @@ local injections = nodes.injections
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
local kern_code = nodecodes.kern
local nuts = nodes.nuts
@@ -40,207 +43,351 @@ local tonode = nuts.tonode
local tonut = nuts.tonut
local getfield = nuts.getfield
+local setfield = nuts.setfield
local getnext = nuts.getnext
local getprev = nuts.getprev
local getid = nuts.getid
-local getattr = nuts.getattr
local getfont = nuts.getfont
local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
-local setfield = nuts.setfield
-local setattr = nuts.setattr
-
local traverse_id = nuts.traverse_id
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
+local find_tail = nuts.tail
-local a_kernpair = attributes.private('kernpair')
-local a_ligacomp = attributes.private('ligacomp')
-local a_markbase = attributes.private('markbase')
-local a_markmark = attributes.private('markmark')
-local a_markdone = attributes.private('markdone')
-local a_cursbase = attributes.private('cursbase')
-local a_curscurs = attributes.private('curscurs')
-local a_cursdone = attributes.private('cursdone')
-
-local unsetvalue = attributes.unsetvalue
-
--- This injector has been tested by Idris Samawi Hamid (several arabic fonts as well as
--- the rather demanding Husayni font), Khaled Hosny (latin and arabic) and Kaj Eigner
--- (arabic, hebrew and thai) and myself (whatever font I come across). I'm pretty sure
--- that this code is not 100% okay but examples are needed to figure things out.
+local properties = nodes.properties.data
function injections.installnewkern(nk)
newkern = nk or newkern
end
-local cursives = { }
-local marks = { }
-local kerns = { }
+local nofregisteredkerns = 0
+local nofregisteredpairs = 0
+local nofregisteredmarks = 0
+local nofregisteredcursives = 0
+----- markanchors = { } -- one base can have more marks
+local keepregisteredcounts = false
--- Currently we do gpos/kern in a bit inofficial way but when we have the extra fields in
--- glyphnodes to manipulate ht/dp/wd explicitly I will provide an alternative; also, we
--- can share tables.
+function injections.keepcounts()
+ keepregisteredcounts = true
+end
--- For the moment we pass the r2l key ... volt/arabtype tests .. idris: this needs
--- checking with husayni (volt and fontforge).
+function injections.resetcounts()
+ nofregisteredkerns = 0
+ nofregisteredpairs = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ keepregisteredcounts = false
+end
function injections.reset(n)
--- if getattr(n,a_kernpair) then
--- setattr(n,a_kernpair,unsetvalue)
--- end
--- if getattr(n,a_markdone) then
--- setattr(n,a_markbase,unsetvalue)
--- setattr(n,a_markmark,unsetvalue)
--- setattr(n,a_markdone,unsetvalue)
--- end
--- if getattr(n,a_cursdone) then
--- setattr(n,a_cursbase,unsetvalue)
--- setattr(n,a_curscurs,unsetvalue)
--- setattr(n,a_cursdone,unsetvalue)
--- end
--- if getattr(n,a_ligacomp) then
--- setattr(n,a_ligacomp,unsetvalue)
--- end
+ local p = rawget(properties,start)
+ if p and p.injections then
+ -- todo: decrement counters? tricky as we then need to change the nof* to not increment
+ -- when we change a property
+ p.injections = nil -- should we keep the liga index?
+ end
end
function injections.setligaindex(n,index)
- setattr(n,a_ligacomp,index)
+ 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)
- return getattr(n,a_ligacomp) or default
+ local p = rawget(properties,n)
+ if p then
+ p = p.injections
+ if p then
+ return p.ligaindex or default
+ end
+ end
+ return default
end
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
- local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) -- hm: nuts or nodes
+ local dx = factor*(exit[1]-entry[1])
+ local dy = -factor*(exit[2]-entry[2])
local ws, wn = tfmstart.width, tfmnext.width
- local bound = #cursives + 1
- setattr(start,a_cursbase,bound)
- setattr(nxt,a_curscurs,bound)
- cursives[bound] = { rlmode, dx, dy, ws, wn }
- return dx, dy, bound
+ nofregisteredcursives = nofregisteredcursives + 1
+ if rlmode < 0 then
+ dx = -(dx + wn)
+ else
+ dx = dx - ws
+ 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
-function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
+function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2lflag & tfmchr not used
local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
- -- dy = y - h
- if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
- local bound = getattr(current,a_kernpair)
- if bound then
- local kb = kerns[bound]
- -- inefficient but singles have less, but weird anyway, needs checking
- kb[2], kb[3], kb[4], kb[5] = (kb[2] or 0) + x, (kb[3] or 0) + y, (kb[4] or 0)+ w, (kb[5] or 0) + h
- else
- bound = #kerns + 1
- setattr(current,a_kernpair,bound)
- kerns[bound] = { rlmode, x, y, w, h, r2lflag, tfmchr.width }
- end
- return x, y, w, h, bound
+ 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
+ nofregisteredpairs = nofregisteredpairs + 1
+ if rlmode and rlmode < 0 then
+ leftkern, rightkern = rightkern, leftkern
+ end
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ if leftkern ~= 0 or rightkern ~= 0 then
+ i.leftkern = i.leftkern or 0 + leftkern
+ 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.injections = {
+ leftkern = leftkern,
+ rightkern = rightkern,
+ yoffset = yoffset,
+ }
+ else
+ p.injections = {
+ yoffset = yoffset,
+ }
+ end
+ elseif leftkern ~= 0 or rightkern ~= 0 then
+ properties[current] = {
+ injections = {
+ leftkern = leftkern,
+ rightkern = rightkern,
+ yoffset = yoffset,
+ },
+ }
+ else
+ properties[current] = {
+ injections = {
+ yoffset = yoffset,
+ },
+ }
+ end
+ return x, y, w, h, nofregisteredpairs
+ end
end
return x, y, w, h -- no bound
end
-function injections.setkern(current,factor,rlmode,x,tfmchr)
- local dx = factor*x
+-- this needs checking for rl < 0 but it is unlikely that a r2l script
+-- uses kernclasses between glyphs so we're probably safe (KE has a
+-- problematic font where marks interfere with rl < 0 in the previous
+-- case)
+
+function injections.setkern(current,factor,rlmode,x,injection)
+ local dx = factor * x
if dx ~= 0 then
- local bound = #kerns + 1
- setattr(current,a_kernpair,bound)
- kerns[bound] = { rlmode, dx }
- return dx, bound
+ 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
-function injections.setmark(start,base,factor,rlmode,ba,ma) -- ba=baseanchor, ma=markanchor
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=baseanchor, ma=markanchor
local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
- local bound = getattr(base,a_markbase)
- local index = 1
- if bound then
- local mb = marks[bound]
- if mb then
- -- if not index then index = #mb + 1 end
- index = #mb + 1
- mb[index] = { dx, dy, rlmode }
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- return dx, dy, bound
+ nofregisteredmarks = nofregisteredmarks + 1
+ -- markanchors[nofregisteredmarks] = base
+ if rlmode >= 0 then
+ dx = tfmbase.width - dx -- see later commented ox
+ end
+ local p = rawget(properties,start)
+ if p then
+ local i = p.injections
+ if i then
+ i.markx = dx
+ i.marky = dy
+ i.markdir = rlmode or 0
+ i.markbase = nofregisteredmarks
+ i.markbasenode = base
else
- report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound)
+ p.injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ }
end
+ else
+ properties[start] = {
+ injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ },
+ }
end
- index = index or 1
- bound = #marks + 1
- setattr(base,a_markbase,bound)
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- marks[bound] = { [index] = { dx, dy, rlmode } }
- return dx, dy, bound
+ 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 trace(head)
- report_injections("begin run")
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n) < 256 then
- local kp = getattr(n,a_kernpair)
- local mb = getattr(n,a_markbase)
- local mm = getattr(n,a_markmark)
- local md = getattr(n,a_markdone)
- local cb = getattr(n,a_cursbase)
- local cc = getattr(n,a_curscurs)
- local char = getchar(n)
- report_injections("font %s, char %U, glyph %c",getfont(n),char,char)
- if kp then
- local k = kerns[kp]
- if k[3] then
- report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5])
- else
- report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2])
+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 p = p[what]
+ if p then
+ local leftkern = p.leftkern or 0
+ local rightkern = p.rightkern or 0
+ local yoffset = p.yoffset or 0
+ local markx = p.markx or 0
+ local marky = p.marky or 0
+ local markdir = p.markdir or 0
+ local markbase = p.markbase or 0 -- will be markbasenode
+ local cursivex = p.cursivex or 0
+ local cursivey = p.cursivey or 0
+ local ligaindex = p.ligaindex or 0
+ 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
- end
- if mb then
- report_injections(" markbase: bound %a",mb)
- end
- if mm then
- local m = marks[mm]
- if mb then
- local m = m[mb]
- if m then
- report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2])
- else
- report_injections(" markmark: bound %a, missing index",mm)
- end
- else
- m = m[1]
- report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2])
+ 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
+ report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
+ end
+ if ligaindex ~= 0 then
+ report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
end
end
- if cb then
- report_injections(" cursbase: bound %a",cb)
+ end
+ end
+end
+
+local function showsub(n,what,where)
+ report_injections("begin subrun: %s",where)
+ for n in traverse_id(glyph_code,n) do
+ showchar(n,where)
+ show(n,what,where," ")
+ end
+ report_injections("end subrun")
+end
+
+local function trace(head)
+ report_injections("begin run: %s kerns, %s pairs, %s marks and %s cursives registered",
+ nofregisteredkerns,nofregisteredpairs,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,"=")
+ elseif id == disc_code then
+ local pre = getfield(n,"pre")
+ local post = getfield(n,"post")
+ local replace = getfield(n,"replace")
+ if pre then
+ showsub(pre,"preinjections","pre")
end
- if cc then
- local c = cursives[cc]
- report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3])
+ if post then
+ showsub(post,"postinjections","post")
+ end
+ if replace then
+ showsub(replace,"replaceinjections","replace")
end
end
+ n = getnext(n)
end
report_injections("end run")
end
--- todo: reuse tables (i.e. no collection), but will be extra fields anyway
--- todo: check for attribute
-
--- We can have a fast test on a font being processed, so we can check faster for marks etc
--- but I'll make a context variant anyway.
-
local function show_result(head)
- local current = head
+ local current = head
local skipping = false
while current do
local id = getid(current)
@@ -259,345 +406,616 @@ local function show_result(head)
end
end
-function injections.handler(head,where,keep)
- head = tonut(head)
- local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
- if has_marks or has_cursives then
- if trace_injections then
- trace(head)
+-- we could also check for marks here but maybe not all are registered (needs checking)
+
+local function collect_glyphs_1(head)
+ local glyphs, nofglyphs = { }, 0
+ local marks, nofmarks = { }, 0
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ local f = getfont(n)
+ if f ~= nf then
+ nf = f
+ tm = fontdata[nf].resources.marks -- other hash in ctx
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks = nofmarks + 1
+ marks[nofmarks] = n
+ else
+ nofglyphs = nofglyphs + 1
+ glyphs[nofglyphs] = n
+ end
+ -- yoffsets can influence curs steps
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ end
end
- -- in the future variant we will not copy items but refs to tables
- local done, ky, rl, valid, cx, wx, mk, nofvalid = false, { }, { }, { }, { }, { }, { }, 0
- if has_kerns then -- move outside loop
- local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
- if getsubtype(n) < 256 then
- nofvalid = nofvalid + 1
- valid[nofvalid] = n
- local f = getfont(n)
- if f ~= nf then
- nf = f
- tm = fontdata[nf].resources.marks -- other hash in ctx
+ end
+ return glyphs, nofglyphs, marks, nofmarks
+end
+
+local function collect_glyphs_2(head)
+ local glyphs, nofglyphs = { }, 0
+ local marks, nofmarks = { }, 0
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do
+ if getsubtype(n) < 256 then
+ local f = getfont(n)
+ if f ~= nf then
+ nf = f
+ tm = fontdata[nf].resources.marks -- other hash in ctx
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks = nofmarks + 1
+ marks[nofmarks] = n
+ else
+ nofglyphs = nofglyphs + 1
+ glyphs[nofglyphs] = n
+ end
+ end
+ end
+ return glyphs, nofglyphs, marks, nofmarks
+end
+
+local function inject_marks(marks,nofmarks)
+ for i=1,nofmarks do
+ local n = marks[i]
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ if pn then
+ -- local markbase = pn.markbase
+ -- if markbase then
+ -- local p = markanchors[markbase]
+ local p = pn.markbasenode
+ if p then
+ local px = getfield(p,"xoffset")
+ local ox = 0
+ local pp = rawget(properties,p)
+ local rightkern = pp and pp.rightkern
+ if rightkern then -- x and w ~= 0
+ if pn.markdir < 0 then
+ -- kern(w-x) glyph(p) kern(x) mark(n)
+ ox = px - pn.markx - rightkern
+ -- report_injections("r2l case 1: %p",ox)
+ else
+ -- kern(x) glyph(p) kern(w-x) mark(n)
+ -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern
+ ox = px - pn.markx - pp.leftkern
+ -- report_injections("l2r case 1: %p",ox)
+ end
+ else
+ -- we need to deal with fonts that have marks with width
+ -- if pn.markdir < 0 then
+ -- ox = px - pn.markx
+ -- -- report_injections("r2l case 3: %p",ox)
+ -- else
+ -- -- ox = px - getfield(p,"width") + pn.markx
+ ox = px - pn.markx
+ -- report_injections("l2r case 3: %p",ox)
+ -- end
+ local wn = getfield(n,"width") -- in arial marks have widths
+ if wn ~= 0 then
+ -- bad: we should center
+ -- insert_node_before(head,n,newkern(-wn/2))
+ -- insert_node_after(head,n,newkern(-wn/2))
+ pn.leftkern = -wn/2
+ pn.rightkern = -wn/2
+ -- wx[n] = { 0, -wn/2, 0, -wn }
+ end
+ -- so far
end
- if tm then
- mk[n] = tm[getchar(n)]
+ setfield(n,"xoffset",ox)
+ --
+ local py = getfield(p,"yoffset")
+ local oy = 0
+ if marks[p] then
+ oy = py + pn.marky
+ else
+ oy = getfield(n,"yoffset") + py + pn.marky
end
- local k = getattr(n,a_kernpair)
- if k then
- local kk = kerns[k]
- if kk then
- local x, y, w, h = kk[2] or 0, kk[3] or 0, kk[4] or 0, kk[5] or 0
- local dy = y - h
- if dy ~= 0 then
- ky[n] = dy
- end
- if w ~= 0 or x ~= 0 then
- wx[n] = kk
- end
- rl[n] = kk[1] -- could move in test
+ setfield(n,"yoffset",oy)
+ else
+ -- normally this can't happen (only when in trace mode which is a special case anyway)
+ -- report_injections("missing mark anchor %i",pn.markbase or 0)
+ end
+ -- end
+ end
+ end
+end
+
+local function inject_cursives(glyphs,nofglyphs)
+ local cursiveanchor, lastanchor = nil, nil
+ local minc, maxc, last = 0, 0, nil
+ for i=1,nofglyphs do
+ local n = glyphs[i]
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ if pn then
+ local cursivex = pn.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex ~= 0 then
+ pn.leftkern = pn.leftkern or 0 + cursivex
+ end
+ if lastanchor then
+ if maxc == 0 then
+ minc = lastanchor
end
+ maxc = lastanchor
+ properties[cursiveanchor].cursivedy = pn.cursivey
end
+ last = n
+ else
+ maxc = 0
+ end
+ elseif maxc > 0 then
+ local ny = getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",ny) -- why not add ?
end
+ maxc = 0
end
- else
- local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n) < 256 then
- nofvalid = nofvalid + 1
- valid[nofvalid] = n
- local f = getfont(n)
- if f ~= nf then
- nf = f
- tm = fontdata[nf].resources.marks -- other hash in ctx
- end
- if tm then
- mk[n] = tm[getchar(n)]
+ if pn.cursiveanchor then
+ cursiveanchor = n
+ lastanchor = i
+ else
+ cursiveanchor = nil
+ lastanchor = nil
+ if maxc > 0 then
+ local ny = getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",ny) -- why not add ?
end
+ maxc = 0
end
end
+ elseif maxc > 0 then
+ local ny = getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",getfield(ti,"yoffset") + ny) -- ?
+ end
+ maxc = 0
+ cursiveanchor = nil
+ lastanchor = nil
end
- if nofvalid > 0 then
- -- we can assume done == true because we have cursives and marks
- local cx = { }
- if has_kerns and next(ky) then
- for n, k in next, ky do
- setfield(n,"yoffset",k)
- end
+ -- if maxc > 0 and not cursiveanchor then
+ -- local ny = getfield(n,"yoffset")
+ -- for i=maxc,minc,-1 do
+ -- local ti = glyphs[i]
+ -- ny = ny + properties[ti].cursivedy
+ -- setfield(ti,"yoffset",ny) -- why not add ?
+ -- end
+ -- maxc = 0
+ -- end
+ end
+ if last and maxc > 0 then
+ local ny = getfield(last,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",ny) -- why not add ?
+ end
+ end
+end
+
+local function inject_kerns(head,glyphs,nofglyphs)
+ -- todo: pre/post/replace
+ for i=1,#glyphs do
+ local n = glyphs[i]
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ insert_node_before(head,n,newkern(leftkern)) -- type 0/2
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern)) -- type 0/2
end
- -- todo: reuse t and use maxt
- if has_cursives then
- local p_cursbase, p = nil, nil
- -- since we need valid[n+1] we can also use a "while true do"
- local t, d, maxt = { }, { }, 0
- for i=1,nofvalid do -- valid == glyphs
- local n = valid[i]
- if not mk[n] then
- local n_cursbase = getattr(n,a_cursbase)
- if p_cursbase then
- local n_curscurs = getattr(n,a_curscurs)
- if p_cursbase == n_curscurs then
- local c = cursives[n_curscurs]
- if c then
- local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
- if rlmode >= 0 then
- dx = dx - ws
- else
- dx = dx + wn
- end
- if dx ~= 0 then
- cx[n] = dx
- rl[n] = rlmode
- end
- -- if rlmode and rlmode < 0 then
- dy = -dy
- -- end
- maxt = maxt + 1
- t[maxt] = p
- d[maxt] = dy
- else
- maxt = 0
+ end
+ end
+end
+
+local function inject_everything(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local glyphs, nofglyphs, marks, nofmarks
+ if nofregisteredpairs > 0 then
+ glyphs, nofglyphs, marks, nofmarks = collect_glyphs_1(head)
+ else
+ glyphs, nofglyphs, marks, nofmarks = collect_glyphs_2(head)
+ end
+ if nofglyphs > 0 then
+ if nofregisteredcursives > 0 then
+ inject_cursives(glyphs,nofglyphs)
+ end
+ if nofregisteredmarks > 0 then
+ inject_marks(marks,nofmarks)
+ end
+ inject_kerns(head,glyphs,nofglyphs)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ nofregisteredpairs = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ end
+ return tonode(head), true
+end
+
+local function inject_kerns_only(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local n = head
+ local p = nil
+ while n do
+ local id = getid(n)
+ if id == glyph_code then
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ if p then
+ local d = getfield(p,"post")
+ if d then
+ local pn = pn.postinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
end
- elseif maxt > 0 then
- local ny = getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- setfield(ti,"yoffset",getfield(ti,"yoffset") + ny)
+ end
+ local d = getfield(p,"replace")
+ if d then
+ local pn = pn.replaceinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ end
+ else
+ local pn = pn.injections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ setfield(p,"replace",newkern(leftkern))
+ end
end
- maxt = 0
end
- if not n_cursbase and maxt > 0 then
- local ny = getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- setfield(ti,"yoffset",ny) -- maybe add to current yoffset
+ else
+ local pn = pn.injections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ head = insert_node_before(head,n,newkern(leftkern))
end
- maxt = 0
end
- p_cursbase, p = n_cursbase, n
end
end
- if maxt > 0 then
- local ny = getfield(n,"yoffset") -- hm, n unset ?
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- setfield(ti,"yoffset",ny)
+ else
+ break
+ end
+ p = nil
+ elseif id == disc_code then
+ local d = getfield(n,"pre")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.preinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ end
+ else
+ break
end
- maxt = 0
end
- if not keep then
- cursives = { }
+ if h ~= d then
+ setfield(n,"pre",h)
end
end
- if has_marks then
- for i=1,nofvalid do
- local p = valid[i]
- local p_markbase = getattr(p,a_markbase)
- if p_markbase then
- local mrks = marks[p_markbase]
- local nofmarks = #mrks
- for n in traverse_id(glyph_code,getnext(p)) do
- local n_markmark = getattr(n,a_markmark)
- if p_markbase == n_markmark then
- local index = getattr(n,a_markdone) or 1
- local d = mrks[index]
- if d then
- local rlmode = d[3]
- --
- local k = wx[p]
- local px = getfield(p,"xoffset")
- local ox = 0
- if k then
- local x = k[2]
- local w = k[4]
- if w then
- if rlmode and rlmode >= 0 then
- -- kern(x) glyph(p) kern(w-x) mark(n)
- ox = px - getfield(p,"width") + d[1] - (w-x)
- -- report_injections("l2r case 1: %p",ox)
- else
- -- kern(w-x) glyph(p) kern(x) mark(n)
- ox = px - d[1] - x
- -- report_injections("r2l case 1: %p",ox)
- end
- else
- if rlmode and rlmode >= 0 then
- -- okay for husayni
- ox = px - getfield(p,"width") + d[1]
- -- report_injections("r2l case 2: %p",ox)
- else
- -- needs checking: is x ok here?
- ox = px - d[1] - x
- -- report_injections("r2l case 2: %p",ox)
- end
- end
- else
- -- if rlmode and rlmode >= 0 then
- -- ox = px - getfield(p,"width") + d[1]
- -- -- report_injections("l2r case 3: %p",ox)
- -- else
- -- ox = px - d[1]
- -- -- report_injections("r2l case 3: %p",ox)
- -- end
- --
- -- we need to deal with fonts that have marks with width
- --
- local wp = getfield(p,"width")
- local wn = getfield(n,"width") -- in arial marks have widths
- if rlmode and rlmode >= 0 then
- ox = px - wp + d[1]
- -- report_injections("l2r case 3: %p",ox)
- else
- ox = px - d[1]
- -- report_injections("r2l case 3: %p",ox)
- end
- if wn ~= 0 then
- -- bad: we should center
- insert_node_before(head,n,newkern(-wn/2))
- insert_node_after(head,n,newkern(-wn/2))
- -- wx[n] = { 0, -wn/2, 0, -wn }
- end
- -- so far
- end
- setfield(n,"xoffset",ox)
- --
- local py = getfield(p,"yoffset")
- local oy = 0
- if mk[p] then
- oy = py + d[2]
- else
- oy = getfield(n,"yoffset") + py + d[2]
- end
- setfield(n,"yoffset",oy)
- --
- if nofmarks == 1 then
- break
- else
- nofmarks = nofmarks - 1
- end
- end
- elseif not n_markmark then
- break -- HH: added 2013-09-12: no need to deal with non marks
- else
- -- KE: there can be <mark> <mkmk> <mark> sequences in ligatures
+ local d = getfield(n,"post")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.postinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
end
end
+ else
+ break
end
end
- if not keep then
- marks = { }
+ if h ~= d then
+ setfield(n,"post",h)
end
end
- -- todo : combine
- if next(wx) then
- for n, k in next, wx do
- -- only w can be nil (kernclasses), can be sped up when w == nil
- local x = k[2]
- local w = k[4]
- if w then
- local rl = k[1] -- r2l = k[6]
- local wx = w - x
- if rl < 0 then -- KE: don't use r2l here
- if wx ~= 0 then
- insert_node_before(head,n,newkern(wx)) -- type 0/2
+ local d = getfield(n,"replace")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n) -- why can it be empty { }
+ if pn then
+ pn = pn.replaceinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
end
- if x ~= 0 then
- insert_node_after (head,n,newkern(x)) -- type 0/2
+ end
+ else
+ break
+ end
+ end
+ if h ~= d then
+ setfield(n,"replace",h)
+ end
+ end
+ p = n
+ else
+ p = nil
+ end
+ n = getnext(n)
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ end
+ return tonode(head), true
+end
+
+local function inject_pairs_only(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ --
+ local n = head
+ local p = nil
+ while n do
+ local id = getid(n)
+ if id == glyph_code then
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ if p then
+ local d = getfield(p,"post")
+ if d then
+ local pn = pn.postinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ -- local rightkern = pn.rightkern
+ -- if rightkern and rightkern ~= 0 then
+ -- insert_node_after(head,n,newkern(rightkern))
+ -- n = getnext(n) -- to be checked
+ -- end
+ end
+ end
+ local d = getfield(p,"replace")
+ if d then
+ local pn = pn.replaceinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ -- local rightkern = pn.rightkern
+ -- if rightkern and rightkern ~= 0 then
+ -- insert_node_after(head,n,newkern(rightkern))
+ -- n = getnext(n) -- to be checked
+ -- end
end
else
- if x ~= 0 then
- insert_node_before(head,n,newkern(x)) -- type 0/2
+ local pn = pn.injections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ setfield(p,"replace",newkern(leftkern))
+ end
+ -- local rightkern = pn.rightkern
+ -- if rightkern and rightkern ~= 0 then
+ -- insert_node_after(head,n,newkern(rightkern))
+ -- n = getnext(n) -- to be checked
+ -- end
+ end
+ end
+ else
+ -- this is the most common case
+ local pn = pn.injections
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
end
- if wx ~= 0 then
- insert_node_after (head,n,newkern(wx)) -- type 0/2
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ insert_node_before(head,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
end
end
- elseif x ~= 0 then
- -- this needs checking for rl < 0 but it is unlikely that a r2l script
- -- uses kernclasses between glyphs so we're probably safe (KE has a
- -- problematic font where marks interfere with rl < 0 in the previous
- -- case)
- insert_node_before(head,n,newkern(x)) -- a real font kern, type 0
end
end
+ else
+ break
end
- if next(cx) then
- for n, k in next, cx do
- if k ~= 0 then
- local rln = rl[n]
- if rln and rln < 0 then
- insert_node_before(head,n,newkern(-k)) -- type 0/2
- else
- insert_node_before(head,n,newkern(k)) -- type 0/2
+ p = nil
+ elseif id == disc_code then
+ local d = getfield(n,"pre")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.preinjections
end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
+ end
+ end
+ else
+ break
end
end
+ if h ~= d then
+ setfield(n,"pre",h)
+ end
end
- if not keep then
- kerns = { }
+ local d = getfield(n,"post")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.postinjections
+ end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
+ end
+ end
+ else
+ break
+ end
+ end
+ if h ~= d then
+ setfield(n,"post",h)
+ end
end
- -- if trace_injections then
- -- show_result(head)
- -- end
- return tonode(head), true
- elseif not keep then
- kerns, cursives, marks = { }, { }, { }
- end
- elseif has_kerns then
- if trace_injections then
- trace(head)
- end
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n) < 256 then
- local k = getattr(n,a_kernpair)
- if k then
- local kk = kerns[k]
- if kk then
- local rl, x, y, w = kk[1], kk[2] or 0, kk[3], kk[4]
- if y and y ~= 0 then
- setfield(n,"yoffset",y) -- todo: h ?
+ local d = getfield(n,"replace")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.replaceinjections
end
- if w then
- -- copied from above
- -- local r2l = kk[6]
- local wx = w - x
- if rl < 0 then -- KE: don't use r2l here
- if wx ~= 0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x ~= 0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx ~= 0 then
- insert_node_after(head,n,newkern(wx))
- end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
end
- else
- -- simple (e.g. kernclass kerns)
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
end
end
+ else
+ break
end
end
+ if h ~= d then
+ setfield(n,"replace",h)
+ end
end
+ p = n
+ else
+ p = nil
end
- if not keep then
- kerns = { }
- end
- -- if trace_injections then
- -- show_result(head)
- -- end
- return tonode(head), true
+ n = getnext(n)
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredpairs = 0
+ nofregisteredkerns = 0
+ end
+ return tonode(head), true
+end
+
+function injections.handler(head,where) -- optimize for n=1 ?
+ if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
+ return inject_everything(head,where)
+ elseif nofregisteredpairs > 0 then
+ return inject_pairs_only(head,where)
+ elseif nofregisteredkerns > 0 then
+ return inject_kerns_only(head,where)
else
- -- no tracing needed
+ return head, false
end
- return tonode(head), false
end
diff --git a/src/fontloader/misc/fontloader-fonts.lua b/src/fontloader/misc/fontloader-fonts.lua
index 678a283..c81e8cd 100644
--- a/src/fontloader/misc/fontloader-fonts.lua
+++ b/src/fontloader/misc/fontloader-fonts.lua
@@ -29,11 +29,12 @@ if not modules then modules = { } end modules ['luatex-fonts'] = {
texio.write_nl("")
texio.write_nl("--------------------------------------------------------------------------------")
-texio.write_nl("The font code has been brought in sync with the context version of 2014.12.01 so")
+texio.write_nl("The font code has been brought in sync with the context version of 2014.12.21 so")
texio.write_nl("if things don't work out as expected the interfacing needs to be checked. When")
texio.write_nl("this works as expected a second upgrade will happen that gives a more complete")
texio.write_nl("support and another sync with the context code (that new code is currently being")
-texio.write_nl("tested. The base pass is now integrated in the main pass.")
+texio.write_nl("tested. The base pass is now integrated in the main pass. The results can differ")
+texio.write_nl("from those in context because there we integrate some mechanisms differently.")
texio.write_nl("--------------------------------------------------------------------------------")
texio.write_nl("")
@@ -260,8 +261,8 @@ generic_context.callback_define_font = fonts.definers.read
if not generic_context.no_callbacks_yet then
- -- callback.register('ligaturing', generic_context.callback_ligaturing)
- -- callback.register('kerning', generic_context.callback_kerning)
+ callback.register('ligaturing', generic_context.callback_ligaturing)
+ callback.register('kerning', generic_context.callback_kerning)
callback.register('pre_linebreak_filter', generic_context.callback_pre_linebreak_filter)
callback.register('hpack_filter', generic_context.callback_hpack_filter)
callback.register('define_font' , generic_context.callback_define_font)
diff --git a/src/fontloader/misc/fontloader-test.tex b/src/fontloader/misc/fontloader-test.tex
index 169a260..6f48e0c 100644
--- a/src/fontloader/misc/fontloader-test.tex
+++ b/src/fontloader/misc/fontloader-test.tex
@@ -35,14 +35,16 @@
\font\gothic=msgothic(ms-gothic) {\gothic whatever}
-\font\testy=file:IranNastaliq.ttf:mode=node;script=arab;language=dflt;+calt;+ccmp;+init;+isol;+medi;+fina;+liga;+rlig;+kern;+mark;+mkmk at 14pt
-\testy این یک متن نمونه است با قلم ذر که درست آمده است.
+\bgroup
-\pdfprotrudechars2 \pdfadjustspacing2
+ \pdfprotrudechars2
+ \pdfadjustspacing2
-\font\testb=file:lmroman12-regular:+liga;extend=1.5 at 12pt \testb \input tufte \par
-\font\testb=file:lmroman12-regular:+liga;slant=0.8 at 12pt \testb \input tufte \par
-\font\testb=file:lmroman12-regular:+liga;protrusion=default at 12pt \testb \input tufte \par
+ \font\testb=file:lmroman12-regular:+liga;extend=1.5 at 12pt \testb \input tufte \par
+ \font\testb=file:lmroman12-regular:+liga;slant=0.8 at 12pt \testb \input tufte \par
+ \font\testb=file:lmroman12-regular:+liga;protrusion=default at 12pt \testb \input tufte \par
+
+\egroup
\setmplibformat{plain}
diff --git a/src/fontloader/runtime/fontloader-fontloader.lua b/src/fontloader/runtime/fontloader-fontloader.lua
index f11a74c..96a7dd3 100644
--- a/src/fontloader/runtime/fontloader-fontloader.lua
+++ b/src/fontloader/runtime/fontloader-fontloader.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 12/11/14 12:02:53
+-- merge date : 12/21/14 22:25:48
do -- begin closure to overcome local limits and interference
@@ -3889,8 +3889,6 @@ nodes.set_attribute=node.set_attribute
nodes.unset_attribute=node.unset_attribute
nodes.protect_glyphs=node.protect_glyphs
nodes.unprotect_glyphs=node.unprotect_glyphs
-nodes.kerning=node.kerning
-nodes.ligaturing=node.ligaturing
nodes.mlist_to_hlist=node.mlist_to_hlist
local direct=node.direct
local nuts={}
@@ -3917,8 +3915,12 @@ nuts.insert_before=direct.insert_before
nuts.insert_after=direct.insert_after
nuts.delete=direct.delete
nuts.copy=direct.copy
+nuts.copy_list=direct.copy_list
nuts.tail=direct.tail
nuts.flush_list=direct.flush_list
+nuts.free=direct.free
+nuts.remove=direct.remove
+nuts.is_node=direct.is_node
nuts.end_of_math=direct.end_of_math
nuts.traverse=direct.traverse
nuts.traverse_id=direct.traverse_id
@@ -8730,6 +8732,7 @@ actions["reorganize glyph lookups"]=function(data,filename,raw)
end
end
end
+local zero={ 0,0 }
actions["reorganize glyph anchors"]=function(data,filename,raw)
local descriptions=data.descriptions
for unicode,description in next,descriptions do
@@ -8738,14 +8741,32 @@ actions["reorganize glyph anchors"]=function(data,filename,raw)
for class,data in next,anchors do
if class=="baselig" then
for tag,specification in next,data do
- for i=1,#specification do
- local si=specification[i]
- specification[i]={ si.x or 0,si.y or 0 }
+ local n=0
+ for k,v in next,specification do
+ if k>n then
+ n=k
+ end
+ local x,y=v.x,v.y
+ if x or y then
+ specification[k]={ x or 0,y or 0 }
+ else
+ specification[k]=zero
+ end
+ end
+ local t={}
+ for i=1,n do
+ t[i]=specification[i] or zero
end
+ data[tag]=t
end
else
for tag,specification in next,data do
- data[tag]={ specification.x or 0,specification.y or 0 }
+ local x,y=specification.x,specification.y
+ if x or y then
+ data[tag]={ x or 0,y or 0 }
+ else
+ data[tag]=zero
+ end
end
end
end
@@ -9819,17 +9840,19 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['node-inj']={
+if not modules then modules={} end modules ['font-inj']={
version=1.001,
- comment="companion to node-ini.mkiv",
+ 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",
}
-local next=next
+if not nodes.properties then return end
+local next,rawget=next,rawget
local utfchar=utf.char
-local trace_injections=false trackers.register("nodes.injections",function(v) trace_injections=v end)
-local report_injections=logs.reporter("nodes","injections")
+local trace_injections=false trackers.register("fonts.injections",function(v) trace_injections=v end)
+local report_injections=logs.reporter("fonts","injections")
+report_injections("using experimental injector")
local attributes,nodes,node=attributes,nodes,node
fonts=fonts
local fontdata=fonts.hashes.identifiers
@@ -9837,6 +9860,7 @@ nodes.injections=nodes.injections or {}
local injections=nodes.injections
local nodecodes=nodes.nodecodes
local glyph_code=nodecodes.glyph
+local disc_code=nodecodes.disc
local kern_code=nodecodes.kern
local nuts=nodes.nuts
local nodepool=nuts.pool
@@ -9844,149 +9868,316 @@ local newkern=nodepool.kern
local tonode=nuts.tonode
local tonut=nuts.tonut
local getfield=nuts.getfield
+local setfield=nuts.setfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getid=nuts.getid
-local getattr=nuts.getattr
local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
-local setfield=nuts.setfield
-local setattr=nuts.setattr
local traverse_id=nuts.traverse_id
local insert_node_before=nuts.insert_before
local insert_node_after=nuts.insert_after
-local a_kernpair=attributes.private('kernpair')
-local a_ligacomp=attributes.private('ligacomp')
-local a_markbase=attributes.private('markbase')
-local a_markmark=attributes.private('markmark')
-local a_markdone=attributes.private('markdone')
-local a_cursbase=attributes.private('cursbase')
-local a_curscurs=attributes.private('curscurs')
-local a_cursdone=attributes.private('cursdone')
-local unsetvalue=attributes.unsetvalue
+local find_tail=nuts.tail
+local properties=nodes.properties.data
function injections.installnewkern(nk)
newkern=nk or newkern
end
-local cursives={}
-local marks={}
-local kerns={}
+local nofregisteredkerns=0
+local nofregisteredpairs=0
+local nofregisteredmarks=0
+local nofregisteredcursives=0
+local keepregisteredcounts=false
+function injections.keepcounts()
+ keepregisteredcounts=true
+end
+function injections.resetcounts()
+ nofregisteredkerns=0
+ nofregisteredpairs=0
+ nofregisteredmarks=0
+ nofregisteredcursives=0
+ keepregisteredcounts=false
+end
function injections.reset(n)
+ local p=rawget(properties,start)
+ if p and p.injections then
+ p.injections=nil
+ end
end
function injections.setligaindex(n,index)
- setattr(n,a_ligacomp,index)
+ 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)
- return getattr(n,a_ligacomp) or default
+ local p=rawget(properties,n)
+ if p then
+ p=p.injections
+ if p then
+ return p.ligaindex or default
+ end
+ end
+ return default
end
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
- local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2])
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+ local dx=factor*(exit[1]-entry[1])
+ local dy=-factor*(exit[2]-entry[2])
local ws,wn=tfmstart.width,tfmnext.width
- local bound=#cursives+1
- setattr(start,a_cursbase,bound)
- setattr(nxt,a_curscurs,bound)
- cursives[bound]={ rlmode,dx,dy,ws,wn }
- return dx,dy,bound
-end
-function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
- local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4]
- if x~=0 or w~=0 or y~=0 or h~=0 then
- local bound=getattr(current,a_kernpair)
- if bound then
- local kb=kerns[bound]
- kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h
+ nofregisteredcursives=nofregisteredcursives+1
+ if rlmode<0 then
+ dx=-(dx+wn)
+ else
+ dx=dx-ws
+ 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
- bound=#kerns+1
- setattr(current,a_kernpair,bound)
- kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width }
+ p.injections={
+ cursivex=dx,
+ cursivey=dy,
+ }
end
- return x,y,w,h,bound
+ else
+ properties[nxt]={
+ injections={
+ cursivex=dx,
+ cursivey=dy,
+ },
+ }
+ end
+ return dx,dy,nofregisteredcursives
+end
+function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
+ local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4]
+ if x~=0 or w~=0 or y~=0 or h~=0 then
+ local yoffset=y-h
+ local leftkern=x
+ local rightkern=w-x
+ if leftkern~=0 or rightkern~=0 or yoffset~=0 then
+ nofregisteredpairs=nofregisteredpairs+1
+ if rlmode and rlmode<0 then
+ leftkern,rightkern=rightkern,leftkern
+ end
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ if leftkern~=0 or rightkern~=0 then
+ i.leftkern=i.leftkern or 0+leftkern
+ 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.injections={
+ leftkern=leftkern,
+ rightkern=rightkern,
+ yoffset=yoffset,
+ }
+ else
+ p.injections={
+ yoffset=yoffset,
+ }
+ end
+ elseif leftkern~=0 or rightkern~=0 then
+ properties[current]={
+ injections={
+ leftkern=leftkern,
+ rightkern=rightkern,
+ yoffset=yoffset,
+ },
+ }
+ else
+ properties[current]={
+ injections={
+ yoffset=yoffset,
+ },
+ }
+ end
+ return x,y,w,h,nofregisteredpairs
+ end
end
return x,y,w,h
end
-function injections.setkern(current,factor,rlmode,x,tfmchr)
+function injections.setkern(current,factor,rlmode,x,injection)
local dx=factor*x
if dx~=0 then
- local bound=#kerns+1
- setattr(current,a_kernpair,bound)
- kerns[bound]={ rlmode,dx }
- return dx,bound
+ 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
-function injections.setmark(start,base,factor,rlmode,ba,ma)
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase)
local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
- local bound=getattr(base,a_markbase)
- local index=1
- if bound then
- local mb=marks[bound]
- if mb then
- index=#mb+1
- mb[index]={ dx,dy,rlmode }
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- return dx,dy,bound
+ nofregisteredmarks=nofregisteredmarks+1
+ if rlmode>=0 then
+ dx=tfmbase.width-dx
+ end
+ local p=rawget(properties,start)
+ if p then
+ local i=p.injections
+ if i then
+ i.markx=dx
+ i.marky=dy
+ i.markdir=rlmode or 0
+ i.markbase=nofregisteredmarks
+ i.markbasenode=base
else
- report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound)
+ p.injections={
+ markx=dx,
+ marky=dy,
+ markdir=rlmode or 0,
+ markbase=nofregisteredmarks,
+ markbasenode=base,
+ }
end
+ else
+ properties[start]={
+ injections={
+ markx=dx,
+ marky=dy,
+ markdir=rlmode or 0,
+ markbase=nofregisteredmarks,
+ markbasenode=base,
+ },
+ }
end
- index=index or 1
- bound=#marks+1
- setattr(base,a_markbase,bound)
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- marks[bound]={ [index]={ dx,dy,rlmode } }
- return dx,dy,bound
+ 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 trace(head)
- report_injections("begin run")
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- local kp=getattr(n,a_kernpair)
- local mb=getattr(n,a_markbase)
- local mm=getattr(n,a_markmark)
- local md=getattr(n,a_markdone)
- local cb=getattr(n,a_cursbase)
- local cc=getattr(n,a_curscurs)
- local char=getchar(n)
- report_injections("font %s, char %U, glyph %c",getfont(n),char,char)
- if kp then
- local k=kerns[kp]
- if k[3] then
- report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5])
- else
- report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2])
+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 p=p[what]
+ if p then
+ local leftkern=p.leftkern or 0
+ local rightkern=p.rightkern or 0
+ local yoffset=p.yoffset or 0
+ local markx=p.markx or 0
+ local marky=p.marky or 0
+ local markdir=p.markdir or 0
+ local markbase=p.markbase or 0
+ local cursivex=p.cursivex or 0
+ local cursivey=p.cursivey or 0
+ local ligaindex=p.ligaindex or 0
+ 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
- end
- if mb then
- report_injections(" markbase: bound %a",mb)
- end
- if mm then
- local m=marks[mm]
- if mb then
- local m=m[mb]
- if m then
- report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2])
- else
- report_injections(" markmark: bound %a, missing index",mm)
- end
- else
- m=m[1]
- report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2])
+ 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
+ report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
+ end
+ if ligaindex~=0 then
+ report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
end
end
- if cb then
- report_injections(" cursbase: bound %a",cb)
+ end
+ end
+end
+local function showsub(n,what,where)
+ report_injections("begin subrun: %s",where)
+ for n in traverse_id(glyph_code,n) do
+ showchar(n,where)
+ show(n,what,where," ")
+ end
+ report_injections("end subrun")
+end
+local function trace(head)
+ report_injections("begin run: %s kerns, %s pairs, %s marks and %s cursives registered",
+ nofregisteredkerns,nofregisteredpairs,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,"=")
+ elseif id==disc_code then
+ local pre=getfield(n,"pre")
+ local post=getfield(n,"post")
+ local replace=getfield(n,"replace")
+ if pre then
+ showsub(pre,"preinjections","pre")
+ end
+ if post then
+ showsub(post,"postinjections","post")
end
- if cc then
- local c=cursives[cc]
- report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3])
+ if replace then
+ showsub(replace,"replaceinjections","replace")
end
end
+ n=getnext(n)
end
report_injections("end run")
end
@@ -10009,298 +10200,553 @@ local function show_result(head)
current=getnext(current)
end
end
-function injections.handler(head,where,keep)
- head=tonut(head)
- local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns)
- if has_marks or has_cursives then
- if trace_injections then
- trace(head)
- end
- local done,ky,rl,valid,cx,wx,mk,nofvalid=false,{},{},{},{},{},{},0
- if has_kerns then
- local nf,tm=nil,nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- nofvalid=nofvalid+1
- valid[nofvalid]=n
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
+local function collect_glyphs_1(head)
+ local glyphs,nofglyphs={},0
+ local marks,nofmarks={},0
+ local nf,tm=nil,nil
+ for n in traverse_id(glyph_code,head) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ local f=getfont(n)
+ if f~=nf then
+ nf=f
+ tm=fontdata[nf].resources.marks
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks=nofmarks+1
+ marks[nofmarks]=n
+ else
+ nofglyphs=nofglyphs+1
+ glyphs[nofglyphs]=n
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ end
+ end
+ end
+ return glyphs,nofglyphs,marks,nofmarks
+end
+local function collect_glyphs_2(head)
+ local glyphs,nofglyphs={},0
+ local marks,nofmarks={},0
+ local nf,tm=nil,nil
+ for n in traverse_id(glyph_code,head) do
+ if getsubtype(n)<256 then
+ local f=getfont(n)
+ if f~=nf then
+ nf=f
+ tm=fontdata[nf].resources.marks
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks=nofmarks+1
+ marks[nofmarks]=n
+ else
+ nofglyphs=nofglyphs+1
+ glyphs[nofglyphs]=n
+ end
+ end
+ end
+ return glyphs,nofglyphs,marks,nofmarks
+end
+local function inject_marks(marks,nofmarks)
+ for i=1,nofmarks do
+ local n=marks[i]
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ if pn then
+ local p=pn.markbasenode
+ if p then
+ local px=getfield(p,"xoffset")
+ local ox=0
+ local pp=rawget(properties,p)
+ local rightkern=pp and pp.rightkern
+ if rightkern then
+ if pn.markdir<0 then
+ ox=px-pn.markx-rightkern
+ else
+ ox=px-pn.markx-pp.leftkern
+ end
+ else
+ ox=px-pn.markx
+ local wn=getfield(n,"width")
+ if wn~=0 then
+ pn.leftkern=-wn/2
+ pn.rightkern=-wn/2
+ end
+ end
+ setfield(n,"xoffset",ox)
+ local py=getfield(p,"yoffset")
+ local oy=0
+ if marks[p] then
+ oy=py+pn.marky
+ else
+ oy=getfield(n,"yoffset")+py+pn.marky
end
- if tm then
- mk[n]=tm[getchar(n)]
+ setfield(n,"yoffset",oy)
+ else
+ end
+ end
+ end
+end
+local function inject_cursives(glyphs,nofglyphs)
+ local cursiveanchor,lastanchor=nil,nil
+ local minc,maxc,last=0,0,nil
+ for i=1,nofglyphs do
+ local n=glyphs[i]
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ if pn then
+ local cursivex=pn.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex~=0 then
+ pn.leftkern=pn.leftkern or 0+cursivex
end
- local k=getattr(n,a_kernpair)
- if k then
- local kk=kerns[k]
- if kk then
- local x,y,w,h=kk[2] or 0,kk[3] or 0,kk[4] or 0,kk[5] or 0
- local dy=y-h
- if dy~=0 then
- ky[n]=dy
- end
- if w~=0 or x~=0 then
- wx[n]=kk
- end
- rl[n]=kk[1]
+ if lastanchor then
+ if maxc==0 then
+ minc=lastanchor
end
+ maxc=lastanchor
+ properties[cursiveanchor].cursivedy=pn.cursivey
end
+ last=n
+ else
+ maxc=0
end
+ elseif maxc>0 then
+ local ny=getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",ny)
+ end
+ maxc=0
end
- else
- local nf,tm=nil,nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- nofvalid=nofvalid+1
- valid[nofvalid]=n
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
- end
- if tm then
- mk[n]=tm[getchar(n)]
+ if pn.cursiveanchor then
+ cursiveanchor=n
+ lastanchor=i
+ else
+ cursiveanchor=nil
+ lastanchor=nil
+ if maxc>0 then
+ local ny=getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",ny)
end
+ maxc=0
end
end
+ elseif maxc>0 then
+ local ny=getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
+ end
+ maxc=0
+ cursiveanchor=nil
+ lastanchor=nil
end
- if nofvalid>0 then
- local cx={}
- if has_kerns and next(ky) then
- for n,k in next,ky do
- setfield(n,"yoffset",k)
- end
+ end
+ if last and maxc>0 then
+ local ny=getfield(last,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",ny)
+ end
+ end
+end
+local function inject_kerns(head,glyphs,nofglyphs)
+ for i=1,#glyphs do
+ local n=glyphs[i]
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ insert_node_before(head,n,newkern(leftkern))
end
- if has_cursives then
- local p_cursbase,p=nil,nil
- local t,d,maxt={},{},0
- for i=1,nofvalid do
- local n=valid[i]
- if not mk[n] then
- local n_cursbase=getattr(n,a_cursbase)
- if p_cursbase then
- local n_curscurs=getattr(n,a_curscurs)
- if p_cursbase==n_curscurs then
- local c=cursives[n_curscurs]
- if c then
- local rlmode,dx,dy,ws,wn=c[1],c[2],c[3],c[4],c[5]
- if rlmode>=0 then
- dx=dx-ws
- else
- dx=dx+wn
- end
- if dx~=0 then
- cx[n]=dx
- rl[n]=rlmode
- end
- dy=-dy
- maxt=maxt+1
- t[maxt]=p
- d[maxt]=dy
- else
- maxt=0
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ end
+ end
+ end
+end
+local function inject_everything(head,where)
+ head=tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local glyphs,nofglyphs,marks,nofmarks
+ if nofregisteredpairs>0 then
+ glyphs,nofglyphs,marks,nofmarks=collect_glyphs_1(head)
+ else
+ glyphs,nofglyphs,marks,nofmarks=collect_glyphs_2(head)
+ end
+ if nofglyphs>0 then
+ if nofregisteredcursives>0 then
+ inject_cursives(glyphs,nofglyphs)
+ end
+ if nofregisteredmarks>0 then
+ inject_marks(marks,nofmarks)
+ end
+ inject_kerns(head,glyphs,nofglyphs)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts=false
+ else
+ nofregisteredkerns=0
+ nofregisteredpairs=0
+ nofregisteredmarks=0
+ nofregisteredcursives=0
+ end
+ return tonode(head),true
+end
+local function inject_kerns_only(head,where)
+ head=tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local n=head
+ local p=nil
+ while n do
+ local id=getid(n)
+ if id==glyph_code then
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ if p then
+ local d=getfield(p,"post")
+ if d then
+ local pn=pn.postinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
end
- elseif maxt>0 then
- local ny=getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
- end
- maxt=0
- end
- if not n_cursbase and maxt>0 then
- local ny=getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- setfield(ti,"yoffset",ny)
- end
- maxt=0
- end
- p_cursbase,p=n_cursbase,n
- end
- end
- if maxt>0 then
- local ny=getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- setfield(ti,"yoffset",ny)
- end
- maxt=0
- end
- if not keep then
- cursives={}
- end
- end
- if has_marks then
- for i=1,nofvalid do
- local p=valid[i]
- local p_markbase=getattr(p,a_markbase)
- if p_markbase then
- local mrks=marks[p_markbase]
- local nofmarks=#mrks
- for n in traverse_id(glyph_code,getnext(p)) do
- local n_markmark=getattr(n,a_markmark)
- if p_markbase==n_markmark then
- local index=getattr(n,a_markdone) or 1
- local d=mrks[index]
- if d then
- local rlmode=d[3]
- local k=wx[p]
- local px=getfield(p,"xoffset")
- local ox=0
- if k then
- local x=k[2]
- local w=k[4]
- if w then
- if rlmode and rlmode>=0 then
- ox=px-getfield(p,"width")+d[1]-(w-x)
- else
- ox=px-d[1]-x
- end
- else
- if rlmode and rlmode>=0 then
- ox=px-getfield(p,"width")+d[1]
- else
- ox=px-d[1]-x
- end
- end
- else
- local wp=getfield(p,"width")
- local wn=getfield(n,"width")
- if rlmode and rlmode>=0 then
- ox=px-wp+d[1]
- else
- ox=px-d[1]
- end
- if wn~=0 then
- insert_node_before(head,n,newkern(-wn/2))
- insert_node_after(head,n,newkern(-wn/2))
- end
- end
- setfield(n,"xoffset",ox)
- local py=getfield(p,"yoffset")
- local oy=0
- if mk[p] then
- oy=py+d[2]
- else
- oy=getfield(n,"yoffset")+py+d[2]
- end
- setfield(n,"yoffset",oy)
- if nofmarks==1 then
- break
- else
- nofmarks=nofmarks-1
- end
+ end
+ local d=getfield(p,"replace")
+ if d then
+ local pn=pn.replaceinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ end
+ else
+ local pn=pn.injections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ setfield(p,"replace",newkern(leftkern))
end
- elseif not n_markmark then
- break
- else
+ end
+ end
+ else
+ local pn=pn.injections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ head=insert_node_before(head,n,newkern(leftkern))
end
end
end
end
- if not keep then
- marks={}
- end
+ else
+ break
end
- if next(wx) then
- for n,k in next,wx do
- local x=k[2]
- local w=k[4]
- if w then
- local rl=k[1]
- local wx=w-x
- if rl<0 then
- if wx~=0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x~=0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x~=0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx~=0 then
- insert_node_after (head,n,newkern(wx))
+ p=nil
+ elseif id==disc_code then
+ local d=getfield(n,"pre")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.preinjections
+ end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
end
end
- elseif x~=0 then
- insert_node_before(head,n,newkern(x))
+ else
+ break
end
end
+ if h~=d then
+ setfield(n,"pre",h)
+ end
end
- if next(cx) then
- for n,k in next,cx do
- if k~=0 then
- local rln=rl[n]
- if rln and rln<0 then
- insert_node_before(head,n,newkern(-k))
- else
- insert_node_before(head,n,newkern(k))
+ local d=getfield(n,"post")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.postinjections
end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ end
+ else
+ break
end
end
+ if h~=d then
+ setfield(n,"post",h)
+ end
end
- if not keep then
- kerns={}
+ local d=getfield(n,"replace")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.replaceinjections
+ end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"replace",h)
+ end
end
- return tonode(head),true
- elseif not keep then
- kerns,cursives,marks={},{},{}
- end
- elseif has_kerns then
- if trace_injections then
- trace(head)
+ p=n
+ else
+ p=nil
end
- for n in traverse_id(glyph_code,head) do
+ n=getnext(n)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts=false
+ else
+ nofregisteredkerns=0
+ end
+ return tonode(head),true
+end
+local function inject_pairs_only(head,where)
+ head=tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local n=head
+ local p=nil
+ while n do
+ local id=getid(n)
+ if id==glyph_code then
if getsubtype(n)<256 then
- local k=getattr(n,a_kernpair)
- if k then
- local kk=kerns[k]
- if kk then
- local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4]
- if y and y~=0 then
- setfield(n,"yoffset",y)
- end
- if w then
- local wx=w-x
- if rl<0 then
- if wx~=0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x~=0 then
- insert_node_after (head,n,newkern(x))
+ local pn=rawget(properties,n)
+ if pn then
+ if p then
+ local d=getfield(p,"post")
+ if d then
+ local pn=pn.postinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
- else
- if x~=0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx~=0 then
- insert_node_after(head,n,newkern(wx))
+ end
+ end
+ local d=getfield(p,"replace")
+ if d then
+ local pn=pn.replaceinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
end
else
- if x~=0 then
- insert_node_before(head,n,newkern(x))
+ local pn=pn.injections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ setfield(p,"replace",newkern(leftkern))
+ end
+ end
+ end
+ else
+ local pn=pn.injections
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ insert_node_before(head,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
end
end
end
end
+ else
+ break
end
+ p=nil
+ elseif id==disc_code then
+ local d=getfield(n,"pre")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.preinjections
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"pre",h)
+ end
+ end
+ local d=getfield(n,"post")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.postinjections
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"post",h)
+ end
+ end
+ local d=getfield(n,"replace")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.replaceinjections
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"replace",h)
+ end
+ end
+ p=n
+ else
+ p=nil
end
- if not keep then
- kerns={}
- end
- return tonode(head),true
+ n=getnext(n)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts=false
else
+ nofregisteredpairs=0
+ nofregisteredkerns=0
+ end
+ return tonode(head),true
+end
+function injections.handler(head,where)
+ if nofregisteredmarks>0 or nofregisteredcursives>0 then
+ return inject_everything(head,where)
+ elseif nofregisteredpairs>0 then
+ return inject_pairs_only(head,where)
+ elseif nofregisteredkerns>0 then
+ return inject_kerns_only(head,where)
+ else
+ return head,false
end
- return tonode(head),false
end
end -- closure
@@ -14565,10 +15011,24 @@ local disc_code=nodes.nodecodes.disc
local ligaturing=node.ligaturing
local kerning=node.kerning
local basepass=true
+local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning=nil end
+local function k_warning() texio.write_nl("warning: node.kerning called directly") k_warning=nil end
+function node.ligaturing(...)
+ if basepass and l_warning then
+ l_warning()
+ end
+ return ligaturing(...)
+end
+function node.kerning(...)
+ if basepass and k_warning then
+ k_warning()
+ end
+ return kerning(...)
+end
function nodes.handlers.setbasepass(v)
basepass=v
end
-function nodes.handlers.characters(head)
+function nodes.handlers.nodepass(head)
local fontdata=fonts.hashes.identifiers
if fontdata then
local usedfonts={}
@@ -14649,15 +15109,27 @@ function nodes.handlers.characters(head)
return head,false
end
end
-function nodes.simple_font_handler(head)
- head=nodes.handlers.characters(head)
- nodes.injections.handler(head)
+function nodes.handlers.basepass(head)
if not basepass then
head=ligaturing(head)
head=kerning(head)
end
- nodes.handlers.protectglyphs(head)
- return head
+ return head,true
+end
+local nodepass=nodes.handlers.nodepass
+local basepass=nodes.handlers.basepass
+local injectpass=nodes.injections.handler
+local protectpass=nodes.handlers.protectglyphs
+function nodes.simple_font_handler(head)
+ if head then
+ head=nodepass(head)
+ head=injectpass(head)
+ head=basepass(head)
+ protectpass(head)
+ return head,true
+ else
+ return head,false
+ end
end
end -- closure