summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/typo-krn.lua
diff options
context:
space:
mode:
authorMojca Miklavec <mojca.miklavec@gmail.com>2014-05-05 20:29:55 +0000
committerMojca Miklavec <mojca.miklavec@gmail.com>2014-05-05 20:29:55 +0000
commitba9a57343987f1c2c72396e7c38f1fa30352c24c (patch)
tree66a8b12cdf67427ce96770fd0e9e581759aade1c /Master/texmf-dist/tex/context/base/typo-krn.lua
parent15242121b8ddf7d4a041fb3998d295dd8232e1eb (diff)
ConTeXt 2014.04.28 23:24
git-svn-id: svn://tug.org/texlive/trunk@33856 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/tex/context/base/typo-krn.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/typo-krn.lua351
1 files changed, 227 insertions, 124 deletions
diff --git a/Master/texmf-dist/tex/context/base/typo-krn.lua b/Master/texmf-dist/tex/context/base/typo-krn.lua
index fb28d3b2de4..a8ffe557be4 100644
--- a/Master/texmf-dist/tex/context/base/typo-krn.lua
+++ b/Master/texmf-dist/tex/context/base/typo-krn.lua
@@ -6,25 +6,42 @@ if not modules then modules = { } end modules ['typo-krn'] = {
license = "see context related readme files"
}
+-- glue is still somewhat suboptimal
+
local next, type, tonumber = next, type, tonumber
local utfchar = utf.char
local nodes, node, fonts = nodes, node, fonts
-local find_node_tail = node.tail or node.slide
-local free_node = node.free
-local free_nodelist = node.flush_list
-local copy_node = node.copy
-local copy_nodelist = node.copy_list
-local insert_node_before = node.insert_before
-local insert_node_after = node.insert_after
-local end_of_math = node.end_of_math
+local tasks = nodes.tasks
+local nuts = nodes.nuts
+local nodepool = nuts.pool
-local texattribute = tex.attribute
-local unsetvalue = attributes.unsetvalue
+local tonode = nuts.tonode
+local tonut = nuts.tonut
-local nodepool = nodes.pool
-local tasks = nodes.tasks
+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
+
+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 setattr = nuts.setattr
+local getfont = nuts.getfont
+local getsubtype = nuts.getsubtype
+local getchar = nuts.getchar
+
+local texsetattribute = tex.setattribute
+local unsetvalue = attributes.unsetvalue
local new_gluespec = nodepool.gluespec
local new_kern = nodepool.kern
@@ -33,6 +50,7 @@ local new_glue = nodepool.glue
local nodecodes = nodes.nodecodes
local kerncodes = nodes.kerncodes
local skipcodes = nodes.skipcodes
+local disccodes = nodes.disccodes
local glyph_code = nodecodes.glyph
local kern_code = nodecodes.kern
@@ -42,6 +60,7 @@ local hlist_code = nodecodes.hlist
local vlist_code = nodecodes.vlist
local math_code = nodecodes.math
+local discretionary_code = disccodes.discretionary
local kerning_code = kerncodes.kerning
local userkern_code = kerncodes.userkern
local userskip_code = skipcodes.userskip
@@ -53,8 +72,16 @@ local fontdata = fonthashes.identifiers
local chardata = fonthashes.characters
local quaddata = fonthashes.quads
local markdata = fonthashes.marks
+local fontproperties = fonthashes.properties
+local fontdescriptions = fonthashes.descriptions
+local fontfeatures = fonthashes.features
+
+local tracers = nodes.tracers
+local setcolor = tracers.colors.set
+local resetcolor = tracers.colors.reset
local v_max = interfaces.variables.max
+local v_auto = interfaces.variables.auto
typesetters = typesetters or { }
local typesetters = typesetters
@@ -62,11 +89,15 @@ local typesetters = typesetters
typesetters.kerns = typesetters.kerns or { }
local kerns = typesetters.kerns
+local report = logs.reporter("kerns")
+local trace_ligatures = false trackers.register("typesetters.kerns.ligatures",function(v) trace_ligatures = v end)
+
kerns.mapping = kerns.mapping or { }
kerns.factors = kerns.factors or { }
local a_kerns = attributes.private("kern")
local a_fontkern = attributes.private('fontkern')
-kerns.attribute = kerns.attribute
+
+local contextsetups = fonts.specifiers.contextsetups
storage.register("typesetters/kerns/mapping", kerns.mapping, "typesetters.kerns.mapping")
storage.register("typesetters/kerns/factors", kerns.factors, "typesetters.kerns.factors")
@@ -79,20 +110,83 @@ local factors = kerns.factors
-- make sure it runs after all others
-- there will be a width adaptor field in nodes so this will change
-- todo: interchar kerns / disc nodes / can be made faster
+-- todo: use insert_before etc
local gluefactor = 4 -- assumes quad = .5 enspace
kerns.keepligature = false -- just for fun (todo: control setting with key/value)
kerns.keeptogether = false -- just for fun (todo: control setting with key/value)
+-- red : kept by dynamic feature
+-- green : kept by static feature
+-- blue : keep by goodie
+
+function kerns.keepligature(n) -- might become default
+ local f = getfont(n)
+ local a = getattr(n,0) or 0
+ if trace_ligatures then
+ local c = getchar(n)
+ local d = fontdescriptions[f][c].name
+ if a > 0 and contextsetups[a].keepligatures == v_auto then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","dynamic","keepligatures")
+ setcolor(n,"darkred")
+ return true
+ end
+ local k = fontfeatures[f].keepligatures
+ if k == v_auto then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"kept","static","keepligatures")
+ setcolor(n,"darkgreen")
+ return true
+ end
+ if not k then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, by %s feature %a",f,d,c,"split","static","keepligatures")
+ resetcolor(n)
+ return false
+ end
+ local k = fontproperties[f].keptligatures
+ if not k then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","no")
+ resetcolor(n)
+ return false
+ end
+ if k and k[c] then
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"kept","by")
+ setcolor(n,"darkblue")
+ return true
+ else
+ report("font %!font:name!, glyph %a, slot %X -> ligature %s, %s goodie specification",f,d,c,"split","by")
+ resetcolor(n)
+ return false
+ end
+ else
+ if a > 0 and contextsetups[a].keepligatures == v_auto then
+ return true
+ end
+ local k = fontfeatures[f].keepligatures
+ if k == v_auto then
+ return true
+ end
+ if not k then
+ return false
+ end
+ local k = fontproperties[f].keptligatures
+ if not k then
+ return false
+ end
+ if k and k[c] then
+ return true
+ end
+ end
+end
+
-- can be optimized .. the prev thing .. but hardly worth the effort
local function kern_injector(fillup,kern)
if fillup then
local g = new_glue(kern)
- local s = g.spec
- s.stretch = kern
- s.stretch_order = 1
+ local s = getfield(g,"spec")
+ setfield(s,"stretch",kern)
+ setfield(s,"stretch_order",1)
return g
else
return new_kern(kern)
@@ -102,25 +196,25 @@ end
local function spec_injector(fillup,width,stretch,shrink)
if fillup then
local s = new_gluespec(width,2*stretch,2*shrink)
- s.stretch_order = 1
+ setfield(s,"stretch_order",1)
return s
else
return new_gluespec(width,stretch,shrink)
end
end
--- needs checking ... base mode / node mode
+-- needs checking ... base mode / node mode -- also use insert_before/after etc
-local function do_process(namespace,attribute,head,force) -- todo: glue so that we can fully stretch
+local function do_process(head,force) -- todo: glue so that we can fully stretch
local start, done, lastfont = head, false, nil
local keepligature = kerns.keepligature
local keeptogether = kerns.keeptogether
local fillup = false
while start do
-- faster to test for attr first
- local attr = force or start[attribute]
+ local attr = force or getattr(start,a_kerns)
if attr and attr > 0 then
- start[attribute] = unsetvalue
+ setattr(start,a_kerns,unsetvalue)
local krn = mapping[attr]
if krn == v_max then
krn = .25
@@ -129,58 +223,58 @@ local function do_process(namespace,attribute,head,force) -- todo: glue so that
fillup = false
end
if krn and krn ~= 0 then
- local id = start.id
- if id == glyph_code then
- lastfont = start.font
- local c = start.components
- if c then
- if keepligature and keepligature(start) then
- -- keep 'm
+ 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, n = getprev(s), getnext(s)
+ local tail = find_node_tail(c)
+ if p then
+ setfield(p,"next",c)
+ setfield(c,"prev",p)
else
- c = do_process(namespace,attribute,c,attr)
- local s = start
- local p, n = s.prev, s.next
- local tail = find_node_tail(c)
- if p then
- p.next = c
- c.prev = p
- else
- head = c
- end
- if n then
- n.prev = tail
- end
- tail.next = n
- start = c
- s.components = nil
- -- we now leak nodes !
- -- free_node(s)
- done = true
+ head = c
+ end
+ if n then
+ setfield(n,"prev",tail)
end
+ setfield(tail,"next",n)
+ start = c
+ setfield(s,"components",nil)
+ -- we now leak nodes !
+ -- free_node(s)
+ done = true
end
- local prev = start.prev
+ local prev = getprev(start)
if not prev then
-- skip
- elseif markdata[lastfont][start.char] then
+ elseif markdata[lastfont][getchar(start)] then
-- skip
else
- local pid = prev.id
+ local pid = getid(prev)
if not pid then
-- nothing
elseif pid == kern_code then
- if prev.subtype == kerning_code or prev[a_fontkern] then
- if keeptogether and prev.prev.id == glyph_code and keeptogether(prev.prev,start) then -- we could also pass start
+ 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)
- prev.subtype = userkern_code
- prev.kern = prev.kern + quaddata[lastfont]*krn -- here
+ 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 prev.font == lastfont then
- local prevchar, lastchar = prev.char, start.char
+ if getfont(prev) == lastfont then
+ local prevchar, lastchar = getchar(prev), getchar(start)
if keeptogether and keeptogether(prev,start) then
-- keep 'm
else
@@ -199,88 +293,102 @@ local function do_process(namespace,attribute,head,force) -- todo: glue so that
-- 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 pre, post, replace = disc.pre, disc.post, disc.replace
- local prv, nxt = disc.prev, disc.next
- if pre and prv then -- must pair with start.prev
- -- this one happens in most cases
- local before = copy_node(prv)
- pre.prev = before
- before.next = pre
- before.prev = nil
- pre = do_process(namespace,attribute,before,attr)
- pre = pre.next
- pre.prev = nil
- 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)
- tail.next = after
- after.prev = tail
- after.next = nil
- post = do_process(namespace,attribute,post,attr)
- tail.next = nil
- 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)
- replace.prev = before
- before.next = replace
- before.prev = nil
- tail.next = after
- after.prev = tail
- after.next = nil
- replace = do_process(namespace,attribute,before,attr)
- replace = replace.next
- replace.prev = nil
- after.prev.next = nil
- disc.replace = replace
- free_node(after)
- free_node(before)
- else
- if prv and prv.id == glyph_code and prv.font == lastfont then
- local prevchar, lastchar = prv.char, start.char
+ local prv, nxt = getprev(disc), getnext(disc)
+ if getsubtype(disc) == discretionary_code then
+ -- maybe we should forget about this variant as there is no glue
+ -- possible
+ local pre, post, replace = getfield(disc,"pre"), getfield(disc,"post"), 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, lastchar = getchar(prv), 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
- disc.replace = kern_injector(false,krn) -- only kerns permitted, no glue
+ 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, lastchar = getchar(prv), 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
end
end
elseif id == glue_code then
- local subtype = start.subtype
+ local subtype = getsubtype(start)
if subtype == userskip_code or subtype == xspaceskip_code or subtype == spaceskip_code then
- local s = start.spec
- local w = s.width
+ local s = getfield(start,"spec")
+ local w = getfield(s,"width")
if w > 0 then
- local width, stretch, shrink = w+gluefactor*w*krn, s.stretch, s.shrink
- start.spec = spec_injector(fillup,width,stretch*width/w,shrink*width/w)
+ local width, stretch, shrink = w+gluefactor*w*krn, getfield(s,"stretch"), getfield(s,"shrink")
+ setfield(start,"spec",spec_injector(fillup,width,stretch*width/w,shrink*width/w))
done = true
end
end
elseif id == kern_code then
- -- if start.subtype == kerning_code then -- handle with glyphs
- -- local sk = start.kern
+ -- if getsubtype(start) == kerning_code then -- handle with glyphs
+ -- local sk = getfield(start,"kern")
-- if sk > 0 then
- -- start.kern = sk*krn
+ -- setfield(start,"kern",sk*krn)
-- done = true
-- end
-- end
elseif lastfont and (id == hlist_code or id == vlist_code) then -- todo: lookahead
- local p = start.prev
- if p and p.id ~= glue_code then
+ local p = getprev(start)
+ if p and getid(p) ~= glue_code then
insert_node_before(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
done = true
end
- local n = start.next
- if n and n.id ~= glue_code then
+ local n = getnext(start)
+ if n and getid(n) ~= glue_code then
insert_node_after(head,start,kern_injector(fillup,quaddata[lastfont]*krn))
done = true
end
@@ -290,7 +398,7 @@ local function do_process(namespace,attribute,head,force) -- todo: glue so that
end
end
if start then
- start = start.next
+ start = getnext(start)
end
end
return head, done
@@ -316,20 +424,15 @@ function kerns.set(factor)
else
factor = unsetvalue
end
- texattribute[a_kerns] = factor
+ texsetattribute(a_kerns,factor)
return factor
end
-local function process(namespace,attribute,head)
- return do_process(namespace,attribute,head) -- no direct map, because else fourth argument is tail == true
+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
-kerns.handler = nodes.installattributehandler {
- name = "kern",
- namespace = kerns,
- processor = process,
-}
-
-- interface
commands.setcharacterkerning = kerns.set