diff options
Diffstat (limited to 'Master/texmf-dist/tex/generic/babel/babel-bidi-basic.lua')
-rw-r--r-- | Master/texmf-dist/tex/generic/babel/babel-bidi-basic.lua | 371 |
1 files changed, 371 insertions, 0 deletions
diff --git a/Master/texmf-dist/tex/generic/babel/babel-bidi-basic.lua b/Master/texmf-dist/tex/generic/babel/babel-bidi-basic.lua new file mode 100644 index 00000000000..c5104648763 --- /dev/null +++ b/Master/texmf-dist/tex/generic/babel/babel-bidi-basic.lua @@ -0,0 +1,371 @@ +-- +-- This is file `babel-bidi-basic.lua', +-- generated with the docstrip utility. +-- +-- The original source files were: +-- +-- babel.dtx (with options: `basic') +-- +-- +-- Copyright (C) 2012-2018 Javier Bezos and Johannes L. Braams. +-- Copyright (C) 1989-2012 Johannes L. Braams and +-- any individual authors listed elsewhere in this file. +-- All rights reserved. +-- +-- This file is part of the Babel system. +-- -------------------------------------- +-- +-- It may be distributed and/or modified under the +-- conditions of the LaTeX Project Public License, either version 1.3 +-- of this license or (at your option) any later version. +-- The latest version of this license is in +-- http://www.latex-project.org/lppl.txt +-- and version 1.3 or later is part of all distributions of LaTeX +-- version 2003/12/01 or later. +-- +-- This work has the LPPL maintenance status "maintained". +-- +-- The Current Maintainer of this work is Javier Bezos. +-- +-- The list of derived (unpacked) files belonging to the distribution +-- and covered by LPPL is defined by the unpacking scripts (with +-- extension |.ins|) which are part of the distribution. +-- +Babel = Babel or {} + +Babel.fontmap = Babel.fontmap or {} +Babel.fontmap[0] = {} -- l +Babel.fontmap[1] = {} -- r +Babel.fontmap[2] = {} -- al/an + +function Babel.pre_otfload_v(head) + -- head = Babel.numbers(head) + head = Babel.bidi(head, true) + return head +end + +function Babel.pre_otfload_h(head, gc, sz, pt, dir) + -- head = Babel.numbers(head) + head = Babel.bidi(head, false, dir) + return head +end + +require('babel-bidi.lua') + +local characters = Babel.characters +local ranges = Babel.ranges + +local DIR = node.id('dir') +local GLYPH = node.id('glyph') + +local function insert_implicit(head, state, outer) + local new_state = state + if state.sim and state.eim and state.sim ~= state.eim then + dir = ((outer == 'r') and 'TLT' or 'TRT') -- ie, reverse + local d = node.new(DIR) + d.dir = '+' .. dir + node.insert_before(head, state.sim, d) + local d = node.new(DIR) + d.dir = '-' .. dir + node.insert_after(head, state.eim, d) + end + new_state.sim, new_state.eim = nil, nil + return head, new_state +end + +local function insert_numeric(head, state) + local new + local new_state = state + if state.san and state.ean and state.san ~= state.ean then + local d = node.new(DIR) + d.dir = '+TLT' + _, new = node.insert_before(head, state.san, d) + if state.san == state.sim then state.sim = new end + local d = node.new(DIR) + d.dir = '-TLT' + _, new = node.insert_after(head, state.ean, d) + if state.ean == state.eim then state.eim = new end + end + new_state.san, new_state.ean = nil, nil + return head, new_state +end + +-- \hbox with an explicit dir can lead to wrong results +-- <R \hbox dir TLT{<R>}> and <L \hbox dir TRT{<L>}> + +function Babel.bidi(head, ispar, hdir) + local d -- d is used mainly for computations in a loop + local prev_d = '' + local new_d = false + + local nodes = {} + local outer_first = nil + + local has_en = false + local first_et = nil + + local ATDIR = luatexbase.registernumber'bbl@attr@dir' + + local save_outer + local temp = node.get_attribute(head, ATDIR) + if temp then + temp = temp % 3 + save_outer = (temp == 0 and 'l') or + (temp == 1 and 'r') or + (temp == 2 and 'al') + elseif ispar then -- Or error? Shouldn't happen + save_outer = ('TRT' == tex.pardir) and 'r' or 'l' + else + save_outer = ('TRT' == hdir) and 'r' or 'l' + end + local outer = save_outer + local last = outer + -- 'al' is only taken into account in the first, current loop + if save_outer == 'al' then save_outer = 'r' end + + local fontmap = Babel.fontmap + + for item in node.traverse(head) do + + -- In what follows, #node is the last (previous) node, because the + -- current one is not added until we start processing the neutrals. + + -- three cases: glyph, dir, otherwise + if item.id == GLYPH then + + local chardata = characters[item.char] + d = chardata and chardata.d or nil + if not d then + for nn, et in ipairs(ranges) do + if item.char < et[1] then + break + elseif item.char <= et[2] then + d = et[3] + break + end + end + end + d = d or 'l' + + local temp = (d == 'l' and 0) or + (d == 'r' and 1) or + (d == 'al' and 2) or + (d == 'an' and 2) or nil + if temp and fontmap and fontmap[temp][item.font] then + item.font = fontmap[temp][item.font] + end + + if new_d then + table.insert(nodes, {nil, (outer == 'l') and 'l' or 'r', nil}) + attr_d = node.get_attribute(item, ATDIR) + attr_d = attr_d % 3 + if attr_d == 1 then + outer_first = 'r' + last = 'r' + elseif attr_d == 2 then + outer_first = 'r' + last = 'al' + else + outer_first = 'l' + last = 'l' + end + outer = last + has_en = false + first_et = nil + new_d = false + end + + elseif item.id == DIR then + d = nil + new_d = true + + else + d = nil + end + + -- AL <= EN/ET/ES -- W2 + W3 + W6 + if last == 'al' and d == 'en' then + d = 'an' -- W3 + elseif last == 'al' and (d == 'et' or d == 'es') then + d = 'on' -- W6 + end + + -- EN + CS/ES + EN -- W4 + if d == 'en' and #nodes >= 2 then + if (nodes[#nodes][2] == 'es' or nodes[#nodes][2] == 'cs') + and nodes[#nodes-1][2] == 'en' then + nodes[#nodes][2] = 'en' + end + end + + -- AN + CS + AN -- W4 too, because uax9 mixes both cases + if d == 'an' and #nodes >= 2 then + if (nodes[#nodes][2] == 'cs') + and nodes[#nodes-1][2] == 'an' then + nodes[#nodes][2] = 'an' + end + end + + -- ET/EN -- W5 + W7->l / W6->on + if d == 'et' then + first_et = first_et or (#nodes + 1) + elseif d == 'en' then + has_en = true + first_et = first_et or (#nodes + 1) + elseif first_et then -- d may be nil here ! + if has_en then + if last == 'l' then + temp = 'l' -- W7 + else + temp = 'en' -- W5 + end + else + temp = 'on' -- W6 + end + for e = first_et, #nodes do + if nodes[e][1].id == GLYPH then nodes[e][2] = temp end + end + first_et = nil + has_en = false + end + + if d then + if d == 'al' then + d = 'r' + last = 'al' + elseif d == 'l' or d == 'r' then + last = d + end + prev_d = d + table.insert(nodes, {item, d, outer_first}) + else + -- Not sure about the following. Looks too 'ad hoc', but it's + -- required for numbers, so that 89 19 becomes 19 89. It also + -- affects n+cs/es+n. + if prev_d == 'an' or prev_d == 'en' then + table.insert(nodes, {item, 'on', nil}) + end + end + + outer_first = nil + + end + + -- TODO -- repeated here in case EN/ET is the last node. Find a + -- better way of doing things: + if first_et then -- dir may be nil here ! + if has_en then + if last == 'l' then + temp = 'l' -- W7 + else + temp = 'en' -- W5 + end + else + temp = 'on' -- W6 + end + for e = first_et, #nodes do + if nodes[e][1].id == GLYPH then nodes[e][2] = temp end + end + end + + -- dummy node, to close things + table.insert(nodes, {nil, (outer == 'l') and 'l' or 'r', nil}) + + --------------- NEUTRAL ----------------- + + outer = save_outer + last = outer + + local first_on = nil + + for q = 1, #nodes do + local item + + local outer_first = nodes[q][3] + outer = outer_first or outer + last = outer_first or last + + local d = nodes[q][2] + if d == 'an' or d == 'en' then d = 'r' end + if d == 'cs' or d == 'et' or d == 'es' then d = 'on' end --- W6 + + if d == 'on' then + first_on = first_on or q + elseif first_on then + if last == d then + temp = d + else + temp = outer + end + for r = first_on, q - 1 do + nodes[r][2] = temp + item = nodes[r][1] -- MIRRORING + if item.id == GLYPH and temp == 'r' then + item.char = characters[item.char].m or item.char + end + end + first_on = nil + end + + if d == 'r' or d == 'l' then last = d end + end + + -------------- IMPLICIT, REORDER ---------------- + + outer = save_outer + last = outer + + local state = {} + state.has_r = false + + for q = 1, #nodes do + + local item = nodes[q][1] + + outer = nodes[q][3] or outer + + local d = nodes[q][2] + + if d == 'nsm' then d = last end -- W1 + if d == 'en' then d = 'an' end + local isdir = (d == 'r' or d == 'l') + + if outer == 'l' and d == 'an' then + state.san = state.san or item + state.ean = item + elseif state.san then + head, state = insert_numeric(head, state) + end + + if outer == 'l' then + if d == 'an' or d == 'r' then -- im -> implicit + if d == 'r' then state.has_r = true end + state.sim = state.sim or item + state.eim = item + elseif d == 'l' and state.sim and state.has_r then + head, state = insert_implicit(head, state, outer) + elseif d == 'l' then + state.sim, state.eim, state.has_r = nil, nil, false + end + else + if d == 'an' or d == 'l' then + state.sim = state.sim or item + state.eim = item + elseif d == 'r' and state.sim then + head, state = insert_implicit(head, state, outer) + elseif d == 'r' then + state.sim, state.eim = nil, nil + end + end + + if isdir then + last = d -- Don't search back - best save now + elseif d == 'on' and state.san then + state.san = state.san or item + state.ean = item + end + + end + + return node.prev(head) or head +end |