summaryrefslogtreecommitdiff
path: root/tex
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2014-12-21 23:15:04 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2014-12-21 23:15:04 +0100
commit69d17e62dd57cce4d59d020319edf1c5121f4319 (patch)
treedf9470198e48f3a516f4e1d31df332fcfa8ab7a9 /tex
parent36be5943fa71b0543ccea4a771c4cea9361cfcc2 (diff)
downloadcontext-69d17e62dd57cce4d59d020319edf1c5121f4319.tar.gz
2014-12-21 22:28:00
Diffstat (limited to 'tex')
-rw-r--r--tex/context/base/attr-ini.lua14
-rw-r--r--tex/context/base/attr-ini.mkiv2
-rw-r--r--tex/context/base/catc-ini.mkiv1
-rw-r--r--tex/context/base/cont-new.mkiv2
-rw-r--r--tex/context/base/context-version.pdfbin4387 -> 4381 bytes
-rw-r--r--tex/context/base/context.mkiv2
-rw-r--r--tex/context/base/font-inj.lua434
-rw-r--r--tex/context/base/font-nod.lua83
-rw-r--r--tex/context/base/font-otf.lua33
-rw-r--r--tex/context/base/font-otn.lua447
-rw-r--r--tex/context/base/font-tra.mkiv13
-rw-r--r--tex/context/base/lang-dis.lua198
-rw-r--r--tex/context/base/lang-hyp.lua236
-rw-r--r--tex/context/base/lang-hyp.mkiv12
-rw-r--r--tex/context/base/lang-ini.lua20
-rw-r--r--tex/context/base/lang-ini.mkiv2
-rw-r--r--tex/context/base/mult-low.lua4
-rw-r--r--tex/context/base/node-ini.lua6
-rw-r--r--tex/context/base/node-nut.lua14
-rw-r--r--tex/context/base/node-shp.lua27
-rw-r--r--tex/context/base/node-tra.lua8
-rw-r--r--tex/context/base/s-fonts-ligatures.mkiv284
-rw-r--r--tex/context/base/s-typesetting-kerning.mkiv127
-rw-r--r--tex/context/base/status-files.pdfbin24632 -> 24862 bytes
-rw-r--r--tex/context/base/status-lua.pdfbin344758 -> 344957 bytes
-rw-r--r--tex/context/base/status-mkiv.lua18
-rw-r--r--tex/context/base/syst-aux.mkiv5
-rw-r--r--tex/context/base/task-ini.lua8
-rw-r--r--tex/context/base/trac-vis.lua2
-rw-r--r--tex/context/base/typo-brk.mkiv5
-rw-r--r--tex/context/base/typo-krn.lua529
-rw-r--r--tex/generic/context/luatex/luatex-basics-nod.lua8
-rw-r--r--tex/generic/context/luatex/luatex-fonts-cbk.lua44
-rw-r--r--tex/generic/context/luatex/luatex-fonts-inj.lua1286
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua1204
-rw-r--r--tex/generic/context/luatex/luatex-fonts.lua9
-rw-r--r--tex/generic/context/luatex/luatex-test.tex14
37 files changed, 3608 insertions, 1493 deletions
diff --git a/tex/context/base/attr-ini.lua b/tex/context/base/attr-ini.lua
index 1e518467c..aaa599d58 100644
--- a/tex/context/base/attr-ini.lua
+++ b/tex/context/base/attr-ini.lua
@@ -53,13 +53,13 @@ storage.register("attributes/list", list, "attributes.list")
names[0], numbers["fontdynamic"] = "fontdynamic", 0
--[[ldx--
-<p>We can use the attributes in the range 127-255 (outside user space). These
-are only used when no attribute is set at the \TEX\ end which normally
-happens in <l n='context'/>.</p>
+<p>private attributes are used by the system and public ones are for users. We use dedicated
+ranges of numbers for them. Of course a the <l n='context'/> end a private attribute can be
+accessible too, so a private attribute can have a public appearance.</p>
--ldx]]--
-sharedstorage.attributes_last_private = sharedstorage.attributes_last_private or 127
-sharedstorage.attributes_last_public = sharedstorage.attributes_last_public or 1024
+sharedstorage.attributes_last_private = sharedstorage.attributes_last_private or 127 -- very private
+sharedstorage.attributes_last_public = sharedstorage.attributes_last_public or 1024 -- less private
function attributes.private(name) -- at the lua end (hidden from user)
local number = numbers[name]
@@ -97,8 +97,8 @@ end
attributes.system = attributes.private
-function attributes.define(name,number,category)
- return (attributes[category or "public"] or attributes["public"])(name,number)
+function attributes.define(name,category)
+ return (attributes[category or "public"] or attributes["public"])(name)
end
-- tracers
diff --git a/tex/context/base/attr-ini.mkiv b/tex/context/base/attr-ini.mkiv
index 0c5762534..d4912ed65 100644
--- a/tex/context/base/attr-ini.mkiv
+++ b/tex/context/base/attr-ini.mkiv
@@ -81,7 +81,9 @@
\expandafter\attributedef\csname\??attributecount#2\endcsname\scratchcounter
\expandafter\newconstant \csname\??attributeid#2\endcsname
\csname\??attributeid#2\endcsname\scratchcounter
+ % some attributes are always global
\doifnotinset\s!global{#3}{\appendetoks\csname\??attributecount#2\endcsname\attributeunsetvalue\to\attributesresetlist}%
+ % here public means 'visible' so it's not to be confused with 'public' at the lua end
\doifinset \s!public{#3}{\expandafter\let\csname#2\s!attribute\expandafter\endcsname\csname\??attributeid#2\endcsname}}
\unexpanded\def\newattribute#1{\attr_basics_define_indeed{public}[\strippedcsname#1][]}
diff --git a/tex/context/base/catc-ini.mkiv b/tex/context/base/catc-ini.mkiv
index d8247217c..581fbfec3 100644
--- a/tex/context/base/catc-ini.mkiv
+++ b/tex/context/base/catc-ini.mkiv
@@ -54,6 +54,7 @@
\setnewconstant\ampersandasciicode 38
\setnewconstant\singlequoteasciicode 39 % '
\setnewconstant\primeasciicode 39 % '
+\setnewconstant\hyphenasciicode 45
\setnewconstant\forwardslashasciicode 47 % /
\setnewconstant\colonasciicode 58
\setnewconstant\lessthanasciicode 60 % < used as alternative verbatim {
diff --git a/tex/context/base/cont-new.mkiv b/tex/context/base/cont-new.mkiv
index 303fef490..6beccd49a 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{2014.12.11 12:02}
+\newcontextversion{2014.12.21 22:25}
%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 750551066..f86b51291 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 8b075404f..51b6e654a 100644
--- a/tex/context/base/context.mkiv
+++ b/tex/context/base/context.mkiv
@@ -28,7 +28,7 @@
%D up and the dependencies are more consistent.
\edef\contextformat {\jobname}
-\edef\contextversion{2014.12.11 12:02}
+\edef\contextversion{2014.12.21 22:25}
\edef\contextkind {beta}
%D For those who want to use this:
diff --git a/tex/context/base/font-inj.lua b/tex/context/base/font-inj.lua
index 68b3e3f23..3b933829d 100644
--- a/tex/context/base/font-inj.lua
+++ b/tex/context/base/font-inj.lua
@@ -52,7 +52,6 @@ local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
local traverse_id = nuts.traverse_id
-local traverse = nuts.traverse
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local find_tail = nuts.tail
@@ -68,6 +67,19 @@ local nofregisteredpairs = 0
local nofregisteredmarks = 0
local nofregisteredcursives = 0
----- markanchors = { } -- one base can have more marks
+local keepregisteredcounts = false
+
+function injections.keepcounts()
+ keepregisteredcounts = true
+end
+
+function injections.resetcounts()
+ nofregisteredkerns = 0
+ nofregisteredpairs = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ keepregisteredcounts = false
+end
function injections.reset(n)
local p = rawget(properties,start)
@@ -81,10 +93,14 @@ end
function injections.setligaindex(n,index)
local p = rawget(properties,n)
if p then
- p = p.injections
- end
- if p then
- p.ligaindex = index
+ local i = p.injections
+ if i then
+ i.ligaindex = index
+ else
+ p.injections = {
+ ligaindex = index
+ }
+ end
else
properties[n] = {
injections = {
@@ -118,10 +134,14 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
--
local p = rawget(properties,start)
if p then
- p = p.injections
- end
- if p then
- p.cursiveanchor = true
+ local i = p.injections
+ if i then
+ i.cursiveanchor = true
+ else
+ p.injections = {
+ cursiveanchor = true,
+ }
+ end
else
properties[start] = {
injections = {
@@ -131,11 +151,16 @@ function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmne
end
local p = rawget(properties,nxt)
if p then
- p = p.injections
- end
- if p then
- p.cursivex = dx
- p.cursivey = dy
+ local i = p.injections
+ if i then
+ i.cursivex = dx
+ i.cursivey = dy
+ else
+ p.injections = {
+ cursivex = dx,
+ cursivey = dy,
+ }
+ end
else
properties[nxt] = {
injections = {
@@ -151,8 +176,8 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay?
local yoffset = y - h
- local leftkern = x
- local rightkern = w - x
+ 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
@@ -160,15 +185,25 @@ function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2l
end
local p = rawget(properties,current)
if p then
- p = p.injections
- end
- if p then
- if leftkern ~= 0 or rightkern ~= 0 then
- p.leftkern = (p.leftkern or 0) + leftkern
- p.rightkern = (p.rightkern or 0) + rightkern
- end
- if yoffset ~= 0 then
- p.yoffset = (p.yoffset or 0) + yoffset
+ local i = p.injections
+ if i then
+ if leftkern ~= 0 or rightkern ~= 0 then
+ i.leftkern = i.leftkern or 0 + leftkern
+ i.rightkern = i.rightkern or 0 + rightkern
+ end
+ if yoffset ~= 0 then
+ i.yoffset = i.yoffset or 0 + yoffset
+ end
+ elseif leftkern ~= 0 or rightkern ~= 0 then
+ p.injections = {
+ leftkern = leftkern,
+ rightkern = rightkern,
+ yoffset = yoffset,
+ }
+ else
+ p.injections = {
+ yoffset = yoffset,
+ }
end
elseif leftkern ~= 0 or rightkern ~= 0 then
properties[current] = {
@@ -205,10 +240,14 @@ function injections.setkern(current,factor,rlmode,x,injection)
injection = "injections"
end
if p then
- p = p[injection]
- end
- if p then
- p.leftkern = dx + (p.leftkern or 0)
+ local i = p[injection]
+ if i then
+ i.leftkern = dx + i.leftkern or 0
+ else
+ p[injection] = {
+ leftkern = dx,
+ }
+ end
else
properties[current] = {
[injection] = {
@@ -231,14 +270,22 @@ function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=basean
end
local p = rawget(properties,start)
if p then
- p = p.injections
- end
- if p then
- p.markx = dx
- p.marky = dy
- p.markdir = rlmode or 0
- p.markbase = nofregisteredmarks
- p.markbasenode = base
+ local i = p.injections
+ if i then
+ i.markx = dx
+ i.marky = dy
+ i.markdir = rlmode or 0
+ i.markbase = nofregisteredmarks
+ i.markbasenode = base
+ else
+ p.injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ }
+ end
else
properties[start] = {
injections = {
@@ -395,46 +442,6 @@ local function collect_glyphs_1(head)
return glyphs, nofglyphs, marks, nofmarks
end
--- local function run(n)
--- local pn = rawget(properties,n)
--- if pn then
--- pn = pn.injections
--- end
--- local f = getfont(n)
--- if f ~= nf then
--- nf = f
--- tm = fontdata[nf].resources.marks -- other hash in ctx
--- end
--- if tm and tm[getchar(n)] then -- also in disc?
--- nofmarks = nofmarks + 1
--- marks[nofmarks] = n
--- else
--- nofglyphs = nofglyphs + 1
--- glyphs[nofglyphs] = n
--- end
--- -- yoffsets can influence curs steps
--- if pn then
--- local yoffset = pn.yoffset
--- if yoffset and yoffset ~= 0 then
--- setfield(n,"yoffset",yoffset)
--- end
--- end
--- end
--- local n = head
--- while n do
--- if getsubtype(n) < 256 then
--- local id = getid(n)
--- if id == glyph_code then
--- run(n)
--- elseif id == disc_code then
--- local d = getfield(n,"pre") if d then for n in traverse(d) do run(d) end end
--- local d = getfield(n,"post") if d then for n in traverse(d) do run(d) end end
--- local d = getfield(n,"replace") if d then for n in traverse(d) do run(d) end end
--- end
--- end
--- n = getnext(n)
--- end
-
local function collect_glyphs_2(head)
local glyphs, nofglyphs = { }, 0
local marks, nofmarks = { }, 0
@@ -458,36 +465,6 @@ local function collect_glyphs_2(head)
return glyphs, nofglyphs, marks, nofmarks
end
--- local function run(n)
--- local f = getfont(n)
--- if f ~= nf then
--- nf = f
--- tm = fontdata[nf].resources.marks -- other hash in ctx
--- end
--- if tm and tm[getchar(n)] then
--- nofmarks = nofmarks + 1
--- marks[nofmarks] = n
--- else
--- nofglyphs = nofglyphs + 1
--- glyphs[nofglyphs] = n
--- end
--- end
--- --
--- local n = head
--- while n do
--- if getsubtype(n) < 256 then
--- local id = getid(n)
--- if id == glyph_code then
--- run(n)
--- elseif id == disc_code then
--- local d = getfield(n,"pre") if d then for n in traverse(d) do run(d) end end
--- local d = getfield(n,"post") if d then for n in traverse(d) do run(d) end end
--- local d = getfield(n,"replace") if d then for n in traverse(d) do run(d) end end
--- end
--- end
--- n = getnext(n)
--- end
-
local function inject_marks(marks,nofmarks)
for i=1,nofmarks do
local n = marks[i]
@@ -570,7 +547,7 @@ local function inject_cursives(glyphs,nofglyphs)
if cursivex then
if cursiveanchor then
if cursivex ~= 0 then
- pn.leftkern = (pn.leftkern or 0) + cursivex
+ pn.leftkern = pn.leftkern or 0 + cursivex
end
if lastanchor then
if maxc == 0 then
@@ -653,14 +630,14 @@ local function inject_kerns(head,glyphs,nofglyphs)
insert_node_before(head,n,newkern(leftkern)) -- type 0/2
end
local rightkern = pn.rightkern
- if rightkern ~= 0 then
+ if rightkern and rightkern ~= 0 then
insert_node_after(head,n,newkern(rightkern)) -- type 0/2
end
end
end
end
-local function inject_everything(head,where,keep)
+local function inject_everything(head,where)
head = tonut(head)
if trace_injections then
trace(head)
@@ -680,7 +657,9 @@ local function inject_everything(head,where,keep)
end
inject_kerns(head,glyphs,nofglyphs)
end
- if not keep then
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
nofregisteredkerns = 0
nofregisteredpairs = 0
nofregisteredmarks = 0
@@ -689,7 +668,7 @@ local function inject_everything(head,where,keep)
return tonode(head), true
end
-local function inject_kerns_only(head,where,keep)
+local function inject_kerns_only(head,where)
head = tonut(head)
if trace_injections then
trace(head)
@@ -751,23 +730,20 @@ local function inject_kerns_only(head,where,keep)
local d = getfield(n,"pre")
if d then
local h = d
- for n in traverse(d) do
- local id = getid(n)
- if id == glyph_code then
- if getsubtype(n) < 256 then
- local pn = rawget(properties,n)
- if pn then
- pn = pn.preinjections
- end
- if pn then
- local leftkern = pn.leftkern
- if leftkern ~= 0 then
- h = insert_node_before(h,n,newkern(leftkern))
- end
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.preinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
end
- else
- break
end
+ else
+ break
end
end
if h ~= d then
@@ -777,23 +753,20 @@ local function inject_kerns_only(head,where,keep)
local d = getfield(n,"post")
if d then
local h = d
- for n in traverse(d) do
- local id = getid(n)
- if id == glyph_code then
- if getsubtype(n) < 256 then
- local pn = rawget(properties,n)
- if pn then
- pn = pn.postinjections
- end
- if pn then
- local leftkern = pn.leftkern
- if leftkern ~= 0 then
- h = insert_node_before(h,n,newkern(leftkern))
- end
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.postinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
end
- else
- break
end
+ else
+ break
end
end
if h ~= d then
@@ -803,24 +776,20 @@ local function inject_kerns_only(head,where,keep)
local d = getfield(n,"replace")
if d then
local h = d
- for n in traverse(d) do
- local id = getid(n)
- if id == glyph_code then
- if getsubtype(n) < 256 then
- local pn = rawget(properties,n) -- why can it be empty { }
- if pn then
- pn = pn.replaceinjections
- end
- if pn then
- local leftkern = pn.leftkern
- if leftkern ~= 0 then
- h = insert_node_before(h,n,newkern(leftkern))
- -- h = insert_node_after(h,n,newkern(leftkern))
- end
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n) -- why can it be empty { }
+ if pn then
+ pn = pn.replaceinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
end
- else
- break
end
+ else
+ break
end
end
if h ~= d then
@@ -834,13 +803,15 @@ local function inject_kerns_only(head,where,keep)
n = getnext(n)
end
--
- if not keep then
- nofregisteredkerns = 0
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
end
return tonode(head), true
end
-local function inject_pairs_only(head,where,keep)
+local function inject_pairs_only(head,where)
head = tonut(head)
if trace_injections then
trace(head)
@@ -928,32 +899,29 @@ local function inject_pairs_only(head,where,keep)
local d = getfield(n,"pre")
if d then
local h = d
- for n in traverse(d) do
- local id = getid(n)
- if id == glyph_code then
- if getsubtype(n) < 256 then
- local pn = rawget(properties,n)
- if pn then
- pn = pn.preinjections
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.preinjections
+ end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
end
- if pn then
- local yoffset = pn.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
- end
- local leftkern = pn.leftkern
- if leftkern ~= 0 then
- h = insert_node_before(h,n,newkern(leftkern))
- end
- local rightkern = pn.rightkern
- if rightkern and rightkern ~= 0 then
- insert_node_after(head,n,newkern(rightkern))
- n = getnext(n) -- to be checked
- end
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
end
- else
- break
end
+ else
+ break
end
end
if h ~= d then
@@ -963,32 +931,29 @@ local function inject_pairs_only(head,where,keep)
local d = getfield(n,"post")
if d then
local h = d
- for n in traverse(d) do
- local id = getid(n)
- if id == glyph_code then
- if getsubtype(n) < 256 then
- local pn = rawget(properties,n)
- if pn then
- pn = pn.postinjections
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.postinjections
+ end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
end
- if pn then
- local yoffset = pn.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
- end
- local leftkern = pn.leftkern
- if leftkern ~= 0 then
- h = insert_node_before(h,n,newkern(leftkern))
- end
- local rightkern = pn.rightkern
- if rightkern and rightkern ~= 0 then
- insert_node_after(head,n,newkern(rightkern))
- n = getnext(n) -- to be checked
- end
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
end
- else
- break
end
+ else
+ break
end
end
if h ~= d then
@@ -998,32 +963,29 @@ local function inject_pairs_only(head,where,keep)
local d = getfield(n,"replace")
if d then
local h = d
- for n in traverse(d) do
- local id = getid(n)
- if id == glyph_code then
- if getsubtype(n) < 256 then
- local pn = rawget(properties,n)
- if pn then
- pn = pn.replaceinjections
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.replaceinjections
+ end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
end
- if pn then
- local yoffset = pn.yoffset
- if yoffset and yoffset ~= 0 then
- setfield(n,"yoffset",yoffset)
- end
- local leftkern = pn.leftkern
- if leftkern ~= 0 then
- h = insert_node_before(h,n,newkern(leftkern))
- end
- local rightkern = pn.rightkern
- if rightkern and rightkern ~= 0 then
- insert_node_after(head,n,newkern(rightkern))
- n = getnext(n) -- to be checked
- end
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
end
- else
- break
end
+ else
+ break
end
end
if h ~= d then
@@ -1037,20 +999,22 @@ local function inject_pairs_only(head,where,keep)
n = getnext(n)
end
--
- if not keep then
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
nofregisteredpairs = 0
nofregisteredkerns = 0
end
return tonode(head), true
end
-function injections.handler(head,where,keep) -- optimize for n=1 ?
+function injections.handler(head,where) -- optimize for n=1 ?
if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
- return inject_everything(head,where,keep)
+ return inject_everything(head,where)
elseif nofregisteredpairs > 0 then
- return inject_pairs_only(head,where,keep)
+ return inject_pairs_only(head,where)
elseif nofregisteredkerns > 0 then
- return inject_kerns_only(head,where,keep)
+ return inject_kerns_only(head,where)
else
return head, false
end
diff --git a/tex/context/base/font-nod.lua b/tex/context/base/font-nod.lua
index da3d9def9..636a668bc 100644
--- a/tex/context/base/font-nod.lua
+++ b/tex/context/base/font-nod.lua
@@ -75,6 +75,7 @@ local copy_node_list = nuts.copy_list
local hpack_node_list = nuts.hpack
local free_node_list = nuts.flush_list
local traverse_nodes = nuts.traverse
+local traverse_id = nuts.traverse_id
local protect_glyphs = nuts.protect_glyphs
local nodepool = nuts.pool
@@ -115,6 +116,24 @@ function char_tracers.collect(head,list,tag,n)
l[#l+1] = { c, f }
elseif id == disc_code then
-- skip
+-- local replace = getfield(head,"replace")
+-- if replace then
+-- for n in traverse_id(glyph_code,replace) do
+-- l[#l+1] = { c, f }
+-- end
+-- end
+-- local pre = getfield(head,"pre")
+-- if pre then
+-- for n in traverse_id(glyph_code,pre) do
+-- l[#l+1] = { c, f }
+-- end
+-- end
+-- local post = getfield(head,"post")
+-- if post then
+-- for n in traverse_id(glyph_code,post) do
+-- l[#l+1] = { c, f }
+-- end
+-- end
else
ok = false
end
@@ -313,21 +332,59 @@ function step_tracers.font(command)
end
end
-function step_tracers.codes(i,command)
+local colors = {
+ pre = { "darkred" },
+ post = { "darkgreen" },
+ replace = { "darkblue" },
+}
+
+function step_tracers.codes(i,command,space)
local c = collection[i]
+
+ local function showchar(c)
+ if command then
+ local f, c = getfont(c), getchar(c)
+ local d = fontdescriptions[f]
+ local d = d and d[c]
+ context[command](f,c,d and d.class or "")
+ else
+ context("[%s:U+%04X]",getfont(c),getchar(c))
+ end
+ end
+
+ local function showdisc(d,w,what)
+ if w then
+ context.startcolor(colors[what])
+ context("%s:",what)
+ for c in traverse_id(glyph_code,w) do
+ showchar(c)
+ end
+ context[space]()
+ context.stopcolor()
+ end
+ end
+
while c do
local id = getid(c)
if id == glyph_code then
- if command then
- local f, c = getfont(c), getchar(c)
- local d = fontdescriptions[f]
- local d = d and d[c]
- context[command](f,c,d and d.class or "")
- else
- context("[%s:U+%04X]",getfont(c),getchar(c))
- end
+ showchar(c)
elseif id == whatsit_code and (getsubtype(c) == localpar_code or getsubtype(c) == dir_code) then
context("[%s]",getfield(c,"dir"))
+ elseif id == disc_code then
+ local pre = getfield(c,"pre")
+ local post = getfield(c,"post")
+ local replace = getfield(c,"replace")
+ if pre or post or replace then
+ context("[")
+ context[space]()
+ showdisc(c,pre,"pre")
+ showdisc(c,post,"post")
+ showdisc(c,replace,"replace")
+ context[space]()
+ context("]")
+ else
+ context("[disc]")
+ end
else
context("[%s]",nodecodes[id])
end
@@ -358,7 +415,8 @@ function step_tracers.check(head)
if collecting then
step_tracers.reset()
local n = copy_node_list(tonut(head))
- injections.handler(n,nil,"trace",true)
+ injections.keepcounts(n) -- one-time
+ injections.handler(n,"trace")
-- handlers.protectglyphs(n) -- can be option
protect_glyphs(n)
collection[1] = n
@@ -370,8 +428,9 @@ function step_tracers.register(head)
local nc = #collection+1
if messages[nc] then
local n = copy_node_list(tonut(head))
- injections.handler(n,nil,"trace",true)
- -- handlers.protectglyphs(n) -- can be option
+ injections.keepcounts(n) -- one-time
+ injections.handler(n,"trace")
+ -- handlers.protectglyph s(n) -- can be option
protect_glyphs(n)
collection[nc] = n
end
diff --git a/tex/context/base/font-otf.lua b/tex/context/base/font-otf.lua
index 302d8eabc..1bb608fd5 100644
--- a/tex/context/base/font-otf.lua
+++ b/tex/context/base/font-otf.lua
@@ -2000,6 +2000,8 @@ actions["reorganize glyph lookups"] = function(data,filename,raw)
end
+local zero = { 0, 0 }
+
actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we replace inplace we safe entries
local descriptions = data.descriptions
for unicode, description in next, descriptions do
@@ -2008,14 +2010,37 @@ actions["reorganize glyph anchors"] = function(data,filename,raw) -- when we rep
for class, data in next, anchors do
if class == "baselig" then
for tag, specification in next, data do
- for i=1,#specification do
- local si = specification[i]
- specification[i] = { si.x or 0, si.y or 0 }
+ -- for i=1,#specification do
+ -- local si = specification[i]
+ -- specification[i] = { si.x or 0, si.y or 0 }
+ -- end
+ -- can be sparse so we need to fill the holes
+ local n = 0
+ for k, v in next, specification do
+ if k > n then
+ n = k
+ end
+ local x, y = v.x, v.y
+ if x or y then
+ specification[k] = { x or 0, y or 0 }
+ else
+ specification[k] = zero
+ end
end
+ local t = { }
+ for i=1,n do
+ t[i] = specification[i] or zero
+ end
+ data[tag] = t -- so # is okay (nicer for packer)
end
else
for tag, specification in next, data do
- data[tag] = { specification.x or 0, specification.y or 0 }
+ local x, y = specification.x, specification.y
+ if x or y then
+ data[tag] = { x or 0, y or 0 }
+ else
+ data[tag] = zero
+ end
end
end
end
diff --git a/tex/context/base/font-otn.lua b/tex/context/base/font-otn.lua
index 797c15d0a..e1be424b1 100644
--- a/tex/context/base/font-otn.lua
+++ b/tex/context/base/font-otn.lua
@@ -6,6 +6,9 @@ if not modules then modules = { } end modules ['font-otn'] = {
license = "see context related readme files",
}
+-- todo: looks like we have a leak somewhere (probably in ligatures)
+-- todo: copy attributes to disc
+
-- this is a context version which can contain experimental code, but when we
-- have serious patches we also need to change the other two font-otn files
@@ -222,6 +225,7 @@ local copy_node = nuts.copy
local copy_node_list = nuts.copy_list
local find_node_tail = nuts.tail
local flush_node_list = nuts.flush_list
+local free_node = nuts.free
local end_of_math = nuts.end_of_math
local traverse_nodes = nuts.traverse
local traverse_id = nuts.traverse_id
@@ -248,6 +252,8 @@ local dir_code = whatcodes.dir
local localpar_code = whatcodes.localpar
local discretionary_code = disccodes.discretionary
+local regular_code = disccodes.regular
+local automatic_code = disccodes.automatic
local ligature_code = glyphcodes.ligature
@@ -386,6 +392,53 @@ local function copy_glyph(g) -- next and prev are untouched !
end
end
+-- temp here (context)
+
+local function collapse_disc(start,next)
+ local replace1 = getfield(start,"replace")
+ local replace2 = getfield(next,"replace")
+ if replace1 and replace2 then
+ local pre2 = getfield(next,"pre")
+ local post2 = getfield(next,"post")
+ setfield(replace1,"prev",nil)
+ if pre2 then
+ local pre1 = getfield(start,"pre")
+ if pre1 then
+ flush_node_list(pre1)
+ end
+ local pre1 = copy_node_list(replace1)
+ local tail1 = find_node_tail(pre1)
+ setfield(tail1,"next",pre2)
+ setfield(pre2,"prev",tail1)
+ setfield(start,"pre",pre1)
+ setfield(next,"pre",nil)
+ else
+ setfield(start,"pre",nil)
+ end
+ if post2 then
+ local post1 = getfield(start,"post")
+ if post1 then
+ flush_node_list(post1)
+ end
+ setfield(start,"post",post2)
+ else
+ setfield(start,"post",nil)
+ end
+ local tail1 = find_node_tail(replace1)
+ setfield(tail1,"next",replace2)
+ setfield(replace2,"prev",tail1)
+ setfield(start,"replace",replace1)
+ setfield(next,"replace",nil)
+ --
+ local nextnext = getnext(next)
+ setfield(nextnext,"prev",start)
+ setfield(start,"next",nextnext)
+ free_node(next)
+ else
+ -- maybe remove it
+ end
+end
+
-- start is a mark and we need to keep that one
local function markstoligature(kind,lookupname,head,start,stop,char)
@@ -441,22 +494,37 @@ local function getcomponentindex(start)
end
end
-local a_noligature = attributes.private("noligature")
-local prehyphenchar = languages and languages.prehyphenchar
-local posthyphenchar = languages and languages.posthyphenchar
+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 not prehyphenchar then
+if prehyphenchar then
- local newlang = lang.new
- local getpre = lang.prehyphenchar
- local getpost = lang.posthyphenchar
+ -- okay
- 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
+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
@@ -490,27 +558,6 @@ local function addhyphens(template,pre,post)
return pre, post
end
-local function showdiscretionary(d) -- will move to tracer
- local pre = getfield(d,"pre")
- local post = getfield(d,"post")
- local replace = getfield(d,"replace")
- if pre then
- for n in traverse_nodes(pre)
- do print("<",nuts.tonode(n))
- end
- end
- if post then
- for n in traverse_nodes(post) do
- print(">",nuts.tonode(n))
- end
- end
- if replace then
- for n in traverse_nodes(replace) do
- print("=",nuts.tonode(n))
- end
- end
-end
-
local function toligature(kind,lookupname,head,start,stop,char,markflag,discfound) -- brr head
if getattr(start,a_noligature) == 1 then
-- so we can do: e\noligature{ff}e e\noligature{f}fie (we only look at the first)
@@ -521,6 +568,12 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
setfield(start,"char",char)
return head, start
end
+ -- needs testing (side effects):
+ local components = getfield(base,"components")
+ if components then
+ flush_node_list(components)
+ end
+ --
local prev = getprev(start)
local next = getnext(stop)
local comp = start
@@ -581,33 +634,69 @@ local function toligature(kind,lookupname,head,start,stop,char,markflag,discfoun
end
start = getnext(start)
end
- elseif getsubtype(discfound) == discretionary_code then
- -- maybe some day
else
- -- forget about marks .. probably no scripts that hyphenate and have marks
- -- todo: use insert_before
- local prev = getfield(discfound,"prev")
- local next = getfield(discfound,"next")
- if prev and next then
- setfield(next,"prev",nil) -- also blocks funny assignments
- setfield(prev,"next",nil) -- also blocks funny assignments
- local pre, post = addhyphens(comp,comp,next) -- takes from components
- setfield(discfound,"pre",pre)
- setfield(discfound,"post",post)
- local prev = getfield(base,"prev")
- local next = getfield(base,"next")
- 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",nil)
- setfield(discfound,"replace",base)
- setfield(discfound,"subtype",discretionary_code)
- base = next
- else
- -- weird disc .. maybe some day
+ -- discfound ... forget about marks .. probably no scripts that hyphenate and have marks
+ 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(comp,"next",pre)
+ setfield(pre,"prev",comp)
+ 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 discretionary_code == regular_code then
+ -- local prev = getfield(base,"prev")
+ -- local next = getfield(base,"next")
+ 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
+ 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 = next -- or restart
+ else
+ -- forget about it in generic usage
+ end
end
end
return head, base
@@ -807,6 +896,20 @@ function handlers.gsub_ligature(head,start,kind,lookupname,ligature,sequence)
return head, start, false, discfound
end
+-- function is_gsub_ligature(start,ligature) -- limited case: in disc nodes, only latin, always glyphs
+-- local s = getnext(start)
+-- while s do
+-- local lg = ligature[getchar(s)]
+-- if lg then
+-- ligature = lg
+-- s = getnext(s)
+-- else
+-- return
+-- end
+-- end
+-- return ligature and ligature.ligature
+-- end
+
--[[ldx--
<p>We get hits on a mark, but we're not sure if the it has to be applied so
we need to explicitly test for basechar, baselig and basemark entries.</p>
@@ -1262,38 +1365,76 @@ function chainprocs.gsub_single(head,start,stop,kind,chainname,currentcontext,lo
resetinjection(current)
if check_discretionaries then
-- some fonts use a chain lookup to replace e.g. an f in a fi ligature
- -- and there can be a isc node in between ... the next code tries to catch
+ -- and there can be a disc node in between ... the next code tries to catch
-- this
local next = getnext(current)
local prev = getprev(current) -- todo: just remember it above
- if getid(next) == disc_code and getsubtype(next) ~= discretionary_code then
- -- maybe set a property
- setfield(next,"prev",prev)
- setfield(prev,"next",next)
- setfield(current,"prev",nil)
- setfield(current,"next",nil)
- local pre = addhyphens(current,current)
- local replace = copy_node(current)
- setfield(replace,"char",replacement)
- setfield(next,"subtype",discretionary_code)
- setfield(next,"replace",replace)
- setfield(next,"pre",pre)
- start = next
- elseif getid(prev) == disc_code and getsubtype(prev) == discretionary_code then
- -- maybe check a property
- setfield(next,"prev",prev)
- setfield(prev,"next",next)
- setfield(current,"prev",nil)
- setfield(current,"next",nil)
- local repl = copy_node(current)
- setfield(repl,"char",replacement)
- local _, post = addhyphens(current,nil,current)
- local replace = getfield(prev,"replace")
- local tail = find_node_tail(replace) -- we could do a check for length 1
- setfield(tail,"next",repl)
- setfield(repl,"prev",tail)
- setfield(prev,"post",post)
- else
+ local done = false
+ if next then
+ if getid(next) == disc_code then
+ local subtype = getsubtype(next)
+ if subtype == discretionary_code then
+ setfield(next,"prev",prev)
+ setfield(prev,"next",next)
+ setfield(current,"prev",nil)
+ setfield(current,"next",nil)
+ local replace = getfield(next,"replace")
+ local pre = getfield(next,"pre")
+ local new = copy_node(current)
+ setfield(new,"char",replacement)
+ if replace then
+ setfield(new,"next",replace)
+ setfield(replace,"prev",new)
+ end
+ if pre then
+ setfield(current,"next",pre)
+ setfield(pre,"prev",current)
+ end
+ setfield(next,"replace",new) -- also updates tail
+ setfield(next,"pre",current) -- also updates tail
+ end
+ start = next
+ done = true
+ local next = getnext(start)
+ if next and getid(next) == disc_code then
+ collapse_disc(start,next)
+ end
+ end
+ end
+ if not done and prev then
+ if getid(prev) == disc_code then
+ local subtype = getsubtype(prev)
+ if subtype == discretionary_code then
+ setfield(next,"prev",prev)
+ setfield(prev,"next",next)
+ setfield(current,"prev",nil)
+ setfield(current,"next",nil)
+ local replace = getfield(prev,"replace")
+ local post = getfield(prev,"post")
+ local new = copy_node(current)
+ setfield(new,"char",replacement)
+ if replace then
+ local tail = find_node_tail(replace)
+ setfield(tail,"next",new)
+ setfield(new,"prev",tail)
+ else
+ replace = new
+ end
+ if post then
+ local tail = find_node_tail(post)
+ setfield(tail,"next",current)
+ setfield(current,"prev",tail)
+ else
+ post = current
+ end
+ setfield(prev,"replace",replace) -- also updates tail
+ setfield(prev,"post",post) -- also updates tail
+ start = prev
+ done = true
+ end
+ end
+ end
+ if not done then
setfield(current,"char",replacement)
end
else
@@ -1938,7 +2079,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if not replace then
break
elseif n > l then
- match = false
+-- match = false
break
end
else
@@ -2016,7 +2157,7 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if not replace or replace == finish then
break
elseif n < 1 then
- match = false
+-- match = false
break
end
else
@@ -2051,6 +2192,8 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
end
elseif f == 2 then
match = seq[1][32]
+-- elseif f > 2 then
+-- match = false -- KE ?
else
for n=f-1,1 do
if not seq[n][32] then
@@ -2106,7 +2249,6 @@ local function normal_handle_contextchain(head,start,kind,chainname,contexts,seq
if not replace then
break
elseif n > s then
- match = false
break
end
else
@@ -2487,31 +2629,34 @@ local function kernrun(disc,run) -- we can assume that prev and next are glyphs
end
end
+-- the if new test might be dangerous as luatex will check / set some tail stuff
+-- in a temp node
+
local function comprun(disc,run)
if trace_compruns then
- report_run("comp") -- will be more detailed
+ report_run("comp: %s",languages.serializediscretionary(disc))
end
--
local pre = getfield(disc,"pre")
if pre then
- local new = run(pre)
- if new ~= pre then
+ local new, done = run(pre)
+ if done then
setfield(disc,"pre",new)
end
end
--
local post = getfield(disc,"post")
if post then
- local new = run(post)
- if new ~= post then
+ local new, done = run(post)
+ if done then
setfield(disc,"post",new)
end
end
--
local replace = getfield(disc,"replace")
if replace then
- local new = run(replace)
- if new ~= replace then
+ local new, done = run(replace)
+ if done then
setfield(disc,"replace",new)
end
end
@@ -2526,7 +2671,7 @@ local function testrun(disc,trun,crun)
if prev then
-- only look ahead
local tail = find_node_tail(replace)
- local nest = getprev(replace)
+ -- local nest = getprev(replace)
setfield(tail,"next",next)
setfield(next,"prev",tail)
if trun(replace,next) then
@@ -2538,7 +2683,7 @@ local function testrun(disc,trun,crun)
setfield(disc,"prev",nil)
setfield(disc,"next",nil)
flush_node_list(disc)
- return replace
+ return replace -- restart
else
setfield(tail,"next",nil)
setfield(next,"prev",disc)
@@ -2586,6 +2731,8 @@ local function discrun(disc,drun,krun)
return next
end
+-- todo: maybe run lr and rl stretches
+
local function featuresprocessor(head,font,attr)
local lookuphash = lookuphashes[font] -- we can also check sequences here
@@ -2633,6 +2780,8 @@ local function featuresprocessor(head,font,attr)
-- 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.
+ -- there can be less subtype and attr checking in the comprun etc helpers
+
for s=1,#datasets do
local dataset = datasets[s]
featurevalue = dataset[1] -- todo: pass to function instead of using a global
@@ -2647,6 +2796,7 @@ local function featuresprocessor(head,font,attr)
local gpossing = typ == "gpos_single" or typ == "gpos_pair"
local subtables = sequence.subtables
local handler = handlers[typ]
+
if chain < 0 then
-- 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
@@ -2662,11 +2812,13 @@ local function featuresprocessor(head,font,attr)
a = true
end
if a then
+ local char = getchar(start)
for i=1,#subtables do
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[getchar(start)]
+ -- local lookupmatch = lookupcache[getchar(start)]
+ local lookupmatch = lookupcache[start]
if lookupmatch then
-- todo: disc?
head, start, success = handler(head,start,kind,lookupname,lookupmatch,sequence,lookuphash,i)
@@ -2700,12 +2852,15 @@ local function featuresprocessor(head,font,attr)
report_missing_cache(typ,lookupname)
else
- local function c_run(start)
+ local function c_run(start) -- no need to check for 256 and attr probably also the same
local head = start
local done = false
while start do
local id = getid(start)
- if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ if id ~= glyph_code then
+ -- very unlikely
+ start = getnext(start)
+ elseif getfont(start) == font and getsubtype(start) < 256 then
local a = getattr(start,0)
if a then
a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
@@ -2727,13 +2882,13 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
end
else
- start = getnext(start)
+ return head, false
end
end
if done then
- success = true
+ success = true -- needed in this subrun?
end
- return head
+ return head, done
end
local function t_run(start,stop)
@@ -2748,8 +2903,22 @@ local function featuresprocessor(head,font,attr)
end
if a then
local lookupmatch = lookupcache[getchar(start)]
- if lookupmatch then
- return true
+ if lookupmatch then -- hm, hyphens can match (tlig) so we need to really check
+ -- if we need more than ligatures we can outline the code and use functions
+ local s = getnext(start)
+ local l = nil
+ while s do
+ local lg = lookupmatch[getchar(s)]
+ if lg then
+ l = lg
+ s = getnext(s)
+ else
+ break
+ end
+ end
+ if l and l.ligature then
+ return true
+ end
end
end
start = getnext(start)
@@ -2842,24 +3011,24 @@ 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
+ 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
start = getnext(start)
- end
+ end
elseif id == whatsit_code then -- will be function
local subtype = getsubtype(start)
if subtype == dir_code then
@@ -2912,7 +3081,10 @@ local function featuresprocessor(head,font,attr)
local done = false
while start do
local id = getid(start)
- if id == glyph_code and getfont(start) == font and getsubtype(start) < 256 then
+ if id ~= glyph_code then
+ -- very unlikely
+ start = getnext(start)
+ elseif getfont(start) == font and getsubtype(start) < 256 then
local a = getattr(start,0)
if a then
a = (a == attr) and (not attribute or getprop(start,a_state) == attribute)
@@ -2920,11 +3092,13 @@ local function featuresprocessor(head,font,attr)
a = not attribute or getprop(start,a_state) == attribute
end
if a then
+ local char = getchar(start)
for i=1,ns do
local lookupname = subtables[i]
local lookupcache = lookuphash[lookupname]
if lookupcache then
- local lookupmatch = lookupcache[getchar(start)]
+ -- local lookupmatch = lookupcache[getchar(start)]
+ local lookupmatch = lookupcache[char]
if lookupmatch then
-- we could move all code inline but that makes things even more unreadable
local ok
@@ -2946,13 +3120,13 @@ local function featuresprocessor(head,font,attr)
start = getnext(start)
end
else
- start = getnext(start)
+ return head, false
end
end
if done then
success = true
end
- return head
+ return head, done
end
local function d_run(prev)
@@ -3034,10 +3208,6 @@ local function featuresprocessor(head,font,attr)
a = not attribute or getprop(start,a_state) == attribute
end
if a then
- -- local lookupmatch = lookupcache[getchar(start)]
- -- if lookupmatch then
- -- return true
- -- end
local char = getchar(start)
for i=1,ns do
local lookupname = subtables[i]
@@ -3045,7 +3215,21 @@ local function featuresprocessor(head,font,attr)
if lookupcache then
local lookupmatch = lookupcache[char]
if lookupmatch then
- return true
+ -- if we need more than ligatures we can outline the code and use functions
+ local s = getnext(start)
+ local l = nil
+ while s do
+ local lg = lookupmatch[getchar(s)]
+ if lg then
+ l = lg
+ s = getnext(s)
+ else
+ break
+ end
+ end
+ if l and l.ligature then
+ return true
+ end
end
else
report_missing_cache(typ,lookupname)
@@ -3175,7 +3359,6 @@ local function featuresprocessor(head,font,attr)
end
-
head = tonode(head)
return head, done
diff --git a/tex/context/base/font-tra.mkiv b/tex/context/base/font-tra.mkiv
index 45d8a7280..6b9fb1f47 100644
--- a/tex/context/base/font-tra.mkiv
+++ b/tex/context/base/font-tra.mkiv
@@ -114,11 +114,14 @@
{\ctxlua{nodes.tracers.steppers.glyphs(\number\otfcollector,#1)}%
\unhbox\otfcollector}
-\unexpanded\def\otfstepcharcommand#1#2#3% font char class
+\unexpanded\def\otfstepspace
{\removeunwantedspaces
- \hskip.5\emwidth \s!plus .125\emwidth\relax
- \doif{#3}{mark}{\underbar}{U+\hexnumber{#2}}:\ruledhbox{\ctxlua{nodes.tracers.fontchar(#1,#2)}}%
- \hskip.5\emwidth \s!plus .125\emwidth\relax}
+ \hskip.5\emwidth \s!plus .125\emwidth \s!minus .125\emwidth\relax}
+
+\unexpanded\def\otfstepcharcommand#1#2#3% font char class
+ {\otfstepspace
+ \doif{#3}{mark}{\underbar}{U+\hexnumber{#2}}:\ruledhbox{\ctxlua{nodes.tracers.fontchar(#1,#2)}}%
+ \otfstepspace}
\unexpanded\def\otfstepfontcommand#1#2#3% id font size
{\begingroup
@@ -142,7 +145,7 @@
{\ctxlua{nodes.tracers.steppers.font("otfstepfontcommand")}}
\unexpanded\def\showotfstepchars#1%
- {\ctxlua{nodes.tracers.steppers.codes(#1,"otfstepcharcommand")}}
+ {\ctxlua{nodes.tracers.steppers.codes(#1,"otfstepcharcommand","otfstepspace")}}
\unexpanded\def\showotfstepmessages#1%
{\ctxlua{nodes.tracers.steppers.messages(#1,"otfstepmessagecommand",true)}}
diff --git a/tex/context/base/lang-dis.lua b/tex/context/base/lang-dis.lua
new file mode 100644
index 000000000..7a7b3f5de
--- /dev/null
+++ b/tex/context/base/lang-dis.lua
@@ -0,0 +1,198 @@
+if not modules then modules = { } end modules ['lang-dis'] = {
+ version = 1.001,
+ comment = "companion to lang-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local concat = table.concat
+
+local nodes = nodes
+
+local tasks = nodes.tasks
+local nuts = nodes.nuts
+local nodepool = nuts.pool
+
+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 getattr = nuts.getattr
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local copy_node = nuts.copy
+local free_node = nuts.free
+local remove_node = nuts.remove
+local traverse_id = nuts.traverse_id
+local traverse_nodes = nuts.traverse
+
+local nodecodes = nodes.nodecodes
+local disccodes = nodes.disccodes
+
+local disc_code = nodecodes.disc
+local glyph_code = nodecodes.glyph
+local discretionary_code = disccodes.discretionary
+
+local a_visualize = attributes.private("visualizediscretionary")
+local setattribute = tex.setattribute
+
+local getlanguagedata = languages.getdata
+
+local expanders = {
+ [disccodes.discretionary] = function(d,template)
+ -- \discretionary
+ return template
+ end,
+ [disccodes.explicit] = function(d,template)
+ -- \-
+ local pre = getfield(d,"pre")
+ if pre and getid(pre) == glyph_code and getchar(pre) <= 0 then
+ setfield(d,"pre",nil)
+ end
+ local post = getfield(d,"post")
+ if post and getid(post) == glyph_code and getchar(post) <= 0 then
+ setfield(d,"post",nil)
+ end
+-- setfield(d,"subtype",discretionary_code) -- to be checked
+ return template
+ end,
+ [disccodes.automatic] = function(d,template)
+ -- following a - : the pre and post chars are already appended and set
+ -- so we have pre=preex and post=postex .. however, the previous
+ -- hyphen is already injected ... downside: the font handler sees this
+ -- so this is another argument for doing a hyphenation pass in context
+ if getfield(d,"pre") then
+ -- we have a preex characters and want that one to replace the
+ -- character in front which is the trigger
+ 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 template and getid(template) ~= glyph_code then
+ template = nil
+ end
+ end
+ end
+ if template then
+ local pseudohead = getprev(template)
+ if pseudohead then
+ while template ~= d do
+ pseudohead, template, removed = remove_node(pseudohead,template)
+ setfield(d,"replace",removed)
+ -- break ?
+ end
+ else
+ -- can't happen
+ end
+ setfield(d,"subtype",discretionary_code)
+ else
+ -- print("lone regular discretionary ignored")
+ end
+ end
+ 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 template and getid(template) ~= glyph_code then
+ template = nil
+ 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
+ if prechar and prechar > 0 then
+ local c = copy_node(template)
+ setfield(c,"char",prechar)
+ setfield(d,"pre",c)
+ end
+ if postchar and postchar > 0 then
+ local c = copy_node(template)
+ setfield(c,"char",postchar)
+ setfield(d,"post",c)
+ end
+ setfield(d,"subtype",discretionary_code)
+ else
+ -- print("lone regular discretionary ignored")
+ end
+ return template
+ end,
+ [disccodes.first] = function()
+ -- forget about them
+ end,
+ [disccodes.second] = function()
+ -- forget about them
+ end,
+}
+
+languages.expanders = expanders
+
+function languages.expand(d,template,subtype)
+ if not subtype then
+ subtype = getsubtype(d)
+ end
+ if subtype ~= discretionary_code then
+ return expanders[subtype](d,template)
+ end
+end
+
+local setlistcolor = nodes.tracers.colors.setlist
+
+function languages.visualizediscretionaries(head)
+ for d in traverse_id(disc_code,tonut(head)) do
+ if getattr(d,a_visualize) then
+ local pre = getfield(d,"pre")
+ local post = getfield(d,"post")
+ local replace = getfield(d,"replace")
+ if pre then
+ setlistcolor(pre,"darkred")
+ end
+ if post then
+ setlistcolor(post,"darkgreen")
+ end
+ if replace then
+ setlistcolor(replace,"darkblue")
+ end
+ end
+ end
+end
+
+local enabled = false
+
+function commands.showdiscretionaries(v)
+ if v == false then
+ setattribute(a_visualize,unsetvalue)
+ else -- also nil
+ if not enabled then
+ nodes.tasks.enableaction("processors","languages.visualizediscretionaries")
+ enabled = true
+ end
+ setattribute(a_visualize,1)
+ end
+end
+
+local toutf = nodes.listtoutf
+
+function languages.serializediscretionary(d) -- will move to tracer
+ return string.formatters["{%s}{%s}{%s}"](
+ toutf(getfield(d,"pre")) or "",
+ toutf(getfield(d,"post")) or "",
+ toutf(getfield(d,"replace")) or ""
+ )
+end
+
diff --git a/tex/context/base/lang-hyp.lua b/tex/context/base/lang-hyp.lua
index 2ab966fe6..60e1699ca 100644
--- a/tex/context/base/lang-hyp.lua
+++ b/tex/context/base/lang-hyp.lua
@@ -6,6 +6,8 @@ if not modules then modules = { } end modules ['lang-hyp'] = {
license = "see context related readme files"
}
+-- todo: hyphenate over range if needed
+
-- to be considered: reset dictionary.hyphenated when a pattern is added
-- or maybe an explicit reset of the cache
@@ -583,48 +585,63 @@ end
if context then
- local nodecodes = nodes.nodecodes
- local glyph_code = nodecodes.glyph
- local math_code = nodecodes.math
+ local nodecodes = nodes.nodecodes
+ local disccodes = nodes.disccodes
+
+ local glyph_code = nodecodes.glyph
+ local disc_code = nodecodes.disc
+ local math_code = nodecodes.math
+
+ local discretionary_code = disccodes.discretionary
+ local explicit_code = disccodes.explicit
+ local regular_code = disccodes.regular
+ local automatic_code = disccodes.automatic
- local nuts = nodes.nuts
- local tonut = nodes.tonut
- local nodepool = nuts.pool
+ local nuts = nodes.nuts
+ local tonut = nodes.tonut
+ local tonode = nodes.tonode
+ local nodepool = nuts.pool
- local new_disc = nodepool.disc
+ local new_disc = nodepool.disc
+ local new_glyph = nodepool.glyph
- local setfield = nuts.setfield
- local getfield = nuts.getfield
- local getchar = nuts.getchar
- local getid = nuts.getid
- local getattr = nuts.getattr
- local getnext = nuts.getnext
- local getprev = nuts.getprev
- local insert_before = nuts.insert_before
- local insert_after = nuts.insert_after
- local copy_node = nuts.copy
- local remove_node = nuts.remove
- local end_of_math = nuts.end_of_math
- local node_tail = nuts.tail
+ local setfield = nuts.setfield
+ local getfield = nuts.getfield
+ local getfont = nuts.getfont
+ local getchar = nuts.getchar
+ local getid = nuts.getid
+ local getattr = nuts.getattr
+ local getnext = nuts.getnext
+ local getprev = nuts.getprev
+ local getsubtype = nuts.getsubtype
+ local insert_before = nuts.insert_before
+ local insert_after = nuts.insert_after
+ local copy_node = nuts.copy
+ local remove_node = nuts.remove
+ local end_of_math = nuts.end_of_math
+ local node_tail = nuts.tail
+ local traverse_id = nuts.traverse_id
- local setcolor = nodes.tracers.colors.set
+ local setcolor = nodes.tracers.colors.set
- local variables = interfaces.variables
- local v_reset = variables.reset
- local v_yes = variables.yes
- local v_all = variables.all
+ local variables = interfaces.variables
+ local v_reset = variables.reset
+ local v_yes = variables.yes
+ local v_all = variables.all
- local settings_to_array = utilities.parsers.settings_to_array
+ local settings_to_array = utilities.parsers.settings_to_array
- local unsetvalue = attributes.unsetvalue
- local texsetattribute = tex.setattribute
+ local unsetvalue = attributes.unsetvalue
+ local texsetattribute = tex.setattribute
- local prehyphenchar = lang.prehyphenchar
- local posthyphenchar = lang.posthyphenchar
+ local prehyphenchar = lang.prehyphenchar
+ local posthyphenchar = lang.posthyphenchar
+ local preexhyphenchar = lang.preexhyphenchar
+ local postexhyphenchar = lang.postexhyphenchar
- local lccodes = characters.lccodes
+ local lccodes = characters.lccodes
- local a_hyphenation = attributes.private("hyphenation")
+ local a_hyphenation = attributes.private("hyphenation")
function traditional.loadpatterns(language)
return dictionaries[language]
@@ -891,6 +908,7 @@ if context then
local instance = nil
local characters = nil
local unicodes = nil
+ local exhyphenchar = tex.exhyphenchar
local extrachars = nil
local hyphenchars = nil
local language = nil
@@ -900,6 +918,8 @@ if context then
local size = 0
local leftchar = false
local rightchar = false -- utfbyte("-")
+ local leftexchar = false
+ local rightexchar = false -- utfbyte("-")
local leftmin = 0
local rightmin = 0
local leftcharmin = nil
@@ -1089,6 +1109,8 @@ if context then
local current = start
+ local attributes = getfield(start,"attr") -- todo: just copy the last disc .. faster
+
for i=1,rsize do
local r = result[i]
if r == true then
@@ -1099,6 +1121,9 @@ if context then
if leftchar then
setfield(disc,"post",serialize(true,leftchar))
end
+ if attributes then
+ setfield(disc,"attr",attributes)
+ end
-- could be a replace as well
insert_before(first,current,disc)
elseif type(r) == "table" then
@@ -1117,6 +1142,9 @@ if context then
if replace and replace ~= "" then
setfield(disc,"replace",serialize(replace))
end
+ if attributes then
+ setfield(disc,"attr",attributes)
+ end
insert_before(first,current,disc)
else
setfield(current,"char",characters[r])
@@ -1135,16 +1163,19 @@ if context then
end
- local function inject()
+ local function inject(leftchar,rightchar,code,attributes)
if first ~= current then
local disc = new_disc()
first, current, glyph = remove_node(first,current)
first, current = insert_before(first,current,disc)
if trace_visualize then
- setcolor(glyph,"darkred") -- these get checked in the colorizer
- setcolor(disc,"darkgreen") -- these get checked in the colorizer
+ setcolor(glyph,"darkred") -- these get checked
+ setcolor(disc,"darkgreen") -- in the colorizer
end
setfield(disc,"replace",glyph)
+ if not leftchar then
+ leftchar = code
+ end
if rightchar then
local glyph = copy_node(glyph)
setfield(glyph,"char",rightchar)
@@ -1152,9 +1183,12 @@ if context then
end
if leftchar then
local glyph = copy_node(glyph)
- setfield(glyph,"char",rightchar)
+ setfield(glyph,"char",leftchar)
setfield(disc,"post",glyph)
end
+ if attributes then
+ setfield(disc,"attr",attributes)
+ end
end
return current
end
@@ -1195,11 +1229,13 @@ if context then
unicodes = dictionary.unicodes
--
local a = getattr(current,a_hyphenation)
- attr = synchronizefeatureset(a)
- leftchar = leftchar or (instance and posthyphenchar(instance))
- rightchar = rightchar or (instance and prehyphenchar (instance))
- leftmin = leftcharmin or getfield(current,"left")
- rightmin = rightcharmin or getfield(current,"right")
+ attr = synchronizefeatureset(a)
+ leftchar = leftchar or (instance and posthyphenchar (instance)) -- we can make this more
+ rightchar = rightchar or (instance and prehyphenchar (instance)) -- efficient if needed
+ leftexchar = (instance and preexhyphenchar (instance))
+ rightexchar = (instance and postexhyphenchar(instance))
+ leftmin = leftcharmin or getfield(current,"left")
+ rightmin = rightcharmin or getfield(current,"right")
if not leftchar or leftchar < 0 then
leftchar = false
end
@@ -1237,18 +1273,24 @@ if context then
end
end
size = 0
- if hyphenchars and hyphenchars[code] then
- current = inject()
+ -- maybe also a strict mode here: no hyphenation before hyphenchars and skip
+ -- the next set (but then, strict is an option)
+ if code == exhyphenchar then
+ current = inject(leftexchar,rightexchar,code,getfield(current,"attr"))
+ elseif hyphenchars and hyphenchars[code] then
+ current = inject(leftchar,rightchar,code,getfield(current,"attr"))
end
end
else
local a = getattr(current,a_hyphenation)
if a ~= attr then
- attr = synchronizefeatureset(a) -- influences extrachars
- leftchar = leftchar or (instance and posthyphenchar(instance))
- rightchar = rightchar or (instance and prehyphenchar (instance))
- leftmin = leftcharmin or getfield(current,"left")
- rightmin = rightcharmin or getfield(current,"right")
+ attr = synchronizefeatureset(a) -- influences extrachars
+ leftchar = leftchar or (instance and posthyphenchar (instance)) -- we can make this more
+ rightchar = rightchar or (instance and prehyphenchar (instance)) -- efficient if needed
+ leftexchar = (instance and preexhyphenchar (instance))
+ rightexchar = (instance and postexhyphenchar(instance))
+ leftmin = leftcharmin or getfield(current,"left")
+ rightmin = rightcharmin or getfield(current,"right")
if not leftchar or leftchar < 0 then
leftchar = false
end
@@ -1266,11 +1308,38 @@ if context then
end
stop = current
current = getnext(current)
- elseif strict and strict[id] then
- current = id == math_code and getnext(end_of_math(current)) or getnext(current)
- size = 0
else
- current = id == math_code and getnext(end_of_math(current)) or getnext(current)
+ if id == disc_code then
+ local subtype = getsubtype(current)
+ if subtype == discretionary_code then -- \discretionary
+ size = 0
+ current = getnext(current)
+ elseif subtype == explicit_code then -- \- => only here
+ size = 0
+ current = getnext(current)
+ while current do
+ local id = getid(current)
+ if id == glyph_code or id == disc_code then
+ current = getnext(current)
+ else
+ break
+ end
+ end
+ -- todo: change to discretionary_code
+ else
+ -- automatic (-) : the hyphenator turns an exhyphen into glyph+disc
+ -- first : done by the hyphenator
+ -- second : done by the hyphenator
+ -- regular : done by the hyphenator
+ size = 0
+ current = getnext(current)
+ end
+ elseif strict and strict[id] then
+ current = id == math_code and getnext(end_of_math(current)) or getnext(current)
+ size = 0
+ else
+ current = id == math_code and getnext(end_of_math(current)) or getnext(current)
+ end
if size > 0 then
if dictionary and leftmin + rightmin <= size then
if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then
@@ -1286,7 +1355,8 @@ if context then
end
end
end
- -- we can have quit due to last so we need to flush the last seen word
+ -- we can have quit due to last so we need to flush the last seen word, we could move this in
+ -- the loop and test for current but ... messy
if size > 0 and dictionary and leftmin + rightmin <= size then
if categories[word[1]] == "lu" and getfield(start,"uchyph") < 0 then
-- skip
@@ -1324,41 +1394,63 @@ if context then
-- \enabledirectives[hyphenators.method=traditional]
-- \enabledirectives[hyphenators.method=builtin]
- -- this avoids a wrapper
-
-- push / pop ? check first attribute
- local replaceaction = nodes.tasks.replaceaction
+ -- local replaceaction = nodes.tasks.replaceaction -- no longer overload this way (too many local switches)
- local function setmethod(method)
- if type(method) == "string" then
- local valid = hyphenators[method]
- if valid and valid.hyphenate then
- newmethod = "languages.hyphenators." .. method .. ".hyphenate"
- else
- newmethod = texmethod
+ local hyphenate = lang.hyphenate
+ local expanders = languages.expanders
+ local methods = { }
+ local usedmethod = false
+ local stack = { }
+
+ local function original(head)
+ local done = hyphenate(head)
+ return head, done
+ end
+
+ local function expanded(head)
+ local done = hyphenate(head)
+ if done then
+ for d in traverse_id(disc_code,tonut(head)) do
+ local s = getsubtype(d)
+ if s ~= discretionary_code then
+ expanders[s](d,template)
+ done = true
+ end
end
- else
- newmethod = texmethod
end
- if oldmethod ~= newmethod then
- replaceaction("processors","words",oldmethod,newmethod)
+ return head, done
+ end
+
+ function hyphenators.handler(head)
+ if usedmethod then
+ return usedmethod(head)
+ else
+ return head, done
end
- oldmethod = newmethod
end
- hyphenators.setmethod = setmethod
+ methods.tex = original
+ methods.original = original
+ methods.expanded = expanded
+ methods.traditional = languages.hyphenators.traditional.hyphenate
+ methods.none = function(head) return head, false end
- local stack = { }
+ usedmethod = original
+ local function setmethod(method)
+ usedmethod = type(method) == "string" and methods[method] or methods.tex
+ end
local function pushmethod(method)
- insert(stack,oldmethod)
+ insert(stack,usedmethod)
setmethod(method)
end
local function popmethod()
- setmethod(remove(stack))
+ usedmethod = remove(stack) or methods.tex
end
+ hyphenators.setmethod = setmethod
hyphenators.pushmethod = pushmethod
hyphenators.popmethod = popmethod
diff --git a/tex/context/base/lang-hyp.mkiv b/tex/context/base/lang-hyp.mkiv
index 966b000c6..b2281135c 100644
--- a/tex/context/base/lang-hyp.mkiv
+++ b/tex/context/base/lang-hyp.mkiv
@@ -30,6 +30,7 @@
\writestatus{loading}{ConTeXt Language Macros / Initialization}
+\registerctxluafile{lang-dis}{1.001}
\registerctxluafile{lang-hyp}{1.001}
\unprotect
@@ -50,6 +51,11 @@
% \enabledirectives[hyphenators.method]%
% \endgroup}
+
+% \exhyphenchar \hyphenasciicode
+% \preexhyphenchar \lessthanasciicode
+% \postexhyphenchar\morethanasciicode
+
%D Here is the real way:
\installcorenamespace{hyphenation}
@@ -152,7 +158,6 @@
\unexpanded\def\registerhyphenationexception
{\dodoubleempty\lang_hyphenation_register_exception}
-
\def\lang_hyphenation_register_exception[#1][#2]%
{\ctxcommand{registerhyphenationexception(
\ifsecondargument
@@ -191,6 +196,11 @@
\stopthyphenation
\endgroup}
+%D For me:
+
+\unexpanded\def\showdiscretionaries
+ {\ctxcommand{showdiscretionaries()}}
+
%D These are (at least now) not cummulative:
\definehyphenationfeatures % just an example
diff --git a/tex/context/base/lang-ini.lua b/tex/context/base/lang-ini.lua
index 302f5b34d..27c4f774e 100644
--- a/tex/context/base/lang-ini.lua
+++ b/tex/context/base/lang-ini.lua
@@ -30,10 +30,12 @@ local trace_patterns = false trackers.register("languages.patterns", function(v
local report_initialization = logs.reporter("languages","initialization")
-local prehyphenchar = lang.prehyphenchar -- global per language
-local posthyphenchar = lang.posthyphenchar -- global per language
-local lefthyphenmin = lang.lefthyphenmin
-local righthyphenmin = lang.righthyphenmin
+local prehyphenchar = lang.prehyphenchar -- global per language
+local posthyphenchar = lang.posthyphenchar -- global per language
+local preexhyphenchar = lang.preexhyphenchar -- global per language
+local postexhyphenchar = lang.postexhyphenchar -- global per language
+local lefthyphenmin = lang.lefthyphenmin
+local righthyphenmin = lang.righthyphenmin
local lang = lang
lang.exceptions = lang.hyphenation
@@ -301,10 +303,12 @@ end
-- not that usefull, global values
-function languages.prehyphenchar (what) return prehyphenchar (tolang(what)) end
-function languages.posthyphenchar(what) return posthyphenchar(tolang(what)) end
-function languages.lefthyphenmin (what) return lefthyphenmin (tolang(what)) end
-function languages.righthyphenmin(what) return righthyphenmin(tolang(what)) end
+function languages.prehyphenchar (what) return prehyphenchar (tolang(what)) end
+function languages.posthyphenchar (what) return posthyphenchar (tolang(what)) end
+function languages.preexhyphenchar (what) return preexhyphenchar (tolang(what)) end
+function languages.postexhyphenchar(what) return postexhyphenchar(tolang(what)) end
+function languages.lefthyphenmin (what) return lefthyphenmin (tolang(what)) end
+function languages.righthyphenmin (what) return righthyphenmin (tolang(what)) end
-- e['implementer']= 'imple{m}{-}{-}menter'
-- e['manual'] = 'man{}{}{}'
diff --git a/tex/context/base/lang-ini.mkiv b/tex/context/base/lang-ini.mkiv
index bf2e42a75..5a745a7d8 100644
--- a/tex/context/base/lang-ini.mkiv
+++ b/tex/context/base/lang-ini.mkiv
@@ -705,4 +705,6 @@
{\ctxcommand{posthyphenchar()}post}%
{replace}}
+% todo: make this configurable
+
\protect \endinput
diff --git a/tex/context/base/mult-low.lua b/tex/context/base/mult-low.lua
index e6c444347..f96ebacbc 100644
--- a/tex/context/base/mult-low.lua
+++ b/tex/context/base/mult-low.lua
@@ -60,7 +60,7 @@ return {
"lessthanasciicode", "morethanasciicode", "doublecommentsignal",
"atsignasciicode", "exclamationmarkasciicode", "questionmarkasciicode",
"doublequoteasciicode", "singlequoteasciicode", "forwardslashasciicode",
- "primeasciicode",
+ "primeasciicode", "hyphenasciicode",
--
"activemathcharcode",
--
@@ -203,7 +203,7 @@ return {
--
"normalbaselineskip", "normallineskip", "normallineskiplimit",
--
- "availablehsize", "localhsize", "setlocalhsize",
+ "availablehsize", "localhsize", "setlocalhsize", "distributedhsize",
--
"nextbox", "dowithnextbox", "dowithnextboxcs", "dowithnextboxcontent", "dowithnextboxcontentcs",
--
diff --git a/tex/context/base/node-ini.lua b/tex/context/base/node-ini.lua
index fb01f2f42..02d4c7a3f 100644
--- a/tex/context/base/node-ini.lua
+++ b/tex/context/base/node-ini.lua
@@ -154,9 +154,9 @@ local disccodes = allocate {
[0] = "discretionary", -- \discretionary
[1] = "explicit", -- \-
[2] = "automatic", -- following a -
- [3] = "regular", -- simple
- [4] = "first", -- hard first item
- [5] = "second", -- hard second item
+ [3] = "regular", -- by hyphenator: simple
+ [4] = "first", -- by hyphenator: hard first item
+ [5] = "second", -- by hyphenator: hard second item
}
local accentcodes = allocate {
diff --git a/tex/context/base/node-nut.lua b/tex/context/base/node-nut.lua
index 50274c2ab..cbf1c686c 100644
--- a/tex/context/base/node-nut.lua
+++ b/tex/context/base/node-nut.lua
@@ -136,6 +136,20 @@ nuts.getsubtype = direct.getsubtype
nuts.getlist = direct.getlist -- only hlist and vlist !
nuts.getleader = direct.getleader
+-- local function track(name)
+-- local n = 0
+-- local f = nuts[name]
+-- function nuts[name](...)
+-- n = n + 1
+-- if n % 1000 == 0 then
+-- print(name,n)
+-- end
+-- return f(...)
+-- end
+-- end
+
+-- track("getsubtype")
+
-- local dgf = direct.getfield function nuts.getlist(n) return dgf(n,"list") end
-- setters
diff --git a/tex/context/base/node-shp.lua b/tex/context/base/node-shp.lua
index 42b622878..a4fb5689d 100644
--- a/tex/context/base/node-shp.lua
+++ b/tex/context/base/node-shp.lua
@@ -73,14 +73,27 @@ local function cleanup_redundant(head) -- better name is: flatten_page
if getsubtype(start) == fulldisc_code then
local replace = getfield(start,"replace")
if replace then
- setfield(start,"replace",nil)
- head, start = remove_node(head,start,true)
- local tail = find_tail(replace)
local prev = getprev(start)
- setfield(tail,"next",start)
- setfield(start,"prev",tail)
- setfield(prev,"next",replace)
- setfield(replace,"prev",prev)
+ local next = getnext(start)
+ local tail = find_tail(replace)
+ setfield(start,"replace",nil)
+ if start == head then
+ remove_node(head,start,true)
+ head = replace
+ else
+ remove_node(head,start,true)
+ end
+ if next then
+ setfield(tail,"next",next)
+ setfield(next,"prev",tail)
+ end
+ if prev then
+ setfield(prev,"next",replace)
+ setfield(replace,"prev",prev)
+ else
+ setfield(replace,"prev",nil) -- to be sure
+ end
+ start = next
elseif wipedisc then
-- pre and post can have values
head, start = remove_node(head,start,true)
diff --git a/tex/context/base/node-tra.lua b/tex/context/base/node-tra.lua
index ea17c5738..5f060e4f3 100644
--- a/tex/context/base/node-tra.lua
+++ b/tex/context/base/node-tra.lua
@@ -319,8 +319,12 @@ local function listtoutf(h,joiner,textonly,last)
end
function nodes.listtoutf(h,joiner,textonly,last)
- local joiner = joiner == true and utfchar(0x200C) or joiner -- zwnj
- return listtoutf(tonut(h),joiner,textonly,last and tonut(last))
+ if h then
+ local joiner = joiner == true and utfchar(0x200C) or joiner -- zwnj
+ return listtoutf(tonut(h),joiner,textonly,last and tonut(last))
+ else
+ return ""
+ end
end
local what = { [0] = "unknown", "line", "box", "indent", "row", "cell" }
diff --git a/tex/context/base/s-fonts-ligatures.mkiv b/tex/context/base/s-fonts-ligatures.mkiv
new file mode 100644
index 000000000..1b8ab30d8
--- /dev/null
+++ b/tex/context/base/s-fonts-ligatures.mkiv
@@ -0,0 +1,284 @@
+%D \module
+%D [ file=s-fonts-ligatures,
+%D version=2014.12.14,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Show Fonts Ligatures,
+%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.
+
+% begin info
+%
+% title : show some ligature building in fonts
+%
+% comment : we trace some ligatures that have rather different implementations in fontss
+% status : experimental, used for luatex testing
+%
+% end info
+
+\definefontfeature
+ [otfligaturetest]
+ [analyze=off,
+ ccmp=yes, % brill uses that .. not really ligatures !
+ %clig=yes,
+ script=latn,
+ language=dflt]
+
+\hyphenation{xf-fi-a}
+\hyphenation{xff-i-b}
+\hyphenation{xffi-c}
+\hyphenation{xffid}
+
+\registerhyphenationexception[xf-fi-a]
+\registerhyphenationexception[xff-i-b]
+\registerhyphenationexception[xffi-c]
+\registerhyphenationexception[xffid]
+
+\starttexdefinition showotfligaturescaption #1
+ \bTD [width=18em,align={flushleft,lohi},nx=3]
+ \nohyphens
+ \ttbf
+ #1
+ \eTD
+\stoptexdefinition
+
+\starttexdefinition showotfligatureslegend #1
+ \bTD [width=6em,align={flushleft,lohi}]
+ \nohyphens \ttxx original
+ \eTD
+ \bTD [width=6em,align={flushleft,lohi}]
+ \nohyphens \ttxx expanded
+ \eTD
+ \bTD [width=6em,align={flushleft,lohi}]
+ \nohyphens \ttxx traditional
+ \eTD
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesline #1#2
+ \bTD[toffset=.5ex,frame=off]
+ \starthyphenation[#1]
+ \LigatureFont
+ \showfontkerns
+ \showdiscretionaries
+ \begstrut#2\endstrut
+ \par
+ \stophyphenation
+ \eTD
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesbanner #1
+ \bTR[frame=off]
+ \bTD [nx=12,align={middle,lohi},height=4ex]
+ \tttf #1
+ \eTD
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturescaptions #1
+ \bTR[height=3ex,align={middle,lohi},nx=3,bottomframe=off]
+ \processcommalist[#1]\showotfligaturescaption
+ \eTR
+ \bTR[height=3ex,align={middle,lohi},nx=3,topframe=off]
+ \processcommalist[#1]\showotfligatureslegend
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligatureslineset #1
+ \showotfligaturesline{original} {#1}
+ \showotfligaturesline{expanded} {#1}
+ \showotfligaturesline{traditional}{#1}
+\stoptexdefinition
+
+
+\starttexdefinition showotfligaturesparagraphset #1
+ \showotfligatureslineset {
+ \hsize \zeropoint
+ \lefthyphenmin \plustwo
+ \righthyphenmin\plustwo
+ #1
+ }
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesextremeset #1
+ \showotfligatureslineset {
+ \hsize \zeropoint
+ \lefthyphenmin \plusone
+ \righthyphenmin\plusone
+ #1
+ }
+\stoptexdefinition
+
+\starttexdefinition showotfligatureslines #1
+ \bTR[height=4ex,bottomframe=off]
+ \processcommalist[#1]\showotfligatureslineset
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesparagraphs #1
+ \bTR[cheight=12ex,topframe=off]
+ \processcommalist[#1]\showotfligaturesparagraphset
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesextremes #1
+ \bTR[cheight=12ex,topframe=off]
+ \processcommalist[#1]\showotfligaturesextremeset
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesdefaults
+ \bTR
+ \bTD [nx=12,align=middle,height=4ex,frame=off]
+ \start \LigatureFont fb \stop \quad
+ \start \LigatureFont ff \stop \quad
+ \start \LigatureFont fi \stop \quad
+ \start \LigatureFont fk \stop \quad
+ \start \LigatureFont fl \stop \quad
+ \start \LigatureFont ft \stop \quad
+ \start \LigatureFont ffb \stop \quad
+ \start \LigatureFont fff \stop \quad
+ \start \LigatureFont ffi \stop \quad
+ \start \LigatureFont ffl \stop \quad
+ \start \LigatureFont ffk \stop \quad
+ \start \LigatureFont fft \stop
+ \eTD
+ \eTR
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesexample #1#2
+ \showotfligaturescaptions {#1}
+ \showotfligatureslines {#2}
+ \showotfligaturesparagraphs{#2}
+ \showotfligaturesextremes {#2}
+\stoptexdefinition
+
+\starttexdefinition showotfligaturesexamples
+ \showotfligaturesexample
+ {leafing,baffling,efficient,shifffahrt}
+ {leafing,baffling,efficient,shifffahrt}
+ \showotfligaturesexample
+ {offbeat,effect,ef-fective,ef\-fective}
+ {offbeat,effect,ef-fective,ef\-fective}
+ \showotfligaturesexample
+ {xf+fi+a,xff+i+b,xffi+c,xffid}
+ {xffia, xffib, xffic, xffid}
+\stoptexdefinition
+
+\starttexdefinition showotfligatures [#1]
+ \begingroup
+ \getdummyparameters[font=Regular,features=default,#1]
+ \definefont[LigatureFont][\dummyparameter{font}*\dummyparameter{features},otfligaturetest ht 2ex]
+ \bTABLE[leftframe=off,rightframe=off]
+ \showotfligaturesbanner{\dummyparameter{font} * \dummyparameter{features}}
+ \showotfligaturesdefaults
+ \showotfligaturesexamples
+ \eTABLE
+ \endgroup
+\stoptexdefinition
+
+\continueifinputfile{s-fonts-ligatures.mkiv}
+
+\starttext
+
+ \startTEXpage \showotfligatures[font=lmroman10-regular.otf, features=default] \stopTEXpage
+ \startTEXpage \showotfligatures[font=dejavu-serif.ttf, features=default] \stopTEXpage
+ \startTEXpage \showotfligatures[font=minionpro.otf, features=default] \stopTEXpage
+ \startTEXpage \showotfligatures[font=minionpro.otf, features=smallcaps] \stopTEXpage
+ \startTEXpage \showotfligatures[font=brill.otf, features=default] \stopTEXpage
+ \startTEXpage \showotfligatures[font=gentiumplus-r.ttf, features=default] \stopTEXpage
+ \startTEXpage \showotfligatures[font=cambria, features=default] \stopTEXpage
+
+\stoptext
+
+% \startluacode
+%
+% local f = fonts.hashes.identifiers[true]
+%
+% local sequences = f.resources.sequences
+% local descriptions = f.shared.rawdata.descriptions
+% local lookuptypes = f.resources.lookuptypes
+% local lookups = f.resources.lookups
+%
+% local ligatures = { "liga", "dlig", "rlig", "clig", "tlig", "ccmp" }
+% local found = { }
+%
+% for i=1,#sequences do
+% local sequence = sequences[i]
+% local features = sequence.features
+% for i=1,#ligatures do
+% local l = ligatures[i]
+% if features[l] then
+% local subtables = sequence.subtables
+% if subtables then
+% for i=1,#subtables do
+% local subtable = subtables[i]
+% local lookup = found[subtable]
+% if lookup then
+% lookup[l] = true
+% else
+% found[subtable] = { [l] = true }
+% end
+% end
+% end
+% end
+% end
+% end
+%
+% context.starttabulate { "|||T|T|T|" }
+%
+% local function flush(l,v,start,unicode,data,done)
+% local features = found[l]
+% if features then
+% local lookuptype = lookuptypes[l]
+% if lookuptype == "ligature" then
+% local t = { }
+% for i=1,#v do
+% t[i] = utf.char(v[i])
+% end
+% t = table.concat(t," ")
+% if not done[t] then
+% context.NC()
+% context(t)
+% context.NC()
+% context(utf.char(unicode))
+% context.NC()
+% context(" %t",table.sortedkeys(features))
+% context.NC()
+% local name = data.name
+% if name then
+% context(name)
+% end
+% context.NC()
+% context("%U",unicode)
+% context.NC()
+% context.NR()
+% done[t] = true
+% end
+% end
+% end
+% end
+%
+% for unicode, data in table.sortedhash(descriptions) do
+% local slookups = data.slookups
+% local mlookups = data.mlookups
+% local done = { }
+% if slookups then
+% for l, v in next, slookups do
+% flush(l,v,1,unicode,data,done)
+% end
+% end
+% if mlookups then
+% for i=1,#mlookups do
+% local v = mlookups[i]
+% flush(v[1],v,2,unicode,data,done)
+% end
+% end
+% end
+%
+% context.stoptabulate()
+%
+% \stopluacode
diff --git a/tex/context/base/s-typesetting-kerning.mkiv b/tex/context/base/s-typesetting-kerning.mkiv
new file mode 100644
index 000000000..074861713
--- /dev/null
+++ b/tex/context/base/s-typesetting-kerning.mkiv
@@ -0,0 +1,127 @@
+%D \module
+%D [ file=s-typesetting-kerning,
+%D version=2014.12.14,
+%D title=\CONTEXT\ Style File,
+%D subtitle=Show Character Kerning,
+%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.
+
+\definecharacterkerning
+ [typesetting-kerning-demo]
+ [factor=.5]
+
+\startbuffer[showcharacterkerning:boxes]
+ \starttextrule{boxes}
+ \showfontkerns
+ \dontcomplain
+ \startlines
+ test \hbox{!} test
+ test\hbox{!} test
+ test \hbox{!}test
+ test:$x$ test
+ \setcharacterkerning[typesetting-kerning-demo]
+ test \hbox{!} test
+ test\hbox{!} test
+ test \hbox{!}test
+ test:$x$ test
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\startbuffer[showcharacterkerning:ligatures]
+ \starttextrule{ligatures}
+ \dontcomplain
+ \startlines
+ effe flink effectief efficient fietsen
+ \blank
+ \setcharacterkerning[typesetting-kerning-demo]
+ effe flink effectief efficient fietsen
+ \blank \hsize\zeropoint
+ effe
+ flink
+ effectief
+ efficient
+ fietsen
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\startbuffer[showcharacterkerning:discretionaries]
+ \starttextrule{discretionary}
+ \dontcomplain
+ \startlines
+ \hbox{\samplediscretionary}
+ \hbox{xxx\samplediscretionary}
+ \hbox{\samplediscretionary xxx}
+ \hbox{xxx\samplediscretionary xxx}
+ \blank
+ \setcharacterkerning[typesetting-kerning-demo]
+ \hbox{\samplediscretionary}
+ \hbox{xxx\samplediscretionary}
+ \hbox{\samplediscretionary xxx}
+ \hbox{xxx\samplediscretionary xxx}
+ \blank \hsize\zeropoint
+ \samplediscretionary
+ xxx\samplediscretionary
+ \samplediscretionary xxx
+ xxx\samplediscretionary xxx
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\startbuffer[showcharacterkerning:explicits]
+ \starttextrule{explicits}
+ \exhyphenchar \hyphenasciicode
+ \preexhyphenchar \lessthanasciicode
+ \postexhyphenchar\morethanasciicode
+ \def\TestDisc
+ {\discretionary
+ {\kern\emwidth<}%
+ {>\kern\emwidth}%
+ {\kern\emwidth=\kern\emwidth}%
+ }
+ \dontcomplain
+ \startlines
+ \hbox{super-charged}
+ \hbox{super\-charged}
+ \hbox{super\TestDisc charged}
+ \hbox{super\discretionary{[}{]}{[]}charged}
+ \blank
+ \setcharacterkerning[typesetting-kerning-demo]
+ \hbox{super-charged}
+ \hbox{super\-charged}
+ \hbox{super\TestDisc charged}
+ \hbox{super\discretionary{[}{]}{[]}charged}
+ \blank \hsize\zeropoint
+ super-charged
+ super\-charged
+ super\TestDisc charged
+ super\discretionary{[}{]}{[]}charged
+ \stoplines
+ \stoptextrule
+\stopbuffer
+
+\starttexdefinition unexpanded showcharacterkerning
+ \getbuffer[showcharacterkerning:boxes]
+ \getbuffer[showcharacterkerning:ligatures]
+ \getbuffer[showcharacterkerning:discretionaries]
+ \getbuffer[showcharacterkerning:explicits]
+\stoptexdefinition
+
+\continueifinputfile{s-typesetting-kerning.mkiv}
+
+\starttext
+
+ \showcharacterkerning
+
+\stoptext
+
+
+% {\hsize1mm efficient\discretionary{\kern1pt!\kern1pt}{\kern1pt!\kern1pt}{\kern1pt!\kern1pt}efficient\par}
+% {\hsize1mm\definedfont[Regular]\setcharacterkerning[typesetting-kerning-demo]efficient\-efficient\par}
+
diff --git a/tex/context/base/status-files.pdf b/tex/context/base/status-files.pdf
index 2444449e2..28a543e8f 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 7612df67e..23bd6e0ec 100644
--- a/tex/context/base/status-lua.pdf
+++ b/tex/context/base/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/status-mkiv.lua b/tex/context/base/status-mkiv.lua
index 65df5dd40..11d9991d6 100644
--- a/tex/context/base/status-mkiv.lua
+++ b/tex/context/base/status-mkiv.lua
@@ -627,6 +627,12 @@ return {
},
{
category = "mkiv",
+ filename = "lang-hyp",
+ loading = "always",
+ status = "okay",
+ },
+ {
+ category = "mkiv",
filename = "lang-frq",
loading = "on demand",
status = "okay",
@@ -3508,6 +3514,18 @@ return {
},
{
category = "lua",
+ filename = "lang-dis",
+ loading = "lang-ini",
+ status = "okay",
+ },
+ {
+ category = "lua",
+ filename = "lang-hyp",
+ loading = "lang-hyp",
+ status = "okay",
+ },
+ {
+ category = "lua",
filename = "lang-ini",
loading = "lang-ini",
status = "okay",
diff --git a/tex/context/base/syst-aux.mkiv b/tex/context/base/syst-aux.mkiv
index d3e34f0b9..84d1b10b6 100644
--- a/tex/context/base/syst-aux.mkiv
+++ b/tex/context/base/syst-aux.mkiv
@@ -5295,7 +5295,7 @@
\let\popmacro \localpopmacro
%D \macros
-%D {setlocalhsize}
+%D {setlocalhsize,distributedhsize}
%D
%D Sometimes we need to work with the \type{\hsize} that is
%D corrected for indentation and left and right skips. The
@@ -5333,6 +5333,9 @@
\fi
\relax}
+\def\distributedhsize#1#2#3%
+ {\dimexpr(#1-\numexpr#3-1\relax\dimexpr#2\relax)/#3\relax}
+
%D \macros
%D {doifvalue,doifnotvalue,doifelsevalue,
%D doifnothing,doifsomething,doifelsenothing,
diff --git a/tex/context/base/task-ini.lua b/tex/context/base/task-ini.lua
index d9ede85c4..f1df46ec8 100644
--- a/tex/context/base/task-ini.lua
+++ b/tex/context/base/task-ini.lua
@@ -39,7 +39,9 @@ appendaction("processors", "characters", "typesetters.breakpoints.handler")
appendaction("processors", "characters", "scripts.injectors.handler") -- disabled
appendaction("processors", "words", "languages.replacements.handler") -- disabled
-appendaction("processors", "words", "builders.kernel.hyphenation") -- always on
+
+appendaction("processors", "words", "languages.hyphenators.handler") -- always on
+
appendaction("processors", "words", "languages.words.check") -- disabled -- might move up, no disc check needed then
appendaction("processors", "words", "typesetters.initials.handler") -- disabled -- might move up
@@ -59,8 +61,9 @@ appendaction("processors", "lists", "typesetters.spacings.handler")
appendaction("processors", "lists", "typesetters.kerns.handler") -- disabled
appendaction("processors", "lists", "typesetters.digits.handler") -- disabled (after otf handling)
appendaction("processors", "lists", "typesetters.italics.handler") -- disabled (after otf/kern handling)
+appendaction("processors", "lists", "languages.visualizediscretionaries") -- disabled
--- appendaction("processors", "lists", "typesetters.initials.handler") -- disabled
+-- appendaction("processors", "lists", "typesetters.initials.handler") -- disabled
appendaction("shipouts", "normalizers", "nodes.handlers.cleanuppage") -- disabled
appendaction("shipouts", "normalizers", "builders.paragraphs.expansion.trace") -- disabled
@@ -151,6 +154,7 @@ disableaction("processors", "typesetters.firstlines.handler")
disableaction("processors", "typesetters.spacings.handler")
disableaction("processors", "typesetters.kerns.handler")
disableaction("processors", "typesetters.italics.handler")
+disableaction("processors", "languages.visualizediscretionaries")
disableaction("processors", "nodes.handlers.stripping")
disableaction("shipouts", "builders.paragraphs.expansion.trace")
diff --git a/tex/context/base/trac-vis.lua b/tex/context/base/trac-vis.lua
index 20b89bdf0..0ee40db80 100644
--- a/tex/context/base/trac-vis.lua
+++ b/tex/context/base/trac-vis.lua
@@ -820,7 +820,7 @@ local function visualize(head,vertical,forced)
if trace_fontkern or prev_trace_fontkern then
head, current = fontkern(head,current)
end
- elseif subtype == user_kern_code then
+ else -- if subtype == user_kern_code then
if trace_kern then
head, current = ruledkern(head,current,vertical)
end
diff --git a/tex/context/base/typo-brk.mkiv b/tex/context/base/typo-brk.mkiv
index af498bfec..a42bed1b7 100644
--- a/tex/context/base/typo-brk.mkiv
+++ b/tex/context/base/typo-brk.mkiv
@@ -25,7 +25,7 @@
\definesystemattribute[breakpoint][public,global]
-\exhyphenchar\minusone % we use a different order then base tex, so we really need this
+% see below: \exhyphenchar \minusone % we use a different order tha n base tex, so we really need this
\unexpanded\def\definebreakpoints
{\dosingleargument\typo_breakpoints_define}
@@ -50,7 +50,8 @@
\endgroup}
\unexpanded\def\setbreakpoints[#1]%
- {\ctxcommand{setbreakpoints("#1")}}
+ {\exhyphenchar\minusone % we use a different order tha n base tex, so we really need this
+ \ctxcommand{setbreakpoints("#1")}}
\unexpanded\def\resetbreakpoints
{\attribute\breakpointattribute\attributeunsetvalue}
diff --git a/tex/context/base/typo-krn.lua b/tex/context/base/typo-krn.lua
index 5729c72c0..1616577dc 100644
--- a/tex/context/base/typo-krn.lua
+++ b/tex/context/base/typo-krn.lua
@@ -11,7 +11,8 @@ if not modules then modules = { } end modules ['typo-krn'] = {
local next, type, tonumber = next, type, tonumber
local utfchar = utf.char
-local nodes, node, fonts = nodes, node, fonts
+local nodes = nodes
+local fonts = fonts
local tasks = nodes.tasks
local nuts = nodes.nuts
@@ -20,11 +21,10 @@ local nodepool = nuts.pool
local tonode = nuts.tonode
local tonut = nuts.tonut
+-- check what is used
+
local find_node_tail = nuts.tail
local free_node = nuts.free
-local free_nodelist = nuts.flush_list
-local copy_node = nuts.copy
-local copy_nodelist = nuts.copy_list
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
local end_of_math = nuts.end_of_math
@@ -51,6 +51,7 @@ local nodecodes = nodes.nodecodes
local kerncodes = nodes.kerncodes
local skipcodes = nodes.skipcodes
local disccodes = nodes.disccodes
+local listcodes = nodes.listcodes
local glyph_code = nodecodes.glyph
local kern_code = nodecodes.kern
@@ -60,7 +61,12 @@ local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local math_code = nodecodes.math
+local box_list_code = listcodes.box
+local user_list_code = listcodes.unknown
+
local discretionary_code = disccodes.discretionary
+local automatic_code = disccodes.automatic
+
local kerning_code = kerncodes.kerning
local userkern_code = kerncodes.userkern
local userskip_code = skipcodes.userskip
@@ -203,20 +209,178 @@ local function spec_injector(fillup,width,stretch,shrink)
end
end
--- needs checking ... base mode / node mode -- also use insert_before/after etc
+-- a simple list injector, no components and such .. just disable ligatures in
+-- kern mode .. maybe not even hyphenate ... anyway, the next one is for simple
+-- sublists .. beware: we can have char -1
+
+local function inject_begin(boundary,prev,keeptogether,krn,ok) -- prev is a glyph
+ local id = getid(boundary)
+ if id == kern_code then
+ if getsubtype(boundary) == kerning_code or getattr(boundary,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ local next = getnext(boundary)
+ if not next or (getid(next) == glyph_code and keeptogether(prev,next)) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(boundary,"subtype",userkern_code)
+ setfield(boundary,"kern",getfield(boundary,"kern") + quaddata[getfont(prev)]*krn)
+ return boundary, true
+ end
+ end
+ elseif id == glyph_code then
+ if keeptogether and keeptogether(boundary,prev) then
+ -- keep 'm
+ else
+ local charone = getchar(prev)
+ if charone > 0 then
+ local font = getfont(boundary)
+ local chartwo = getchar(boundary)
+ local kerns = chardata[font][charone].kerns
+ local kern = new_kern((kerns and kerns[chartwo] or 0) + quaddata[font]*krn)
+ setfield(boundary,"prev",kern)
+ setfield(kern,"next",boundary)
+ return kern, true
+ end
+ end
+ end
+ return boundary, ok
+end
+
+local function inject_end(boundary,next,keeptogether,krn,ok)
+ local tail = find_node_tail(boundary)
+ local id = getid(tail)
+ if id == kern_code then
+ if getsubtype(tail) == kerning_code or getattr(tail,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ local prev = getprev(tail)
+ if getid(prev) == glyph_code and keeptogether(prev,two) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(tail,"subtype",userkern_code)
+ setfield(tail,"kern",getfield(tail,"kern") + quaddata[getfont(next)]*krn)
+ return boundary, true
+ end
+ end
+ elseif id == glyph_code then
+ if keeptogether and keeptogether(tail,two) then
+ -- keep 'm
+ else
+ local charone = getchar(tail)
+ if charone > 0 then
+ local font = getfont(tail)
+ local chartwo = getchar(next)
+ local kerns = chardata[font][charone].kerns
+ local kern = (kerns and kerns[chartwo] or 0) + quaddata[font]*krn
+ insert_node_after(boundary,tail,new_kern(kern))
+ return boundary, true
+ end
+ end
+ end
+ return boundary, ok
+end
+
+local function process_list(head,keeptogether,krn,font,okay)
+ local start = head
+ local prev = nil
+ local pid = nil
+ local kern = 0
+ local mark = font and markdata[font]
+ while start do
+ local id = getid(start)
+ if id == glyph_code then
+ if not font then
+ font = getfont(start)
+ mark = markdata[font]
+ kern = quaddata[font]*krn
+ end
+ if prev then
+ local char = getchar(start)
+ if mark[char] then
+ -- skip
+ elseif pid == kern_code then
+ if getsubtype(prev) == kerning_code or getattr(prev,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ local prevprev = getprev(prev)
+ if getid(prevprev) == glyph_code and keeptogether(prevprev,start) then
+ inject = false
+ end
+ end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(prev,"subtype",userkern_code)
+ setfield(prev,"kern",getfield(prev,"kern") + kern)
+ okay = true
+ end
+ end
+ elseif pid == glyph_code then
+ if keeptogether and keeptogether(prev,start) then
+ -- keep 'm
+ else
+ local prevchar = getchar(prev)
+ local kerns = chardata[font][prevchar].kerns
+ -- if kerns then
+ -- print("it happens indeed, basemode kerns not yet injected")
+ -- end
+ insert_node_before(head,start,new_kern((kerns and kerns[char] or 0) + kern))
+ okay = true
+ end
+ end
+ end
+ end
+ if start then
+ prev = start
+ pid = id
+ start = getnext(start)
+ end
+ end
+ return head, okay, prev
+end
-local function do_process(head,force) -- todo: glue so that we can fully stretch
+local function closest_bound(b,get)
+ b = get(b)
+ if b and getid(b) ~= glue_code then
+ while b do
+ if not getattr(b,a_kerns) then
+ break
+ elseif getid(b) == glyph_code then
+ return b, getfont(b)
+ else
+ b = get(b)
+ end
+ end
+ end
+end
+
+function kerns.handler(head)
+ local head = tonut(head)
local start = head
local done = false
local lastfont = nil
local keepligature = kerns.keepligature
local keeptogether = kerns.keeptogether
local fillup = false
+ local bound = false
+ local prev = nil
+ local previd = nil
+ local prevchar = nil
+ local prevfont = nil
+ local prevmark = nil
while start do
- -- faster to test for attr first
- local attr = force or getattr(start,a_kerns)
+ -- fontkerns don't get the attribute but they always sit between glyphs so
+ -- are always valid bound .. disc nodes also somtimes don't get them
+ local id = getid(start)
+ local attr = getattr(start,a_kerns)
if attr and attr > 0 then
- setattr(start,a_kerns,unsetvalue)
+ setattr(start,a_kerns,0) -- unsetvalue)
local krn = mapping[attr]
if krn == v_max then
krn = .25
@@ -224,21 +388,21 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
else
fillup = false
end
- if krn and krn ~= 0 then
- local id = getid(start)
- if id == glyph_code then -- we could use the subtype ligature
- lastfont = getfont(start)
- local c = getfield(start,"components")
- if not c then
- -- fine
- elseif keepligature and keepligature(start) then
- -- keep 'm
- else
- c = do_process(c,attr)
- local s = start
- local p = getprev(s)
- local n = getnext(s)
- local tail = find_node_tail(c)
+ if not krn or krn == 0 then
+ bound = false
+ elseif id == glyph_code then -- we could use the subtype ligature
+ local c = getfield(start,"components")
+ if not c then
+ -- fine
+ elseif keepligature and keepligature(start) then
+ -- keep 'm
+ c = nil
+ else
+ while c do
+ local s = start
+ local t = find_node_tail(c)
+ local p = getprev(s)
+ local n = getnext(s)
if p then
setfield(p,"next",c)
setfield(c,"prev",p)
@@ -246,172 +410,190 @@ local function do_process(head,force) -- todo: glue so that we can fully stretch
head = c
end
if n then
- setfield(n,"prev",tail)
+ setfield(n,"prev",t)
+ setfield(t,"next",n)
end
- setfield(tail,"next",n)
start = c
setfield(s,"components",nil)
- -- we now leak nodes !
- -- free_node(s)
- done = true
+ free_node(s)
+ c = getfield(start,"components")
end
- local prev = getprev(start)
- if not prev then
- -- skip
- elseif markdata[lastfont][getchar(start)] then
- -- skip
- else
- local pid = getid(prev)
- if not pid then
- -- nothing
- elseif pid == kern_code then
- if getsubtype(prev) == kerning_code or getattr(prev,a_fontkern) then
- if keeptogether and getid(getprev(prev)) == glyph_code and keeptogether(getprev(prev),start) then -- we could also pass start
- -- keep 'm
- else
- -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
- setfield(prev,"subtype",userkern_code)
- setfield(prev,"kern",getfield(prev,"kern") + quaddata[lastfont]*krn) -- here
- done = true
- end
- end
- elseif pid == glyph_code then
- if getfont(prev) == lastfont then
- local prevchar, lastchar = getchar(prev), getchar(start)
- if keeptogether and keeptogether(prev,start) then
- -- keep 'm
- else
- local kerns = chardata[lastfont][prevchar].kerns
- local kern = kerns and kerns[lastchar] or 0
- krn = kern + quaddata[lastfont]*krn -- here
- insert_node_before(head,start,kern_injector(fillup,krn))
- done = true
- end
- else
- krn = quaddata[lastfont]*krn -- here
- insert_node_before(head,start,kern_injector(fillup,krn))
- done = true
- end
- elseif pid == disc_code then
- -- a bit too complicated, we can best not copy and just calculate
- -- but we could have multiple glyphs involved so ...
- local disc = prev -- disc
- local prv = getprev(disc)
- local nxt = getnext(disc)
- if getsubtype(disc) == discretionary_code then
- -- maybe we should forget about this variant as there is no glue
- -- possible .. hardly used so a copy doesn't hurt much
- local pre = getfield(disc,"pre")
- local post = getfield(disc,"post")
- local replace = getfield(disc,"replace")
- if pre and prv then -- must pair with getprev(start)
- local before = copy_node(prv)
- setfield(pre,"prev",before)
- setfield(before,"next",pre)
- setfield(before,"prev",nil)
- pre = do_process(before,attr)
- pre = getnext(pre)
- setfield(pre,"prev",nil)
- setfield(disc,"pre",pre)
- free_node(before)
- end
- if post and nxt then -- must pair with start
- local after = copy_node(nxt)
- local tail = find_node_tail(post)
- setfield(tail,"next",after)
- setfield(after,"prev",tail)
- setfield(after,"next",nil)
- post = do_process(post,attr)
- setfield(tail,"next",nil)
- setfield(disc,"post",post)
- free_node(after)
- end
- if replace and prv and nxt then -- must pair with start and start.prev
- local before = copy_node(prv)
- local after = copy_node(nxt)
- local tail = find_node_tail(replace)
- setfield(replace,"prev",before)
- setfield(before,"next",replace)
- setfield(before,"prev",nil)
- setfield(tail,"next",after)
- setfield(after,"prev",tail)
- setfield(after,"next",nil)
- replace = do_process(before,attr)
- replace = getnext(replace)
- setfield(replace,"prev",nil)
- setfield(getfield(after,"prev"),"next",nil)
- setfield(disc,"replace",replace)
- free_node(after)
- free_node(before)
- elseif prv and getid(prv) == glyph_code and getfont(prv) == lastfont then
- local prevchar = getchar(prv)
- local lastchar = getchar(start)
- local kerns = chardata[lastfont][prevchar].kerns
- local kern = kerns and kerns[lastchar] or 0
- krn = kern + quaddata[lastfont]*krn -- here
- setfield(disc,"replace",kern_injector(false,krn)) -- only kerns permitted, no glue
- else
- krn = quaddata[lastfont]*krn -- here
- setfield(disc,"replace",kern_injector(false,krn)) -- only kerns permitted, no glue
- end
- else
- -- this one happens in most cases: automatic (-), explicit (\-), regular (patterns)
- if prv and getid(prv) == glyph_code and getfont(prv) == lastfont then
- -- the normal case
- local prevchar = getchar(prv)
- local lastchar = getchar(start)
- local kerns = chardata[lastfont][prevchar].kerns
- local kern = kerns and kerns[lastchar] or 0
- krn = kern + quaddata[lastfont]*krn
- else
- krn = quaddata[lastfont]*krn
- end
- insert_node_before(head,start,kern_injector(fillup,krn))
+ end
+ local char = getchar(start)
+ local font = getfont(start)
+ local mark = markdata[font]
+ if not bound then
+ -- yet
+ elseif mark[char] then
+ -- skip
+ elseif previd == kern_code then
+ if getsubtype(prev) == kerning_code or getattr(prev,a_fontkern) then
+ local inject = true
+ if keeptogether then
+ if previd == glyph_code and keeptogether(prev,start) then
+ inject = false
end
end
+ if inject then
+ -- not yet ok, as injected kerns can be overlays (from node-inj.lua)
+ setfield(prev,"subtype",userkern_code)
+ setfield(prev,"kern",getfield(prev,"kern") + quaddata[font]*krn)
+ done = true
+ end
end
- elseif id == glue_code then
- local subtype = getsubtype(start)
- if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then
- local s = getfield(start,"spec")
- local w = getfield(s,"width")
- if w > 0 then
- local width = w+gluefactor*w*krn
- local stretch = getfield(s,"stretch")
- local shrink = getfield(s,"shrink")
- setfield(start,"spec",spec_injector(fillup,width,stretch*width/w,shrink*width/w))
+ elseif previd == glyph_code then
+ if prevfont == font then
+ if keeptogether and keeptogether(prev,start) then
+ -- keep 'm
+ else
+ local kerns = chardata[font][prevchar].kerns
+ local kern = (kerns and kerns[char] or 0) + quaddata[font]*krn
+ insert_node_before(head,start,kern_injector(fillup,kern))
done = true
end
+ else
+ insert_node_before(head,start,kern_injector(fillup,quaddata[font]*krn))
+ done = true
+ end
+ end
+ prev = start
+ prevchar = char
+ prevfont = font
+ prevmark = mark
+ previd = id
+ bound = true
+ elseif id == disc_code then
+ local prev, next, pglyph, nglyph -- delayed till needed
+ local subtype = getsubtype(start)
+ if subtype == automatic_code then
+ -- this is kind of special, as we have already injected the
+ -- previous kern
+ local prev = getprev(start)
+ local pglyph = prev and getid(prev) == glyph_code
+ languages.expand(start,pglyph and prev)
+ -- we can have a different start now
+ elseif subtype ~= discretionary_code then
+ prev = getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ languages.expand(start,pglyph and prev)
+ end
+ local pre = getfield(start,"pre")
+ local post = getfield(start,"post")
+ local replace = getfield(start,"replace")
+ -- we really need to reasign the fields as luatex keeps track of
+ -- the tail in a temp preceding head .. kind of messy so we might
+ -- want to come up with a better solution some day like a real
+ -- pretail etc fields in a disc node
+ --
+ -- maybe i'll merge the now split functions
+ if pre then
+ local okay = false
+ if not prev then
+ prev = prev or getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ end
+ if pglyph then
+ pre, okay = inject_begin(pre,prev,keeptogether,krn,okay)
+ end
+ pre, okay = process_list(pre,keeptogether,krn,false,okay)
+ if okay then
+ setfield(start,"pre",pre)
+ done = true
+ end
+ end
+ if post then
+ local okay = false
+ if not next then
+ next = getnext(start)
+ nglyph = next and getid(next) == glyph_code
+ end
+ if nglyph then
+ post, okay = inject_end(post,next,keeptogether,krn,okay)
end
- elseif id == kern_code then
- -- if getsubtype(start) == kerning_code then -- handle with glyphs
- -- local sk = getfield(start,"kern")
- -- if sk > 0 then
- -- setfield(start,"kern",sk*krn)
- -- done = true
- -- end
- -- end
- elseif lastfont and (id == hlist_code or id == vlist_code) then -- todo: lookahead
- local p = getprev(start)
- if p and getid(p) ~= glue_code then
- insert_node_before(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
+ post, okay = process_list(post,keeptogether,krn,false,okay)
+ if okay then
+ setfield(start,"post",post)
done = true
end
- local n = getnext(start)
- if n and getid(n) ~= glue_code then
- insert_node_after(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
+ end
+ if replace then
+ local okay = false
+ if not prev then
+ prev = prev or getprev(start)
+ pglyph = prev and getid(prev) == glyph_code
+ end
+ if pglyph then
+ replace, okay = inject_begin(replace,prev,keeptogether,krn,okay)
+ end
+ if not next then
+ next = getnext(start)
+ nglyph = next and getid(next) == glyph_code
+ end
+ if nglyph then
+ replace, okay = inject_end(replace,next,keeptogether,krn,okay)
+ end
+ replace, okay = process_list(replace,keeptogether,krn,false,okay)
+ if okay then
+ setfield(start,"replace",replace)
done = true
end
- elseif id == math_code then
- start = end_of_math(start)
+ elseif prevfont then
+ setfield(start,"replace",new_kern(quaddata[prevfont]*krn))
+ done = true
end
+ bound = false
+ elseif id == kern_code then
+ bound = getsubtype(start) == kerning_code or getattr(start,a_fontkern)
+ prev = start
+ previd = id
+ elseif id == glue_code then
+ local subtype = getsubtype(start)
+ if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then
+ local s = getfield(start,"spec")
+ local w = getfield(s,"width")
+ if w > 0 then
+ local width = w+gluefactor*w*krn
+ local stretch = getfield(s,"stretch")
+ local shrink = getfield(s,"shrink")
+ setfield(start,"spec",spec_injector(fillup,width,stretch*width/w,shrink*width/w))
+ done = true
+ end
+ end
+ bound = false
+ elseif id == hlist_code or id == vlist_code then
+ local subtype = getsubtype(start)
+ if subtype == user_list_code or subtype == box_list_code then
+ -- special case
+ local b, f = closest_bound(start,getprev)
+ if b then
+ insert_node_before(head,start,kern_injector(fillup,quaddata[f]*krn))
+ done = true
+ end
+ local b, f = closest_bound(start,getnext)
+ if b then
+ insert_node_after(head,start,kern_injector(fillup,quaddata[f]*krn))
+ done = true
+ end
+ end
+ bound = false
+ elseif id == math_code then
+ start = end_of_math(start)
+ bound = false
end
- end
- if start then
+ if start then
+ start = getnext(start)
+ end
+ elseif id == kern_code then
+ bound = getsubtype(start) == kerning_code or getattr(start,a_fontkern)
+ prev = start
+ previd = id
+ start = getnext(start)
+ else
+ bound = false
start = getnext(start)
end
end
- return head, done
+ return tonode(head), done
end
local enabled = false
@@ -438,11 +620,6 @@ function kerns.set(factor)
return factor
end
-function kerns.handler(head)
- local head, done = do_process(tonut(head)) -- no direct map, because else fourth argument is tail == true
- return tonode(head), done
-end
-
-- interface
commands.setcharacterkerning = kerns.set
diff --git a/tex/generic/context/luatex/luatex-basics-nod.lua b/tex/generic/context/luatex/luatex-basics-nod.lua
index ea539f3f6..1ec2895ba 100644
--- a/tex/generic/context/luatex/luatex-basics-nod.lua
+++ b/tex/generic/context/luatex/luatex-basics-nod.lua
@@ -154,8 +154,8 @@ nodes.unset_attribute = node.unset_attribute
nodes.protect_glyphs = node.protect_glyphs
nodes.unprotect_glyphs = node.unprotect_glyphs
-nodes.kerning = node.kerning
-nodes.ligaturing = node.ligaturing
+-----.kerning = node.kerning
+-----.ligaturing = node.ligaturing
nodes.mlist_to_hlist = node.mlist_to_hlist
-- in generic code, at least for some time, we stay nodes, while in context
@@ -194,8 +194,12 @@ nuts.insert_before = direct.insert_before
nuts.insert_after = direct.insert_after
nuts.delete = direct.delete
nuts.copy = direct.copy
+nuts.copy_list = direct.copy_list
nuts.tail = direct.tail
nuts.flush_list = direct.flush_list
+nuts.free = direct.free
+nuts.remove = direct.remove
+nuts.is_node = direct.is_node
nuts.end_of_math = direct.end_of_math
nuts.traverse = direct.traverse
nuts.traverse_id = direct.traverse_id
diff --git a/tex/generic/context/luatex/luatex-fonts-cbk.lua b/tex/generic/context/luatex/luatex-fonts-cbk.lua
index 965b96893..414cafb25 100644
--- a/tex/generic/context/luatex/luatex-fonts-cbk.lua
+++ b/tex/generic/context/luatex/luatex-fonts-cbk.lua
@@ -29,11 +29,28 @@ local kerning = node.kerning
local basepass = true
+local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning = nil end
+local function k_warning() texio.write_nl("warning: node.kerning called directly") k_warning = nil end
+
+function node.ligaturing(...)
+ if basepass and l_warning then
+ l_warning()
+ end
+ return ligaturing(...)
+end
+
+function node.kerning(...)
+ if basepass and k_warning then
+ k_warning()
+ end
+ return kerning(...)
+end
+
function nodes.handlers.setbasepass(v)
basepass = v
end
-function nodes.handlers.characters(head)
+function nodes.handlers.nodepass(head)
local fontdata = fonts.hashes.identifiers
if fontdata then
local usedfonts = { }
@@ -115,14 +132,27 @@ function nodes.handlers.characters(head)
end
end
-function nodes.simple_font_handler(head)
- -- lang.hyphenate(head)
- head = nodes.handlers.characters(head)
- nodes.injections.handler(head)
+function nodes.handlers.basepass(head)
if not basepass then
head = ligaturing(head)
head = kerning(head)
end
- nodes.handlers.protectglyphs(head)
- return head
+ return head, true
+end
+
+local nodepass = nodes.handlers.nodepass
+local basepass = nodes.handlers.basepass
+local injectpass = nodes.injections.handler
+local protectpass = nodes.handlers.protectglyphs
+
+function nodes.simple_font_handler(head)
+ if head then
+ head = nodepass(head)
+ head = injectpass(head)
+ head = basepass(head)
+ protectpass(head)
+ return head, true
+ else
+ return head, false
+ end
end
diff --git a/tex/generic/context/luatex/luatex-fonts-inj.lua b/tex/generic/context/luatex/luatex-fonts-inj.lua
index 402403529..3b933829d 100644
--- a/tex/generic/context/luatex/luatex-fonts-inj.lua
+++ b/tex/generic/context/luatex/luatex-fonts-inj.lua
@@ -1,23 +1,25 @@
-if not modules then modules = { } end modules ['node-inj'] = {
+if not modules then modules = { } end modules ['font-inj'] = {
version = 1.001,
- comment = "companion to node-ini.mkiv",
+ comment = "companion to font-lib.mkiv",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files",
}
--- This is very experimental (this will change when we have luatex > .50 and
--- a few pending thingies are available. Also, Idris needs to make a few more
--- test fonts. Some optimizations can go away when we have faster machines.
+-- This property based variant is not faster but looks nicer than the attribute one. We
+-- need to use rawget (which is apbout 4 times slower than a direct access but we cannot
+-- get/set that one for our purpose!
--- todo: ignore kerns between disc and glyph
+if not nodes.properties then return end
-local next = next
+local next, rawget = next, rawget
local utfchar = utf.char
-local trace_injections = false trackers.register("nodes.injections", function(v) trace_injections = v end)
+local trace_injections = false trackers.register("fonts.injections", function(v) trace_injections = v end)
-local report_injections = logs.reporter("nodes","injections")
+local report_injections = logs.reporter("fonts","injections")
+
+report_injections("using experimental injector")
local attributes, nodes, node = attributes, nodes, node
@@ -29,6 +31,7 @@ local injections = nodes.injections
local nodecodes = nodes.nodecodes
local glyph_code = nodecodes.glyph
+local disc_code = nodecodes.disc
local kern_code = nodecodes.kern
local nuts = nodes.nuts
@@ -40,207 +43,351 @@ local tonode = nuts.tonode
local tonut = nuts.tonut
local getfield = nuts.getfield
+local setfield = nuts.setfield
local getnext = nuts.getnext
local getprev = nuts.getprev
local getid = nuts.getid
-local getattr = nuts.getattr
local getfont = nuts.getfont
local getsubtype = nuts.getsubtype
local getchar = nuts.getchar
-local setfield = nuts.setfield
-local setattr = nuts.setattr
-
local traverse_id = nuts.traverse_id
local insert_node_before = nuts.insert_before
local insert_node_after = nuts.insert_after
+local find_tail = nuts.tail
-local a_kernpair = attributes.private('kernpair')
-local a_ligacomp = attributes.private('ligacomp')
-local a_markbase = attributes.private('markbase')
-local a_markmark = attributes.private('markmark')
-local a_markdone = attributes.private('markdone')
-local a_cursbase = attributes.private('cursbase')
-local a_curscurs = attributes.private('curscurs')
-local a_cursdone = attributes.private('cursdone')
-
-local unsetvalue = attributes.unsetvalue
-
--- This injector has been tested by Idris Samawi Hamid (several arabic fonts as well as
--- the rather demanding Husayni font), Khaled Hosny (latin and arabic) and Kaj Eigner
--- (arabic, hebrew and thai) and myself (whatever font I come across). I'm pretty sure
--- that this code is not 100% okay but examples are needed to figure things out.
+local properties = nodes.properties.data
function injections.installnewkern(nk)
newkern = nk or newkern
end
-local cursives = { }
-local marks = { }
-local kerns = { }
+local nofregisteredkerns = 0
+local nofregisteredpairs = 0
+local nofregisteredmarks = 0
+local nofregisteredcursives = 0
+----- markanchors = { } -- one base can have more marks
+local keepregisteredcounts = false
--- Currently we do gpos/kern in a bit inofficial way but when we have the extra fields in
--- glyphnodes to manipulate ht/dp/wd explicitly I will provide an alternative; also, we
--- can share tables.
+function injections.keepcounts()
+ keepregisteredcounts = true
+end
--- For the moment we pass the r2l key ... volt/arabtype tests .. idris: this needs
--- checking with husayni (volt and fontforge).
+function injections.resetcounts()
+ nofregisteredkerns = 0
+ nofregisteredpairs = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ keepregisteredcounts = false
+end
function injections.reset(n)
--- if getattr(n,a_kernpair) then
--- setattr(n,a_kernpair,unsetvalue)
--- end
--- if getattr(n,a_markdone) then
--- setattr(n,a_markbase,unsetvalue)
--- setattr(n,a_markmark,unsetvalue)
--- setattr(n,a_markdone,unsetvalue)
--- end
--- if getattr(n,a_cursdone) then
--- setattr(n,a_cursbase,unsetvalue)
--- setattr(n,a_curscurs,unsetvalue)
--- setattr(n,a_cursdone,unsetvalue)
--- end
--- if getattr(n,a_ligacomp) then
--- setattr(n,a_ligacomp,unsetvalue)
--- end
+ local p = rawget(properties,start)
+ if p and p.injections then
+ -- todo: decrement counters? tricky as we then need to change the nof* to not increment
+ -- when we change a property
+ p.injections = nil -- should we keep the liga index?
+ end
end
function injections.setligaindex(n,index)
- setattr(n,a_ligacomp,index)
+ local p = rawget(properties,n)
+ if p then
+ local i = p.injections
+ if i then
+ i.ligaindex = index
+ else
+ p.injections = {
+ ligaindex = index
+ }
+ end
+ else
+ properties[n] = {
+ injections = {
+ ligaindex = index
+ }
+ }
+ end
end
function injections.getligaindex(n,default)
- return getattr(n,a_ligacomp) or default
+ local p = rawget(properties,n)
+ if p then
+ p = p.injections
+ if p then
+ return p.ligaindex or default
+ end
+ end
+ return default
end
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
- local dx, dy = factor*(exit[1]-entry[1]), factor*(exit[2]-entry[2])
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext) -- hm: nuts or nodes
+ local dx = factor*(exit[1]-entry[1])
+ local dy = -factor*(exit[2]-entry[2])
local ws, wn = tfmstart.width, tfmnext.width
- local bound = #cursives + 1
- setattr(start,a_cursbase,bound)
- setattr(nxt,a_curscurs,bound)
- cursives[bound] = { rlmode, dx, dy, ws, wn }
- return dx, dy, bound
+ nofregisteredcursives = nofregisteredcursives + 1
+ if rlmode < 0 then
+ dx = -(dx + wn)
+ else
+ dx = dx - ws
+ end
+ --
+ local p = rawget(properties,start)
+ if p then
+ local i = p.injections
+ if i then
+ i.cursiveanchor = true
+ else
+ p.injections = {
+ cursiveanchor = true,
+ }
+ end
+ else
+ properties[start] = {
+ injections = {
+ cursiveanchor = true,
+ },
+ }
+ end
+ local p = rawget(properties,nxt)
+ if p then
+ local i = p.injections
+ if i then
+ i.cursivex = dx
+ i.cursivey = dy
+ else
+ p.injections = {
+ cursivex = dx,
+ cursivey = dy,
+ }
+ end
+ else
+ properties[nxt] = {
+ injections = {
+ cursivex = dx,
+ cursivey = dy,
+ },
+ }
+ end
+ return dx, dy, nofregisteredcursives
end
-function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
+function injections.setpair(current,factor,rlmode,r2lflag,spec,injection) -- r2lflag & tfmchr not used
local x, y, w, h = factor*spec[1], factor*spec[2], factor*spec[3], factor*spec[4]
- -- dy = y - h
- if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then
- local bound = getattr(current,a_kernpair)
- if bound then
- local kb = kerns[bound]
- -- inefficient but singles have less, but weird anyway, needs checking
- kb[2], kb[3], kb[4], kb[5] = (kb[2] or 0) + x, (kb[3] or 0) + y, (kb[4] or 0)+ w, (kb[5] or 0) + h
- else
- bound = #kerns + 1
- setattr(current,a_kernpair,bound)
- kerns[bound] = { rlmode, x, y, w, h, r2lflag, tfmchr.width }
- end
- return x, y, w, h, bound
+ if x ~= 0 or w ~= 0 or y ~= 0 or h ~= 0 then -- okay?
+ local yoffset = y - h
+ local leftkern = x -- both kerns are set in a pair kern compared
+ local rightkern = w - x -- to normal kerns where we set only leftkern
+ if leftkern ~= 0 or rightkern ~= 0 or yoffset ~= 0 then
+ nofregisteredpairs = nofregisteredpairs + 1
+ if rlmode and rlmode < 0 then
+ leftkern, rightkern = rightkern, leftkern
+ end
+ local p = rawget(properties,current)
+ if p then
+ local i = p.injections
+ if i then
+ if leftkern ~= 0 or rightkern ~= 0 then
+ i.leftkern = i.leftkern or 0 + leftkern
+ i.rightkern = i.rightkern or 0 + rightkern
+ end
+ if yoffset ~= 0 then
+ i.yoffset = i.yoffset or 0 + yoffset
+ end
+ elseif leftkern ~= 0 or rightkern ~= 0 then
+ p.injections = {
+ leftkern = leftkern,
+ rightkern = rightkern,
+ yoffset = yoffset,
+ }
+ else
+ p.injections = {
+ yoffset = yoffset,
+ }
+ end
+ elseif leftkern ~= 0 or rightkern ~= 0 then
+ properties[current] = {
+ injections = {
+ leftkern = leftkern,
+ rightkern = rightkern,
+ yoffset = yoffset,
+ },
+ }
+ else
+ properties[current] = {
+ injections = {
+ yoffset = yoffset,
+ },
+ }
+ end
+ return x, y, w, h, nofregisteredpairs
+ end
end
return x, y, w, h -- no bound
end
-function injections.setkern(current,factor,rlmode,x,tfmchr)
- local dx = factor*x
+-- this needs checking for rl < 0 but it is unlikely that a r2l script
+-- uses kernclasses between glyphs so we're probably safe (KE has a
+-- problematic font where marks interfere with rl < 0 in the previous
+-- case)
+
+function injections.setkern(current,factor,rlmode,x,injection)
+ local dx = factor * x
if dx ~= 0 then
- local bound = #kerns + 1
- setattr(current,a_kernpair,bound)
- kerns[bound] = { rlmode, dx }
- return dx, bound
+ nofregisteredkerns = nofregisteredkerns + 1
+ local p = rawget(properties,current)
+ if not injection then
+ injection = "injections"
+ end
+ if p then
+ local i = p[injection]
+ if i then
+ i.leftkern = dx + i.leftkern or 0
+ else
+ p[injection] = {
+ leftkern = dx,
+ }
+ end
+ else
+ properties[current] = {
+ [injection] = {
+ leftkern = dx,
+ },
+ }
+ end
+ return dx, nofregisteredkerns
else
return 0, 0
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma) -- ba=baseanchor, ma=markanchor
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase) -- ba=baseanchor, ma=markanchor
local dx, dy = factor*(ba[1]-ma[1]), factor*(ba[2]-ma[2])
- local bound = getattr(base,a_markbase)
- local index = 1
- if bound then
- local mb = marks[bound]
- if mb then
- -- if not index then index = #mb + 1 end
- index = #mb + 1
- mb[index] = { dx, dy, rlmode }
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- return dx, dy, bound
+ nofregisteredmarks = nofregisteredmarks + 1
+ -- markanchors[nofregisteredmarks] = base
+ if rlmode >= 0 then
+ dx = tfmbase.width - dx -- see later commented ox
+ end
+ local p = rawget(properties,start)
+ if p then
+ local i = p.injections
+ if i then
+ i.markx = dx
+ i.marky = dy
+ i.markdir = rlmode or 0
+ i.markbase = nofregisteredmarks
+ i.markbasenode = base
else
- report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound)
+ p.injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ }
end
+ else
+ properties[start] = {
+ injections = {
+ markx = dx,
+ marky = dy,
+ markdir = rlmode or 0,
+ markbase = nofregisteredmarks,
+ markbasenode = base,
+ },
+ }
end
- index = index or 1
- bound = #marks + 1
- setattr(base,a_markbase,bound)
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- marks[bound] = { [index] = { dx, dy, rlmode } }
- return dx, dy, bound
+ return dx, dy, nofregisteredmarks
end
local function dir(n)
return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
end
-local function trace(head)
- report_injections("begin run")
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n) < 256 then
- local kp = getattr(n,a_kernpair)
- local mb = getattr(n,a_markbase)
- local mm = getattr(n,a_markmark)
- local md = getattr(n,a_markdone)
- local cb = getattr(n,a_cursbase)
- local cc = getattr(n,a_curscurs)
- local char = getchar(n)
- report_injections("font %s, char %U, glyph %c",getfont(n),char,char)
- if kp then
- local k = kerns[kp]
- if k[3] then
- report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5])
- else
- report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2])
+local function showchar(n,nested)
+ local char = getchar(n)
+ report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char)
+end
+
+local function show(n,what,nested,symbol)
+ if n then
+ local p = rawget(properties,n)
+ if p then
+ local p = p[what]
+ if p then
+ local leftkern = p.leftkern or 0
+ local rightkern = p.rightkern or 0
+ local yoffset = p.yoffset or 0
+ local markx = p.markx or 0
+ local marky = p.marky or 0
+ local markdir = p.markdir or 0
+ local markbase = p.markbase or 0 -- will be markbasenode
+ local cursivex = p.cursivex or 0
+ local cursivey = p.cursivey or 0
+ local ligaindex = p.ligaindex or 0
+ local margin = nested and 4 or 2
+ --
+ if rightkern ~= 0 or yoffset ~= 0 then
+ report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset)
+ elseif leftkern ~= 0 then
+ report_injections("%w%s kern: dx %p",margin,symbol,leftkern)
end
- end
- if mb then
- report_injections(" markbase: bound %a",mb)
- end
- if mm then
- local m = marks[mm]
- if mb then
- local m = m[mb]
- if m then
- report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2])
- else
- report_injections(" markmark: bound %a, missing index",mm)
- end
- else
- m = m[1]
- report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2])
+ if markx ~= 0 or marky ~= 0 or markbase ~= 0 then
+ report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase ~= 0 and "yes" or "no")
+ end
+ if cursivex ~= 0 or cursivey ~= 0 then
+ report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
+ end
+ if ligaindex ~= 0 then
+ report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
end
end
- if cb then
- report_injections(" cursbase: bound %a",cb)
+ end
+ end
+end
+
+local function showsub(n,what,where)
+ report_injections("begin subrun: %s",where)
+ for n in traverse_id(glyph_code,n) do
+ showchar(n,where)
+ show(n,what,where," ")
+ end
+ report_injections("end subrun")
+end
+
+local function trace(head)
+ report_injections("begin run: %s kerns, %s pairs, %s marks and %s cursives registered",
+ nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives)
+ local n = head
+ while n do
+ local id = getid(n)
+ if id == glyph_code then
+ showchar(n)
+ show(n,"injections",false," ")
+ show(n,"preinjections",false,"<")
+ show(n,"postinjections",false,">")
+ show(n,"replaceinjections",false,"=")
+ elseif id == disc_code then
+ local pre = getfield(n,"pre")
+ local post = getfield(n,"post")
+ local replace = getfield(n,"replace")
+ if pre then
+ showsub(pre,"preinjections","pre")
end
- if cc then
- local c = cursives[cc]
- report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3])
+ if post then
+ showsub(post,"postinjections","post")
+ end
+ if replace then
+ showsub(replace,"replaceinjections","replace")
end
end
+ n = getnext(n)
end
report_injections("end run")
end
--- todo: reuse tables (i.e. no collection), but will be extra fields anyway
--- todo: check for attribute
-
--- We can have a fast test on a font being processed, so we can check faster for marks etc
--- but I'll make a context variant anyway.
-
local function show_result(head)
- local current = head
+ local current = head
local skipping = false
while current do
local id = getid(current)
@@ -259,345 +406,616 @@ local function show_result(head)
end
end
-function injections.handler(head,where,keep)
- head = tonut(head)
- local has_marks, has_cursives, has_kerns = next(marks), next(cursives), next(kerns)
- if has_marks or has_cursives then
- if trace_injections then
- trace(head)
+-- we could also check for marks here but maybe not all are registered (needs checking)
+
+local function collect_glyphs_1(head)
+ local glyphs, nofglyphs = { }, 0
+ local marks, nofmarks = { }, 0
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ local f = getfont(n)
+ if f ~= nf then
+ nf = f
+ tm = fontdata[nf].resources.marks -- other hash in ctx
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks = nofmarks + 1
+ marks[nofmarks] = n
+ else
+ nofglyphs = nofglyphs + 1
+ glyphs[nofglyphs] = n
+ end
+ -- yoffsets can influence curs steps
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ end
end
- -- in the future variant we will not copy items but refs to tables
- local done, ky, rl, valid, cx, wx, mk, nofvalid = false, { }, { }, { }, { }, { }, { }, 0
- if has_kerns then -- move outside loop
- local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do -- only needed for relevant fonts
- if getsubtype(n) < 256 then
- nofvalid = nofvalid + 1
- valid[nofvalid] = n
- local f = getfont(n)
- if f ~= nf then
- nf = f
- tm = fontdata[nf].resources.marks -- other hash in ctx
+ end
+ return glyphs, nofglyphs, marks, nofmarks
+end
+
+local function collect_glyphs_2(head)
+ local glyphs, nofglyphs = { }, 0
+ local marks, nofmarks = { }, 0
+ local nf, tm = nil, nil
+ for n in traverse_id(glyph_code,head) do
+ if getsubtype(n) < 256 then
+ local f = getfont(n)
+ if f ~= nf then
+ nf = f
+ tm = fontdata[nf].resources.marks -- other hash in ctx
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks = nofmarks + 1
+ marks[nofmarks] = n
+ else
+ nofglyphs = nofglyphs + 1
+ glyphs[nofglyphs] = n
+ end
+ end
+ end
+ return glyphs, nofglyphs, marks, nofmarks
+end
+
+local function inject_marks(marks,nofmarks)
+ for i=1,nofmarks do
+ local n = marks[i]
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ if pn then
+ -- local markbase = pn.markbase
+ -- if markbase then
+ -- local p = markanchors[markbase]
+ local p = pn.markbasenode
+ if p then
+ local px = getfield(p,"xoffset")
+ local ox = 0
+ local pp = rawget(properties,p)
+ local rightkern = pp and pp.rightkern
+ if rightkern then -- x and w ~= 0
+ if pn.markdir < 0 then
+ -- kern(w-x) glyph(p) kern(x) mark(n)
+ ox = px - pn.markx - rightkern
+ -- report_injections("r2l case 1: %p",ox)
+ else
+ -- kern(x) glyph(p) kern(w-x) mark(n)
+ -- ox = px - getfield(p,"width") + pn.markx - pp.leftkern
+ ox = px - pn.markx - pp.leftkern
+ -- report_injections("l2r case 1: %p",ox)
+ end
+ else
+ -- we need to deal with fonts that have marks with width
+ -- if pn.markdir < 0 then
+ -- ox = px - pn.markx
+ -- -- report_injections("r2l case 3: %p",ox)
+ -- else
+ -- -- ox = px - getfield(p,"width") + pn.markx
+ ox = px - pn.markx
+ -- report_injections("l2r case 3: %p",ox)
+ -- end
+ local wn = getfield(n,"width") -- in arial marks have widths
+ if wn ~= 0 then
+ -- bad: we should center
+ -- insert_node_before(head,n,newkern(-wn/2))
+ -- insert_node_after(head,n,newkern(-wn/2))
+ pn.leftkern = -wn/2
+ pn.rightkern = -wn/2
+ -- wx[n] = { 0, -wn/2, 0, -wn }
+ end
+ -- so far
end
- if tm then
- mk[n] = tm[getchar(n)]
+ setfield(n,"xoffset",ox)
+ --
+ local py = getfield(p,"yoffset")
+ local oy = 0
+ if marks[p] then
+ oy = py + pn.marky
+ else
+ oy = getfield(n,"yoffset") + py + pn.marky
end
- local k = getattr(n,a_kernpair)
- if k then
- local kk = kerns[k]
- if kk then
- local x, y, w, h = kk[2] or 0, kk[3] or 0, kk[4] or 0, kk[5] or 0
- local dy = y - h
- if dy ~= 0 then
- ky[n] = dy
- end
- if w ~= 0 or x ~= 0 then
- wx[n] = kk
- end
- rl[n] = kk[1] -- could move in test
+ setfield(n,"yoffset",oy)
+ else
+ -- normally this can't happen (only when in trace mode which is a special case anyway)
+ -- report_injections("missing mark anchor %i",pn.markbase or 0)
+ end
+ -- end
+ end
+ end
+end
+
+local function inject_cursives(glyphs,nofglyphs)
+ local cursiveanchor, lastanchor = nil, nil
+ local minc, maxc, last = 0, 0, nil
+ for i=1,nofglyphs do
+ local n = glyphs[i]
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ if pn then
+ local cursivex = pn.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex ~= 0 then
+ pn.leftkern = pn.leftkern or 0 + cursivex
+ end
+ if lastanchor then
+ if maxc == 0 then
+ minc = lastanchor
end
+ maxc = lastanchor
+ properties[cursiveanchor].cursivedy = pn.cursivey
end
+ last = n
+ else
+ maxc = 0
+ end
+ elseif maxc > 0 then
+ local ny = getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",ny) -- why not add ?
end
+ maxc = 0
end
- else
- local nf, tm = nil, nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n) < 256 then
- nofvalid = nofvalid + 1
- valid[nofvalid] = n
- local f = getfont(n)
- if f ~= nf then
- nf = f
- tm = fontdata[nf].resources.marks -- other hash in ctx
- end
- if tm then
- mk[n] = tm[getchar(n)]
+ if pn.cursiveanchor then
+ cursiveanchor = n
+ lastanchor = i
+ else
+ cursiveanchor = nil
+ lastanchor = nil
+ if maxc > 0 then
+ local ny = getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",ny) -- why not add ?
end
+ maxc = 0
end
end
+ elseif maxc > 0 then
+ local ny = getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",getfield(ti,"yoffset") + ny) -- ?
+ end
+ maxc = 0
+ cursiveanchor = nil
+ lastanchor = nil
end
- if nofvalid > 0 then
- -- we can assume done == true because we have cursives and marks
- local cx = { }
- if has_kerns and next(ky) then
- for n, k in next, ky do
- setfield(n,"yoffset",k)
- end
+ -- if maxc > 0 and not cursiveanchor then
+ -- local ny = getfield(n,"yoffset")
+ -- for i=maxc,minc,-1 do
+ -- local ti = glyphs[i]
+ -- ny = ny + properties[ti].cursivedy
+ -- setfield(ti,"yoffset",ny) -- why not add ?
+ -- end
+ -- maxc = 0
+ -- end
+ end
+ if last and maxc > 0 then
+ local ny = getfield(last,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti = glyphs[i]
+ ny = ny + properties[ti].cursivedy
+ setfield(ti,"yoffset",ny) -- why not add ?
+ end
+ end
+end
+
+local function inject_kerns(head,glyphs,nofglyphs)
+ -- todo: pre/post/replace
+ for i=1,#glyphs do
+ local n = glyphs[i]
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.injections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ insert_node_before(head,n,newkern(leftkern)) -- type 0/2
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern)) -- type 0/2
end
- -- todo: reuse t and use maxt
- if has_cursives then
- local p_cursbase, p = nil, nil
- -- since we need valid[n+1] we can also use a "while true do"
- local t, d, maxt = { }, { }, 0
- for i=1,nofvalid do -- valid == glyphs
- local n = valid[i]
- if not mk[n] then
- local n_cursbase = getattr(n,a_cursbase)
- if p_cursbase then
- local n_curscurs = getattr(n,a_curscurs)
- if p_cursbase == n_curscurs then
- local c = cursives[n_curscurs]
- if c then
- local rlmode, dx, dy, ws, wn = c[1], c[2], c[3], c[4], c[5]
- if rlmode >= 0 then
- dx = dx - ws
- else
- dx = dx + wn
- end
- if dx ~= 0 then
- cx[n] = dx
- rl[n] = rlmode
- end
- -- if rlmode and rlmode < 0 then
- dy = -dy
- -- end
- maxt = maxt + 1
- t[maxt] = p
- d[maxt] = dy
- else
- maxt = 0
+ end
+ end
+end
+
+local function inject_everything(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local glyphs, nofglyphs, marks, nofmarks
+ if nofregisteredpairs > 0 then
+ glyphs, nofglyphs, marks, nofmarks = collect_glyphs_1(head)
+ else
+ glyphs, nofglyphs, marks, nofmarks = collect_glyphs_2(head)
+ end
+ if nofglyphs > 0 then
+ if nofregisteredcursives > 0 then
+ inject_cursives(glyphs,nofglyphs)
+ end
+ if nofregisteredmarks > 0 then
+ inject_marks(marks,nofmarks)
+ end
+ inject_kerns(head,glyphs,nofglyphs)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ nofregisteredpairs = 0
+ nofregisteredmarks = 0
+ nofregisteredcursives = 0
+ end
+ return tonode(head), true
+end
+
+local function inject_kerns_only(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local n = head
+ local p = nil
+ while n do
+ local id = getid(n)
+ if id == glyph_code then
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ if p then
+ local d = getfield(p,"post")
+ if d then
+ local pn = pn.postinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
end
- elseif maxt > 0 then
- local ny = getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- setfield(ti,"yoffset",getfield(ti,"yoffset") + ny)
+ end
+ local d = getfield(p,"replace")
+ if d then
+ local pn = pn.replaceinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ end
+ else
+ local pn = pn.injections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ setfield(p,"replace",newkern(leftkern))
+ end
end
- maxt = 0
end
- if not n_cursbase and maxt > 0 then
- local ny = getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- setfield(ti,"yoffset",ny) -- maybe add to current yoffset
+ else
+ local pn = pn.injections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ head = insert_node_before(head,n,newkern(leftkern))
end
- maxt = 0
end
- p_cursbase, p = n_cursbase, n
end
end
- if maxt > 0 then
- local ny = getfield(n,"yoffset") -- hm, n unset ?
- for i=maxt,1,-1 do
- ny = ny + d[i]
- local ti = t[i]
- setfield(ti,"yoffset",ny)
+ else
+ break
+ end
+ p = nil
+ elseif id == disc_code then
+ local d = getfield(n,"pre")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.preinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ end
+ else
+ break
end
- maxt = 0
end
- if not keep then
- cursives = { }
+ if h ~= d then
+ setfield(n,"pre",h)
end
end
- if has_marks then
- for i=1,nofvalid do
- local p = valid[i]
- local p_markbase = getattr(p,a_markbase)
- if p_markbase then
- local mrks = marks[p_markbase]
- local nofmarks = #mrks
- for n in traverse_id(glyph_code,getnext(p)) do
- local n_markmark = getattr(n,a_markmark)
- if p_markbase == n_markmark then
- local index = getattr(n,a_markdone) or 1
- local d = mrks[index]
- if d then
- local rlmode = d[3]
- --
- local k = wx[p]
- local px = getfield(p,"xoffset")
- local ox = 0
- if k then
- local x = k[2]
- local w = k[4]
- if w then
- if rlmode and rlmode >= 0 then
- -- kern(x) glyph(p) kern(w-x) mark(n)
- ox = px - getfield(p,"width") + d[1] - (w-x)
- -- report_injections("l2r case 1: %p",ox)
- else
- -- kern(w-x) glyph(p) kern(x) mark(n)
- ox = px - d[1] - x
- -- report_injections("r2l case 1: %p",ox)
- end
- else
- if rlmode and rlmode >= 0 then
- -- okay for husayni
- ox = px - getfield(p,"width") + d[1]
- -- report_injections("r2l case 2: %p",ox)
- else
- -- needs checking: is x ok here?
- ox = px - d[1] - x
- -- report_injections("r2l case 2: %p",ox)
- end
- end
- else
- -- if rlmode and rlmode >= 0 then
- -- ox = px - getfield(p,"width") + d[1]
- -- -- report_injections("l2r case 3: %p",ox)
- -- else
- -- ox = px - d[1]
- -- -- report_injections("r2l case 3: %p",ox)
- -- end
- --
- -- we need to deal with fonts that have marks with width
- --
- local wp = getfield(p,"width")
- local wn = getfield(n,"width") -- in arial marks have widths
- if rlmode and rlmode >= 0 then
- ox = px - wp + d[1]
- -- report_injections("l2r case 3: %p",ox)
- else
- ox = px - d[1]
- -- report_injections("r2l case 3: %p",ox)
- end
- if wn ~= 0 then
- -- bad: we should center
- insert_node_before(head,n,newkern(-wn/2))
- insert_node_after(head,n,newkern(-wn/2))
- -- wx[n] = { 0, -wn/2, 0, -wn }
- end
- -- so far
- end
- setfield(n,"xoffset",ox)
- --
- local py = getfield(p,"yoffset")
- local oy = 0
- if mk[p] then
- oy = py + d[2]
- else
- oy = getfield(n,"yoffset") + py + d[2]
- end
- setfield(n,"yoffset",oy)
- --
- if nofmarks == 1 then
- break
- else
- nofmarks = nofmarks - 1
- end
- end
- elseif not n_markmark then
- break -- HH: added 2013-09-12: no need to deal with non marks
- else
- -- KE: there can be <mark> <mkmk> <mark> sequences in ligatures
+ local d = getfield(n,"post")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.postinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
end
end
+ else
+ break
end
end
- if not keep then
- marks = { }
+ if h ~= d then
+ setfield(n,"post",h)
end
end
- -- todo : combine
- if next(wx) then
- for n, k in next, wx do
- -- only w can be nil (kernclasses), can be sped up when w == nil
- local x = k[2]
- local w = k[4]
- if w then
- local rl = k[1] -- r2l = k[6]
- local wx = w - x
- if rl < 0 then -- KE: don't use r2l here
- if wx ~= 0 then
- insert_node_before(head,n,newkern(wx)) -- type 0/2
+ local d = getfield(n,"replace")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n) -- why can it be empty { }
+ if pn then
+ pn = pn.replaceinjections
+ end
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
end
- if x ~= 0 then
- insert_node_after (head,n,newkern(x)) -- type 0/2
+ end
+ else
+ break
+ end
+ end
+ if h ~= d then
+ setfield(n,"replace",h)
+ end
+ end
+ p = n
+ else
+ p = nil
+ end
+ n = getnext(n)
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredkerns = 0
+ end
+ return tonode(head), true
+end
+
+local function inject_pairs_only(head,where)
+ head = tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ --
+ local n = head
+ local p = nil
+ while n do
+ local id = getid(n)
+ if id == glyph_code then
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ if p then
+ local d = getfield(p,"post")
+ if d then
+ local pn = pn.postinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ -- local rightkern = pn.rightkern
+ -- if rightkern and rightkern ~= 0 then
+ -- insert_node_after(head,n,newkern(rightkern))
+ -- n = getnext(n) -- to be checked
+ -- end
+ end
+ end
+ local d = getfield(p,"replace")
+ if d then
+ local pn = pn.replaceinjections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ local t = find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ -- local rightkern = pn.rightkern
+ -- if rightkern and rightkern ~= 0 then
+ -- insert_node_after(head,n,newkern(rightkern))
+ -- n = getnext(n) -- to be checked
+ -- end
end
else
- if x ~= 0 then
- insert_node_before(head,n,newkern(x)) -- type 0/2
+ local pn = pn.injections
+ if pn then
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ setfield(p,"replace",newkern(leftkern))
+ end
+ -- local rightkern = pn.rightkern
+ -- if rightkern and rightkern ~= 0 then
+ -- insert_node_after(head,n,newkern(rightkern))
+ -- n = getnext(n) -- to be checked
+ -- end
+ end
+ end
+ else
+ -- this is the most common case
+ local pn = pn.injections
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
end
- if wx ~= 0 then
- insert_node_after (head,n,newkern(wx)) -- type 0/2
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ insert_node_before(head,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
end
end
- elseif x ~= 0 then
- -- this needs checking for rl < 0 but it is unlikely that a r2l script
- -- uses kernclasses between glyphs so we're probably safe (KE has a
- -- problematic font where marks interfere with rl < 0 in the previous
- -- case)
- insert_node_before(head,n,newkern(x)) -- a real font kern, type 0
end
end
+ else
+ break
end
- if next(cx) then
- for n, k in next, cx do
- if k ~= 0 then
- local rln = rl[n]
- if rln and rln < 0 then
- insert_node_before(head,n,newkern(-k)) -- type 0/2
- else
- insert_node_before(head,n,newkern(k)) -- type 0/2
+ p = nil
+ elseif id == disc_code then
+ local d = getfield(n,"pre")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.preinjections
end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
+ end
+ end
+ else
+ break
end
end
+ if h ~= d then
+ setfield(n,"pre",h)
+ end
end
- if not keep then
- kerns = { }
+ local d = getfield(n,"post")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.postinjections
+ end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
+ end
+ end
+ else
+ break
+ end
+ end
+ if h ~= d then
+ setfield(n,"post",h)
+ end
end
- -- if trace_injections then
- -- show_result(head)
- -- end
- return tonode(head), true
- elseif not keep then
- kerns, cursives, marks = { }, { }, { }
- end
- elseif has_kerns then
- if trace_injections then
- trace(head)
- end
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n) < 256 then
- local k = getattr(n,a_kernpair)
- if k then
- local kk = kerns[k]
- if kk then
- local rl, x, y, w = kk[1], kk[2] or 0, kk[3], kk[4]
- if y and y ~= 0 then
- setfield(n,"yoffset",y) -- todo: h ?
+ local d = getfield(n,"replace")
+ if d then
+ local h = d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n) < 256 then
+ local pn = rawget(properties,n)
+ if pn then
+ pn = pn.replaceinjections
end
- if w then
- -- copied from above
- -- local r2l = kk[6]
- local wx = w - x
- if rl < 0 then -- KE: don't use r2l here
- if wx ~= 0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x ~= 0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx ~= 0 then
- insert_node_after(head,n,newkern(wx))
- end
+ if pn then
+ local yoffset = pn.yoffset
+ if yoffset and yoffset ~= 0 then
+ setfield(n,"yoffset",yoffset)
end
- else
- -- simple (e.g. kernclass kerns)
- if x ~= 0 then
- insert_node_before(head,n,newkern(x))
+ local leftkern = pn.leftkern
+ if leftkern ~= 0 then
+ h = insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern = pn.rightkern
+ if rightkern and rightkern ~= 0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n = getnext(n) -- to be checked
end
end
+ else
+ break
end
end
+ if h ~= d then
+ setfield(n,"replace",h)
+ end
end
+ p = n
+ else
+ p = nil
end
- if not keep then
- kerns = { }
- end
- -- if trace_injections then
- -- show_result(head)
- -- end
- return tonode(head), true
+ n = getnext(n)
+ end
+ --
+ if keepregisteredcounts then
+ keepregisteredcounts = false
+ else
+ nofregisteredpairs = 0
+ nofregisteredkerns = 0
+ end
+ return tonode(head), true
+end
+
+function injections.handler(head,where) -- optimize for n=1 ?
+ if nofregisteredmarks > 0 or nofregisteredcursives > 0 then
+ return inject_everything(head,where)
+ elseif nofregisteredpairs > 0 then
+ return inject_pairs_only(head,where)
+ elseif nofregisteredkerns > 0 then
+ return inject_kerns_only(head,where)
else
- -- no tracing needed
+ return head, false
end
- return tonode(head), false
end
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index f11a74ca5..96a7dd361 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 : 12/11/14 12:02:53
+-- merge date : 12/21/14 22:25:48
do -- begin closure to overcome local limits and interference
@@ -3889,8 +3889,6 @@ nodes.set_attribute=node.set_attribute
nodes.unset_attribute=node.unset_attribute
nodes.protect_glyphs=node.protect_glyphs
nodes.unprotect_glyphs=node.unprotect_glyphs
-nodes.kerning=node.kerning
-nodes.ligaturing=node.ligaturing
nodes.mlist_to_hlist=node.mlist_to_hlist
local direct=node.direct
local nuts={}
@@ -3917,8 +3915,12 @@ nuts.insert_before=direct.insert_before
nuts.insert_after=direct.insert_after
nuts.delete=direct.delete
nuts.copy=direct.copy
+nuts.copy_list=direct.copy_list
nuts.tail=direct.tail
nuts.flush_list=direct.flush_list
+nuts.free=direct.free
+nuts.remove=direct.remove
+nuts.is_node=direct.is_node
nuts.end_of_math=direct.end_of_math
nuts.traverse=direct.traverse
nuts.traverse_id=direct.traverse_id
@@ -8730,6 +8732,7 @@ actions["reorganize glyph lookups"]=function(data,filename,raw)
end
end
end
+local zero={ 0,0 }
actions["reorganize glyph anchors"]=function(data,filename,raw)
local descriptions=data.descriptions
for unicode,description in next,descriptions do
@@ -8738,14 +8741,32 @@ actions["reorganize glyph anchors"]=function(data,filename,raw)
for class,data in next,anchors do
if class=="baselig" then
for tag,specification in next,data do
- for i=1,#specification do
- local si=specification[i]
- specification[i]={ si.x or 0,si.y or 0 }
+ local n=0
+ for k,v in next,specification do
+ if k>n then
+ n=k
+ end
+ local x,y=v.x,v.y
+ if x or y then
+ specification[k]={ x or 0,y or 0 }
+ else
+ specification[k]=zero
+ end
+ end
+ local t={}
+ for i=1,n do
+ t[i]=specification[i] or zero
end
+ data[tag]=t
end
else
for tag,specification in next,data do
- data[tag]={ specification.x or 0,specification.y or 0 }
+ local x,y=specification.x,specification.y
+ if x or y then
+ data[tag]={ x or 0,y or 0 }
+ else
+ data[tag]=zero
+ end
end
end
end
@@ -9819,17 +9840,19 @@ end -- closure
do -- begin closure to overcome local limits and interference
-if not modules then modules={} end modules ['node-inj']={
+if not modules then modules={} end modules ['font-inj']={
version=1.001,
- comment="companion to node-ini.mkiv",
+ comment="companion to font-lib.mkiv",
author="Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright="PRAGMA ADE / ConTeXt Development Team",
license="see context related readme files",
}
-local next=next
+if not nodes.properties then return end
+local next,rawget=next,rawget
local utfchar=utf.char
-local trace_injections=false trackers.register("nodes.injections",function(v) trace_injections=v end)
-local report_injections=logs.reporter("nodes","injections")
+local trace_injections=false trackers.register("fonts.injections",function(v) trace_injections=v end)
+local report_injections=logs.reporter("fonts","injections")
+report_injections("using experimental injector")
local attributes,nodes,node=attributes,nodes,node
fonts=fonts
local fontdata=fonts.hashes.identifiers
@@ -9837,6 +9860,7 @@ nodes.injections=nodes.injections or {}
local injections=nodes.injections
local nodecodes=nodes.nodecodes
local glyph_code=nodecodes.glyph
+local disc_code=nodecodes.disc
local kern_code=nodecodes.kern
local nuts=nodes.nuts
local nodepool=nuts.pool
@@ -9844,149 +9868,316 @@ local newkern=nodepool.kern
local tonode=nuts.tonode
local tonut=nuts.tonut
local getfield=nuts.getfield
+local setfield=nuts.setfield
local getnext=nuts.getnext
local getprev=nuts.getprev
local getid=nuts.getid
-local getattr=nuts.getattr
local getfont=nuts.getfont
local getsubtype=nuts.getsubtype
local getchar=nuts.getchar
-local setfield=nuts.setfield
-local setattr=nuts.setattr
local traverse_id=nuts.traverse_id
local insert_node_before=nuts.insert_before
local insert_node_after=nuts.insert_after
-local a_kernpair=attributes.private('kernpair')
-local a_ligacomp=attributes.private('ligacomp')
-local a_markbase=attributes.private('markbase')
-local a_markmark=attributes.private('markmark')
-local a_markdone=attributes.private('markdone')
-local a_cursbase=attributes.private('cursbase')
-local a_curscurs=attributes.private('curscurs')
-local a_cursdone=attributes.private('cursdone')
-local unsetvalue=attributes.unsetvalue
+local find_tail=nuts.tail
+local properties=nodes.properties.data
function injections.installnewkern(nk)
newkern=nk or newkern
end
-local cursives={}
-local marks={}
-local kerns={}
+local nofregisteredkerns=0
+local nofregisteredpairs=0
+local nofregisteredmarks=0
+local nofregisteredcursives=0
+local keepregisteredcounts=false
+function injections.keepcounts()
+ keepregisteredcounts=true
+end
+function injections.resetcounts()
+ nofregisteredkerns=0
+ nofregisteredpairs=0
+ nofregisteredmarks=0
+ nofregisteredcursives=0
+ keepregisteredcounts=false
+end
function injections.reset(n)
+ local p=rawget(properties,start)
+ if p and p.injections then
+ p.injections=nil
+ end
end
function injections.setligaindex(n,index)
- setattr(n,a_ligacomp,index)
+ local p=rawget(properties,n)
+ if p then
+ local i=p.injections
+ if i then
+ i.ligaindex=index
+ else
+ p.injections={
+ ligaindex=index
+ }
+ end
+ else
+ properties[n]={
+ injections={
+ ligaindex=index
+ }
+ }
+ end
end
function injections.getligaindex(n,default)
- return getattr(n,a_ligacomp) or default
+ local p=rawget(properties,n)
+ if p then
+ p=p.injections
+ if p then
+ return p.ligaindex or default
+ end
+ end
+ return default
end
-function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
- local dx,dy=factor*(exit[1]-entry[1]),factor*(exit[2]-entry[2])
+function injections.setcursive(start,nxt,factor,rlmode,exit,entry,tfmstart,tfmnext)
+ local dx=factor*(exit[1]-entry[1])
+ local dy=-factor*(exit[2]-entry[2])
local ws,wn=tfmstart.width,tfmnext.width
- local bound=#cursives+1
- setattr(start,a_cursbase,bound)
- setattr(nxt,a_curscurs,bound)
- cursives[bound]={ rlmode,dx,dy,ws,wn }
- return dx,dy,bound
-end
-function injections.setpair(current,factor,rlmode,r2lflag,spec,tfmchr)
- local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4]
- if x~=0 or w~=0 or y~=0 or h~=0 then
- local bound=getattr(current,a_kernpair)
- if bound then
- local kb=kerns[bound]
- kb[2],kb[3],kb[4],kb[5]=(kb[2] or 0)+x,(kb[3] or 0)+y,(kb[4] or 0)+w,(kb[5] or 0)+h
+ nofregisteredcursives=nofregisteredcursives+1
+ if rlmode<0 then
+ dx=-(dx+wn)
+ else
+ dx=dx-ws
+ end
+ local p=rawget(properties,start)
+ if p then
+ local i=p.injections
+ if i then
+ i.cursiveanchor=true
+ else
+ p.injections={
+ cursiveanchor=true,
+ }
+ end
+ else
+ properties[start]={
+ injections={
+ cursiveanchor=true,
+ },
+ }
+ end
+ local p=rawget(properties,nxt)
+ if p then
+ local i=p.injections
+ if i then
+ i.cursivex=dx
+ i.cursivey=dy
else
- bound=#kerns+1
- setattr(current,a_kernpair,bound)
- kerns[bound]={ rlmode,x,y,w,h,r2lflag,tfmchr.width }
+ p.injections={
+ cursivex=dx,
+ cursivey=dy,
+ }
end
- return x,y,w,h,bound
+ else
+ properties[nxt]={
+ injections={
+ cursivex=dx,
+ cursivey=dy,
+ },
+ }
+ end
+ return dx,dy,nofregisteredcursives
+end
+function injections.setpair(current,factor,rlmode,r2lflag,spec,injection)
+ local x,y,w,h=factor*spec[1],factor*spec[2],factor*spec[3],factor*spec[4]
+ if x~=0 or w~=0 or y~=0 or h~=0 then
+ local yoffset=y-h
+ local leftkern=x
+ local rightkern=w-x
+ if leftkern~=0 or rightkern~=0 or yoffset~=0 then
+ nofregisteredpairs=nofregisteredpairs+1
+ if rlmode and rlmode<0 then
+ leftkern,rightkern=rightkern,leftkern
+ end
+ local p=rawget(properties,current)
+ if p then
+ local i=p.injections
+ if i then
+ if leftkern~=0 or rightkern~=0 then
+ i.leftkern=i.leftkern or 0+leftkern
+ i.rightkern=i.rightkern or 0+rightkern
+ end
+ if yoffset~=0 then
+ i.yoffset=i.yoffset or 0+yoffset
+ end
+ elseif leftkern~=0 or rightkern~=0 then
+ p.injections={
+ leftkern=leftkern,
+ rightkern=rightkern,
+ yoffset=yoffset,
+ }
+ else
+ p.injections={
+ yoffset=yoffset,
+ }
+ end
+ elseif leftkern~=0 or rightkern~=0 then
+ properties[current]={
+ injections={
+ leftkern=leftkern,
+ rightkern=rightkern,
+ yoffset=yoffset,
+ },
+ }
+ else
+ properties[current]={
+ injections={
+ yoffset=yoffset,
+ },
+ }
+ end
+ return x,y,w,h,nofregisteredpairs
+ end
end
return x,y,w,h
end
-function injections.setkern(current,factor,rlmode,x,tfmchr)
+function injections.setkern(current,factor,rlmode,x,injection)
local dx=factor*x
if dx~=0 then
- local bound=#kerns+1
- setattr(current,a_kernpair,bound)
- kerns[bound]={ rlmode,dx }
- return dx,bound
+ nofregisteredkerns=nofregisteredkerns+1
+ local p=rawget(properties,current)
+ if not injection then
+ injection="injections"
+ end
+ if p then
+ local i=p[injection]
+ if i then
+ i.leftkern=dx+i.leftkern or 0
+ else
+ p[injection]={
+ leftkern=dx,
+ }
+ end
+ else
+ properties[current]={
+ [injection]={
+ leftkern=dx,
+ },
+ }
+ end
+ return dx,nofregisteredkerns
else
return 0,0
end
end
-function injections.setmark(start,base,factor,rlmode,ba,ma)
+function injections.setmark(start,base,factor,rlmode,ba,ma,tfmbase)
local dx,dy=factor*(ba[1]-ma[1]),factor*(ba[2]-ma[2])
- local bound=getattr(base,a_markbase)
- local index=1
- if bound then
- local mb=marks[bound]
- if mb then
- index=#mb+1
- mb[index]={ dx,dy,rlmode }
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- return dx,dy,bound
+ nofregisteredmarks=nofregisteredmarks+1
+ if rlmode>=0 then
+ dx=tfmbase.width-dx
+ end
+ local p=rawget(properties,start)
+ if p then
+ local i=p.injections
+ if i then
+ i.markx=dx
+ i.marky=dy
+ i.markdir=rlmode or 0
+ i.markbase=nofregisteredmarks
+ i.markbasenode=base
else
- report_injections("possible problem, %U is base mark without data (id %a)",getchar(base),bound)
+ p.injections={
+ markx=dx,
+ marky=dy,
+ markdir=rlmode or 0,
+ markbase=nofregisteredmarks,
+ markbasenode=base,
+ }
end
+ else
+ properties[start]={
+ injections={
+ markx=dx,
+ marky=dy,
+ markdir=rlmode or 0,
+ markbase=nofregisteredmarks,
+ markbasenode=base,
+ },
+ }
end
- index=index or 1
- bound=#marks+1
- setattr(base,a_markbase,bound)
- setattr(start,a_markmark,bound)
- setattr(start,a_markdone,index)
- marks[bound]={ [index]={ dx,dy,rlmode } }
- return dx,dy,bound
+ return dx,dy,nofregisteredmarks
end
local function dir(n)
return (n and n<0 and "r-to-l") or (n and n>0 and "l-to-r") or "unset"
end
-local function trace(head)
- report_injections("begin run")
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- local kp=getattr(n,a_kernpair)
- local mb=getattr(n,a_markbase)
- local mm=getattr(n,a_markmark)
- local md=getattr(n,a_markdone)
- local cb=getattr(n,a_cursbase)
- local cc=getattr(n,a_curscurs)
- local char=getchar(n)
- report_injections("font %s, char %U, glyph %c",getfont(n),char,char)
- if kp then
- local k=kerns[kp]
- if k[3] then
- report_injections(" pairkern: dir %a, x %p, y %p, w %p, h %p",dir(k[1]),k[2],k[3],k[4],k[5])
- else
- report_injections(" kern: dir %a, dx %p",dir(k[1]),k[2])
+local function showchar(n,nested)
+ local char=getchar(n)
+ report_injections("%wfont %s, char %U, glyph %c",nested and 2 or 0,getfont(n),char,char)
+end
+local function show(n,what,nested,symbol)
+ if n then
+ local p=rawget(properties,n)
+ if p then
+ local p=p[what]
+ if p then
+ local leftkern=p.leftkern or 0
+ local rightkern=p.rightkern or 0
+ local yoffset=p.yoffset or 0
+ local markx=p.markx or 0
+ local marky=p.marky or 0
+ local markdir=p.markdir or 0
+ local markbase=p.markbase or 0
+ local cursivex=p.cursivex or 0
+ local cursivey=p.cursivey or 0
+ local ligaindex=p.ligaindex or 0
+ local margin=nested and 4 or 2
+ if rightkern~=0 or yoffset~=0 then
+ report_injections("%w%s pair: lx %p, rx %p, dy %p",margin,symbol,leftkern,rightkern,yoffset)
+ elseif leftkern~=0 then
+ report_injections("%w%s kern: dx %p",margin,symbol,leftkern)
end
- end
- if mb then
- report_injections(" markbase: bound %a",mb)
- end
- if mm then
- local m=marks[mm]
- if mb then
- local m=m[mb]
- if m then
- report_injections(" markmark: bound %a, index %a, dx %p, dy %p",mm,md,m[1],m[2])
- else
- report_injections(" markmark: bound %a, missing index",mm)
- end
- else
- m=m[1]
- report_injections(" markmark: bound %a, dx %p, dy %p",mm,m and m[1],m and m[2])
+ if markx~=0 or marky~=0 or markbase~=0 then
+ report_injections("%w%s mark: dx %p, dy %p, dir %s, base %s",margin,symbol,markx,marky,markdir,markbase~=0 and "yes" or "no")
+ end
+ if cursivex~=0 or cursivey~=0 then
+ report_injections("%w%s curs: dx %p, dy %p",margin,symbol,cursivex,cursivey)
+ end
+ if ligaindex~=0 then
+ report_injections("%w%s liga: index %i",margin,symbol,ligaindex)
end
end
- if cb then
- report_injections(" cursbase: bound %a",cb)
+ end
+ end
+end
+local function showsub(n,what,where)
+ report_injections("begin subrun: %s",where)
+ for n in traverse_id(glyph_code,n) do
+ showchar(n,where)
+ show(n,what,where," ")
+ end
+ report_injections("end subrun")
+end
+local function trace(head)
+ report_injections("begin run: %s kerns, %s pairs, %s marks and %s cursives registered",
+ nofregisteredkerns,nofregisteredpairs,nofregisteredmarks,nofregisteredcursives)
+ local n=head
+ while n do
+ local id=getid(n)
+ if id==glyph_code then
+ showchar(n)
+ show(n,"injections",false," ")
+ show(n,"preinjections",false,"<")
+ show(n,"postinjections",false,">")
+ show(n,"replaceinjections",false,"=")
+ elseif id==disc_code then
+ local pre=getfield(n,"pre")
+ local post=getfield(n,"post")
+ local replace=getfield(n,"replace")
+ if pre then
+ showsub(pre,"preinjections","pre")
+ end
+ if post then
+ showsub(post,"postinjections","post")
end
- if cc then
- local c=cursives[cc]
- report_injections(" curscurs: bound %a, dir %a, dx %p, dy %p",cc,dir(c[1]),c[2],c[3])
+ if replace then
+ showsub(replace,"replaceinjections","replace")
end
end
+ n=getnext(n)
end
report_injections("end run")
end
@@ -10009,298 +10200,553 @@ local function show_result(head)
current=getnext(current)
end
end
-function injections.handler(head,where,keep)
- head=tonut(head)
- local has_marks,has_cursives,has_kerns=next(marks),next(cursives),next(kerns)
- if has_marks or has_cursives then
- if trace_injections then
- trace(head)
- end
- local done,ky,rl,valid,cx,wx,mk,nofvalid=false,{},{},{},{},{},{},0
- if has_kerns then
- local nf,tm=nil,nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- nofvalid=nofvalid+1
- valid[nofvalid]=n
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
+local function collect_glyphs_1(head)
+ local glyphs,nofglyphs={},0
+ local marks,nofmarks={},0
+ local nf,tm=nil,nil
+ for n in traverse_id(glyph_code,head) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ local f=getfont(n)
+ if f~=nf then
+ nf=f
+ tm=fontdata[nf].resources.marks
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks=nofmarks+1
+ marks[nofmarks]=n
+ else
+ nofglyphs=nofglyphs+1
+ glyphs[nofglyphs]=n
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ end
+ end
+ end
+ return glyphs,nofglyphs,marks,nofmarks
+end
+local function collect_glyphs_2(head)
+ local glyphs,nofglyphs={},0
+ local marks,nofmarks={},0
+ local nf,tm=nil,nil
+ for n in traverse_id(glyph_code,head) do
+ if getsubtype(n)<256 then
+ local f=getfont(n)
+ if f~=nf then
+ nf=f
+ tm=fontdata[nf].resources.marks
+ end
+ if tm and tm[getchar(n)] then
+ nofmarks=nofmarks+1
+ marks[nofmarks]=n
+ else
+ nofglyphs=nofglyphs+1
+ glyphs[nofglyphs]=n
+ end
+ end
+ end
+ return glyphs,nofglyphs,marks,nofmarks
+end
+local function inject_marks(marks,nofmarks)
+ for i=1,nofmarks do
+ local n=marks[i]
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ if pn then
+ local p=pn.markbasenode
+ if p then
+ local px=getfield(p,"xoffset")
+ local ox=0
+ local pp=rawget(properties,p)
+ local rightkern=pp and pp.rightkern
+ if rightkern then
+ if pn.markdir<0 then
+ ox=px-pn.markx-rightkern
+ else
+ ox=px-pn.markx-pp.leftkern
+ end
+ else
+ ox=px-pn.markx
+ local wn=getfield(n,"width")
+ if wn~=0 then
+ pn.leftkern=-wn/2
+ pn.rightkern=-wn/2
+ end
+ end
+ setfield(n,"xoffset",ox)
+ local py=getfield(p,"yoffset")
+ local oy=0
+ if marks[p] then
+ oy=py+pn.marky
+ else
+ oy=getfield(n,"yoffset")+py+pn.marky
end
- if tm then
- mk[n]=tm[getchar(n)]
+ setfield(n,"yoffset",oy)
+ else
+ end
+ end
+ end
+end
+local function inject_cursives(glyphs,nofglyphs)
+ local cursiveanchor,lastanchor=nil,nil
+ local minc,maxc,last=0,0,nil
+ for i=1,nofglyphs do
+ local n=glyphs[i]
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ if pn then
+ local cursivex=pn.cursivex
+ if cursivex then
+ if cursiveanchor then
+ if cursivex~=0 then
+ pn.leftkern=pn.leftkern or 0+cursivex
end
- local k=getattr(n,a_kernpair)
- if k then
- local kk=kerns[k]
- if kk then
- local x,y,w,h=kk[2] or 0,kk[3] or 0,kk[4] or 0,kk[5] or 0
- local dy=y-h
- if dy~=0 then
- ky[n]=dy
- end
- if w~=0 or x~=0 then
- wx[n]=kk
- end
- rl[n]=kk[1]
+ if lastanchor then
+ if maxc==0 then
+ minc=lastanchor
end
+ maxc=lastanchor
+ properties[cursiveanchor].cursivedy=pn.cursivey
end
+ last=n
+ else
+ maxc=0
end
+ elseif maxc>0 then
+ local ny=getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",ny)
+ end
+ maxc=0
end
- else
- local nf,tm=nil,nil
- for n in traverse_id(glyph_code,head) do
- if getsubtype(n)<256 then
- nofvalid=nofvalid+1
- valid[nofvalid]=n
- local f=getfont(n)
- if f~=nf then
- nf=f
- tm=fontdata[nf].resources.marks
- end
- if tm then
- mk[n]=tm[getchar(n)]
+ if pn.cursiveanchor then
+ cursiveanchor=n
+ lastanchor=i
+ else
+ cursiveanchor=nil
+ lastanchor=nil
+ if maxc>0 then
+ local ny=getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",ny)
end
+ maxc=0
end
end
+ elseif maxc>0 then
+ local ny=getfield(n,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
+ end
+ maxc=0
+ cursiveanchor=nil
+ lastanchor=nil
end
- if nofvalid>0 then
- local cx={}
- if has_kerns and next(ky) then
- for n,k in next,ky do
- setfield(n,"yoffset",k)
- end
+ end
+ if last and maxc>0 then
+ local ny=getfield(last,"yoffset")
+ for i=maxc,minc,-1 do
+ local ti=glyphs[i]
+ ny=ny+properties[ti].cursivedy
+ setfield(ti,"yoffset",ny)
+ end
+ end
+end
+local function inject_kerns(head,glyphs,nofglyphs)
+ for i=1,#glyphs do
+ local n=glyphs[i]
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.injections
+ end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ insert_node_before(head,n,newkern(leftkern))
end
- if has_cursives then
- local p_cursbase,p=nil,nil
- local t,d,maxt={},{},0
- for i=1,nofvalid do
- local n=valid[i]
- if not mk[n] then
- local n_cursbase=getattr(n,a_cursbase)
- if p_cursbase then
- local n_curscurs=getattr(n,a_curscurs)
- if p_cursbase==n_curscurs then
- local c=cursives[n_curscurs]
- if c then
- local rlmode,dx,dy,ws,wn=c[1],c[2],c[3],c[4],c[5]
- if rlmode>=0 then
- dx=dx-ws
- else
- dx=dx+wn
- end
- if dx~=0 then
- cx[n]=dx
- rl[n]=rlmode
- end
- dy=-dy
- maxt=maxt+1
- t[maxt]=p
- d[maxt]=dy
- else
- maxt=0
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ end
+ end
+ end
+end
+local function inject_everything(head,where)
+ head=tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local glyphs,nofglyphs,marks,nofmarks
+ if nofregisteredpairs>0 then
+ glyphs,nofglyphs,marks,nofmarks=collect_glyphs_1(head)
+ else
+ glyphs,nofglyphs,marks,nofmarks=collect_glyphs_2(head)
+ end
+ if nofglyphs>0 then
+ if nofregisteredcursives>0 then
+ inject_cursives(glyphs,nofglyphs)
+ end
+ if nofregisteredmarks>0 then
+ inject_marks(marks,nofmarks)
+ end
+ inject_kerns(head,glyphs,nofglyphs)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts=false
+ else
+ nofregisteredkerns=0
+ nofregisteredpairs=0
+ nofregisteredmarks=0
+ nofregisteredcursives=0
+ end
+ return tonode(head),true
+end
+local function inject_kerns_only(head,where)
+ head=tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local n=head
+ local p=nil
+ while n do
+ local id=getid(n)
+ if id==glyph_code then
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ if p then
+ local d=getfield(p,"post")
+ if d then
+ local pn=pn.postinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
end
- elseif maxt>0 then
- local ny=getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- setfield(ti,"yoffset",getfield(ti,"yoffset")+ny)
- end
- maxt=0
- end
- if not n_cursbase and maxt>0 then
- local ny=getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- setfield(ti,"yoffset",ny)
- end
- maxt=0
- end
- p_cursbase,p=n_cursbase,n
- end
- end
- if maxt>0 then
- local ny=getfield(n,"yoffset")
- for i=maxt,1,-1 do
- ny=ny+d[i]
- local ti=t[i]
- setfield(ti,"yoffset",ny)
- end
- maxt=0
- end
- if not keep then
- cursives={}
- end
- end
- if has_marks then
- for i=1,nofvalid do
- local p=valid[i]
- local p_markbase=getattr(p,a_markbase)
- if p_markbase then
- local mrks=marks[p_markbase]
- local nofmarks=#mrks
- for n in traverse_id(glyph_code,getnext(p)) do
- local n_markmark=getattr(n,a_markmark)
- if p_markbase==n_markmark then
- local index=getattr(n,a_markdone) or 1
- local d=mrks[index]
- if d then
- local rlmode=d[3]
- local k=wx[p]
- local px=getfield(p,"xoffset")
- local ox=0
- if k then
- local x=k[2]
- local w=k[4]
- if w then
- if rlmode and rlmode>=0 then
- ox=px-getfield(p,"width")+d[1]-(w-x)
- else
- ox=px-d[1]-x
- end
- else
- if rlmode and rlmode>=0 then
- ox=px-getfield(p,"width")+d[1]
- else
- ox=px-d[1]-x
- end
- end
- else
- local wp=getfield(p,"width")
- local wn=getfield(n,"width")
- if rlmode and rlmode>=0 then
- ox=px-wp+d[1]
- else
- ox=px-d[1]
- end
- if wn~=0 then
- insert_node_before(head,n,newkern(-wn/2))
- insert_node_after(head,n,newkern(-wn/2))
- end
- end
- setfield(n,"xoffset",ox)
- local py=getfield(p,"yoffset")
- local oy=0
- if mk[p] then
- oy=py+d[2]
- else
- oy=getfield(n,"yoffset")+py+d[2]
- end
- setfield(n,"yoffset",oy)
- if nofmarks==1 then
- break
- else
- nofmarks=nofmarks-1
- end
+ end
+ local d=getfield(p,"replace")
+ if d then
+ local pn=pn.replaceinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
+ end
+ end
+ else
+ local pn=pn.injections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ setfield(p,"replace",newkern(leftkern))
end
- elseif not n_markmark then
- break
- else
+ end
+ end
+ else
+ local pn=pn.injections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ head=insert_node_before(head,n,newkern(leftkern))
end
end
end
end
- if not keep then
- marks={}
- end
+ else
+ break
end
- if next(wx) then
- for n,k in next,wx do
- local x=k[2]
- local w=k[4]
- if w then
- local rl=k[1]
- local wx=w-x
- if rl<0 then
- if wx~=0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x~=0 then
- insert_node_after (head,n,newkern(x))
- end
- else
- if x~=0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx~=0 then
- insert_node_after (head,n,newkern(wx))
+ p=nil
+ elseif id==disc_code then
+ local d=getfield(n,"pre")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.preinjections
+ end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
end
end
- elseif x~=0 then
- insert_node_before(head,n,newkern(x))
+ else
+ break
end
end
+ if h~=d then
+ setfield(n,"pre",h)
+ end
end
- if next(cx) then
- for n,k in next,cx do
- if k~=0 then
- local rln=rl[n]
- if rln and rln<0 then
- insert_node_before(head,n,newkern(-k))
- else
- insert_node_before(head,n,newkern(k))
+ local d=getfield(n,"post")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.postinjections
end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ end
+ else
+ break
end
end
+ if h~=d then
+ setfield(n,"post",h)
+ end
end
- if not keep then
- kerns={}
+ local d=getfield(n,"replace")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.replaceinjections
+ end
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"replace",h)
+ end
end
- return tonode(head),true
- elseif not keep then
- kerns,cursives,marks={},{},{}
- end
- elseif has_kerns then
- if trace_injections then
- trace(head)
+ p=n
+ else
+ p=nil
end
- for n in traverse_id(glyph_code,head) do
+ n=getnext(n)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts=false
+ else
+ nofregisteredkerns=0
+ end
+ return tonode(head),true
+end
+local function inject_pairs_only(head,where)
+ head=tonut(head)
+ if trace_injections then
+ trace(head)
+ end
+ local n=head
+ local p=nil
+ while n do
+ local id=getid(n)
+ if id==glyph_code then
if getsubtype(n)<256 then
- local k=getattr(n,a_kernpair)
- if k then
- local kk=kerns[k]
- if kk then
- local rl,x,y,w=kk[1],kk[2] or 0,kk[3],kk[4]
- if y and y~=0 then
- setfield(n,"yoffset",y)
- end
- if w then
- local wx=w-x
- if rl<0 then
- if wx~=0 then
- insert_node_before(head,n,newkern(wx))
- end
- if x~=0 then
- insert_node_after (head,n,newkern(x))
+ local pn=rawget(properties,n)
+ if pn then
+ if p then
+ local d=getfield(p,"post")
+ if d then
+ local pn=pn.postinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
- else
- if x~=0 then
- insert_node_before(head,n,newkern(x))
- end
- if wx~=0 then
- insert_node_after(head,n,newkern(wx))
+ end
+ end
+ local d=getfield(p,"replace")
+ if d then
+ local pn=pn.replaceinjections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ local t=find_tail(d)
+ insert_node_after(d,t,newkern(leftkern))
end
end
else
- if x~=0 then
- insert_node_before(head,n,newkern(x))
+ local pn=pn.injections
+ if pn then
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ setfield(p,"replace",newkern(leftkern))
+ end
+ end
+ end
+ else
+ local pn=pn.injections
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ insert_node_before(head,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
end
end
end
end
+ else
+ break
end
+ p=nil
+ elseif id==disc_code then
+ local d=getfield(n,"pre")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.preinjections
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"pre",h)
+ end
+ end
+ local d=getfield(n,"post")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.postinjections
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"post",h)
+ end
+ end
+ local d=getfield(n,"replace")
+ if d then
+ local h=d
+ for n in traverse_id(glyph_code,d) do
+ if getsubtype(n)<256 then
+ local pn=rawget(properties,n)
+ if pn then
+ pn=pn.replaceinjections
+ end
+ if pn then
+ local yoffset=pn.yoffset
+ if yoffset and yoffset~=0 then
+ setfield(n,"yoffset",yoffset)
+ end
+ local leftkern=pn.leftkern
+ if leftkern~=0 then
+ h=insert_node_before(h,n,newkern(leftkern))
+ end
+ local rightkern=pn.rightkern
+ if rightkern and rightkern~=0 then
+ insert_node_after(head,n,newkern(rightkern))
+ n=getnext(n)
+ end
+ end
+ else
+ break
+ end
+ end
+ if h~=d then
+ setfield(n,"replace",h)
+ end
+ end
+ p=n
+ else
+ p=nil
end
- if not keep then
- kerns={}
- end
- return tonode(head),true
+ n=getnext(n)
+ end
+ if keepregisteredcounts then
+ keepregisteredcounts=false
else
+ nofregisteredpairs=0
+ nofregisteredkerns=0
+ end
+ return tonode(head),true
+end
+function injections.handler(head,where)
+ if nofregisteredmarks>0 or nofregisteredcursives>0 then
+ return inject_everything(head,where)
+ elseif nofregisteredpairs>0 then
+ return inject_pairs_only(head,where)
+ elseif nofregisteredkerns>0 then
+ return inject_kerns_only(head,where)
+ else
+ return head,false
end
- return tonode(head),false
end
end -- closure
@@ -14565,10 +15011,24 @@ local disc_code=nodes.nodecodes.disc
local ligaturing=node.ligaturing
local kerning=node.kerning
local basepass=true
+local function l_warning() texio.write_nl("warning: node.ligaturing called directly") l_warning=nil end
+local function k_warning() texio.write_nl("warning: node.kerning called directly") k_warning=nil end
+function node.ligaturing(...)
+ if basepass and l_warning then
+ l_warning()
+ end
+ return ligaturing(...)
+end
+function node.kerning(...)
+ if basepass and k_warning then
+ k_warning()
+ end
+ return kerning(...)
+end
function nodes.handlers.setbasepass(v)
basepass=v
end
-function nodes.handlers.characters(head)
+function nodes.handlers.nodepass(head)
local fontdata=fonts.hashes.identifiers
if fontdata then
local usedfonts={}
@@ -14649,15 +15109,27 @@ function nodes.handlers.characters(head)
return head,false
end
end
-function nodes.simple_font_handler(head)
- head=nodes.handlers.characters(head)
- nodes.injections.handler(head)
+function nodes.handlers.basepass(head)
if not basepass then
head=ligaturing(head)
head=kerning(head)
end
- nodes.handlers.protectglyphs(head)
- return head
+ return head,true
+end
+local nodepass=nodes.handlers.nodepass
+local basepass=nodes.handlers.basepass
+local injectpass=nodes.injections.handler
+local protectpass=nodes.handlers.protectglyphs
+function nodes.simple_font_handler(head)
+ if head then
+ head=nodepass(head)
+ head=injectpass(head)
+ head=basepass(head)
+ protectpass(head)
+ return head,true
+ else
+ return head,false
+ end
end
end -- closure
diff --git a/tex/generic/context/luatex/luatex-fonts.lua b/tex/generic/context/luatex/luatex-fonts.lua
index 678a28300..c81e8cd1a 100644
--- a/tex/generic/context/luatex/luatex-fonts.lua
+++ b/tex/generic/context/luatex/luatex-fonts.lua
@@ -29,11 +29,12 @@ if not modules then modules = { } end modules ['luatex-fonts'] = {
texio.write_nl("")
texio.write_nl("--------------------------------------------------------------------------------")
-texio.write_nl("The font code has been brought in sync with the context version of 2014.12.01 so")
+texio.write_nl("The font code has been brought in sync with the context version of 2014.12.21 so")
texio.write_nl("if things don't work out as expected the interfacing needs to be checked. When")
texio.write_nl("this works as expected a second upgrade will happen that gives a more complete")
texio.write_nl("support and another sync with the context code (that new code is currently being")
-texio.write_nl("tested. The base pass is now integrated in the main pass.")
+texio.write_nl("tested. The base pass is now integrated in the main pass. The results can differ")
+texio.write_nl("from those in context because there we integrate some mechanisms differently.")
texio.write_nl("--------------------------------------------------------------------------------")
texio.write_nl("")
@@ -260,8 +261,8 @@ generic_context.callback_define_font = fonts.definers.read
if not generic_context.no_callbacks_yet then
- -- callback.register('ligaturing', generic_context.callback_ligaturing)
- -- callback.register('kerning', generic_context.callback_kerning)
+ callback.register('ligaturing', generic_context.callback_ligaturing)
+ callback.register('kerning', generic_context.callback_kerning)
callback.register('pre_linebreak_filter', generic_context.callback_pre_linebreak_filter)
callback.register('hpack_filter', generic_context.callback_hpack_filter)
callback.register('define_font' , generic_context.callback_define_font)
diff --git a/tex/generic/context/luatex/luatex-test.tex b/tex/generic/context/luatex/luatex-test.tex
index 169a260dd..6f48e0ced 100644
--- a/tex/generic/context/luatex/luatex-test.tex
+++ b/tex/generic/context/luatex/luatex-test.tex
@@ -35,14 +35,16 @@
\font\gothic=msgothic(ms-gothic) {\gothic whatever}
-\font\testy=file:IranNastaliq.ttf:mode=node;script=arab;language=dflt;+calt;+ccmp;+init;+isol;+medi;+fina;+liga;+rlig;+kern;+mark;+mkmk at 14pt
-\testy این یک متن نمونه است با قلم ذر که درست آمده است.
+\bgroup
-\pdfprotrudechars2 \pdfadjustspacing2
+ \pdfprotrudechars2
+ \pdfadjustspacing2
-\font\testb=file:lmroman12-regular:+liga;extend=1.5 at 12pt \testb \input tufte \par
-\font\testb=file:lmroman12-regular:+liga;slant=0.8 at 12pt \testb \input tufte \par
-\font\testb=file:lmroman12-regular:+liga;protrusion=default at 12pt \testb \input tufte \par
+ \font\testb=file:lmroman12-regular:+liga;extend=1.5 at 12pt \testb \input tufte \par
+ \font\testb=file:lmroman12-regular:+liga;slant=0.8 at 12pt \testb \input tufte \par
+ \font\testb=file:lmroman12-regular:+liga;protrusion=default at 12pt \testb \input tufte \par
+
+\egroup
\setmplibformat{plain}