[latex3-commits] [git/LaTeX3-latex3-luaotfload] bidi-dev: merge mirror (f641dfe)

Ulrike Fischer fischer at troubleshooting-tex.de
Sat Aug 24 15:09:19 CEST 2019


Repository : https://github.com/latex3/luaotfload
On branch  : bidi-dev
Link       : https://github.com/latex3/luaotfload/commit/f641dfe4f28d8856fecb14f8d9ff04f597b3d30d

>---------------------------------------------------------------

commit f641dfe4f28d8856fecb14f8d9ff04f597b3d30d
Merge: 9905253 bd2f9cc
Author: Ulrike Fischer <fischer at troubleshooting-tex.de>
Date:   Sat Aug 24 15:09:19 2019 +0200

    merge mirror


>---------------------------------------------------------------

f641dfe4f28d8856fecb14f8d9ff04f597b3d30d
 .../unicode-data => src}/OpentypeMirroring.txt     |   0
 src/luaotfload-filelist.lua                        |   1 +
 src/luaotfload-main.lua                            |   1 +
 src/luaotfload-mirror.lua                          | 102 +++++++++++++++++++++
 .../generic/unicode-data}/BidiMirroring-510.txt    |   0
 texmf/tex/latex-dev/luaotfload/luaotfload-bidi.lua |   6 +-
 .../latex-dev/luaotfload/luaotfload-filelist.lua   |   1 +
 texmf/tex/latex-dev/luaotfload/luaotfload-main.lua |   1 +
 .../tex/latex-dev/luaotfload/luaotfload-mirror.lua | 102 +++++++++++++++++++++
 9 files changed, 211 insertions(+), 3 deletions(-)

diff --cc src/luaotfload-filelist.lua
index 2f0f78a,93b3470..94bc458
--- a/src/luaotfload-filelist.lua
+++ b/src/luaotfload-filelist.lua
@@@ -248,8 -248,8 +248,9 @@@ luaotfload.filelist.data 
      { name = "letterspace"       ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "embolden"          ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
      { name = "notdef"            ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+     { name = "mirror"            ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
      { name = "loaders"           ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
 +    { name = "multiscript"       ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "parsers"           ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "resolvers"         ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "unicode"           ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
diff --cc src/luaotfload-main.lua
index 628b2ef,2d208b3..fdacc55
--- a/src/luaotfload-main.lua
+++ b/src/luaotfload-main.lua
@@@ -300,8 -300,8 +300,9 @@@ luaotfload.main = function (
      loadmodule "letterspace"  --- extra character kerning
      loadmodule "embolden"     --- fake bold
      loadmodule "notdef"       --- missing glyph handling
+     loadmodule "mirror"       --- mirroring for r2l text
      initialize "auxiliary"    --- additional high-level functionality
 +    loadmodule "bidi"         --- ...
      loadmodule "multiscript"  --- ...
  
      luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec
diff --cc texmf/tex/latex-dev/luaotfload/luaotfload-bidi.lua
index 8e58995,0000000..bf3d49d
mode 100644,000000..100644
--- a/texmf/tex/latex-dev/luaotfload/luaotfload-bidi.lua
+++ b/texmf/tex/latex-dev/luaotfload/luaotfload-bidi.lua
@@@ -1,614 -1,0 +1,614 @@@
 +-----------------------------------------------------------------------
 +--         FILE:  luaotfload-bidi.lua
 +--  DESCRIPTION:  part of luaotfload / fallback
 +-----------------------------------------------------------------------
 +
 +local ProvidesLuaModule = { 
 +    name          = "luaotfload-bidi",
-     version       = "2.9904",     --TAGVERSION
-     date          = "2019-08-02", --TAGDATE
++    version       = "3.0003",       --TAGVERSION
++    date          = "2019-08-11", --TAGDATE
 +    description   = "luaotfload submodule / bidi",
 +    license       = "GPL v2.0",
 +    author        = "Marcel Krüger"
 +}
 +
 +if luatexbase and luatexbase.provides_module then
 +  luatexbase.provides_module (ProvidesLuaModule)
 +end  
 +
 +local nodenew            = node.direct.new
 +local nodecopy           = node.direct.copy
 +local nodeflush          = node.direct.flush_node
 +local free               = node.direct.free
 +local setsubtype         = node.direct.setsubtype
 +local setchar            = node.direct.setchar
 +local getchar            = node.direct.getchar
 +local getfont            = node.direct.getfont
 +local getid              = node.direct.getid
 +local setnext            = node.direct.setnext
 +local getnext            = node.direct.getnext
 +local setprev            = node.direct.setprev
 +local getprev            = node.direct.getprev
 +local traverse           = node.direct.traverse
 +local getwhd             = node.direct.getwhd
 +local tail               = node.direct.tail
 +local remove             = node.direct.remove
 +local insert_after       = node.direct.insert_after
 +local insert_before      = node.direct.insert_before
 +local traverse_char      = node.direct.traverse_char
 +local protect_glyph      = node.direct.protect_glyph
 +local getdirection       = node.direct.getdirection
 +local setdirection       = node.direct.setdirection
 +local otffeatures        = fonts.constructors.newfeatures "otf"
 +
 +local codepoint = lpeg.S'0123456789ABCDEF'^4/function(c)return tonumber(c, 16)end
 +local bidi_classes do
 +  local entry = lpeg.Cg(codepoint * ';' * (1-lpeg.P';')^0 * ';' * (1-lpeg.P';')^0 * ';' * (1-lpeg.P';')^0 * ';' * lpeg.C((1-lpeg.P';')^0) * ';')^-1 * (1-lpeg.P'\n')^0 * '\n'
 +  local file = lpeg.Cf(
 +      lpeg.Ct''
 +    * entry^0
 +  , rawset)
 +
 +  local f = io.open(kpse.find_file"UnicodeData.txt")
 +  bidi_classes = setmetatable(file:match(f:read'*a'), {
 +      __index = function(t, cp)
 +        if     (cp >= 0xAC00 and cp <= 0xDCA3)
 +            or (cp >= 0xD800 and cp <= 0xF8FF)
 +            or (cp >= 0x17000 and cp <= 0x187F7)
 +            or (cp >= 0x20000 and cp <= 0x2EBE0) -- Technically there are some
 +                                                 -- small gaps in there, but
 +                                                 -- why would anyone store
 +                                                 -- other kinds of characters
 +                                                 -- there? Also it would add
 +                                                 -- three additional ranges...
 +            or (cp >= 0xF0000 and cp <= 0x10FFFD) then
 +          t[cp] = "L"
 +          return "L"
 +        else
 +          t[cp] = "ON"
 +          return "ON"
 +        end
 +      end
 +    })
 +  f:close()
 +end
 +
 +local bidi_brackets do
 +  local entry = lpeg.Cg(codepoint * '; ' * lpeg.Ct(lpeg.Cg(codepoint, 'other') * '; ' * lpeg.Cg(lpeg.S'oc', 'type')) * ' ')^-1 * (1-lpeg.P'\n')^0 * '\n'
 +  local file = lpeg.Cf(
 +      lpeg.Ct''
 +    * entry^0
 +  , rawset)
 +
 +  local f = io.open(kpse.find_file"BidiBrackets.txt")
 +  bidi_brackets = file:match(f:read'*a')
 +  f:close()
 +end
 +
 +-- At the time of writing (Unicode 12.1.0), this is a complete list of
 +-- characters whose canonical decomposition contains a bidi_brackets
 +-- entry. Given that this isn't stored directly AFAICT, it is easier to
 +-- list them here than parse some file.
 +local bidi_brackets_canonical = {
 +  [0x2329] = 0x3008,
 +  [0x232A] = 0x3009,
 +}
 +for k, v in pairs(bidi_brackets) do
 +  bidi_brackets_canonical[k] = bidi_brackets_canonical[k] or k
 +end
 +
 +local opentype_mirroring do
 +  local entry = lpeg.Cg(codepoint * '; ' * codepoint * ' ')^-1 * (1-lpeg.P'\n')^0 * '\n'
 +  local file = lpeg.Cf(
 +      lpeg.Ct''
 +    * entry^0
 +  , rawset)
 +
-   local f = io.open(kpse.find_file"OpentypeMirroring.txt")
++  local f = io.open(kpse.find_file"BidiMirroring-510.txt")
 +  opentype_mirroring = file:match(f:read'*a')
 +  f:close()
 +end
 +
 +local bidi_fonts = setmetatable({}, {
 +  __index = function(t, fid)
 +    local f = font.getfont(fid)
 +    -- table.tofile('myfont2', f)
 +    local res = f and f.bidi or false
 +    t[fid] = res
 +    return res
 +  end,
 +})
 +
 +local function makebidifont(tfmdata)
 +  tfmdata.bidi = true
 +end
 +
 +local glyph_id = node.id'glyph'
 +local dir_id = node.id'dir'
 +local glue_id = node.id'glue'
 +local kern_id = node.id'kern'
 +
 +local Strong = {
 +  L = 'L',
 +  R = 'R',
 +  AN = 'R',
 +  EN = 'R',
 +}
 +
 +local NI = {
 +  B = true,
 +  S = true,
 +  WS = true,
 +  ON = true,
 +  FSI = true,
 +  LRI = true,
 +  PDI = true,
 +}
 +
 +local function adjust_nsm(pre, stop, dir, node_class, node_origclass)
 +  local follow = getnext(pre)
 +  local follow_origclass = node_origclass[follow]
 +  while follow ~= stop and (not follow_origclass or follow_origclass == "NSM") do
 +    if follow_origclass then
 +      node_class[follow] = dir
 +    end
 +    follow = getnext(follow)
 +    follow_origclass = node_origclass[follow]
 +  end
 +end
 +local gettime = socket.gettime
 +local fulltime1, fulltime2, fulltime3 = 0, 0, 0
 +function do_wni(head, level, stop, sos, eos, node_class, node_level, node_origclass)
 +  local starttime = gettime()
 +  local opposite, direction
 +  if level % 2 == 0 then
 +    direction, opposite = 'L', 'R'
 +  else
 +    direction, opposite = 'R', 'L'
 +  end
 +  local stop = getnext(stop)
 +  local prevclass, prevstrong = sos, sos
 +  -- We combine W1--W7, that shouldn't make a difference and is
 +  -- faster.
 +  local cur = head
 +  while cur ~= stop do
 +    local curclass = node_class[cur]
 +    if curclass == "NSM" then
 +      curclass = prevclass == "PDI" and "ON" or prevclass
 +      node_class[cur] = curclass
 +    elseif curclass == "EN" then
 +      if prevstrong == "AL" then
 +        curclass = "AN"
 +        node_class[cur] = curclass
 +      elseif prevstrong == "L" then
 +        node_class[cur] = "L"
 +        -- HACK: No curclass change. Therefore prevclass is still EN,
 +        -- such that this W7 change does not affect the ES/ET changes
 +        -- in W4-W5
 +      end
 +    elseif curclass == "ES" then
 +      if prevclass == "EN" then
 +        local follow = getnext(cur)
 +        local followclass = node_class[follow]
 +        while follow ~= stop and not followclass do
 +          follow = getnext(follow)
 +          followclass = node_class[follow]
 +        end
 +        if follow ~= stop and followclass == "EN" then
 +          curclass = "EN"
 +          node_class[cur] = prevstrong == "L" and "L" or curclass
 +        end
 +      end
 +    elseif curclass == "CS" then
 +      if prevclass == "EN" or prevclass == "AN" then
 +        local follow = getnext(cur)
 +        local followclass = node_class[follow]
 +        while follow ~= stop and not followclass do
 +          follow = getnext(follow)
 +          followclass = node_class[follow]
 +        end
 +        if follow ~= stop then
 +          if followclass == "EN" then
 +            if prevstrong == "AL" then
 +              curclass = "AN"
 +              node_class[cur] = curclass
 +            elseif prevclass == "EN" then
 +              curclass = "EN"
 +              node_class[cur] = prevstrong == "L" and "L" or curclass
 +            else
 +              curclass = "ON"
 +              node_class[cur] = curclass
 +            end
 +          elseif followclass == "AN" and prevclass == "AN" then
 +            curclass = "AN"
 +            node_class[cur] = curclass
 +          else
 +            curclass = "ON"
 +            node_class[cur] = curclass
 +          end
 +        else
 +          curclass = "ON"
 +          node_class[cur] = curclass
 +        end
 +      else
 +        curclass = "ON"
 +        node_class[cur] = curclass
 +      end
 +    elseif curclass == "ET" then
 +      local follow = getnext(cur)
 +      local followclass = node_class[follow]
 +      while follow ~= stop and (followclass == "ET" or not followclass) do
 +        follow = getnext(follow)
 +        followclass = node_class[follow]
 +      end
 +      if followclass == "EN" then
 +        follow = cur
 +        followclass = curclass
 +        while follow ~= stop and (followclass == "ET" or not followclass) do
 +          if followclass then
 +            node_class[follow] = "EN"
 +          end
 +          follow = getnext(follow)
 +          followclass = node_class[follow]
 +        end
 +      else
 +        curclass = "ON"
 +        node_class[cur] = curclass
 +      end
 +    elseif curclass == "AL" then
 +      prevstrong = "AL"
 +      curclass = "R"
 +      node_class[cur] = curclass
 +    elseif curclass == "L" or curclass == "R" then
 +      prevstrong = curclass
 +    elseif not curclass then
 +      curclass = prevclass -- Do not change prevclass for the next run
 +    end
 +    prevclass = curclass
 +    cur = getnext(cur)
 +  end
 +  cur = head
 +  local last_e, last_s = 0, 0
 +  local stack = {}
 +  local need_context = {}
 +  while cur ~= stop do
 +    local curclass = node_class[cur]
 +    if curclass == "ON" and getid(cur) == glyph_id and bidi_fonts[getfont(cur)] then
 +      local cp = bidi_brackets_canonical[getchar(cur)]
 +      local bracket = bidi_brackets[cp]
 +      if bracket then
 +        if bracket.type == 'o' then
 +          local info = {cur, bracket.other}
 +          stack[#stack + 1] = info
 +        else -- if cp.type == 'c'
 +          for i = #stack,1,-1 do
 +            local entry = stack[i]
 +            if entry[2] == cp then
 +              for j = i,#stack do
 +                stack[j] = nil
 +              end
 +              if last_e >= i then
 +                local beg = entry[1]
 +                node_class[beg], node_class[cur] = direction, direction
 +                adjust_nsm(beg, stop, direction, node_class, node_origclass)
 +                adjust_nsm(cur, stop, direction, node_class, node_origclass)
 +                last_s, last_e = i-1, i-1
 +              elseif last_s >= i then
 +                need_context[entry[1]] = cur
 +                if entry[3] then
 +                  local beg = entry[1]
 +                  node_class[beg], node_class[cur] = opposite, opposite
 +                  adjust_nsm(beg, stop, opposite, node_class, node_origclass)
 +                  adjust_nsm(cur, stop, opposite, node_class, node_origclass)
 +                end
 +                last_s = i-1
 +              end
 +              break
 +            end
 +          end
 +        end
 +      end
 +    else
 +      local strong = Strong[curclass]
 +      if strong == direction then
 +        last_e, last_s = #stack, #stack
 +      elseif strong == opposite then
 +        last_s = #stack
 +      end
 +    end
 +    cur = getnext(cur)
 +  end
 +  cur = head
 +  prevstrong = sos
 +  local newlevels = direction == 'L' and {
 +    L = level,
 +    R = level+1,
 +    AN = level+2,
 +    EN = level+2,
 +  } or {
 +    L = level+1,
 +    R = level,
 +    AN = level+1,
 +    EN = level+1,
 +  }
 +  while cur ~= stop do
 +    local curclass = node_class[cur]
 +    local strong = Strong[curclass]
 +    if strong then
 +      prevstrong = strong
 +      node_level[cur] = newlevels[curclass]
 +      cur = getnext(cur)
 +    elseif need_context[cur] then
 +      local final = need_context[cur]
 +      node_class[cur], node_class[final] = prevstrong, prevstrong
 +      adjust_nsm(final, stop, prevstrong, node_class, node_origclass)
 +      adjust_nsm(cur, stop, prevstrong, node_class, node_origclass)
 +      node_level[cur] = newlevels[prevstrong]
 +      cur = getnext(cur)
 +    else
 +      local follow = getnext(cur)
 +      local followclass = need_context[follow] and prevstrong or Strong[node_class[follow]]
 +      while follow ~= stop and not followclass do
 +        follow = getnext(follow)
 +        followclass = need_context[follow] and prevstrong or Strong[node_class[follow]]
 +      end
 +      if follow == stop then
 +        followclass = eos
 +      end
 +      local outerdir = followclass == prevstrong and followclass or direction
 +      follow = cur
 +      followclass = curclass
 +      while follow ~= stop and not Strong[followclass] do
 +        node_class[follow], node_level[follow] = followclass and outerdir, followclass and newlevels[outerdir]
 +        follow = getnext(follow)
 +        followclass = need_context[follow] and prevstrong or node_class[follow]
 +      end
 +      cur = follow
 +    end
 +  end
 +  fulltime1 = fulltime1 + gettime() - starttime
 +end
 +node_class, node_origclass, node_level = {}, {}, {} -- Making these local was significantly
 +-- slower necause they are sparse arrays with medium sized integer
 +-- keys, requiring relativly big allocations
 +function dobidi(head, a, b, c, par_direction)
 +  head = node.direct.todirect(head)
 +  local node_class, node_origclass, node_level = node_class, node_origclass, node_level
 +  local dir_matches = {}
 +  par_direction = par_direction == "TRT" and "R" or "L" -- We hope to only encounter TRT/TLT
 +  local parlevel, level, oldlevel, overwrite, isolate = par_direction == "R" and 1 or 0
 +  level, oldlevel = parlevel, -1
 +  local stack = {}
 +  local function push(dir, new_overwrite)
 +    stack[#stack+1] = {level, overwrite, isolate}
 +    level, overwrite, isolate = level + (level + dir + 1)%2 + 1, new_overwrite, nil
 +  end
 +  local function pop()
 +    local last = stack[#stack]
 +    stack[#stack] = nil
 +    level, overwrite, isolate = last[1], last[2], last[3]
 +  end
 +  local isolating_level_runs = {}
 +  local current_run
 +  local old_dir
 +  for cur, tcur, scur in traverse(head) do
 +    local class, curlevel, isolate_flag
 +    if tcur == glyph_id and bidi_fonts[getfont(cur)] then
 +      class = bidi_classes[getchar(cur)]
 +      if class == "RLE" then
 +        class, curlevel = nil, level
 +        push(1)
 +      elseif class == "LRE" then
 +        class, curlevel = nil, level
 +        push(0)
 +      elseif class == "RLO" then
 +        class, curlevel = nil, level
 +        push(1, "R")
 +      elseif class == "LRO" then
 +        class, curlevel = nil, level
 +        push(0, "L")
 +      elseif class == "PDF" then
 +        class = nil
 +        if not isolate and #stack >= 1 then
 +          pop()
 +        end
 +      -- elseif class == "RLI" then -- Not supported yet, use textdir
 +      --   -- TODO
 +      -- elseif class == "LRI" then -- Not supported yet, use textdir
 +      --   -- TODO
 +      -- elseif class == "FSI" then -- Not supported yet, use textdir
 +      --   -- TODO
 +      -- elseif class == "PDI" then -- Not supported yet, use textdir
 +      --   -- TODO
 +      elseif class == "BN" then
 +        class = overwrite or nil
 +      elseif class == "B" then
 +        assert(false) -- FIXME: Can this happen in TeX?
 +      else
 +        class = overwrite or class
 +      end
 +    elseif tcur == dir_id then
 +      local dir, reset = getdirection(cur)
 +      if reset then
 +        while not isolate and #stack >= 1 do
 +          pop()
 +        end
 +        if isolate then
 +          isolate_flag = isolate
 +          pop()
 +        else
 +          -- Unmatched reset. LuaTeX inserts them sometimes, just
 +          -- dropping them normally works fine. But deleting is
 +          -- difficult here because the loop needs the next pointer.
 +          -- Technically they should stay
 +          if old_dir then nodeflush(old_dir) end
 +          head = remove(head, cur)
 +          old_dir = cur
 +          goto SKIP
 +        end
 +        class = overwrite or "PDI"
 +      else
 +        curlevel = level
 +        dir = dir == 1 and 1 or 0
 +        class = overwrite or (dir == 1 and "LRI" or "RLI")
 +        push(dir, nil)
 +        isolate_flag = false
 +      end
 +    elseif tcur == glue_id or tcur == kern_id then -- Not sure about kerns
 +      class = "WS"
 +    else
 +      class = "ON"
 +    end
 +    curlevel = curlevel or level
 +    node_class[cur], node_origclass[cur] = class, class
 +    --
 +    if curlevel ~= oldlevel and class then
 +      local os = (oldlevel > curlevel and oldlevel or curlevel) % 2 == 1 and 'R' or 'L'
 +      oldlevel = curlevel
 +      if current_run then
 +        current_run[3] = getprev(cur)
 +        current_run[5] = os
 +        current_run = nil
 +      end
 +      if isolate_flag then
 +        current_run = isolate_flag
 +        local beg = current_run.remember
 +        if getnext(beg) ~= cur then -- Handle stupid input
 +          dir_matches[beg] = {getnext(beg), getprev(cur)}
 +          setprev(getnext(beg), nil)
 +          setnext(getprev(cur), nil)
 +          setnext(beg, cur)
 +          setprev(cur, beg)
 +        end
 +      else
 +        current_run = {cur, curlevel, nil, os}
 +        isolating_level_runs[#isolating_level_runs+1] = current_run
 +      end
 +    end
 +    if isolate_flag == false then
 +      current_run.remember = cur
 +      isolate = current_run
 +      current_run = nil
 +    end
 +    ::SKIP::
 +  end
 +  local t = tail(head)
 +  do
 +    local tid = getid(t)
 +    while t and tid > dir_id and tid ~= glyph_id do t = getprev(t) tid = getid(t) end
 +    if not t then return head end -- Everything is discardable, so ignore it
 +  end
 +  if current_run then
 +    current_run[3] = t
 +    current_run[5] = (oldlevel > parlevel and oldlevel or parlevel) % 2 == 1 and 'R' or 'L'
 +    -- Should always be level IINM, but let's us the offical check
 +    current_run = nil
 +  end
 +  for i = 1,#stack do
 +    if isolate then
 +      local beg = isolate.remember
 +      local n
 +      if beg == t then
 +        n = getprev(t)
 +        if not n then return head end
 +        setnext(n, free(t))
 +      else
 +        dir_matches[beg] = {getnext(beg), t}
 +        if old_dir then
 +          n = old_dir
 +          setdirection(n, getdirection(beg), 1)
 +          old_dir = nil
 +        else
 +          n = nodecopy(beg)
 +          setsubtype(n, 1)
 +        end
 +        node_class[n], node_origclass[n] = "PDI", "PDI"
 +        setnext(n, getnext(t))
 +        setprev(getnext(beg), nil)
 +        setnext(t, nil)
 +        setnext(beg, n)
 +        setprev(n, beg)
 +      end
 +      t = n
 +      isolate[3], isolate[5] = n, isolate[2] % 2 == 1 and 'R' or 'L'
 +    end
 +    pop()
 +  end
 +  for i = 1, #isolating_level_runs do
 +    local run = isolating_level_runs[i]
 +    do_wni(run[1], run[2], run[3], run[4], run[5], node_class, node_level, node_origclass)
 +  end
 +  level = parlevel
 +  local curdir = level
 +  function push(n, newlevel)
 +    local dirnode = nodenew(dir_id)
 +    setdirection(dirnode, newlevel % 2, 0)
 +    stack[#stack + 1] = {level, dirnode}
 +    -- tableinsert(stack, 
 +    level = newlevel
 +    return insert_before(head, n, dirnode)
 +  end
 +  function pop(head, n)
 +    local entry = stack[#stack]
 +    stack[#stack] = nil
 +    level = entry[1]
 +    local dirnode = nodecopy(entry[2])
 +    setsubtype(dirnode, 1)
 +    return insert_before(head, n, dirnode), entry[2]
 +  end
 +  for cur, tcur, scur in traverse(head) do
 +    local curlevel = node_level[cur]
 +    if tcur == dir_id and scur == 1 then
 +      local newlevel = curlevel + (curlevel + getdirection(cur) + 1)%2 + 1
 +      while level > newlevel do
 +        head = pop(head, cur)
 +      end
 +      stack[#stack] = nil
 +      level = curlevel
 +    end
 +    if curlevel and level ~= curlevel then
 +      local push_pos = cur
 +      while level > curlevel do
 +        head, push_pos = pop(head, cur)
 +      end
 +      if level < curlevel then
 +        push(push_pos, curlevel)
 +      end
 +    end
 +    if tcur == dir_id and scur == 0 then
 +      local newlevel = curlevel + (curlevel + getdirection(cur) + 1)%2 + 1
 +      stack[#stack + 1] = {level, cur}
 +      level = newlevel
 +      local remembered = dir_matches[cur]
 +      if remembered then
 +        local newnext, newprev = remembered[1], remembered[2]
 +        setnext(newprev, getnext(cur))
 +        setprev(getnext(cur), newprev)
 +        setprev(newnext, cur)
 +        setnext(cur, newnext)
 +      end
 +    elseif level % 2 == 1 and tcur == glyph_id and scur == 0 and bidi_fonts[getfont(cur)] then
 +      local char = opentype_mirroring[getchar(cur)]
 +      if char then
 +        setchar(cur, char)
 +      end
 +    end
 +  end
 +  return node.direct.tonode(head)
 +end
 +
 +otffeatures.register {
 +  name        = "bidi",
 +  description = "Apply Unicode bidi algorithm",
 +  default = 1,
 +  manipulators = {
 +    node = makebidifont,
 +  },
 +  --                -- We have to see how processors interact with
 +  --                -- multiscript fonts
 +  -- processors = {
 +  --   node = donotdef,
 +  -- }
 +}
 +
 +--- vim:sw=2:ts=2:expandtab:tw=71
diff --cc texmf/tex/latex-dev/luaotfload/luaotfload-filelist.lua
index 2f0f78a,93b3470..94bc458
--- a/texmf/tex/latex-dev/luaotfload/luaotfload-filelist.lua
+++ b/texmf/tex/latex-dev/luaotfload/luaotfload-filelist.lua
@@@ -248,8 -248,8 +248,9 @@@ luaotfload.filelist.data 
      { name = "letterspace"       ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "embolden"          ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
      { name = "notdef"            ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
+     { name = "mirror"            ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
      { name = "loaders"           ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
 +    { name = "multiscript"       ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "parsers"           ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "resolvers"         ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" }, 
      { name = "unicode"           ,kind = kind_library, ext =".lua", gitdir=gitdirsrc, texdir=texdirtex, gitpref = "luaotfload-" },
diff --cc texmf/tex/latex-dev/luaotfload/luaotfload-main.lua
index 628b2ef,2d208b3..fdacc55
--- a/texmf/tex/latex-dev/luaotfload/luaotfload-main.lua
+++ b/texmf/tex/latex-dev/luaotfload/luaotfload-main.lua
@@@ -300,8 -300,8 +300,9 @@@ luaotfload.main = function (
      loadmodule "letterspace"  --- extra character kerning
      loadmodule "embolden"     --- fake bold
      loadmodule "notdef"       --- missing glyph handling
+     loadmodule "mirror"       --- mirroring for r2l text
      initialize "auxiliary"    --- additional high-level functionality
 +    loadmodule "bidi"         --- ...
      loadmodule "multiscript"  --- ...
  
      luaotfload.aux.start_rewrite_fontname () --- to be migrated to fontspec





More information about the latex3-commits mailing list