summaryrefslogtreecommitdiff
path: root/tex/context/base/mkiv/typo-dha.lua
diff options
context:
space:
mode:
authorContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
committerContext Git Mirror Bot <phg42.2a@gmail.com>2016-01-12 17:15:07 +0100
commit8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch)
tree94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/mkiv/typo-dha.lua
parentf5aed2e51223c36c84c5f25a6cad238b2af59087 (diff)
downloadcontext-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/mkiv/typo-dha.lua')
-rw-r--r--tex/context/base/mkiv/typo-dha.lua450
1 files changed, 450 insertions, 0 deletions
diff --git a/tex/context/base/mkiv/typo-dha.lua b/tex/context/base/mkiv/typo-dha.lua
new file mode 100644
index 000000000..30984a26c
--- /dev/null
+++ b/tex/context/base/mkiv/typo-dha.lua
@@ -0,0 +1,450 @@
+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
+--
+-- \textdir TLT LATIN ARAB => LATIN BARA
+-- \textdir TRT LATIN ARAB => LATIN BARA
+-- \textdir TRT LRO LATIN ARAB => LATIN ARAB
+-- \textdir TLT LRO LATIN ARAB => LATIN ARAB
+-- \textdir TLT RLO LATIN ARAB => NITAL ARAB
+-- \textdir TRT 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.default", function(v) trace_directions = v end)
+
+local report_directions = logs.reporter("typesetting","text directions")
+
+local nuts = nodes.nuts
+local tonut = nuts.tonut
+local tonode = nuts.tonode
+local nutstring = nuts.tostring
+
+local getnext = nuts.getnext
+local getprev = nuts.getprev
+local getfont = nuts.getfont
+local getchar = nuts.getchar
+local getid = nuts.getid
+local getsubtype = nuts.getsubtype
+local getlist = nuts.getlist
+local getfield = nuts.getfield
+local getattr = nuts.getattr
+local getprop = nuts.getprop
+
+local setfield = nuts.setfield
+local setprop = nuts.setprop
+local setchar = nuts.setchar
+
+local insert_node_before = nuts.insert_before
+local insert_node_after = nuts.insert_after
+local remove_node = nuts.remove
+local end_of_math = nuts.end_of_math
+
+local nodepool = nuts.pool
+
+local nodecodes = nodes.nodecodes
+local mathcodes = nodes.mathcodes
+
+local glyph_code = nodecodes.glyph
+local math_code = nodecodes.math
+local penalty_code = nodecodes.penalty
+local kern_code = nodecodes.kern
+local glue_code = nodecodes.glue
+local hlist_code = nodecodes.hlist
+local vlist_code = nodecodes.vlist
+local dir_code = nodecodes.dir
+local localpar_code = nodecodes.localpar
+
+local new_textdir = nodepool.textdir
+
+local hasbit = number.hasbit
+local formatters = string.formatters
+local insert = table.insert
+
+local fonthashes = fonts.hashes
+local fontdata = fonthashes.identifiers
+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_state = attributes.private('state')
+local a_directions = attributes.private('directions')
+
+local strip = false
+
+local s_isol = fonts.analyzers.states.isol
+
+local function stopdir(finish)
+ local n = new_textdir(finish == "TRT" and "-TRT" or "-TLT")
+ setprop(n,"direction",true)
+ return n
+end
+
+local function startdir(finish)
+ local n = new_textdir(finish == "TRT" and "+TRT" or "+TLT")
+ setprop(n,"direction",true)
+ return n
+end
+
+local function nextisright(current)
+ current = getnext(current)
+ local id = getid(current)
+ if id == glyph_code then
+ local character = getchar(current)
+ local direction = chardirections[character]
+ return direction == "r" or direction == "al" or direction == "an"
+ end
+end
+
+local function previsright(current)
+ current = getprev(current)
+ local id = getid(current)
+ if id == glyph_code then
+ local character = getchar(current)
+ local direction = chardirections[character]
+ return direction == "r" or direction == "al" or direction == "an"
+ end
+end
+
+local function process(start)
+
+ local head = tonut(start) -- we have a global head
+ 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
+ local id = getid(current)
+ local next = getnext(current)
+ if id == math_code then
+ current = getnext(end_of_math(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
+ if id == glyph_code then
+ if attr and attr > 0 then
+ local character = getchar(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
+ setprop(current,a_state,s_isol) -- hm
+ direction = "l"
+ reversed = true
+ end
+ end
+ if direction == "on" then
+ local mirror = charmirrors[character]
+ if mirror and fontchar[getfont(current)][mirror] then
+ local class = charclasses[character]
+ if class == "open" then
+ if nextisright(current) then
+ setchar(current,mirror)
+ setprop(current,"direction","r")
+ elseif autodir < 0 then
+ setchar(current,mirror)
+ setprop(current,"direction","r")
+ else
+ mirror = false
+ setprop(current,"direction","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")
+ else
+ setprop(current,"direction","l")
+ mirror = false
+ end
+ elseif autodir < 0 then
+ setchar(current,mirror)
+ setprop(current,"direction","r")
+ else
+ setprop(current,"direction","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")
+ elseif direction == "r" then
+ if trace_directions then
+ setcolor(current,"r",reversed)
+ end
+ setprop(current,"direction","r")
+ elseif direction == "en" then -- european number
+ if trace_directions then
+ setcolor(current,"l")
+ end
+ setprop(current,"direction","l")
+ elseif direction == "al" then -- arabic letter
+ if trace_directions then
+ setcolor(current,"r")
+ end
+ setprop(current,"direction","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
+ elseif direction == "lro" then -- Left-to-Right Override -> right becomes left
+ top = top + 1
+ stack[top] = { override, embedded }
+ override = -1
+ obsolete[#obsolete+1] = current
+ elseif direction == "rlo" then -- Right-to-Left Override -> left becomes right
+ top = top + 1
+ stack[top] = { override, embedded }
+ override = 1
+ obsolete[#obsolete+1] = current
+ elseif direction == "lre" then -- Left-to-Right Embedding -> TLT
+ top = top + 1
+ stack[top] = { override, embedded }
+ embedded = 1
+ obsolete[#obsolete+1] = current
+ elseif direction == "rle" then -- Right-to-Left Embedding -> TRT
+ top = top + 1
+ stack[top] = { override, embedded }
+ embedded = -1
+ obsolete[#obsolete+1] = current
+ 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
+ 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
+ setprop(current,"direction",'g')
+ elseif id == kern_code then
+ setprop(current,"direction",'k')
+ elseif id == dir_code then
+ local dir = getfield(current,"dir")
+ if dir == "+TRT" then
+ autodir = -1
+ elseif dir == "+TLT" then
+ autodir = 1
+ elseif dir == "-TRT" or dir == "-TLT" then
+ if embedded and embedded~= 0 then
+ autodir = embedded
+ else
+ autodir = 0
+ end
+ else
+ -- message
+ end
+ textdir = autodir
+ setprop(current,"direction",true)
+ elseif id == localpar_code then
+ local dir = getfield(current,"dir")
+ if dir == 'TRT' then
+ autodir = -1
+ elseif dir == 'TLT' then
+ autodir = 1
+ end
+ pardir = autodir
+ textdir = pardir
+ setprop(current,"direction",true)
+ else
+ setprop(current,"direction",true)
+ end
+ 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(end_of_math(getnext(current)))
+ else
+ local cp = getprop(current,"direction")
+ if cp == "n" then
+ local swap = state == "r"
+ if swap then
+ head = insert_node_before(head,current,startdir("TLT"))
+ 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 = insert_node_after(head,current,stopdir("TLT"))
+ end
+ elseif cp == "l" then
+ if state ~= "l" then
+ if state == "r" then
+ head = insert_node_before(head,last or current,stopdir("TRT"))
+ end
+ head = insert_node_before(head,current,startdir("TLT"))
+ state = "l"
+ done = true
+ end
+ last = false
+ elseif cp == "r" then
+ if state ~= "r" then
+ if state == "l" then
+ head = insert_node_before(head,last or current,stopdir("TLT"))
+ end
+ head = insert_node_before(head,current,startdir("TRT"))
+ 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 = insert_node_before(head,current,stopdir("TRT"))
+ elseif state == "l" then
+ head = insert_node_before(head,current,stopdir("TLT"))
+ end
+ state = false
+ last = false
+ end
+ setprop(current,"direction",true)
+ end
+ local next = getnext(current)
+ if next then
+ current = next
+ else
+ if state == "r" then
+ head = insert_node_after(head,current,stopdir("TRT"))
+ elseif state == "l" then
+ head = insert_node_after(head,current,stopdir("TLT"))
+ end
+ break
+ end
+ end
+
+ return tonode(head), done
+
+end
+
+directions.installhandler(interfaces.variables.default,process)