summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/node-ali.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkxl/node-ali.lmt')
-rw-r--r--tex/context/base/mkxl/node-ali.lmt285
1 files changed, 285 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/node-ali.lmt b/tex/context/base/mkxl/node-ali.lmt
new file mode 100644
index 000000000..0a7cf30ce
--- /dev/null
+++ b/tex/context/base/mkxl/node-ali.lmt
@@ -0,0 +1,285 @@
+if not modules then modules = { } end modules ['node-ali'] = {
+ version = 1.001,
+ comment = "companion to node-ini.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local a_alignchar = attributes.private("aligncharacter")
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local getwidth = nuts.getwidth
+local setwidth = nuts.setwidth
+local getid = nuts.getid
+local getattr = nuts.getattr
+local setnext = nuts.setnext
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local setglue = nuts.setglue
+local getglue = nuts.getglue
+local getlist = nuts.getlist
+local setlist = nuts.setlist
+local setattrlist = nuts.setattrlist
+local getchar = nuts.getchar
+local addmargins = nuts.addmargins
+local findtail = nuts.tail
+local hasglyph = nuts.hasglyph
+local getwordrange = nuts.getwordrange
+local dimensions = nuts.rangedimensions
+local nextrecord = nuts.traversers.alignrecord
+local nextunset = nuts.traversers.unset
+local nextglyph = nuts.traversers.glyph
+local nextglue = nuts.traversers.glue
+local nextnode = nuts.traversers.node
+local prevnode = nuts.treversers.node
+local flushnode = nuts.flush
+local hpack = nuts.hpack
+
+local glyph_code = nodes.nodecodes.glyph
+local glue_code = nodes.nodecodes.glue
+local kern_code = nodes.nodecodes.kern
+local disc_code = nodes.nodecodes.disc
+
+local spaceskip_code = nodes.gluecodes.spaceskip
+local xspaceskip_code = nodes.gluecodes.xspaceskip
+local fontkern_code = nodes.kerncodes.fontkern
+
+local newkern = nuts.pool.kern
+local insertbefore = nuts.insertbefore
+local insertafter = nuts.insertafter
+
+-- todo statistics and tracing
+
+local method = 2
+local unislots = fonts.hashes.unislots -- todo
+local chardata = fonts.hashes.characters
+
+function nodes.handlers.aligncharacter(head,attr,preamble)
+ local attr = getattr(attr,a_alignchar) -- 1 : value doesn't matter (for now)
+ if attr then
+ local widths = { }
+ local data = { }
+ local rows = 0
+ local cols = 0
+ for col in nextrecord, preamble do
+ cols = cols + 1
+ local w, s = getwidth(col,true)
+ widths[cols] = { col, w, s }
+ end
+ --
+ for row in nextunset, head do
+ rows = rows + 1
+ local c = 0
+ local d = { }
+ data[rows] = d
+ for col in nextunset, getlist(row) do
+ c = c + 1
+ if widths[c][2] then
+ local list = getlist(col)
+ -- if method == 1 then
+ -- local left = nil
+ -- local right = nil
+ -- local middle = nil
+ -- for g, char in nextglyph, list do
+ -- if not left then
+ -- left = g
+ -- end
+ -- if char == getattr(g,a_alignchar) then
+ -- middle = g
+ -- end
+ -- right = g
+ -- end
+ -- d[c] = middle and { col, left, middle, right, 0, 0, getwidth(middle) } or false
+ -- elseif method == 2 then
+ local middle = nil
+ -- we can either cache unislots or we can cache for this font
+ for g, char, font in nextglyph, list do
+ local unicode = getattr(g,a_alignchar)
+ if unicode then
+ if char == unicode then
+ middle = g
+ elseif unislots[font][char] == unicode then
+ middle = g
+ end
+ end
+ end
+ if middle then
+ local left, right = getwordrange(middle) -- not real gain but handy anyway (less code too)
+ -- local left = middle
+ -- local right = middle
+ -- for g, id, subtype in nextnode, middle do
+ -- if id == glyph_code or id == disc_code then
+ -- right = g
+ -- elseif id == kern_code and subtype == fontkern_code then
+ -- right = g
+ -- else
+ -- break
+ -- end
+ -- end
+ -- for g, id, subtype in prevnode, middle do
+ -- if id == glyph_code or id == disc_code then
+ -- left = g
+ -- elseif id == kern_code and subtype == fontkern_code then
+ -- left = g
+ -- else
+ -- break
+ -- end
+ -- end
+ d[c] = { col, left, middle, right, 0, 0, getwidth(middle) }
+ else
+ d[c] = false
+ end
+ -- else
+ -- local middle = nil
+ -- for g, char in nextglyph, list do
+ -- if char == getattr(g,a_alignchar) then
+ -- middle = g
+ -- end
+ -- end
+ -- if middle then
+ -- local left = list
+ -- local right = findtail(list)
+ -- if getid(left) == glue_code then
+ -- left = getnext(left)
+ -- end
+ -- if getid(right) == glue_code then
+ -- right = getprev(right)
+ -- end
+ -- d[c] = { col, left, middle, right, 0, 0, getwidth(middle) }
+ -- else
+ -- d[c] = false
+ -- end
+ -- end
+ else
+ d[c] = false
+ end
+ end
+ end
+ --
+ for col=1,cols do
+ local maxl = 0
+ local maxr = 0
+ local minm = 0
+ local maxm = 0
+ local colw = widths[col]
+ for row=1,rows do
+ local d = data[row][col]
+ if d then
+ local p = d[1]
+ local l = d[2]
+ local m = d[3]
+ local r = d[4]
+ if m then
+ local lw = l == m and 0 or dimensions(p,l,m)
+ local rw = m == r and 0 or dimensions(p,getnext(m),getnext(r))
+ d[5] = lw
+ d[6] = rw
+ if lw > maxl then
+ maxl = lw
+ end
+ if rw > maxr then
+ maxr = rw
+ end
+ local mw = d[7]
+ if maxm == 0 then
+ minm = mw
+ maxm = mw
+ else
+ if mw > maxm then
+ maxm = mw
+ end
+ if mw < minm then
+ minm = mw
+ end
+ end
+ end
+ end
+ end
+ --
+ local fixedwidth = colw[3] ~= 0
+ --
+ local old = colw[2]
+ local new = old
+ for row=1,rows do
+ local d = data[row][col]
+ if d then
+ local p = d[1]
+ local l = d[2]
+ local m = d[3]
+ local r = d[4]
+ if l and m and r then
+ local lw = d[5]
+ local rw = d[6]
+ local mw = d[7]
+ dl = maxl - lw
+ dr = maxr - rw
+ if dl ~= 0 or dr ~= 0 or mw ~= maxm then
+ local lst = getlist(p)
+ local wid = getwidth(p)
+ if dl ~= 0 then
+ local k = newkern(dl)
+ lst = insertbefore(lst,l,k)
+ setattrlist(k,m)
+ setlist(p,lst)
+ wid = wid + dl
+ end
+ if dr ~= 0 then
+ local k = newkern(dr)
+ insertafter(lst,r,k)
+ setattrlist(k,m)
+ wid = wid + dr
+ end
+ if mw ~= maxm then
+ local dw = (maxm - mw)
+ local dx = dw / 2
+ addmargins(m,-dx,-dx)
+ wid = wid + dw
+ end
+ setwidth(p,wid)
+ if wid > new then
+ new = wid
+ end
+ setlist(p,lst)
+ -- somewhat fuzzy:
+ if fixedwidth then
+ local l = hpack(h,getwidth(p),"exactly")
+ setglue(p,getglue(l))
+ setlist(l)
+ flushnode(l)
+ else
+ setglue(p)
+ end
+ --
+ end
+ end
+ end
+ end
+ if new > old then
+ if fixedwidth then
+ -- issue overflow warning
+ else
+ setwidth(colw[1],new)
+ end
+ end
+ end
+ end
+end
+
+local enabled = false
+
+interfaces.implement {
+ name = "enablealignmentcharacter",
+ -- onlyonce = true,
+ public = true,
+ protected = true,
+ actions = function()
+ if not enabled then
+ nodes.tasks.enableaction("alignments", "nodes.handlers.aligncharacter")
+ enabled = true
+ end
+ end,
+}
+