summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/tex/context/base/typo-dha.lua
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/tex/context/base/typo-dha.lua')
-rw-r--r--Master/texmf-dist/tex/context/base/typo-dha.lua416
1 files changed, 416 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/context/base/typo-dha.lua b/Master/texmf-dist/tex/context/base/typo-dha.lua
new file mode 100644
index 00000000000..3410c2dfca0
--- /dev/null
+++ b/Master/texmf-dist/tex/context/base/typo-dha.lua
@@ -0,0 +1,416 @@
+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 : delayed inserts here
+-- todo : get rid of local functions here
+-- beware: math adds whatsits afterwards so that will mess things up
+-- 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)
+-- todo : check if we still have crashes in luatex when non-matched (used to be the case)
+
+-- 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 setfield = nuts.setfield
+local getattr = nuts.getattr
+local setattr = nuts.setattr
+local getprop = nuts.getprop
+local setprop = nuts.setprop
+
+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 whatcodes = nodes.whatcodes
+local mathcodes = nodes.mathcodes
+
+local glyph_code = nodecodes.glyph
+local whatsit_code = nodecodes.whatsit
+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 localpar_code = whatcodes.localpar
+local dir_code = whatcodes.dir
+
+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)
+ return new_textdir(finish == "TRT" and "-TRT" or "-TLT")
+end
+
+local function startdir(finish)
+ return new_textdir(finish == "TRT" and "+TRT" or "+TLT")
+end
+
+local function process(start)
+
+ local head = tonut(start) -- we have a global head
+
+ local current = head
+ local inserted = nil
+ local finish = nil
+ local autodir = 0
+ local embedded = 0
+ local override = 0
+ local pardir = 0
+ local textdir = 0
+ local done = false
+ local finished = nil
+ local finidir = nil
+ local stack = { }
+ local top = 0
+ local obsolete = { }
+ local lro = false
+ local lro = false
+ local prevattr = false
+ local fences = { }
+
+ local function finish_auto_before()
+ head, inserted = insert_node_before(head,current,stopdir(finish))
+ finished, finidir, autodir = inserted, finish, 0
+ finish, done = nil, true
+ end
+
+ local function finish_auto_after()
+ head, current = insert_node_after(head,current,stopdir(finish))
+ finished, finidir, autodir = current, finish, 0
+ finish, done = nil, true
+ end
+
+ local function force_auto_left_before(direction)
+ if finish then
+ head, inserted = insert_node_before(head,current,stopdir(finish))
+ finished = inserted
+ finidir = finish
+ end
+ if embedded >= 0 then
+ finish, autodir = "TLT", 1
+ else
+ finish, autodir = "TRT", -1
+ end
+ done = true
+ if finidir == finish then
+ head = remove_node(head,finished,true)
+ else
+ head, inserted = insert_node_before(head,current,startdir(finish))
+ end
+ end
+
+ local function force_auto_right_before(direction)
+ if finish then
+ head, inserted = insert_node_before(head,current,stopdir(finish))
+ finished = inserted
+ finidir = finish
+ end
+ if embedded <= 0 then
+ finish, autodir, done = "TRT", -1
+ else
+ finish, autodir, done = "TLT", 1
+ end
+ done = true
+ if finidir == finish then
+ head = remove_node(head,finished,true)
+ else
+ head, inserted = insert_node_before(head,current,startdir(finish))
+ end
+ 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
+
+ while current do
+ local id = getid(current)
+ if id == math_code then
+ current = getnext(end_of_math(getnext(current)))
+ else
+ local attr = getattr(current,a_directions)
+ if attr and attr > 0 and attr ~= prevattr then
+ if not getglobal(a) then
+ lro, rlo = false, false
+ end
+ prevattr = attr
+ end
+ if id == glyph_code then
+ if attr and attr > 0 then
+ local character = getchar(current)
+ 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)
+ 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
+ if autodir >= 0 then
+ force_auto_right_before(direction)
+ end
+ setfield(current,"char",mirror)
+ done = true
+ elseif autodir < 0 then
+ setfield(current,"char",mirror)
+ done = true
+ else
+ mirror = false
+ 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
+ setfield(current,"char",mirror)
+ done = true
+ force_auto_right_before(direction)
+ else
+ mirror = false
+ end
+ elseif autodir < 0 then
+ setfield(current,"char",mirror)
+ done = true
+ else
+ mirror = false
+ end
+ end
+ if trace_directions then
+ setcolor(current,direction,false,mirror)
+ end
+ elseif direction == "l" then
+ if trace_directions then
+ setcolor(current,"l",reversed)
+ end
+ if autodir <= 0 then -- could be option
+ force_auto_left_before(direction)
+ end
+ elseif direction == "r" then
+ if trace_directions then
+ setcolor(current,"r",reversed)
+ end
+ if autodir >= 0 then
+ force_auto_right_before(direction)
+ end
+ elseif direction == "en" then -- european number
+ if trace_directions then
+ setcolor(current,"l")
+ end
+ if autodir <= 0 then -- could be option
+ force_auto_left_before(direction)
+ end
+ elseif direction == "al" then -- arabic number
+ if trace_directions then
+ setcolor(current,"r")
+ end
+ if autodir >= 0 then
+ force_auto_right_before(direction)
+ end
+ elseif direction == "an" then -- arabic number
+ if trace_directions then
+ setcolor(current,"r")
+ end
+ if autodir >= 0 then
+ force_auto_right_before(direction)
+ end
+ 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, embedded = s[1], s[2]
+ top = top - 1
+ end
+ obsolete[#obsolete+1] = current
+ else
+ setcolor(current)
+ end
+ else
+ -- we do nothing
+ end
+ elseif id == whatsit_code then
+ local subtype = getsubtype(current)
+ if subtype == 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
+ elseif subtype == dir_code then
+ -- todo: also treat as lro|rlo and stack
+ if finish then
+ finish_auto_before()
+ end
+ local dir = getfield(current,"dir")
+ if dir == "+TRT" then
+ finish, autodir = "TRT", -1
+ elseif dir == "-TRT" then
+ finish, autodir = nil, 0
+ elseif dir == "+TLT" then
+ finish, autodir = "TLT", 1
+ elseif dir == "-TLT" then
+ finish, autodir = nil, 0
+ end
+ textdir = autodir
+ else
+ if finish then
+ finish_auto_before()
+ end
+ end
+ elseif finish then
+ finish_auto_before()
+ end
+ local cn = getnext(current)
+ if cn then
+ -- we're okay
+ elseif finish then
+ finish_auto_after()
+ end
+ current = cn
+ end
+ end
+
+ if done and strip then
+ local n = #obsolete
+ if n > 0 then
+ for i=1,n do
+ remove_node(head,obsolete[i],true)
+ end
+ report_directions("%s character nodes removed",n)
+ end
+ end
+
+ return tonode(head), done
+
+end
+
+directions.installhandler(interfaces.variables.default,process)
+