summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/typo-syn.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkxl/typo-syn.lmt')
-rw-r--r--tex/context/base/mkxl/typo-syn.lmt435
1 files changed, 435 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/typo-syn.lmt b/tex/context/base/mkxl/typo-syn.lmt
new file mode 100644
index 000000000..dbc5b27ff
--- /dev/null
+++ b/tex/context/base/mkxl/typo-syn.lmt
@@ -0,0 +1,435 @@
+if not modules then modules = { } end modules ['typo-syn'] = {
+ version = 1.000,
+ optimize = true,
+ comment = "companion to typo-syn.mkxl",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+local nodes = nodes
+
+local tasks = nodes.tasks
+local enableaction = tasks.enableaction
+----- disableaction = tasks.disableaction
+
+local nuts = nodes.nuts
+local tonut = nodes.tonut
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getattr = nuts.getattr
+local setattrlist = nuts.setattrlist
+local getattrlist = nuts.getattrlist
+
+local getprop = nuts.getprop
+local setprop = nuts.setprop
+
+local setlink = nuts.setlink
+local setprev = nuts.setprev
+local setnext = nuts.setnext
+local setoffsets = nuts.setoffsets
+
+local getwhd = nuts.getwhd
+
+local getwidth = nuts.getwidth
+local setwidth = nuts.setwidth
+local getdepth = nuts.getdepth
+local setdepth = nuts.setdepth
+local getheight = nuts.getheight
+local setheight = nuts.setheight
+local gettotal = nuts.gettotal
+local getlist = nuts.getlist
+local setlist = nuts.setlist
+local getdisc = nuts.getdisc
+local setdisc = nuts.setdisc
+
+local hpack = nuts.hpack
+local rangedimensions = nuts.rangedimensions
+local insertbefore = nuts.insertbefore
+local removenode = nuts.remove
+local flushnode = nuts.flush
+
+local traverselist = nuts.traverselist
+
+local nodecodes = nodes.nodecodes
+local glyph_code = nodecodes.glyph
+local rule_code = nodecodes.rule
+local disc_code = nodecodes.disc
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local glue_code = nodecodes.glue
+local kern_code = nodecodes.kern
+local penalty_code = nodecodes.penalty
+
+local line_code = nodes.listcodes.line
+local fontkern_code = nodes.kerncodes.fontkern
+local parfillrightskip_code = nodes.gluecodes.parfillrightskip
+local baselineskip_code = nodes.gluecodes.baselineskip
+
+-----------------
+
+local a_synchronize = attributes.private("synchronize")
+
+local parallels = typesetters.parallels or { }
+typesetters.parallels = parallels or { }
+
+local registervalue = attributes.registervalue
+local getvalue = attributes.getvalue
+local hasvalues = attributes.hasvalues
+
+local trace = false
+-- local trace = true
+local report = logs.reporter("parallel")
+
+local pushsavelevel = tex.pushsavelevel -- token.expandmacro("bgroup")
+local popsavelevel = tex.popsavelevel -- token.expandmacro("egroup")
+local dontcomplain = tex.dontcomplain
+
+local slack = 6553.6
+local index = 0
+local lastattr = nil
+local lastline = nil
+
+interfaces.implement {
+ name = "registersynchronize",
+ arguments = { "dimen", "dimen", "box" },
+ actions = function(ht,dp,box)
+ index = index + 1
+ box = tonut(box)
+ local t = {
+ index = index,
+ lineheight = ht,
+ linedepth = dp,
+ height = getheight(height),
+ depth = getheight(depth),
+ box = box,
+ }
+ local v = registervalue(a_synchronize,t)
+ tex.setattribute(a_synchronize,v)
+ if index > 0 then
+ enableaction("vboxbuilders", "typesetters.parallels.handler")
+ enableaction("mvlbuilders", "typesetters.parallels.handler")
+ end
+ end,
+
+}
+
+local function hsplit(box,width)
+ local first = getlist(box)
+ local last = first
+ local current = first
+ local previous = current
+ local sofar = 0
+ local lastdisc = nil
+ -- todo: option
+ width = width - slack
+ --
+ while true do
+ previous = current
+ local id = getid(current)
+ if id == glyph_code then
+ local wd = getwidth(current)
+ if sofar + wd > width then
+ break
+ else
+ sofar = sofar + wd
+ end
+ elseif id == kern_code then
+ if getsubtype(current) == fontkern_code then
+ -- assume sane kerns
+ local wd = getwidth(current)
+ sofar = sofar + wd
+ else
+ last = previous
+ local wd = getwidth(current)
+ if sofar + wd > width then
+ break
+ else
+ sofar = sofar + wd
+ end
+ lastdisc = nil
+ end
+ elseif id == disc_code then
+ -- move on / inject post if needed
+ local pre, post, replace = getdisc(current)
+ local wdr = replace and rangedimensions(box,replace) or 0
+ if sofar + wdr > width then
+ -- handle post and pre here
+ last = previous
+ break
+ end
+ local wdp = pre and rangedimensions(box,pre) or 0
+-- if sofar + wdp > width then
+-- last = previous
+--lastdisc = current
+-- break
+-- end
+ sofar = sofar + wdr
+ lastdisc = current
+ elseif id == glue_code then
+ last = previous
+ local wd = getwidth(current)
+ if sofar + wd > width then
+ break
+ else
+ sofar = sofar + wd
+ end
+ lastdisc = nil
+ elseif id == hlist_code or id == vlist_code then
+ last = previous
+ local wd = getwidth(current)
+ if sofar + wd > width then
+ break
+ else
+ sofar = sofar + wd
+ end
+ lastdisc = nil
+ elseif id == rule_code then
+ last = previous
+ local wd = getwidth(current)
+ if sofar + wd > width then
+ break
+ else
+ sofar = sofar + wd
+ end
+ lastdisc = nil
+ else
+ lastdisc = nil
+ end
+ local next = getnext(current)
+ if next then
+ current = next
+ else
+ last = previous
+ break
+ end
+ end
+ local next
+ if lastdisc then
+ local pre, post, replace = getdisc(lastdisc)
+ last = getprev(lastdisc)
+ --
+ next = getnext(lastdisc)
+ if next then
+ setprev(next)
+ end
+ --
+ setlink(last,pre)
+ if post then
+ setlink(post,next)
+ next = post
+ end
+ setdisc(lastdisc,nil,nil,replace)
+ flushnode(lastdisc)
+ else
+ next = getnext(last)
+ if next then
+ setprev(next)
+ end
+ setnext(last)
+ end
+ while last do
+ local id = getid(last)
+ if id == glue_code or id == penalty_code then
+ first, last = removenode(first,last,true)
+ else
+ break
+ end
+ end
+ if first then
+ pushsavelevel()
+ dontcomplain()
+ local result, badness = hpack(first,width,"exactly")
+ if badness > 200 then
+ result = hpack(first)
+ end
+ popsavelevel()
+ setattrlist(result,getattrlist(box)) -- useattrlist(result,box)
+ setheight(result,getheight(box))
+ setdepth(result,getdepth(box))
+ setlist(box,next)
+ setwidth(box,rangedimensions(box,next))
+ return result
+ end
+end
+
+local function getproperties(parent)
+ local props = getprop(parent,"parallel")
+ if not props then
+ local w, h, d = getwhd(parent)
+ props = {
+ width = w,
+ height = h,
+ depth = d,
+ }
+ setprop(parent,"parallel",props)
+ end
+ return props
+end
+
+local function setproperties(parent,data,result,level,ctotal)
+ local props = getproperties(parent)
+ local depth = props.depth
+ local height = props.height
+ local delta = data.linedepth - depth
+ if delta > 0 then
+ depth = data.linedepth
+ setdepth(parent,depth)
+ props.depth = depth
+ local n = getnext(parent)
+ if n and getid(n) == glue_code and getsubtype(n) == baselineskip_code then
+ setwidth(n,getwidth(n) - delta)
+ end
+ end
+-- if height < data.lineheight then
+-- height = data.lineheight
+-- setheight(parent,height)
+-- props.height = height
+-- end
+ local offset = level * ctotal
+ if props.depth + offset > depth then
+ setdepth(parent,props.depth+offset)
+ end
+ setoffsets(result,0,-offset)
+ setwidth(result,0)
+end
+
+local function flush(head,first,last,a,parent,nesting)
+ if first and nesting == 0 then
+ local data = getvalue(a_synchronize,a)
+ local upto = getnext(last)
+ if upto and getid(upto) == penalty_code then
+ upto = getnext(upto)
+ end
+ if upto and getid(upto) == glue_code and getsubtype(upto) == parfillrightskip_code then
+ upto = getnext(upto)
+ end
+ local props = getproperties(parent)
+ local width = rangedimensions(parent,first,upto)
+ if width > props.width then
+ width = props.width
+ end
+ local content = data.box
+ local index = data.index
+ if not content then
+ if trace then
+ report("index %i, verdict %a",index,"done")
+ end
+ else
+ local result = nil
+ local cwidth = getwidth(content)
+ local ctotal = gettotal(content)
+ if cwidth <= width then -- slack
+ if trace then
+ report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"fit")
+ end
+ result = content
+ data.box = nil
+ elseif cwidth > width then
+ if trace then
+ report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"overflow")
+ end
+ result = hsplit(content,width)
+ lastattr = a
+ lastline = parent
+ else
+ report("index %i, verdict %a",index,"weird")
+ end
+ if result then
+ setproperties(parent,data,result,1,ctotal)
+ head = insertbefore(head,first,result)
+ end
+ end
+ end
+ return head
+end
+
+local function lastflush(lastline,lastattr)
+ local data = getvalue(a_synchronize,lastattr)
+ if not data then
+ return
+ end
+ local content = data.box
+ if not content or getwidth(content) == 0 then
+ return
+ end
+ local head = getlist(lastline)
+ if not head then
+ return
+ end
+ local first = head
+ local last = nil
+ local props = getproperties(lastline)
+ local width = props.width
+ local height = props.height
+ local depth = props.depth
+ local level = 1
+ if depth < data.linedepth then
+ depth = data.linedepth
+ setdepth(lastline,depth)
+ end
+ if height < data.lineheight then
+ height = data.lineheight
+ setheight(lastline,height)
+ end
+ while true do
+ local content = data.box
+ local index = data.index
+ if content then
+ local result = nil
+ local total = 0
+ local cwidth = getwidth(content)
+ local ctotal = gettotal(content)
+ if cwidth <= width then -- slack
+ if trace then
+ report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"fit")
+ end
+ result = content
+ data.box = nil
+ elseif cwidth > width then
+ if trace then
+ report("index %i, available %p, content %p, verdict %a",index,width,cwidth,"overflow")
+ end
+ result = hsplit(content,width)
+ else
+ report("index %i, verdict %a",index,"weird")
+ end
+ if result then
+ level = level + 1
+ setproperties(lastline,data,result,level,ctotal)
+ head = insertbefore(head,first,result)
+ setlist(lastline,head)
+ else
+ break
+ end
+ else
+ break
+ end
+ end
+end
+
+local processranges = nuts.processranges
+
+function parallels.handler(head,where)
+ if where == "hmodepar" and hasvalues(a_synchronize) then
+ lastattr = nil
+ lastline = nil
+ for n, id, subtype in traverselist(head) do
+ if subtype == line_code then
+ lastattr = nil
+ local list = getlist(n)
+ local head = processranges(a_synchronize,flush,list,n)
+ if head ~= list then
+ setlist(n,head)
+ end
+ end
+ end
+ if lastattr and lastline then
+ lastflush(lastline,lastattr)
+ end
+ end
+ return head
+end