summaryrefslogtreecommitdiff
path: root/tex/context/base/mkxl/typo-dha.lmt
diff options
context:
space:
mode:
Diffstat (limited to 'tex/context/base/mkxl/typo-dha.lmt')
-rw-r--r--tex/context/base/mkxl/typo-dha.lmt481
1 files changed, 481 insertions, 0 deletions
diff --git a/tex/context/base/mkxl/typo-dha.lmt b/tex/context/base/mkxl/typo-dha.lmt
new file mode 100644
index 000000000..e1a6662c4
--- /dev/null
+++ b/tex/context/base/mkxl/typo-dha.lmt
@@ -0,0 +1,481 @@
+if not modules then modules = { } end modules ['typo-dha'] = {
+ version = 1.001,
+ comment = "companion to typo-dir.mkiv",
+ author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
+ copyright = "PRAGMA ADE / ConTeXt Development Team",
+ license = "see context related readme files"
+}
+
+-- Some analysis by Idris:
+--
+-- 1. Assuming the reading- vs word-order distinction (bidi-char types) is governing;
+-- 2. Assuming that 'ARAB' represents an actual arabic string in raw input order, not word-order;
+-- 3. Assuming that 'BARA' represent the correct RL word order;
+--
+-- Then we have, with input: LATIN ARAB
+--
+-- \textdirection 1 LATIN ARAB => LATIN BARA
+-- \textdirection 1 LATIN ARAB => LATIN BARA
+-- \textdirection 1 LRO LATIN ARAB => LATIN ARAB
+-- \textdirection 1 LRO LATIN ARAB => LATIN ARAB
+-- \textdirection 1 RLO LATIN ARAB => NITAL ARAB
+-- \textdirection 1 RLO LATIN ARAB => NITAL ARAB
+
+-- elseif d == "es" then -- European Number Separator
+-- elseif d == "et" then -- European Number Terminator
+-- elseif d == "cs" then -- Common Number Separator
+-- elseif d == "nsm" then -- Non-Spacing Mark
+-- elseif d == "bn" then -- Boundary Neutral
+-- elseif d == "b" then -- Paragraph Separator
+-- elseif d == "s" then -- Segment Separator
+-- elseif d == "ws" then -- Whitespace
+-- elseif d == "on" then -- Other Neutrals
+
+-- todo : use new dir functions
+-- todo : make faster
+-- todo : move dir info into nodes
+-- todo : swappable tables and floats i.e. start-end overloads (probably loop in builders)
+
+-- I removed the original tracing code and now use the colorful one. If I ever want to change
+-- something I will just inject prints for tracing.
+
+local nodes, node = nodes, node
+
+local trace_directions = false trackers.register("typesetters.directions", function(v) trace_directions = v end)
+
+local report_directions = logs.reporter("typesetting","text directions")
+
+local nuts = nodes.nuts
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getattr = nuts.getattr
+local getprop = nuts.getprop
+local getdirection = nuts.getdirection
+local isglyph = nuts.isglyph -- or ischar
+
+local setprop = nuts.setprop
+local setstate = nuts.setstate
+local setchar = nuts.setchar
+
+local insertnodebefore = nuts.insertbefore
+local insertnodeafter = nuts.insertafter
+local remove_node = nuts.remove
+local endofmath = nuts.endofmath
+
+local startofpar = nuts.startofpar
+
+local nodepool = nuts.pool
+
+local nodecodes = nodes.nodecodes
+local gluecodes = nodes.gluecodes
+
+local glyph_code = nodecodes.glyph
+local math_code = nodecodes.math
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+local dir_code = nodecodes.dir
+local par_code = nodecodes.par
+
+local dirvalues = nodes.dirvalues
+local lefttoright_code = dirvalues.lefttoright
+local righttoleft_code = dirvalues.righttoleft
+
+local parfillskip_code = gluecodes.parfillskip
+
+local new_direction = nodepool.direction
+
+local insert = table.insert
+
+local fonthashes = fonts.hashes
+local fontchar = fonthashes.characters
+
+local chardirections = characters.directions
+local charmirrors = characters.mirrors
+local charclasses = characters.textclasses
+
+local directions = typesetters.directions
+local setcolor = directions.setcolor
+local getglobal = directions.getglobal
+
+local a_directions = attributes.private('directions')
+
+local strip = false
+
+local s_isol = fonts.analyzers.states.isol
+
+local function stopdir(finish) -- we could use finish directly
+ local n = new_direction(finish == righttoleft_code and righttoleft_code or lefttoright_code,true)
+ setprop(n,"direction",true)
+ return n
+end
+
+local function startdir(finish) -- we could use finish directly
+ local n = new_direction(finish == righttoleft_code and righttoleft_code or lefttoright_code)
+ setprop(n,"direction",true)
+ return n
+end
+
+local function nextisright(current)
+ current = getnext(current)
+ local character, id = isglyph(current)
+ if character then
+ local direction = chardirections[character]
+ return direction == "r" or direction == "al" or direction == "an"
+ end
+end
+
+local function previsright(current)
+ current = getprev(current)
+ local character, id = isglyph(current)
+ if character then
+ local direction = chardirections[character]
+ return direction == "r" or direction == "al" or direction == "an"
+ end
+end
+
+local function process(start)
+
+ local head = start
+ local current = head
+ local autodir = 0
+ local embedded = 0
+ local override = 0
+ local pardir = 0
+ local textdir = 0
+ local done = false
+ local stack = { }
+ local top = 0
+ local obsolete = { }
+ local rlo = false
+ local lro = false
+ local prevattr = false
+ local fences = { }
+
+ while current do
+ -- no isglyph here as we test for skips first
+ local id = getid(current)
+ local next = getnext(current)
+ if id == math_code then
+ current = getnext(endofmath(next))
+ elseif getprop(current,"direction") then
+ -- this handles unhbox etc
+ current = next
+ else
+ local attr = getattr(current,a_directions)
+ if attr and attr > 0 then
+ if attr ~= prevattr then
+ if not getglobal(a) then
+ lro = false
+ rlo = false
+ end
+ prevattr = attr
+ end
+ end
+ local prop = true
+ if id == glyph_code then
+ if attr and attr > 0 then
+ local character, font = isglyph(current)
+ if character == 0 then
+ -- skip signals
+ -- setprop(current,"direction",true)
+ else
+ local direction = chardirections[character]
+ local reversed = false
+ if rlo or override > 0 then
+ if direction == "l" then
+ direction = "r"
+ reversed = true
+ end
+ elseif lro or override < 0 then
+ if direction == "r" or direction == "al" then
+ setstate(current,s_isol) -- hm
+ direction = "l"
+ reversed = true
+ end
+ end
+ if direction == "on" then
+ local mirror = charmirrors[character]
+ if mirror and fontchar[font][mirror] then
+ local class = charclasses[character]
+ if class == "open" then
+ if nextisright(current) then
+ setchar(current,mirror)
+ -- setprop(current,"direction","r")
+ prop = "r"
+ elseif autodir < 0 then
+ setchar(current,mirror)
+ -- setprop(current,"direction","r")
+ prop = "r"
+ else
+ mirror = false
+ -- setprop(current,"direction","l")
+ prop = "l"
+ end
+ local fencedir = autodir == 0 and textdir or autodir
+ fences[#fences+1] = fencedir
+ elseif class == "close" and #fences > 0 then
+ local fencedir = fences[#fences]
+ fences[#fences] = nil
+ if fencedir < 0 then
+ setchar(current,mirror)
+ -- setprop(current,"direction","r")
+ prop = "r"
+ else
+ -- setprop(current,"direction","l")
+ prop = "l"
+ mirror = false
+ end
+ elseif autodir < 0 then
+ setchar(current,mirror)
+ -- setprop(current,"direction","r")
+ prop = "r"
+ else
+ -- setprop(current,"direction","l")
+ prop = "l"
+ mirror = false
+ end
+ else
+ -- setprop(current,"direction",true)
+ end
+ if trace_directions then
+ setcolor(current,direction,false,mirror)
+ end
+ elseif direction == "l" then
+ if trace_directions then
+ setcolor(current,"l",reversed)
+ end
+ -- setprop(current,"direction","l")
+ prop = "l"
+ elseif direction == "r" then
+ if trace_directions then
+ setcolor(current,"r",reversed)
+ end
+ -- setprop(current,"direction","r")
+ prop = "r"
+ elseif direction == "en" then -- european number
+ if trace_directions then
+ setcolor(current,"l")
+ end
+ -- setprop(current,"direction","l")
+ prop = "l"
+ elseif direction == "al" then -- arabic letter
+ if trace_directions then
+ setcolor(current,"r")
+ end
+ -- setprop(current,"direction","r")
+ prop = "r"
+ elseif direction == "an" then -- arabic number
+ -- needs a better scanner as it can be a float
+ if trace_directions then
+ setcolor(current,"l") -- was r
+ end
+ -- setprop(current,"direction","n") -- was r
+ prop = "n"
+ elseif direction == "lro" then -- Left-to-Right Override -> right becomes left
+ top = top + 1
+ stack[top] = { override, embedded }
+ override = -1
+ obsolete[#obsolete+1] = current
+ goto obsolete
+ elseif direction == "rlo" then -- Right-to-Left Override -> left becomes right
+ top = top + 1
+ stack[top] = { override, embedded }
+ override = 1
+ obsolete[#obsolete+1] = current
+ goto obsolete
+ elseif direction == "lre" then -- Left-to-Right Embedding -> lefttoright_code
+ top = top + 1
+ stack[top] = { override, embedded }
+ embedded = 1
+ obsolete[#obsolete+1] = current
+ goto obsolete
+ elseif direction == "rle" then -- Right-to-Left Embedding -> righttoleft_code
+ top = top + 1
+ stack[top] = { override, embedded }
+ embedded = -1
+ obsolete[#obsolete+1] = current
+ goto obsolete
+ elseif direction == "pdf" then -- Pop Directional Format
+ if top > 0 then
+ local s = stack[top]
+ override = s[1]
+ embedded = s[2]
+ top = top - 1
+ else
+ override = 0
+ embedded = 0
+ end
+ obsolete[#obsolete+1] = current
+ goto obsolete
+ elseif trace_directions then
+ setcolor(current)
+ -- setprop(current,"direction",true)
+ else
+ -- setprop(current,"direction",true)
+ end
+ end
+ else
+ -- setprop(current,"direction",true)
+ end
+ elseif id == glue_code then
+ if getsubtype(current) == parfillskip_code then
+ -- setprop(current,"direction","!")
+ prop = "!"
+ else
+ -- setprop(current,"direction","g")
+ prop = "g"
+ end
+ elseif id == kern_code then
+ -- setprop(current,"direction","k")
+ prop = "k"
+ elseif id == dir_code then
+ local direction, pop = getdirection(current)
+ if direction == righttoleft_code then
+ if not pop then
+ autodir = -1
+ elseif embedded and embedded~= 0 then
+ autodir = embedded
+ else
+ autodir = 0
+ end
+ elseif direction == lefttoright_code then
+ if not pop then
+ autodir = 1
+ elseif embedded and embedded~= 0 then
+ autodir = embedded
+ else
+ autodir = 0
+ end
+ end
+ textdir = autodir
+ -- setprop(current,"direction",true)
+ elseif id == par_code and startofpar(current) then
+ local direction = getdirection(current)
+ if direction == righttoleft_code then
+ autodir = -1
+ elseif direction == lefttoright_code then
+ autodir = 1
+ end
+ pardir = autodir
+ textdir = pardir
+ -- setprop(current,"direction",true)
+ else
+ -- setprop(current,"direction",true)
+ end
+ setprop(current,"direction",prop)
+ ::obsolete::
+ current = next
+ end
+ end
+
+ -- todo: track if really needed
+ -- todo: maybe we need to set the property (as it can be a copied list)
+
+ if done and strip then
+ local n = #obsolete
+ if n > 0 then
+ for i=1,n do
+ remove_node(head,obsolete[i],true)
+ end
+ if trace_directions then
+ report_directions("%s character nodes removed",n)
+ end
+ end
+ end
+
+ local state = false
+ local last = false
+ local collapse = true
+ current = head
+
+ -- todo: textdir
+ -- todo: inject before parfillskip
+
+ while current do
+ local id = getid(current)
+ if id == math_code then
+ -- todo: this might be tricky nesting
+ current = getnext(endofmath(getnext(current)))
+ else
+ local cp = getprop(current,"direction")
+ if cp == "n" then
+ local swap = state == "r"
+ if swap then
+ head = insertnodebefore(head,current,startdir(lefttoright_code))
+ end
+ setprop(current,"direction",true)
+ while true do
+ local n = getnext(current)
+ if n and getprop(n,"direction") == "n" then
+ current = n
+ setprop(current,"direction",true)
+ else
+ break
+ end
+ end
+ if swap then
+ head, current = insertnodeafter(head,current,stopdir(lefttoright_code))
+ end
+ elseif cp == "l" then
+ if state ~= "l" then
+ if state == "r" then
+ head = insertnodebefore(head,last or current,stopdir(righttoleft_code))
+ end
+ head = insertnodebefore(head,current,startdir(lefttoright_code))
+ state = "l"
+ done = true
+ end
+ last = false
+ elseif cp == "r" then
+ if state ~= "r" then
+ if state == "l" then
+ head = insertnodebefore(head,last or current,stopdir(lefttoright_code))
+ end
+ head = insertnodebefore(head,current,startdir(righttoleft_code))
+ state = "r"
+ done = true
+ end
+ last = false
+ elseif collapse then
+ if cp == "k" or cp == "g" then
+ last = last or current
+ else
+ last = false
+ end
+ else
+ if state == "r" then
+ head = insertnodebefore(head,current,stopdir(righttoleft_code))
+ elseif state == "l" then
+ head = insertnodebefore(head,current,stopdir(lefttoright_code))
+ end
+ state = false
+ last = false
+ end
+ setprop(current,"direction",true)
+ end
+ local next = getnext(current)
+ if next then
+ current = next
+ else
+ local sd = (state == "r" and stopdir(righttoleft_code)) or (state == "l" and stopdir(lefttoright_code))
+ if sd then
+ if id == glue_code and getsubtype(current) == parfillskip_code then
+ head = insertnodebefore(head,current,sd)
+ else
+ head = insertnodeafter(head,current,sd)
+ end
+ end
+ break
+ end
+ end
+
+ return head
+
+end
+
+directions.installhandler(interfaces.variables.default,process)