summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--tex/context/base/cont-new.mkiv2
-rw-r--r--tex/context/base/context-version.pdfbin4181 -> 4184 bytes
-rw-r--r--tex/context/base/context.mkiv6
-rw-r--r--tex/context/base/font-aux.lua76
-rw-r--r--tex/context/base/font-ctx.lua13
-rw-r--r--tex/context/base/font-dsp.lua1
-rw-r--r--tex/context/base/font-inj.lua98
-rw-r--r--tex/context/base/font-nod.lua34
-rw-r--r--tex/context/base/font-otf.lua17
-rw-r--r--tex/context/base/font-otj.lua1286
-rw-r--r--tex/context/base/font-otl.lua19
-rw-r--r--tex/context/base/font-otn.lua256
-rw-r--r--tex/context/base/font-ots.lua374
-rw-r--r--tex/context/base/lang-dis.lua66
-rw-r--r--tex/context/base/lpdf-epa.lua11
-rw-r--r--tex/context/base/m-morse.mkvi273
-rw-r--r--tex/context/base/m-newotf.mkiv15
-rw-r--r--tex/context/base/node-fnt.lua2
-rw-r--r--tex/context/base/status-files.pdfbin24498 -> 24517 bytes
-rw-r--r--tex/context/base/status-lua.pdfbin255952 -> 256263 bytes
-rw-r--r--tex/context/base/typo-cap.lua51
-rw-r--r--tex/context/base/typo-cap.mkiv10
-rw-r--r--tex/generic/context/luatex/luatex-fonts-inj.lua16
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua30
24 files changed, 2121 insertions, 535 deletions
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index fb713cf57..0d629b2fb 100644
--- a/tex/context/base/cont-new.mkiv
+++ b/tex/context/base/cont-new.mkiv
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2015.09.01 11:10}
+\newcontextversion{2015.09.04 11:00}
%D This file is loaded at runtime, thereby providing an excellent place for
%D hacks, patches, extensions and new features.
diff --git a/tex/context/base/context-version.pdf b/tex/context/base/context-version.pdf
index b2d52084f..5340fc16b 100644
--- a/tex/context/base/context-version.pdf
+++ b/tex/context/base/context-version.pdf
Binary files differ
diff --git a/tex/context/base/context.mkiv b/tex/context/base/context.mkiv
index 31e02d6e5..4a84d5af8 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -39,7 +39,7 @@
%D up and the dependencies are more consistent.
\edef\contextformat {\jobname}
-\edef\contextversion{2015.09.01 11:10}
+\edef\contextversion{2015.09.04 11:00}
\edef\contextkind {beta}
%D For those who want to use this:
@@ -207,7 +207,7 @@
\loadmarkfile{hand-ini}
\loadmarkfile{lang-ini}
-\loadmarkfile{lang-hyp}
+\loadmarkfile{lang-hyp} % also loads dis
\loadmarkfile{lang-lab}
\loadmarkfile{unic-ini}
@@ -365,7 +365,7 @@
\loadmarkfile{char-enc} % will move up
-\loadmkvifile{font-lib} % way too late
+\loadmkvifile{font-lib} % way too late but after language
\loadmkvifile{font-fil}
\loadmkvifile{font-var}
\loadmkvifile{font-fea}
diff --git a/tex/context/base/font-aux.lua b/tex/context/base/font-aux.lua
index 2a605d224..fc6c90bc1 100644
--- a/tex/context/base/font-aux.lua
+++ b/tex/context/base/font-aux.lua
@@ -11,6 +11,11 @@ local tonumber, type = tonumber, type
local fonts, font = fonts, font
+local fonts = fonts
+local handlers = fonts.handlers
+local otf = handlers.otf -- brrr
+local afm = handlers.afm -- brrr
+
local iterators = { }
fonts.iterators = iterators
@@ -163,3 +168,74 @@ function iterators.glyphs(data)
return dummy
end
end
+
+-- for the moment here, it might move to some other file later
+
+function afm.getkern(tfmdata,left,right)
+ local c = tfmdata.characters[left]
+ if c then
+ local kerns = c.kerns
+ if kerns then
+ return kerns[right] -- already scaled
+ end
+ end
+ return 0
+end
+
+local getters = { -- maybe better getters[format][...]
+ kern = {
+ ["type1"] = afm.getkern,
+ ["opentype"] = otf.getkern,
+ },
+ substitution = {
+ ["opentype"] = otf.getsubstitution,
+ },
+ alternate = {
+ ["opentype"] = otf.getalternate,
+ },
+ multiple = {
+ ["opentype"] = otf.getmultiple,
+ }
+}
+
+fonts.getters = getters
+
+function fonts.getkern(tfmdata,left,right)
+ local format = tfmdata.properties.format
+ local getter = getters.kern[format]
+ if getter then
+ return getter(tfmdata,left,right)
+ else
+ return 0
+ end
+end
+
+function fonts.getsubstitution(tfmdata,k,kind)
+ local format = tfmdata.properties.format
+ local getter = getters.substitution[format]
+ if getter then
+ return getter(tfmdata,k,kind,value)
+ else
+ return 0
+ end
+end
+
+function fonts.getalternate(tfmdata,k,kind,value)
+ local format = tfmdata.properties.format
+ local getter = getters.substitution[format]
+ if getter then
+ return getter(tfmdata,k,kind,value)
+ else
+ return 0
+ end
+end
+
+function fonts.getmultiple(tfmdata,k,kind)
+ local format = tfmdata.properties.format
+ local getter = getters.substitution[format]
+ if getter then
+ return getter(tfmdata,k,kind,value)
+ else
+ return 0
+ end
+end
diff --git a/tex/context/base/font-ctx.lua b/tex/context/base/font-ctx.lua
index ca9a83086..4dd75b480 100644
--- a/tex/context/base/font-ctx.lua
+++ b/tex/context/base/font-ctx.lua
@@ -50,6 +50,7 @@ local implement = interfaces.implement
local fonts = fonts
local handlers = fonts.handlers
local otf = handlers.otf -- brrr
+----- afm = handlers.afm -- brrr
local names = fonts.names
local definers = fonts.definers
local specifiers = fonts.specifiers
@@ -1366,14 +1367,14 @@ function constructors.calculatescale(tfmdata,scaledpoints,relativeid,specificati
if special then
-- we also have available specification.textsize
local parameters = tfmdata.parameters
- local designsize = parameters.designsize
+ -- local designsize = parameters.designsize
if special == "ht" then
--- inspect(parameters)
- local height = parameters.ascender * designsize / parameters.units
- scaledpoints = (scaledpoints/height) * designsize
+ local height = parameters.ascender / parameters.units
+ scaledpoints = scaledpoints / height
elseif special == "cp" then
- local height = (tfmdata.descriptions[utf.byte("X")].height or parameters.ascender) * designsize / parameters.units
- scaledpoints = (scaledpoints/height) * designsize
+ local glyph = tfmdata.descriptions[utfbyte("X")]
+ local height = (glyph and glyph.height or parameters.ascender) / parameters.units
+ scaledpoints = scaledpoints / height
end
end
end
diff --git a/tex/context/base/font-dsp.lua b/tex/context/base/font-dsp.lua
index 8cdd645c8..148889020 100644
--- a/tex/context/base/font-dsp.lua
+++ b/tex/context/base/font-dsp.lua
@@ -1745,6 +1745,7 @@ do
},
nofsteps = 1,
type = "gpos_pair",
+ -- type = "gpos_single", -- maybe better
flags = { false, false, false, false },
order = { name },
features = { [name] = feature },
diff --git a/tex/context/base/font-inj.lua b/tex/context/base/font-inj.lua
index cdf14b935..da1364d9d 100644
--- a/tex/context/base/font-inj.lua
+++ b/tex/context/base/font-inj.lua
@@ -204,7 +204,10 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
end
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]
+ local x = factor*spec[1]
+ local y = factor*spec[2]
+ local w = factor*spec[3]
+ local h = factor*spec[4]
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
@@ -549,9 +552,19 @@ local function inject_marks(marks,marki,nofmarks)
else
-- kern(x) glyph(p) kern(w-x) mark(n)
-- ox = px - getfield(p,"width") + pn.markx - pp.leftkern
- local leftkern = pp.leftkern
- if leftkern then
- ox = px - pn.markx - leftkern
+ --
+ -- 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.
+ --
+ if false then
+ -- a mark with kerning
+ local leftkern = pp.leftkern
+ if leftkern then
+ ox = px - pn.markx - leftkern
+ else
+ ox = px - pn.markx
+ end
else
ox = px - pn.markx
end
@@ -714,7 +727,7 @@ local function inject_kerns(head,glist,ilist,length) -- not complete ! compare w
if leftkern and leftkern ~= 0 then
local t = find_tail(dp)
insert_node_after(dp,t,newkern(leftkern))
-setfield(p,"post",dp) -- currently we need to force a tail refresh
+ setfield(p,"post",dp) -- currently we need to force a tail refresh
end
end
end
@@ -725,7 +738,7 @@ setfield(p,"post",dp) -- currently we need to force a tail refresh
if leftkern and leftkern ~= 0 then
local t = find_tail(dr)
insert_node_after(dr,t,newkern(leftkern))
-setfield(p,"replace",dr) -- currently we need to force a tail refresh
+ setfield(p,"replace",dr) -- currently we need to force a tail refresh
end
end
else
@@ -788,7 +801,7 @@ local function inject_kerns_only(head,where)
trace(head,"kerns")
end
local n = head
- local p = nil
+ local p = nil -- disc node when non-nil
while n do
local id = getid(n)
if id == glyph_code then
@@ -804,7 +817,7 @@ local function inject_kerns_only(head,where)
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
-setfield(p,"post",d) -- currently we need to force a tail refresh
+ setfield(p,"post",d) -- currently we need to force a tail refresh
end
end
end
@@ -816,7 +829,7 @@ setfield(p,"post",d) -- currently we need to force a tail refresh
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
-setfield(p,"replace",d) -- currently we need to force a tail refresh
+ setfield(p,"replace",d) -- currently we need to force a tail refresh
end
end
else
@@ -829,6 +842,7 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
end
end
else
+ -- this is the most common case
local i = rawget(pn,"injections")
if i then
local leftkern = i.leftkern
@@ -838,8 +852,6 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
end
end
end
- else
- break
end
p = nil
elseif id == disc_code then
@@ -866,7 +878,6 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
setfield(n,"pre",h)
end
end
- -- weird
local d = getfield(n,"post")
if d then
local h = d
@@ -895,7 +906,7 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
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 { }
+ local pn = rawget(properties,n)
if pn then
local i = rawget(pn,"replaceinjections")
if i then
@@ -933,7 +944,6 @@ local function inject_pairs_only(head,where)
if trace_injections then
trace(head,"pairs")
end
- --
local n = head
local p = nil -- disc node when non-nil
while n do
@@ -951,7 +961,7 @@ local function inject_pairs_only(head,where)
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
-setfield(p,"post",d) -- currently we need to force a tail refresh
+ setfield(p,"post",d) -- currently we need to force a tail refresh
end
-- local rightkern = i.rightkern
-- if rightkern and rightkern ~= 0 then
@@ -968,7 +978,7 @@ setfield(p,"post",d) -- currently we need to force a tail refresh
if leftkern and leftkern ~= 0 then
local t = find_tail(d)
insert_node_after(d,t,newkern(leftkern))
-setfield(p,"replace",d) -- currently we need to force a tail refresh
+ setfield(p,"replace",d) -- currently we need to force a tail refresh
end
-- local rightkern = i.rightkern
-- if rightkern and rightkern ~= 0 then
@@ -994,24 +1004,22 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
-- this is the most common case
local i = rawget(pn,"injections")
if i then
- local yoffset = i.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
- end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
- insert_node_before(head,n,newkern(leftkern))
+ head = insert_node_before(head,n,newkern(leftkern))
end
local rightkern = i.rightkern
if rightkern and rightkern ~= 0 then
insert_node_after(head,n,newkern(rightkern))
n = getnext(n) -- to be checked
end
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
end
end
end
- else
- break
end
p = nil
elseif id == disc_code then
@@ -1020,16 +1028,12 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
local h = d
for n in traverse_id(glyph_code,d) do
if getsubtype(n) < 256 then
- local p = rawget(properties,n)
- if p then
- local i = rawget(p,"preinjections")
+ local pn = rawget(properties,n)
+ if pn then
+ local i = rawget(pn,"preinjections")
if i then
- local yoffset = i.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
- end
local leftkern = i.leftkern
- if leftkern ~= 0 then
+ if leftkern and leftkern ~= 0 then
h = insert_node_before(h,n,newkern(leftkern))
end
local rightkern = i.rightkern
@@ -1037,6 +1041,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
insert_node_after(head,n,newkern(rightkern))
n = getnext(n) -- to be checked
end
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
end
end
else
@@ -1052,14 +1060,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
local h = d
for n in traverse_id(glyph_code,d) do
if getsubtype(n) < 256 then
- local p = rawget(properties,n)
- if p then
- local i = rawget(p,"postinjections")
+ local pn = rawget(properties,n)
+ if pn then
+ local i = rawget(pn,"postinjections")
if i then
- local yoffset = i.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
- end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
h = insert_node_before(h,n,newkern(leftkern))
@@ -1069,6 +1073,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
insert_node_after(head,n,newkern(rightkern))
n = getnext(n) -- to be checked
end
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
end
end
else
@@ -1084,14 +1092,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
local h = d
for n in traverse_id(glyph_code,d) do
if getsubtype(n) < 256 then
- local p = rawget(properties,n)
- if p then
- local i = rawget(p,"replaceinjections")
+ local pn = rawget(properties,n)
+ if pn then
+ local i = rawget(pn,"replaceinjections")
if i then
- local yoffset = i.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
- end
local leftkern = i.leftkern
if leftkern and leftkern ~= 0 then
h = insert_node_before(h,n,newkern(leftkern))
@@ -1101,6 +1105,10 @@ setfield(p,"replace",d) -- currently we need to force a tail refresh
insert_node_after(head,n,newkern(rightkern))
n = getnext(n) -- to be checked
end
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
end
end
else
diff --git a/tex/context/base/font-nod.lua b/tex/context/base/font-nod.lua
index e2000be7e..8d199f868 100644
--- a/tex/context/base/font-nod.lua
+++ b/tex/context/base/font-nod.lua
@@ -184,6 +184,7 @@ function char_tracers.string(t)
end
local f_unicode = formatters["%U"]
+local f_badcode = formatters["{%i}"]
function char_tracers.unicodes(t,decimal)
local tt = { }
@@ -489,30 +490,35 @@ local function toutf(list,result,nofresult,stopcriterium)
result, nofresult = toutf(components,result,nofresult)
else
local c = getchar(n)
- local fc = fontcharacters[getfont(n)]
- if fc then
- local fcc = fc[c]
- if fcc then
- local u = fcc.unicode
- if not u then
- nofresult = nofresult + 1
- result[nofresult] = utfchar(c)
- elseif type(u) == "table" then
- for i=1,#u do
+ if c > 0 then
+ local fc = fontcharacters[getfont(n)]
+ if fc then
+ local fcc = fc[c]
+ if fcc then
+ local u = fcc.unicode
+ if not u then
nofresult = nofresult + 1
- result[nofresult] = utfchar(u[i])
+ result[nofresult] = utfchar(c)
+ elseif type(u) == "table" then
+ for i=1,#u do
+ nofresult = nofresult + 1
+ result[nofresult] = utfchar(u[i])
+ end
+ else
+ nofresult = nofresult + 1
+ result[nofresult] = utfchar(u)
end
else
nofresult = nofresult + 1
- result[nofresult] = utfchar(u)
+ result[nofresult] = utfchar(c)
end
else
nofresult = nofresult + 1
- result[nofresult] = utfchar(c)
+ result[nofresult] = f_unicode(c)
end
else
nofresult = nofresult + 1
- result[nofresult] = f_unicode(c)
+ result[nofresult] = f_badcode(c)
end
end
elseif id == disc_code then
diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua
index 79d3ac60d..851a25cca 100644
--- a/tex/context/base/font-otf.lua
+++ b/tex/context/base/font-otf.lua
@@ -2997,3 +2997,20 @@ function otf.getmultiple(tfmdata,k,kind)
end
return { k }
end
+
+function otf.getkern(tfmdata,left,right,kind)
+ local kerns = getgsub(tfmdata,left,kind or "kern",true) -- for now we use getsub
+ if kerns then
+ local found = kerns[right]
+ local kind = type(found)
+ if kind == "table" then
+ found = found[1][3] -- can be more clever
+ elseif kind ~= "number" then
+ found = false
+ end
+ if found then
+ return found * tfmdata.parameters.factor
+ end
+ end
+ return 0
+end
diff --git a/tex/context/base/font-otj.lua b/tex/context/base/font-otj.lua
new file mode 100644
index 000000000..a8069b2dc
--- /dev/null
+++ b/tex/context/base/font-otj.lua
@@ -0,0 +1,1286 @@
+if not modules then modules = { } end modules ['font-otj'] = {
+ version = 1.001,
+ 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 apbout 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.
+
+-- The subtype test is not needed as there will be no (new) properties set, given that we
+-- reset the properties.
+
+if not nodes.properties then return end
+
+local next, rawget = next, rawget
+local utfchar = utf.char
+local fastcopy = table.fastcopy
+
+local trace_injections = false trackers.register("fonts.injections", function(v) trace_injections = v end)
+
+local report_injections = logs.reporter("fonts","injections")
+
+local attributes, nodes, node = attributes, nodes, node
+
+fonts = fonts
+local fontdata = fonts.hashes.identifiers
+
+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
+
+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 getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+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 properties = nodes.properties.data
+
+function injections.installnewkern(nk)
+ newkern = nk or newkern
+end
+
+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
+
+-- 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 and rawget(p,"injections") then
+ p.injections = nil
+ end
+end
+
+function injections.copy(target,source)
+ local sp = rawget(properties,source)
+ if sp then
+ local tp = rawget(properties,target)
+ local si = rawget(sp,"injections")
+ if si then
+ si = fastcopy(si)
+ if tp then
+ tp.injections = si
+ else
+ propertydata[target] = {
+ injections = si,
+ }
+ end
+ else
+ if tp then
+ tp.injections = nil
+ end
+ end
+ end
+end
+
+function injections.setligaindex(n,index)
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(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 = rawget(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) -- hm: nuts or nodes
+ 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
+ --
+ local p = rawget(properties,start)
+ if p then
+ local i = rawget(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 = rawget(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,injection) -- r2lflag & tfmchr not used
+ local x = factor*spec[1]
+ local y = factor*spec[2]
+ local w = factor*spec[3]
+ local h = factor*spec[4]
+ 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
+ if not injection then
+ injection = "injections"
+ end
+ local p = rawget(properties,current)
+ if p then
+ local i = rawget(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, nofregisteredpairs
+ end
+ end
+ return x, y, w, h -- no bound
+end
+
+-- 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
+ nofregisteredkerns = nofregisteredkerns + 1
+ local p = rawget(properties,current)
+ if not injection then
+ injection = "injections"
+ end
+ if p then
+ local i = rawget(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,tfmbase,mkmk) -- ba=baseanchor, ma=markanchor
+ local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
+ nofregisteredmarks = nofregisteredmarks + 1
+ -- markanchors[nofregisteredmarks] = base
+ 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 = rawget(p,"injections")
+ if i then
+ if i.markmark then
+ -- out of order mkmk: yes or no or option
+ else
+ i.markx = dx
+ i.marky = dy
+ i.markdir = rlmode or 0
+ i.markbase = nofregisteredmarks
+ i.markbasenode = base
+ i.markmark = mkmk
+ end
+ else
+ p.injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ markmark = mkmk,
+ }
+ end
+ else
+ properties[start] = {
+ injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ markmark = mkmk,
+ },
+ }
+ 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 = rawget(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 -- will be markbasenode
+ local cursivex = i.cursivex or 0
+ local cursivey = i.cursivey or 0
+ local ligaindex = i.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
+ 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
+ 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,where)
+ report_injections("begin run %s: %s kerns, %s pairs, %s marks and %s cursives registered",
+ where or "",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,"=")
+ show(n,"emptyinjections",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 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
+ report_injections("char: %C, width %p, xoffset %p, yoffset %p",
+ getchar(current),getfield(current,"width"),getfield(current,"xoffset"),getfield(current,"yoffset"))
+ skipping = false
+ elseif id == kern_code then
+ report_injections("kern: %p",getfield(current,"kern"))
+ skipping = false
+ elseif not skipping then
+ report_injections()
+ skipping = true
+ end
+ current = getnext(current)
+ end
+end
+
+-- G +D-pre G
+-- D-post+
+-- +D-replace+
+--
+-- G +D-pre +D-pre
+-- D-post +D-post
+-- +D-replace +D-replace
+
+local function inject_kerns_only(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head,"kerns")
+ 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
+ while current do
+ local id = getid(current)
+ local next = getnext(current)
+ if id == glyph_code then
+ if getsubtype(current) < 256 then
+ local p = rawget(properties,current)
+ if p then
+ local i = rawget(p,"injections")
+ if i then
+ -- left|glyph|right
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ insert_node_before(head,current,newkern(leftkern))
+ end
+ end
+ if prevdisc then
+ local postdone = false
+ local replacedone = false
+ if post then
+ local i = rawget(p,"postinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local posttail = find_tail(post)
+ insert_node_after(post,posttail,newkern(leftkern))
+ postdone = true
+ end
+ end
+ end
+ if replace then
+ local i = rawget(p,"replaceinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local replacetail = find_tail(replace)
+ insert_node_after(replace,replacetail,newkern(leftkern))
+ replacedone = true
+ end
+ end
+ else
+-- local i = rawget(p,"emptyinjections")
+-- if i then
+-- inspect(i)
+-- local leftkern = i.leftkern
+-- if leftkern and leftkern ~= 0 then
+-- replace = newkern(leftkern)
+-- done = true
+-- end
+-- end
+ end
+ if postdone then
+ setfield(prevdisc,"post",post)
+ end
+ if replacedone then
+ setfield(prevdisc,"replace",replace)
+ end
+ end
+ end
+ end
+ prevdisc = nil
+ prevglyph = current
+ elseif id == disc_code then
+ pre = getfield(current,"pre")
+ post = getfield(current,"post")
+ replace = getfield(current,"replace")
+ local predone = false
+ local postdone = false
+ local replacedone = false
+ if pre then
+ -- left|pre glyphs|right
+ for n in traverse_id(glyph_code,pre) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"preinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ pre = insert_node_before(pre,n,newkern(leftkern))
+ predone = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if post then
+ -- left|post glyphs|right
+ for n in traverse_id(glyph_code,post) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"postinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ post = insert_node_before(post,n,newkern(leftkern))
+ postdone = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ -- left|replace glyphs|right
+ for n in traverse_id(glyph_code,replace) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"replaceinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ replace = insert_node_before(replace,n,newkern(leftkern))
+ replacedone = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if predone then
+ setfield(current,"pre",pre)
+ end
+ if postdone then
+ setfield(current,"post",post)
+ end
+ if replacedone then
+ setfield(current,"replace",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
+ return tonode(head), true
+end
+
+local function inject_pairs_only(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head,"pairs")
+ 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
+ while current do
+ local id = getid(current)
+ local next = getnext(current)
+ if id == glyph_code then
+ if getsubtype(current) < 256 then
+ local p = rawget(properties,current)
+ if p then
+ local i = rawget(p,"injections")
+ if i then
+ -- left|glyph|right
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(current,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ insert_node_before(head,current,newkern(leftkern))
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,current,newkern(rightkern))
+ end
+ else
+ local i = rawget(p,"replaceinjections")
+ 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
+ local replace = getfield(pr,"replace")
+ if replace then
+ -- error, we expect an empty one
+ else
+ setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern
+ end
+ end
+ end
+ end
+ end
+ if prevdisc and p then
+ local postdone = false
+ local replacedone = false
+ if post then
+ local i = rawget(p,"postinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local posttail = find_tail(post)
+ insert_node_after(post,posttail,newkern(leftkern))
+ postdone = true
+ end
+ end
+ end
+ if replace then
+ local i = rawget(p,"replaceinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local replacetail = find_tail(replace)
+ insert_node_after(replace,replacetail,newkern(leftkern))
+ replacedone = true
+ end
+ end
+ end
+ if postdone then
+ setfield(prevdisc,"post",post)
+ end
+ if replacedone then
+ setfield(prevdisc,"replace",replace)
+ end
+ end
+ end
+ end
+ prevdisc = nil
+ prevglyph = current
+ elseif id == disc_code then
+ pre = getfield(current,"pre")
+ post = getfield(current,"post")
+ replace = getfield(current,"replace")
+ local predone = false
+ local postdone = false
+ local replacedone = false
+ if pre then
+ -- left|pre glyphs|right
+ for n in traverse_id(glyph_code,pre) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"preinjections")
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ pre = insert_node_before(pre,n,newkern(leftkern))
+ predone = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(pre,n,newkern(rightkern))
+ predone = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if post then
+ -- left|post glyphs|right
+ for n in traverse_id(glyph_code,post) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"postinjections")
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ post = insert_node_before(post,n,newkern(leftkern))
+ postdone = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(post,n,newkern(rightkern))
+ postdone = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ -- left|replace glyphs|right
+ for n in traverse_id(glyph_code,replace) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"replaceinjections")
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ replace = insert_node_before(replace,n,newkern(leftkern))
+ replacedone = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(replace,n,newkern(rightkern))
+ replacedone = true
+ end
+ end
+ end
+ end
+ end
+ end
+ if prevglyph then
+ if pre then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = rawget(p,"preinjections")
+ if i then
+ -- glyph|pre glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ pre = insert_node_before(pre,pre,newkern(rightkern))
+ predone = true
+ end
+ end
+ end
+ end
+ if replace then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = rawget(p,"replaceinjections")
+ if i then
+ -- glyph|replace glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ replace = insert_node_before(replace,replace,newkern(rightkern))
+ replacedone = true
+ end
+ end
+ end
+ end
+ end
+ if predone then
+ setfield(current,"pre",pre)
+ end
+ if postdone then
+ setfield(current,"post",post)
+ end
+ if replacedone then
+ setfield(current,"replace",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
+ return tonode(head), true
+end
+
+local function inject_everything(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head,"everything")
+ end
+ local hascursives = nofregisteredcursives > 0
+ local hasmarks = nofregisteredmarks > 0
+ --
+ 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 cursiveanchor = nil
+ local lastanchor = nil
+ local minc = 0
+ local maxc = 0
+ local last = 0
+ local glyphs = { }
+ --
+ local function processmark(p,n,pn) -- p = basenode
+ local px = getfield(p,"xoffset")
+ local ox = 0
+ local rightkern = nil
+ local pp = rawget(properties,p)
+ if pp then
+ pp = rawget(pp,"injections")
+ if pp then
+ rightkern = pp.rightkern
+ end
+ end
+ 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
+ --
+ -- 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.
+ --
+ if false then
+ -- a mark with kerning
+ local leftkern = pp.leftkern
+ if leftkern then
+ ox = px - pn.markx - leftkern
+ else
+ ox = px - pn.markx
+ end
+ else
+ ox = px - pn.markx
+ end
+ 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
+ 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 oy = getfield(n,"yoffset") + py + pn.marky
+ setfield(n,"yoffset",oy)
+ end
+ --
+ while current do
+ local id = getid(current)
+ local next = getnext(current)
+ if id == glyph_code then
+ if getsubtype(current) < 256 then
+ local p = rawget(properties,current)
+ if p then
+ local i = rawget(p,"injections")
+ if i then
+ -- cursives
+ if hascursives then
+ local cursivex = p.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex ~= 0 then
+ p.leftkern = (p.leftkern or 0) + cursivex
+ end
+ if lastanchor then
+ if maxc == 0 then
+ minc = 1
+ maxc = 1
+ glyphs[1] = lastanchor
+ else
+ maxc = maxc + 1
+ glyphs[maxc] = lastanchor
+ end
+ properties[cursiveanchor].cursivedy = p.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
+ if p.cursiveanchor then
+ cursiveanchor = current -- no need for both now
+ lastanchor = current
+ 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
+ end
+ -- marks
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,current,i)
+ end
+ end
+ -- left|glyph|right
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(current,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ insert_node_before(head,current,newkern(leftkern))
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,current,newkern(rightkern))
+ end
+ else
+ local i = rawget(p,"replaceinjections")
+ 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
+ local replace = getfield(pr,"replace")
+ if replace then
+ -- error, we expect an empty one
+ else
+ setfield(next,"replace",newkern(rightkern)) -- maybe also leftkern
+ end
+ end
+ end
+ end
+ end
+ if prevdisc then
+ if p then
+ local postdone = false
+ local replacedone = false
+ if post then
+ local i = rawget(p,"postinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local posttail = find_tail(post)
+ insert_node_after(post,posttail,newkern(leftkern))
+ postdone = true
+ end
+ end
+ end
+ if replace then
+ local i = rawget(p,"replaceinjections")
+ if i then
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ local replacetail = find_tail(replace)
+ insert_node_after(replace,replacetail,newkern(leftkern))
+ replacedone = true
+ end
+ end
+ end
+ if postdone then
+ setfield(prevdisc,"post",post)
+ end
+ if replacedone then
+ setfield(prevdisc,"replace",replace)
+ end
+ end
+ end
+ else
+ -- cursive
+ if hascursives and maxc > 0 then
+ local ny = getfield(current,"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
+ end
+ end
+ prevdisc = nil
+ prevglyph = current
+ elseif id == disc_code then
+ pre = getfield(current,"pre")
+ post = getfield(current,"post")
+ replace = getfield(current,"replace")
+ local predone = false
+ local postdone = false
+ local replacedone = false
+ if pre then
+ -- left|pre glyphs|right
+ for n in traverse_id(glyph_code,pre) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"preinjections")
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ pre = insert_node_before(pre,n,newkern(leftkern))
+ predone = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(pre,n,newkern(rightkern))
+ predone = true
+ end
+ end
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,current,i)
+ end
+ end
+ end
+ end
+ end
+ end
+ if post then
+ -- left|post glyphs|right
+ for n in traverse_id(glyph_code,post) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"postinjections")
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ post = insert_node_before(post,n,newkern(leftkern))
+ postdone = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(post,n,newkern(rightkern))
+ postdone = true
+ end
+ end
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,current,i)
+ end
+ end
+ end
+ end
+ end
+ end
+ if replace then
+ -- left|replace glyphs|right
+ for n in traverse_id(glyph_code,replace) do
+ if getsubtype(n) < 256 then
+ local p = rawget(properties,n)
+ if p then
+ local i = rawget(p,"injections") or rawget(p,"replaceinjections")
+ if i then
+ local yoffset = i.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = i.leftkern
+ if leftkern and leftkern ~= 0 then
+ insert_node_before(replace,n,newkern(leftkern))
+ replacedone = true
+ end
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(replace,n,newkern(rightkern))
+ replacedone = true
+ end
+ end
+ if hasmarks then
+ local pm = i.markbasenode
+ if pm then
+ processmark(pm,current,i)
+ end
+ end
+ end
+ end
+ end
+ end
+ if prevglyph then
+ if pre then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = rawget(p,"preinjections")
+ if i then
+ -- glyph|pre glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ pre = insert_node_before(pre,pre,newkern(rightkern))
+ predone = true
+ end
+ end
+ end
+ end
+ if replace then
+ local p = rawget(properties,prevglyph)
+ if p then
+ local i = rawget(p,"replaceinjections")
+ if i then
+ -- glyph|replace glyphs
+ local rightkern = i.rightkern
+ if rightkern and rightkern ~= 0 then
+ replace = insert_node_before(replace,replace,newkern(rightkern))
+ replacedone = true
+ end
+ end
+ end
+ end
+ end
+ if predone then
+ setfield(current,"pre",pre)
+ end
+ if postdone then
+ setfield(current,"post",post)
+ end
+ if replacedone then
+ setfield(current,"replace",replace)
+ end
+ prevglyph = nil
+ prevdisc = current
+ else
+ prevglyph = nil
+ prevdisc = nil
+ end
+ prev = current
+ current = next
+ end
+ -- cursive
+ if hascursives then
+ 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
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ nofregisteredpairs = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 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
+end
diff --git a/tex/context/base/font-otl.lua b/tex/context/base/font-otl.lua
index 96775d0f0..5a4831835 100644
--- a/tex/context/base/font-otl.lua
+++ b/tex/context/base/font-otl.lua
@@ -679,7 +679,7 @@ function otf.collectlookups(rawdata,kind,script,language)
return unpack(languagelookup)
end
--- moved from font-oth.lua
+-- moved from font-oth.lua, todo: also afm
local function getgsub(tfmdata,k,kind,value)
local shared = tfmdata.shared
@@ -735,6 +735,23 @@ function otf.getmultiple(tfmdata,k,kind)
return { k }
end
+function otf.getkern(tfmdata,left,right,kind)
+ local kerns = getgsub(tfmdata,left,kind or "kern",true) -- for now we use getsub
+ if kerns then
+ local found = kerns[right]
+ local kind = type(found)
+ if kind == "table" then
+ found = found[1][3] -- can be more clever
+ elseif kind ~= "number" then
+ found = false
+ end
+ if found then
+ return found * tfmdata.parameters.factor
+ end
+ end
+ return 0
+end
+
local function check_otf(forced,specification,suffix)
local name = specification.name
if forced then
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index 9a85dcf96..9c09185a3 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -255,11 +255,7 @@ local math_code = nodecodes.math
local dir_code = whatcodes.dir
local localpar_code = whatcodes.localpar
-
local discretionary_code = disccodes.discretionary
-local regular_code = disccodes.regular
------ automatic_code = disccodes.automatic
-
local ligature_code = glyphcodes.ligature
local privateattribute = attributes.private
@@ -508,8 +504,8 @@ end
-- iteration this becomes a KAF-LAM-ALEF with a SHADDA on the second and a FATHA on the
-- third component.
-local function getcomponentindex(start)
- if getid(start) ~= glyph_code then
+local function getcomponentindex(start) -- we could store this offset in the glyph (nofcomponents)
+ if getid(start) ~= glyph_code then -- and then get rid of all components
return 0
elseif getsubtype(start) == ligature_code then
local i = 0
@@ -526,69 +522,7 @@ local function getcomponentindex(start)
end
end
-local a_noligature = attributes.private("noligature")
-local prehyphenchar = languages and languages.prehyphenchar
-local posthyphenchar = languages and languages.posthyphenchar
------ preexhyphenchar = languages and languages.preexhyphenchar
------ postexhyphenchar = languages and languages.postexhyphenchar
-
-if prehyphenchar then
-
- -- okay
-
-elseif context then
-
- report_warning("no language support") os.exit()
-
-else
-
- local newlang = lang.new
- local getpre = lang.prehyphenchar
- local getpost = lang.posthyphenchar
- -- local getpreex = lang.preexhyphenchar
- -- local getpostex = lang.postexhyphenchar
-
- prehyphenchar = function(l) local l = newlang(l) return l and getpre (l) or -1 end
- posthyphenchar = function(l) local l = newlang(l) return l and getpost (l) or -1 end
- -- preexhyphenchar = function(l) local l = newlang(l) return l and getpreex (l) or -1 end
- -- postexhyphenchar = function(l) local l = newlang(l) return l and getpostex(l) or -1 end
-
-end
-
-local function addhyphens(template,pre,post)
- -- inserted by hyphenation algorithm
- local l = getfield(template,"lang")
- local p = prehyphenchar(l)
- if p and p > 0 then
- local c = copy_node(template)
- setfield(c,"char",p)
- if pre then
- local t = find_node_tail(pre)
- setfield(t,"next",c)
- setfield(c,"prev",t)
- else
- pre = c
- end
- end
- local p = posthyphenchar(l)
- if p and p > 0 then
- local c = copy_node(template)
- setfield(c,"char",p)
- if post then
- -- post has a prev nesting node .. alternatively we could
- local prev = getprev(post)
- setfield(c,"next",post)
- setfield(post,"prev",c)
- if prev then
- setfield(prev,"next",c)
- setfield(c,"prev",prev)
- end
- else
- post = c
- end
- end
- return pre, post
-end
+local a_noligature = attributes.private("noligature")
local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head
if getattr(start,a_noligature) == 1 then
@@ -603,8 +537,8 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
-- needs testing (side effects):
local components = getfield(start,"components")
if components then
--- we get a double free .. needs checking
--- flush_node_list(components)
+ -- we get a double free .. needs checking
+ -- flush_node_list(components)
end
--
local prev = getprev(start)
@@ -626,8 +560,8 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
if next then
setfield(next,"prev",base)
end
- setfield(base,"next",next)
setfield(base,"prev",prev)
+ setfield(base,"next",next)
if not discfound then
local deletemarks = markflag ~= "mark"
local components = start
@@ -674,53 +608,34 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
local discprev = getfield(discfound,"prev")
local discnext = getfield(discfound,"next")
if discprev and discnext then
- local subtype = getsubtype(discfound)
- if subtype == discretionary_code then
- local pre = getfield(discfound,"pre")
- local post = getfield(discfound,"post")
- local replace = getfield(discfound,"replace")
- if not replace then -- todo: signal simple hyphen
- local prev = getfield(base,"prev")
- local copied = copy_node_list(comp)
- setfield(discnext,"prev",nil) -- also blocks funny assignments
- setfield(discprev,"next",nil) -- also blocks funny assignments
- if pre then
- setfield(discprev,"next",pre)
- setfield(pre,"prev",discprev)
- end
- pre = comp
- if post then
- local tail = find_node_tail(post)
- setfield(tail,"next",discnext)
- setfield(discnext,"prev",tail)
- setfield(post,"prev",nil)
- else
- post = discnext
- end
- setfield(prev,"next",discfound)
- setfield(next,"prev",discfound)
- setfield(discfound,"next",next)
- setfield(discfound,"prev",prev)
- setfield(base,"next",nil)
- setfield(base,"prev",nil)
- setfield(base,"components",copied)
- setfield(discfound,"pre",pre)
- setfield(discfound,"post",post)
- setfield(discfound,"replace",base)
- setfield(discfound,"subtype",discretionary_code)
- base = prev -- restart
- end
- elseif subtype == regular_code then
- -- local prev = getfield(base,"prev")
- -- local next = getfield(base,"next")
+ -- we assume normalization in context, and don't care about generic ... especially
+ -- \- can give problems as there we can have a negative char but that won't match
+ -- anyway
+ local pre = getfield(discfound,"pre")
+ local post = getfield(discfound,"post")
+ local replace = getfield(discfound,"replace")
+ if not replace then -- todo: signal simple hyphen
+ local prev = getfield(base,"prev")
local copied = copy_node_list(comp)
setfield(discnext,"prev",nil) -- also blocks funny assignments
setfield(discprev,"next",nil) -- also blocks funny assignments
- local pre, post = addhyphens(comp,comp,discnext,subtype) -- takes from components
+ if pre then
+ setfield(discprev,"next",pre)
+ setfield(pre,"prev",discprev)
+ end
+ pre = comp
+ if post then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",discnext)
+ setfield(discnext,"prev",tail)
+ setfield(post,"prev",nil)
+ else
+ post = discnext
+ end
setfield(prev,"next",discfound)
- setfield(next,"prev",discfound)
- setfield(discfound,"next",next)
setfield(discfound,"prev",prev)
+ setfield(discfound,"next",next)
+ setfield(next,"prev",discfound)
setfield(base,"next",nil)
setfield(base,"prev",nil)
setfield(base,"components",copied)
@@ -728,9 +643,7 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
setfield(discfound,"post",post)
setfield(discfound,"replace",base)
setfield(discfound,"subtype",discretionary_code)
- base = next -- or restart
- else
- -- forget about it in generic usage
+ base = prev -- restart
end
end
end
@@ -753,8 +666,8 @@ local function multiple_glyphs(head,start,multiple,ignoremarks)
local n = copy_node(start) -- ignore components
resetinjection(n)
setfield(n,"char",multiple[k])
- setfield(n,"next",sn)
setfield(n,"prev",start)
+ setfield(n,"next",sn)
if sn then
setfield(sn,"prev",n)
end
@@ -949,7 +862,8 @@ function handlers.gpos_pair(head,start,kind,lookupname,kerns,sequence,lookuphash
if not snext then
return head, start, false
else
- local prev, done = start, false
+ local prev = start
+ local done = false
local factor = tfmdata.parameters.factor
local lookuptype = lookuptypes[lookupname]
while snext and getid(snext) == glyph_code and getfont(snext) == currentfont and getsubtype(snext)<256 do
@@ -1518,11 +1432,7 @@ function chainprocs.gsub_ligature(head,start,stop,kind,chainname,currentcontext,
else
local schar = getchar(s)
if skipmark and marks[schar] then -- marks
--- if s == stop then -- maybe add this
--- break
--- else
s = getnext(s)
--- end
else
local lg = ligatures[schar]
if lg then
@@ -1955,7 +1865,7 @@ end
local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlookup,chainlookupname,chainindex,sequence,chainproc)
if not start then
- return -- safeguard
+ return head, start, false
end
local startishead = start == head
@@ -2165,7 +2075,7 @@ local function chaindisk(head,start,last,kind,chainname,ck,lookuphash,chainlooku
setfield(tail,"next",replace)
setfield(replace,"prev",tail)
end
- setfield(lookaheaddisc,"pre",cf) -- also updates tail
+ setfield(lookaheaddisc,"pre",cf) -- also updates tail
setfield(lookaheaddisc,"replace",new) -- also updates tail
start = getprev(lookaheaddisc)
@@ -2248,6 +2158,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
local skipbase = flags[3]
local markclass = sequence.markclass
local skipped = false
+
for k=1,#contexts do -- i've only seen ccmp having > 1 (e.g. dejavu)
local match = true
local current = start
@@ -2316,7 +2227,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
notmatchpre[last] = nil
notmatchpost[last] = true
notmatchreplace[last] = nil
- local pre = getfield(last,"pre")
+ local pre = getfield(last,"pre")
+ local replace = getfield(last,"replace")
if pre then
local n = n
while pre do
@@ -2336,7 +2248,6 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
else
notmatchpre[last] = true
end
- local replace = getfield(last,"replace")
if replace then
-- so far we never entered this branch
while replace do
@@ -2361,10 +2272,12 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
break
end
else
- last = getnext(last) -- no skipping here
+ notmatchreplace[last] = true
end
+ last = getnext(last)
else
- last = getnext(last) -- no skipping here
+ match = false
+ break
end
else
match = false
@@ -2726,7 +2639,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
end
end
- if diskchain then -- maybe move up so that we can turn checking on/off
+ if diskseen then -- maybe move up so that we can turn checking on/off
notmatchpre = { }
notmatchpost = { }
notmatchreplace = { }
@@ -2815,7 +2728,7 @@ local function initialize(sequence,script,language,enabled)
local order = sequence.order
if order then
for i=1,#order do --
- local kind = order[i] --
+ local kind = order[i] --
local valid = enabled[kind]
if valid then
local scripts = features[kind] --
@@ -2869,7 +2782,7 @@ end
--
-- * languages that use complex disc nodes
-local function kernrun(disc,run) -- we can assume that prev and next are glyphs
+local function kernrun(disc,run)
--
-- we catch <font 1><disc font 2>
--
@@ -2886,22 +2799,18 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
--
local prevmarks = prev
--
- -- can be optional:
+ -- can be optional, because why on earth do we get a disc after a mark (okay, maybe when a ccmp
+ -- has happened but then it should be in the disc so basically this test indicates an error)
--
- -- while prevmarks and getid(prevmarks) == glyph_code and getfont(prevmarks) == currentfont and marks[getchar(prevmarks)] and getsubtype(prevmarks) < 256 do
while prevmarks and getid(prevmarks) == glyph_code and marks[getchar(prevmarks)] and getfont(prevmarks) == currentfont and getsubtype(prevmarks) < 256 do
prevmarks = getprev(prevmarks)
end
--
- if prev and (pre or replace) then
- if not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
- prev = false
- end
+ if prev and (pre or replace) and not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
+ prev = false
end
- if next and (post or replace) then
- if not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
- next = false
- end
+ if next and (post or replace) and not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
+ next = false
end
--
if not pre then
@@ -3123,8 +3032,6 @@ local function featuresprocessor(head,font,attr)
-- Keeping track of the headnode is needed for devanagari (I generalized it a bit
-- so that multiple cases are also covered.)
- -- todo: retain prev
-
-- We don't goto the next node of a disc node is created so that we can then treat
-- the pre, post and replace. It's abit of a hack but works out ok for most cases.
@@ -3144,7 +3051,6 @@ local function featuresprocessor(head,font,attr)
local gpossing = typ == "gpos_single" or typ == "gpos_pair" -- maybe all of them
local subtables = sequence.subtables
local handler = handlers[typ]
-
if typ == "gsub_reversecontextchain" then -- chain < 0
-- this is a limited case, no special treatments like 'init' etc
-- we need to get rid of this slide! probably no longer needed in latest luatex
@@ -3165,8 +3071,7 @@ local function featuresprocessor(head,font,attr)
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- -- local lookupmatch = lookupcache[getchar(start)]
- local lookupmatch = lookupcache[start]
+ local lookupmatch = lookupcache[char]
if lookupmatch then
-- todo: disc?
head, start, success = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
@@ -3194,7 +3099,7 @@ local function featuresprocessor(head,font,attr)
local start = head -- local ?
rlmode = 0 -- to be checked ?
if ns == 1 then -- happens often
- local lookupname = subtables[1]
+ local lookupname = subtables[1]
local lookupcache = lookuphash[lookupname]
if not lookupcache then -- also check for empty cache
report_missing_cache(typ,lookupname)
@@ -3294,7 +3199,7 @@ local function featuresprocessor(head,font,attr)
-- sequence kan weg
local h, d, ok = handler(head,prev,kind,lookupname,lookupmatch,sequence,lookuphash,1)
if ok then
- done = true
+ done = true
success = true
end
end
@@ -3320,7 +3225,7 @@ local function featuresprocessor(head,font,attr)
if lookupmatch then
local h, d, ok = handler(sub,n,kind,lookupname,lookupmatch,sequence,lookuphash,1,injection)
if ok then
- done = true
+ done = true
success = true
end
end
@@ -3364,24 +3269,15 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
end
elseif id == disc_code then
- local discretionary = getsubtype(start) == discretionary_code
- if gpossing then
- if discretionary then
- kernrun(start,k_run)
- else
- discrun(start,d_run,k_run)
- end
- start = getnext(start)
- elseif discretionary then
- if typ == "gsub_ligature" then
- start = testrun(start,t_run,c_run)
- else
- comprun(start,c_run)
- start = getnext(start)
- end
- else
+ if gpossing then
+ kernrun(start,k_run)
+ start = getnext(start)
+ elseif typ == "gsub_ligature" then
+ start = testrun(start,t_run,c_run)
+ else
+ comprun(start,c_run)
start = getnext(start)
- end
+ end
elseif id == whatsit_code then -- will be function
local subtype = getsubtype(start)
if subtype == dir_code then
@@ -3497,7 +3393,7 @@ local function featuresprocessor(head,font,attr)
-- brr prev can be disc
local char = getchar(prev)
for i=1,ns do
- local lookupname = subtables[i]
+ local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
local lookupmatch = lookupcache[char]
@@ -3532,7 +3428,7 @@ local function featuresprocessor(head,font,attr)
if id == glyph_code then
local char = getchar(n)
for i=1,ns do
- local lookupname = subtables[i]
+ local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
local lookupmatch = lookupcache[char]
@@ -3567,7 +3463,7 @@ local function featuresprocessor(head,font,attr)
if a then
local char = getchar(start)
for i=1,ns do
- local lookupname = subtables[i]
+ local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
local lookupmatch = lookupcache[char]
@@ -3612,7 +3508,7 @@ local function featuresprocessor(head,font,attr)
end
if a then
for i=1,ns do
- local lookupname = subtables[i]
+ local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
local char = getchar(start)
@@ -3645,27 +3541,19 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
end
elseif id == disc_code then
- local discretionary = getsubtype(start) == discretionary_code
if gpossing then
- if discretionary then
- kernrun(start,k_run)
- else
- discrun(start,d_run,k_run)
- end
+ kernrun(start,k_run)
start = getnext(start)
- elseif discretionary then
- if typ == "gsub_ligature" then
- start = testrun(start,t_run,c_run)
- else
- comprun(start,c_run)
- start = getnext(start)
- end
+ elseif typ == "gsub_ligature" then
+ start = testrun(start,t_run,c_run)
else
+ comprun(start,c_run)
start = getnext(start)
end
elseif id == whatsit_code then
local subtype = getsubtype(start)
if subtype == dir_code then
+ local dir = getfield(start,"dir")
if dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
diff --git a/tex/context/base/font-ots.lua b/tex/context/base/font-ots.lua
index 27e0f161e..2204d1496 100644
--- a/tex/context/base/font-ots.lua
+++ b/tex/context/base/font-ots.lua
@@ -126,6 +126,7 @@ local trace_compruns = false registertracker("otf.compruns", function(v
local quit_on_no_replacement = true -- maybe per font
local zwnjruns = true
+local optimizekerns = true
registerdirective("otf.zwnjruns", function(v) zwnjruns = v end)
registerdirective("otf.chain.quitonnoreplacement",function(value) quit_on_no_replacement = value end)
@@ -196,11 +197,7 @@ local math_code = nodecodes.math
local dir_code = whatcodes.dir
local localpar_code = whatcodes.localpar
-
local discretionary_code = disccodes.discretionary
-local regular_code = disccodes.regular
------ automatic_code = disccodes.automatic
-
local ligature_code = glyphcodes.ligature
local privateattribute = attributes.private
@@ -563,69 +560,7 @@ local function getcomponentindex(start) -- we could store this offset in the gly
end
end
-local a_noligature = attributes.private("noligature")
-local prehyphenchar = languages and languages.prehyphenchar
-local posthyphenchar = languages and languages.posthyphenchar
------ preexhyphenchar = languages and languages.preexhyphenchar
------ postexhyphenchar = languages and languages.postexhyphenchar
-
-if prehyphenchar then
-
- -- okay
-
-elseif context then
-
- report_warning("no language support") os.exit()
-
-else
-
- local newlang = lang.new
- local getpre = lang.prehyphenchar
- local getpost = lang.posthyphenchar
- -- local getpreex = lang.preexhyphenchar
- -- local getpostex = lang.postexhyphenchar
-
- prehyphenchar = function(l) local l = newlang(l) return l and getpre (l) or -1 end
- posthyphenchar = function(l) local l = newlang(l) return l and getpost (l) or -1 end
- -- preexhyphenchar = function(l) local l = newlang(l) return l and getpreex (l) or -1 end
- -- postexhyphenchar = function(l) local l = newlang(l) return l and getpostex(l) or -1 end
-
-end
-
-local function addhyphens(template,pre,post)
- -- inserted by hyphenation algorithm
- local l = getfield(template,"lang")
- local p = prehyphenchar(l)
- if p and p > 0 then
- local c = copy_node(template)
- setfield(c,"char",p)
- if pre then
- local t = find_node_tail(pre)
- setfield(t,"next",c)
- setfield(c,"prev",t)
- else
- pre = c
- end
- end
- local p = posthyphenchar(l)
- if p and p > 0 then
- local c = copy_node(template)
- setfield(c,"char",p)
- if post then
- -- post has a prev nesting node .. alternatively we could
- local prev = getprev(post)
- setfield(c,"next",post)
- setfield(post,"prev",c)
- if prev then
- setfield(prev,"next",c)
- setfield(c,"prev",prev)
- end
- else
- post = c
- end
- end
- return pre, post
-end
+local a_noligature = attributes.private("noligature")
local function toligature(head,start,stop,char,dataset,sequence,markflag,discfound) -- brr head
if getattr(start,a_noligature) == 1 then
@@ -640,8 +575,8 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
-- needs testing (side effects):
local components = getfield(start,"components")
if components then
--- we get a double free .. needs checking
--- flush_node_list(components)
+ -- we get a double free .. needs checking
+ -- flush_node_list(components)
end
--
local prev = getprev(start)
@@ -663,8 +598,8 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
if next then
setfield(next,"prev",base)
end
- setfield(base,"next",next)
setfield(base,"prev",prev)
+ setfield(base,"next",next)
if not discfound then
local deletemarks = markflag ~= "mark"
local components = start
@@ -711,53 +646,34 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
local discprev = getfield(discfound,"prev")
local discnext = getfield(discfound,"next")
if discprev and discnext then
- local subtype = getsubtype(discfound)
- if subtype == discretionary_code then
- local pre = getfield(discfound,"pre")
- local post = getfield(discfound,"post")
- local replace = getfield(discfound,"replace")
- if not replace then -- todo: signal simple hyphen
- local prev = getfield(base,"prev")
- local copied = copy_node_list(comp)
- setfield(discnext,"prev",nil) -- also blocks funny assignments
- setfield(discprev,"next",nil) -- also blocks funny assignments
- if pre then
- setfield(discprev,"next",pre)
- setfield(pre,"prev",discprev)
- end
- pre = comp
- if post then
- local tail = find_node_tail(post)
- setfield(tail,"next",discnext)
- setfield(discnext,"prev",tail)
- setfield(post,"prev",nil)
- else
- post = discnext
- end
- setfield(prev,"next",discfound)
- setfield(next,"prev",discfound)
- setfield(discfound,"next",next)
- setfield(discfound,"prev",prev)
- setfield(base,"next",nil)
- setfield(base,"prev",nil)
- setfield(base,"components",copied)
- setfield(discfound,"pre",pre)
- setfield(discfound,"post",post)
- setfield(discfound,"replace",base)
- setfield(discfound,"subtype",discretionary_code)
- base = prev -- restart
- end
- elseif subtype == regular_code then
- -- local prev = getfield(base,"prev")
- -- local next = getfield(base,"next")
+ -- we assume normalization in context, and don't care about generic ... especially
+ -- \- can give problems as there we can have a negative char but that won't match
+ -- anyway
+ local pre = getfield(discfound,"pre")
+ local post = getfield(discfound,"post")
+ local replace = getfield(discfound,"replace")
+ if not replace then -- todo: signal simple hyphen
+ local prev = getfield(base,"prev")
local copied = copy_node_list(comp)
setfield(discnext,"prev",nil) -- also blocks funny assignments
setfield(discprev,"next",nil) -- also blocks funny assignments
- local pre, post = addhyphens(comp,comp,discnext,subtype) -- takes from components
+ if pre then
+ setfield(discprev,"next",pre)
+ setfield(pre,"prev",discprev)
+ end
+ pre = comp
+ if post then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",discnext)
+ setfield(discnext,"prev",tail)
+ setfield(post,"prev",nil)
+ else
+ post = discnext
+ end
setfield(prev,"next",discfound)
- setfield(next,"prev",discfound)
- setfield(discfound,"next",next)
setfield(discfound,"prev",prev)
+ setfield(discfound,"next",next)
+ setfield(next,"prev",discfound)
setfield(base,"next",nil)
setfield(base,"prev",nil)
setfield(base,"components",copied)
@@ -765,9 +681,7 @@ local function toligature(head,start,stop,char,dataset,sequence,markflag,discfou
setfield(discfound,"post",post)
setfield(discfound,"replace",base)
setfield(discfound,"subtype",discretionary_code)
- base = next -- or restart
- else
- -- forget about it in generic usage
+ base = prev -- restart
end
end
end
@@ -790,8 +704,8 @@ local function multiple_glyphs(head,start,multiple,ignoremarks)
local n = copy_node(start) -- ignore components
resetinjection(n)
setfield(n,"char",multiple[k])
- setfield(n,"next",sn)
setfield(n,"prev",start)
+ setfield(n,"next",sn)
if sn then
setfield(sn,"prev",n)
end
@@ -980,13 +894,13 @@ function handlers.gpos_single(head,start,dataset,sequence,kerns,rlmode,step,i,in
if step.format == "pair" then
local dx, dy, w, h = setpair(start,factor,rlmode,sequence.flags[4],kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),dx,dy,w,h)
+ logprocess("%s: shifting single %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),dx,dy,w,h,injection or "injections")
end
else
-- needs checking .. maybe no kerns format for single
local k = setkern(start,factor,rlmode,kerns,injection)
if trace_kerns then
- logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(startchar),k)
+ logprocess("%s: shifting single %s by %p as %s",pref(dataset,sequence),gref(startchar),k,injection or "injections")
end
end
return head, start, false
@@ -1009,18 +923,30 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje
break
elseif step.format == "pair" then
local a, b = krn[1], krn[2]
+ if optimizekerns then
+ -- this permits a mixed table, but we could also decide to optimize this
+ -- in the loader and use format 'kern'
+ if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then
+ local k = setkern(snext,factor,rlmode,a[3],injection)
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %p",pref(dataset,sequence),gref(nextchar),k)
+ end
+ done = true
+ break
+ end
+ end
if a and #a > 0 then
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection) -- characters[startchar])
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,injection)
if trace_kerns then
local startchar = getchar(start)
- logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
+ logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
end
end
if b and #b > 0 then
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection) -- characters[nextchar])
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,injection)
if trace_kerns then
local startchar = getchar(snext)
- logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
+ logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p) as %s",pref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h,injection or "injections")
end
end
done = true
@@ -1028,7 +954,7 @@ function handlers.gpos_pair(head,start,dataset,sequence,kerns,rlmode,step,i,inje
elseif krn ~= 0 then
local k = setkern(snext,factor,rlmode,krn,injection)
if trace_kerns then
- logprocess("%s: inserting kern %p between %s and %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar))
+ logprocess("%s: inserting kern %p between %s and %s as %s",pref(dataset,sequence),k,gref(getchar(prev)),gref(nextchar),injection or "injections")
end
done = true
break
@@ -1566,16 +1492,28 @@ function chainprocs.gpos_pair(head,start,stop,dataset,sequence,currentlookup,rlm
break
elseif step.format == "pair" then
local a, b = krn[1], krn[2]
+ if optimizekerns then
+ -- this permits a mixed table, but we could also decide to optimize this
+ -- in the loader and use format 'kern'
+ if not b and a[1] == 0 and a[2] == 0 and a[4] == 0 then
+ local k = setkern(snext,factor,rlmode,a[3],"injections")
+ if trace_kerns then
+ logprocess("%s: shifting single %s by %p",cref(dataset,sequence),gref(startchar),k)
+ end
+ done = true
+ break
+ end
+ end
if a and #a > 0 then
local startchar = getchar(start)
- local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a) -- currentlookups flags?
+ local x, y, w, h = setpair(start,factor,rlmode,sequence.flags[4],a,"injections") -- currentlookups flags?
if trace_kerns then
logprocess("%s: shifting first of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
end
end
if b and #b > 0 then
local startchar = getchar(start)
- local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b)
+ local x, y, w, h = setpair(snext,factor,rlmode,sequence.flags[4],b,"injections")
if trace_kerns then
logprocess("%s: shifting second of pair %s and %s by (%p,%p) and correction (%p,%p)",cref(dataset,sequence),gref(startchar),gref(nextchar),x,y,w,h)
end
@@ -1848,7 +1786,7 @@ end
local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,ck,chainproc)
if not start then
- return -- safeguard
+ return head, start, false
end
local startishead = start == head
@@ -2058,8 +1996,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
setfield(tail,"next",replace)
setfield(replace,"prev",tail)
end
- setfield(lookaheaddisc,"pre",cf) -- also updates pre-tail
- setfield(lookaheaddisc,"replace",new) -- also updates replace-tail
+ setfield(lookaheaddisc,"pre",cf) -- also updates tail
+ setfield(lookaheaddisc,"replace",new) -- also updates tail
start = getprev(lookaheaddisc)
sweephead[cf] = getnext(clast)
@@ -2114,8 +2052,8 @@ local function chaindisk(head,start,last,dataset,sequence,chainlookup,rlmode,k,c
else
replace = new
end
- setfield(backtrackdisc,"post",post) -- also updates post-tail
- setfield(backtrackdisc,"replace",replace) -- also updates replace-tail
+ setfield(backtrackdisc,"post",post) -- also updates tail
+ setfield(backtrackdisc,"replace",replace) -- also updates tail
start = getprev(backtrackdisc)
sweephead[post] = getnext(clast)
sweephead[replace] = getnext(last)
@@ -2270,7 +2208,8 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
notmatchpre[last] = nil
notmatchpost[last] = true
notmatchreplace[last] = nil
- local pre = getfield(last,"pre")
+ local pre = getfield(last,"pre")
+ local replace = getfield(last,"replace")
if pre then
local n = n
while pre do
@@ -2290,7 +2229,6 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
else
notmatchpre[last] = true
end
- local replace = getfield(last,"replace")
if replace then
-- so far we never entered this branch
while replace do
@@ -2315,10 +2253,12 @@ local function handle_contextchain(head,start,dataset,sequence,contexts,rlmode)
break
end
else
- last = getnext(last) -- no skipping here
+ notmatchreplace[last] = true
end
+ last = getnext(last)
else
- last = getnext(last) -- no skipping here
+ match = false
+ break
end
else
match = false
@@ -2808,78 +2748,61 @@ local function kernrun(disc,run)
prevmarks = getprev(prevmarks)
end
--
- if prev and (pre or replace) then
- if not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
- prev = false
- end
+ if prev and (pre or replace) and not (getid(prev) == glyph_code and getfont(prev) == currentfont and getsubtype(prev)<256) then
+ prev = false
end
- if next and (post or replace) then
- if not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
- next = false
- end
+ if next and (post or replace) and not (getid(next) == glyph_code and getfont(next) == currentfont and getsubtype(next)<256) then
+ next = false
end
--
- if not pre then
- -- go on
- elseif prev then
- local nest = getprev(pre)
- setfield(pre,"prev",prev)
- setfield(prev,"next",pre)
- run(prevmarks,"preinjections")
- setfield(pre,"prev",nest)
- setfield(prev,"next",disc)
- else
- run(pre,"preinjections")
+ if pre then
+ run(pre,"injections")
+ if prev then
+ local nest = getprev(pre)
+ setfield(pre,"prev",prev)
+ setfield(prev,"next",pre)
+ run(prevmarks,"preinjections",getnext(pre))
+ setfield(pre,"prev",nest)
+ setfield(prev,"next",disc)
+ end
end
--
- if not post then
- -- go on
- elseif next then
- local tail = find_node_tail(post)
- setfield(tail,"next",next)
- setfield(next,"prev",tail)
- run(post,"postinjections",next)
- setfield(tail,"next",nil)
- setfield(next,"prev",disc)
- else
- run(post,"postinjections")
+ if post then
+ run(post,"injections")
+ if next then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(tail,"postinjections",next)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ end
end
--
- if not replace and prev and next then
- -- this should be already done by discfound
+ if replace then
+ run(replace,"injections")
+ if prev then
+ local nest = getprev(replace)
+ setfield(replace,"prev",prev)
+ setfield(prev,"next",replace)
+ run(prevmarks,"replaceinjections",getnext(replace))
+ setfield(replace,"prev",nest)
+ setfield(prev,"next",disc)
+ end
+ if next then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ run(tail,"replaceinjections",next)
+ setfield(tail,"next",nil)
+ setfield(next,"prev",disc)
+ end
+ elseif prev and next then
setfield(prev,"next",next)
setfield(next,"prev",prev)
- run(prevmarks,"injections",next)
- setfield(prev,"next",disc)
- setfield(next,"prev",disc)
- elseif prev and next then
- local tail = find_node_tail(replace)
- local nest = getprev(replace)
- setfield(replace,"prev",prev)
- setfield(prev,"next",replace)
- setfield(tail,"next",next)
- setfield(next,"prev",tail)
- run(prevmarks,"replaceinjections",next)
- setfield(replace,"prev",nest)
- setfield(prev,"next",disc)
- setfield(tail,"next",nil)
- setfield(next,"prev",disc)
- elseif prev then
- local nest = getprev(replace)
- setfield(replace,"prev",prev)
- setfield(prev,"next",replace)
- run(prevmarks,"replaceinjections")
- setfield(replace,"prev",nest)
+ run(prevmarks,"emptyinjections",next)
setfield(prev,"next",disc)
- elseif next then
- local tail = find_node_tail(replace)
- setfield(tail,"next",next)
- setfield(next,"prev",tail)
- run(replace,"replaceinjections",next)
- setfield(tail,"next",nil)
setfield(next,"prev",disc)
- else
- run(replace,"replaceinjections")
end
end
@@ -2903,7 +2826,7 @@ local function comprun(disc,run)
local pre = getfield(disc,"pre")
if pre then
sweepnode = disc
- sweeptype = "pre" -- in alternative code preinjections is used (also used then for proeprties, saves a variable)
+ sweeptype = "pre"
local new, done = run(pre)
if done then
setfield(disc,"pre",new)
@@ -3144,7 +3067,7 @@ local function featuresprocessor(head,font,attr)
local start = head -- local ?
rlmode = 0 -- to be checked ?
if nofsteps == 1 then -- happens often
- local step = steps[1]
+ local step = steps[1]
local lookupcache = step.coverage
if not lookupcache then -- also check for empty cache
report_missing_cache(dataset,sequence)
@@ -3247,14 +3170,14 @@ if not a or (a == attr) then
-- sequence kan weg
local h, d, ok = handler(head,start,dataset,sequence,lookupmatch,rlmode,step,1)
if ok then
- done = true
+ done = true
success = true
end
end
end
end
- local function k_run(sub,injection,last)
+ local function k_run(sub,injection,last,bound)
local a = getattr(sub,0)
-- if a then
-- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
@@ -3272,9 +3195,9 @@ if not a or (a == attr) then
if id == glyph_code then
local lookupmatch = lookupcache[getchar(n)]
if lookupmatch then
- local h, d, ok = handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection)
+ local h, d, ok = handler(sub,n,dataset,sequence,lookupmatch,rlmode,step,1,injection,bound)
if ok then
- done = true
+ done = true
success = true
end
end
@@ -3318,24 +3241,15 @@ if not a or (a == attr) then
start = getnext(start)
end
elseif id == disc_code then
- local discretionary = getsubtype(start) == discretionary_code
- if gpossing then
- if discretionary then
- kernrun(start,k_run)
- else
- discrun(start,d_run,k_run)
- end
- start = getnext(start)
- elseif discretionary then
- if typ == "gsub_ligature" then
- start = testrun(start,t_run,c_run)
- else
- comprun(start,c_run)
- start = getnext(start)
- end
- else
+ if gpossing then
+ kernrun(start,k_run)
+ start = getnext(start)
+ elseif typ == "gsub_ligature" then
+ start = testrun(start,t_run,c_run)
+ else
+ comprun(start,c_run)
start = getnext(start)
- end
+ end
elseif id == whatsit_code then -- will be function
local subtype = getsubtype(start)
if subtype == dir_code then
@@ -3472,7 +3386,7 @@ if not a or (a == attr) then
end
end
- local function k_run(sub,injection,last)
+ local function k_run(sub,injection,last,bound)
local a = getattr(sub,0)
-- if a then
-- a = (a == attr) and (not attribute or getprop(sub,a_state) == attribute)
@@ -3494,7 +3408,7 @@ if not a or (a == attr) then
if lookupcache then
local lookupmatch = lookupcache[char]
if lookupmatch then
- local h, d, ok = handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection)
+ local h, d, ok = handler(head,n,dataset,sequence,lookupmatch,step,rlmode,i,injection,bound)
if ok then
done = true
break
@@ -3525,7 +3439,7 @@ if not a or (a == attr) then
if not a or (a == attr) then
local char = getchar(start)
for i=1,nofsteps do
- local step = steps[i]
+ local step = steps[i]
local lookupcache = step.coverage
if lookupcache then
local lookupmatch = lookupcache[char]
@@ -3603,27 +3517,19 @@ if not a or (a == attr) then
start = getnext(start)
end
elseif id == disc_code then
- local discretionary = getsubtype(start) == discretionary_code
if gpossing then
- if discretionary then
- kernrun(start,k_run)
- else
- discrun(start,d_run,k_run)
- end
+ kernrun(start,k_run)
start = getnext(start)
- elseif discretionary then
- if typ == "gsub_ligature" then
- start = testrun(start,t_run,c_run)
- else
- comprun(start,c_run)
- start = getnext(start)
- end
+ elseif typ == "gsub_ligature" then
+ start = testrun(start,t_run,c_run)
else
+ comprun(start,c_run)
start = getnext(start)
end
elseif id == whatsit_code then
local subtype = getsubtype(start)
if subtype == dir_code then
+ local dir = getfield(start,"dir")
if dir == "+TLT" then
topstack = topstack + 1
dirstack[topstack] = dir
diff --git a/tex/context/base/lang-dis.lua b/tex/context/base/lang-dis.lua
index 91b0e9460..d503cdffd 100644
--- a/tex/context/base/lang-dis.lua
+++ b/tex/context/base/lang-dis.lua
@@ -47,6 +47,8 @@ local setattribute = tex.setattribute
local getlanguagedata = languages.getdata
+local check_regular = true
+
-- local expanders = {
-- [disccodes.discretionary] = function(d,template)
-- -- \discretionary
@@ -207,41 +209,47 @@ local expanders = {
return template
end,
[disccodes.regular] = function(d,template)
- -- simple
- if not template then
- -- can there be font kerns already?
- template = getprev(d)
- if template and getid(template) ~= glyph_code then
- template = getnext(d)
+ if check_regular then
+ -- simple
+ if not template then
+ -- can there be font kerns already?
+ template = getprev(d)
if template and getid(template) ~= glyph_code then
- template = nil
+ template = getnext(d)
+ if template and getid(template) ~= glyph_code then
+ template = nil
+ end
end
end
- end
- if template then
- local language = template and getfield(template,"lang")
- local data = getlanguagedata(language)
- local prechar = data.prehyphenchar
- local postchar = data.posthyphenchar
- local pre, post, replace = getdisc(d) -- pre can be set
- local done = false
- if prechar and prechar > 0 then
- done = true
- pre = copy_node(template)
- setfield(pre,"char",prechar)
- end
- if postchar and postchar > 0 then
- done = true
- post = copy_node(template)
- setfield(post,"char",postchar)
- end
- if done then
- setdisc(d,pre,post,replace,discretionary_code)
+ if template then
+ local language = template and getfield(template,"lang")
+ local data = getlanguagedata(language)
+ local prechar = data.prehyphenchar
+ local postchar = data.posthyphenchar
+ local pre, post, replace = getdisc(d) -- pre can be set
+ local done = false
+ if prechar and prechar > 0 then
+ done = true
+ pre = copy_node(template)
+ -- setfield(pre,"char",prechar)
+ setchar(pre,prechar)
+ end
+ if postchar and postchar > 0 then
+ done = true
+ post = copy_node(template)
+ -- setfield(post,"char",postchar)
+ setchar(post,postchar)
+ end
+ if done then
+ setdisc(d,pre,post,replace,discretionary_code)
+ end
+ else
+ -- print("lone regular discretionary ignored")
end
+ return template
else
- -- print("lone regular discretionary ignored")
+ setfield(d,"subtype",discretionary_code)
end
- return template
end,
[disccodes.first] = function()
-- forget about them
diff --git a/tex/context/base/lpdf-epa.lua b/tex/context/base/lpdf-epa.lua
index dd5ecc609..59f62a310 100644
--- a/tex/context/base/lpdf-epa.lua
+++ b/tex/context/base/lpdf-epa.lua
@@ -12,6 +12,7 @@ if not modules then modules = { } end modules ['lpdf-epa'] = {
local type, tonumber = type, tonumber
local format, gsub, lower = string.format, string.gsub, string.lower
local formatters = string.formatters
+local abs = math.abs
----- lpegmatch, lpegpatterns = lpeg.match, lpeg.patterns
@@ -38,6 +39,8 @@ local escapetex = characters.filters.utf.private.escape
local bookmarks = structures.bookmarks
+local maxdimen = 2^30-1
+
local layerspec = { -- predefining saves time
"epdflinks"
}
@@ -178,7 +181,11 @@ function codeinjections.mergereferences(specification)
local h = yscale * (a_ury - a_lly)
if subtype == "Link" then
local a = annotation.A
- if a then
+ if not a then
+ report_link("missing link annotation")
+ elseif w > width or h > height or w < 0 or h < 0 or abs(x) > (maxdimen/2) or abs(y) > (maxdimen/2) then
+ report_link("broken link rectangle [%f %f %f %f] (max: %f)",a_llx,a_lly,a_urx,a_ury,maxdimen/2)
+ else
local linktype = a.S
if linktype == "GoTo" then
link_goto(x,y,w,h,document,annotation,pagedata,namespace)
@@ -189,8 +196,6 @@ function codeinjections.mergereferences(specification)
elseif trace_links then
report_link("unsupported link annotation %a",linktype)
end
- else
- report_link("missing link annotation")
end
elseif trace_links then
report_link("unsupported annotation %a",subtype)
diff --git a/tex/context/base/m-morse.mkvi b/tex/context/base/m-morse.mkvi
new file mode 100644
index 000000000..a2c20dff7
--- /dev/null
+++ b/tex/context/base/m-morse.mkvi
@@ -0,0 +1,273 @@
+%D \module
+%D [ file=m-morse,
+%D version=2010.12.10,
+%D title=\CONTEXT\ Extra Modules,
+%D subtitle=Morse,
+%D author=Hans Hagen,
+%D date=\currentdate,
+%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}]
+%C
+%C This module is part of the \CONTEXT\ macro||package and is
+%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
+%C details.
+
+% todo: act upon the node list
+% make it a buffer operation
+% nice in cld manual
+
+\startluacode
+
+moduledata.morse = moduledata.morse or { }
+local morse = moduledata.morse
+
+local utfcharacters, gsub = string.utfcharacters, string.gsub
+local ucchars, shchars = characters.ucchars, characters.shchars
+
+local codes = {
+
+ ["A"] = "·—",
+ ["B"] = "—···",
+ ["C"] = "—·—·",
+ ["D"] = "—··",
+ ["E"] = "·",
+ ["F"] = "··—·",
+ ["G"] = "——·",
+ ["H"] = "····",
+ ["I"] = "··",
+ ["J"] = "·———",
+ ["K"] = "—·—",
+ ["L"] = "·—··",
+ ["M"] = "——",
+ ["N"] = "—·",
+ ["O"] = "———",
+ ["P"] = "·——·",
+ ["Q"] = "——·—",
+ ["R"] = "·—·",
+ ["S"] = "···",
+ ["T"] = "—",
+ ["U"] = "··—",
+ ["V"] = "···—",
+ ["W"] = "·——",
+ ["X"] = "—··—",
+ ["Y"] = "—·——",
+ ["Z"] = "——··",
+
+ ["0"] = "—————",
+ ["1"] = "·————",
+ ["2"] = "··———",
+ ["3"] = "···——",
+ ["4"] = "····—",
+ ["5"] = "·····",
+ ["6"] = "—····",
+ ["7"] = "——···",
+ ["8"] = "———··",
+ ["9"] = "————·",
+
+ ["."] = "·—·—·—",
+ [","] = "——··——",
+ [":"] = "———···",
+ [";"] = "—·—·—",
+
+ ["?"] = "··——··",
+ ["!"] = "—·—·——",
+
+ ["-"] = "—····—",
+ ["/"] = "—··—· ",
+
+ ["("] = "—·——·",
+ [")"] = "—·——·—",
+
+ ["="] = "—···—",
+ ["@"] = "·——·—·",
+
+ ["'"] = "·————·",
+ ['"'] = "·—··—·",
+
+ ["À"] = "·——·—",
+ ["Å"] = "·——·—",
+ ["Ä"] = "·—·—",
+ ["Æ"] = "·—·—",
+ ["Ç"] = "—·—··",
+ ["É"] = "··—··",
+ ["È"] = "·—··—",
+ ["Ñ"] = "——·——",
+ ["Ö"] = "———·",
+ ["Ø"] = "———·",
+ ["Ü"] = "··——",
+ ["ß"] = "··· ···",
+
+}
+
+morse.codes = codes
+
+local fallbackself = false
+
+local function codefallback(t,k)
+ if k then
+ local u = ucchars[k]
+ local v = rawget(t,u) or rawget(t,shchars[u]) or false
+ t[k] = v
+ return v
+ elseif fallbackself then
+ return k
+ else
+ return false
+ end
+end
+
+table.setmetatableindex(codes,codefallback)
+
+local MorseBetweenWords = context.MorseBetweenWords
+local MorseBetweenCharacters = context.MorseBetweenCharacters
+local MorseLong = context.MorseLong
+local MorseShort = context.MorseShort
+local MorseSpace = context.MorseSpace
+local MorseUnknown = context.MorseUnknown
+
+local function toverbose(str)
+ str = gsub(str,"%s*+%s*","+")
+ str = gsub(str,"%s+"," ")
+ local done = false
+ for m in utfcharacters(str) do
+ if done then
+ MorseBetweenCharacters()
+ end
+ if m == "·" or m == "." then
+ MorseShort()
+ done = true
+ elseif m == "—" or m == "-" then
+ MorseLong()
+ done = true
+ elseif m == " " then
+ if done then
+ MorseBetweenCharacters()
+ end
+ done = false
+ elseif m == "+" then
+ MorseBetweenWords()
+ done = false
+ else
+ MorseUnknown(m)
+ end
+ end
+end
+
+local function toregular(str)
+ local inmorse = false
+ for s in utfcharacters(str) do
+ local m = codes[s]
+ if m then
+ if inmorse then
+ MorseBetweenWords()
+ else
+ inmorse = true
+ end
+ local done = false
+ for m in utfcharacters(m) do
+ if done then
+ MorseBetweenCharacters()
+ else
+ done = true
+ end
+ if m == "·" then
+ MorseShort()
+ elseif m == "—" then
+ MorseLong()
+ elseif m == " " then
+ MorseBetweenCharacters()
+ end
+ end
+ inmorse = true
+ elseif s == "\n" or s == " " then
+ MorseSpace()
+ inmorse = false
+ else
+ if inmorse then
+ MorseBetweenWords()
+ else
+ inmorse = true
+ end
+ MorseUnknown(s)
+ end
+ end
+end
+
+local function tomorse(str,verbose)
+ if verbose then
+ toverbose(str)
+ else
+ toregular(str)
+ end
+end
+
+morse.tomorse = tomorse
+
+function morse.filetomorse(name,verbose)
+ tomorse(resolvers.loadtexfile(name),verbose)
+end
+
+function morse.showtable()
+ context.starttabulate { "|l|l|" } -- { "|l|l|l|" }
+ for k, v in table.sortedpairs(codes) do
+ context.NC() context(k)
+ -- context.NC() context(v)
+ context.NC() tomorse(v,true)
+ context.NC() context.NR()
+ end
+ context.stoptabulate()
+end
+
+\stopluacode
+
+\unprotect
+
+% todo: \setupmorse, but probably it's not worth the trouble.
+
+\def\MorseWidth {0.4em}
+\def\MorseHeight {0.2em}
+%def\MorseShort {\dontleavehmode\blackrule[\c!height=\MorseHeight,\c!width=\dimexpr\MorseWidth]}
+%def\MorseLong {\dontleavehmode\blackrule[\c!height=\MorseHeight,\c!width=3\dimexpr\MorseWidth]}
+\def\MorseShort {\dontleavehmode\vrule\!!width \dimexpr\MorseWidth\!!height\MorseHeight\!!depth\zeropoint\relax}
+\def\MorseLong {\dontleavehmode\vrule\!!width3\dimexpr\MorseWidth\!!height\MorseHeight\!!depth\zeropoint\relax}
+\def\MorseBetweenCharacters {\kern\MorseWidth}
+\def\MorseBetweenWords {\hskip3\dimexpr\MorseWidth\relax}
+\def\MorseSpace {\hskip7\dimexpr\MorseWidth\relax}
+\def\MorseUnknown #text{[\detokenize{#text}]}
+
+\unexpanded\def\MorseCode #text{\ctxlua{moduledata.morse.tomorse(\!!bs#text\!!es,true)}}
+\unexpanded\def\MorseString #text{\ctxlua{moduledata.morse.tomorse(\!!bs#text\!!es)}}
+\unexpanded\def\MorseFile #text{\ctxlua{moduledata.morse.filetomorse("#text")}}
+\unexpanded\def\MorseTable {\ctxlua{moduledata.morse.showtable()}}
+
+\let\Morse \MorseString
+
+%def\MorseShort {·}
+%def\MorseLong {—}
+
+\protect
+
+\continueifinputfile{m-morse.mkvi}
+
+\starttext
+
+\MorseTable
+
+\startlines
+\MorseCode{—·—· ——— —· — · —··— —+—— —·— ·· ···—}
+\MorseCode{—·—· ——— —· — · —··— — + —— —·— ·· ···—}
+\Morse{ÀÁÂÃÄÅàáâãäå}
+\Morse{ÆÇæç}
+\Morse{ÈÉÊËèéêë}
+\Morse{ÌÍÎÏìíîï}
+\Morse{Ññ}
+\Morse{ÒÓÔÕÖòóôõö}
+\Morse{Øø}
+\Morse{ÙÚÛÜùúû}
+\Morse{Ýýÿ}
+\Morse{ß}
+\Morse{Ţţ}
+\stoplines
+
+\Morse{A B C D E F G H I J K L M N O P Q R S T U V W X Y Z}
+
+\stoptext
diff --git a/tex/context/base/m-newotf.mkiv b/tex/context/base/m-newotf.mkiv
index df91cbe02..8668eb827 100644
--- a/tex/context/base/m-newotf.mkiv
+++ b/tex/context/base/m-newotf.mkiv
@@ -11,6 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% \endinput
+
%D This module will go away as soon as we use the new loader code by default.
%D That will happen after extensive testing. Generic support will happen after
%D that.
@@ -19,6 +21,8 @@
\startluacode
local files = {
+ "font-otj",
+"font-otj-new",
"font-otr",
"font-cff",
"font-ttf",
@@ -67,6 +71,17 @@
directives.register("nodes.injections.fontkern", function(v) setfield(kern,"subtype",v and 0 or 1) end)
+ local fonts = fonts
+ local handlers = fonts.handlers
+ local otf = handlers.otf -- brrr
+ local afm = handlers.afm -- brrr
+ local getters = fonts.getters
+
+ getters.kern .opentype = otf.getkern
+ getters.substitution.opentype = otf.getsubstitution
+ getters.alternate .opentype = otf.getalternate
+ getters.multiple .opentype = otf.getmultiple
+
\stopluacode
\protect \endinput
diff --git a/tex/context/base/node-fnt.lua b/tex/context/base/node-fnt.lua
index 9cb9b487d..4272f304b 100644
--- a/tex/context/base/node-fnt.lua
+++ b/tex/context/base/node-fnt.lua
@@ -138,6 +138,8 @@ function fonts.setdiscexpansion(v)
end
end
+fonts.setdiscexpansion(true)
+
function handlers.characters(head)
-- either next or not, but definitely no already processed list
starttiming(nodes)
diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf
index 7ccbf6cdc..b1f0fb99b 100644
--- a/tex/context/base/status-files.pdf
+++ b/tex/context/base/status-files.pdf
Binary files differ
diff --git a/tex/context/base/status-lua.pdf b/tex/context/base/status-lua.pdf
index c8718cfe4..0d09a329b 100644
--- a/tex/context/base/status-lua.pdf
+++ b/tex/context/base/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/typo-cap.lua b/tex/context/base/typo-cap.lua
index eaf14bd63..7f0656130 100644
--- a/tex/context/base/typo-cap.lua
+++ b/tex/context/base/typo-cap.lua
@@ -11,6 +11,7 @@ local format, insert = string.format, table.insert
local div, randomnumber = math.div, math.random
local trace_casing = false trackers.register("typesetters.casing", function(v) trace_casing = v end)
+local check_kerns = false directives.register("typesetters.casing.checkkerns", function(v) check_kerns = v end)
local report_casing = logs.reporter("typesetting","casing")
@@ -51,6 +52,8 @@ local userskip_code = skipcodes.userskip
local tasks = nodes.tasks
+local newkern = nuts.pool.kern
+
local fonthashes = fonts.hashes
local fontdata = fonthashes.identifiers
local fontchar = fonthashes.characters
@@ -199,25 +202,67 @@ local function camel(start,attr,lastfont,n,count,where,first)
return start, done_1 or done_2, true
end
+-- local function mixed(start,attr,lastfont,n,count,where,first)
+-- if where == "post" then
+-- return
+-- end
+-- local used = first or start
+-- local char = getchar(first)
+-- local dc = uccodes[char]
+-- if not dc then
+-- return start, false, true
+-- elseif dc == char then
+-- local lfa = lastfont[n]
+-- if lfa then
+-- setfield(first,"font",lfa)
+-- return start, true, true
+-- else
+-- return start, false, true
+-- end
+-- else
+-- replacer(first or start,uccodes)
+-- return start, true, true
+-- end
+-- end
+
local function mixed(start,attr,lastfont,n,count,where,first)
if where == "post" then
return
end
local used = first or start
- local char = getchar(first)
+ local char = getchar(used)
local dc = uccodes[char]
if not dc then
return start, false, true
elseif dc == char then
local lfa = lastfont[n]
if lfa then
- setfield(first,"font",lfa)
+ setfield(used,"font",lfa)
return start, true, true
else
return start, false, true
end
else
- replacer(first or start,uccodes)
+ if check_kerns then
+ local p = getprev(used)
+ if p and getid(p) == glyph_code then
+ local c = lccodes[char]
+ local c = type(c) == "table" and c[1] or c
+ replacer(used,uccodes)
+ local fp = getfont(p)
+ local fc = getfont(used)
+ if fp ~= fc then
+ local k = fonts.getkern(fontdata[fp],getchar(p),c)
+ if k ~= 0 then
+ insert_after(p,p,newkern(k))
+ end
+ end
+ else
+ replacer(used,uccodes)
+ end
+ else
+ replacer(used,uccodes)
+ end
return start, true, true
end
end
diff --git a/tex/context/base/typo-cap.mkiv b/tex/context/base/typo-cap.mkiv
index 2859ba104..114532e4e 100644
--- a/tex/context/base/typo-cap.mkiv
+++ b/tex/context/base/typo-cap.mkiv
@@ -266,14 +266,14 @@
% [MixedCaps]
% [MixedCaps*default cp \the\exheight]
-\definefontfeature
- [mixeddefault]
- [default]
- [extend=1.2]
+% \definefontfeature
+% [mixeddefault]
+% [default]
+% [extend=1.2]
\definefont
[MixedCaps]
- [CurrentFont*default,mixeddefault cp \the\exheight]
+ [CurrentFont*default cp 1.2\exheight]
\setupcapitals
[\v!mixed]
diff --git a/tex/generic/context/luatex/luatex-fonts-inj.lua b/tex/generic/context/luatex/luatex-fonts-inj.lua
index cdf14b935..10108a271 100644
--- a/tex/generic/context/luatex/luatex-fonts-inj.lua
+++ b/tex/generic/context/luatex/luatex-fonts-inj.lua
@@ -549,9 +549,19 @@ local function inject_marks(marks,marki,nofmarks)
else
-- kern(x) glyph(p) kern(w-x) mark(n)
-- ox = px - getfield(p,"width") + pn.markx - pp.leftkern
- local leftkern = pp.leftkern
- if leftkern then
- ox = px - pn.markx - leftkern
+ --
+ -- 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.
+ --
+ if false then
+ -- a mark with kerning
+ local leftkern = pp.leftkern
+ if leftkern then
+ ox = px - pn.markx - leftkern
+ else
+ ox = px - pn.markx
+ end
else
ox = px - pn.markx
end
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index da21fa6d8..7d3e981fe 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : luatex-fonts-merged.lua
-- parent file : luatex-fonts.lua
--- merge date : 09/01/15 11:10:11
+-- merge date : 09/04/15 11:00:13
do -- begin closure to overcome local limits and interference
@@ -9496,6 +9496,22 @@ function otf.getmultiple(tfmdata,k,kind)
end
return { k }
end
+function otf.getkern(tfmdata,left,right,kind)
+ local kerns=getgsub(tfmdata,left,kind or "kern",true)
+ if kerns then
+ local found=kerns[right]
+ local kind=type(found)
+ if kind=="table" then
+ found=found[1][3]
+ elseif kind~="number" then
+ found=false
+ end
+ if found then
+ return found*tfmdata.parameters.factor
+ end
+ end
+ return 0
+end
end -- closure
@@ -10572,9 +10588,15 @@ local function inject_marks(marks,marki,nofmarks)
if pn.markdir<0 then
ox=px-pn.markx-rightkern
else
- local leftkern=pp.leftkern
- if leftkern then
- ox=px-pn.markx-leftkern
+
+
+ if false then
+ local leftkern=pp.leftkern
+ if leftkern then
+ ox=px-pn.markx-leftkern
+ else
+ ox=px-pn.markx
+ end
else
ox=px-pn.markx
end