OSDN Git Service

added several tex.setattribute('global', attr_dir, 0), because node.set_attribute...
[luatex-ja/luatexja.git] / src / ltj-direction.lua
index 759f5a5..08804aa 100644 (file)
@@ -56,51 +56,50 @@ local dir_node_auto   = luatexja.dir_table.dir_node_auto
 local dir_node_manual = luatexja.dir_table.dir_node_manual
 
 
-
-local function get_dir_count()
-   return tex_getcount('ltj@dir@count')
-end
-luatexja.direction.get_dir_count = get_dir_count 
-
+local get_dir_count
 -- \tate, \yoko
 do
-  local node_next = node.next
-  local node_set_attr = node.set_attribute
-  local function set_list_direction(v, name)
-     local lv, w = tex.nest[tex.nest.ptr], tex.lists.page_head
-     if lv.mode == 1 and w then
-        if w.id==id_whatsit and w.subtype==sid_user
-        and w.user_id==DIR then
-          node_set_attr(w, attr_dir, v)
-          
-        end
-     else
-        local w = node_next(to_direct(lv.head))
-        if to_node(w) then
-           if getid(w)==id_whatsit and getsubtype(w)==sid_user
-           and getfield(w, 'user_id')==DIR  then
-             set_attr(w, attr_dir, v)
-             tex_set_attr('global', attr_dir, 0)  
-          else
+   local abs = math.abs
+   function get_dir_count()
+      return tex_getcount('ltj@dir@count')
+   end
+   luatexja.direction.get_dir_count = get_dir_count 
+
+   local node_next = node.next
+   local node_set_attr = node.set_attribute
+   local function set_list_direction(v, name)
+      local lv, w = tex.nest[tex.nest.ptr], tex.lists.page_head
+      if lv.mode == 1 and w then
+        if w.id==id_whatsit and w.subtype==sid_user
+        and w.user_id==DIR then
+           node_set_attr(w, attr_dir, v)
+        end
+      else
+        local w = node_next(to_direct(lv.head))
+        if to_node(w) then
+           if getid(w)==id_whatsit and getsubtype(w)==sid_user
+           and getfield(w, 'user_id')==DIR  then
+              set_attr(w, attr_dir, v)
+           else
               ltjb.package_error(
                  'luatexja',
                  "Use `\\" .. name .. "' at top of list",
                  'Direction change command by LuaTeX-ja is available\n'
-                 .. 'only when the current list is null.')
-           end
-        else
-           local w = node_new(id_whatsit, sid_user)
-           setfield(w, 'next', hd)
-           setfield(w, 'user_id', DIR)
-           setfield(w, 'type', 110)
-           set_attr(w, attr_dir, v)
-           Dnode.write(w)
-          tex_set_attr('global', attr_dir, 0)
-        end
-       tex_set_attr('global', attr_icflag, 0)
-     end
-  end
-  luatexja.direction.set_list_direction = set_list_direction
+                   .. 'only when the current list is null.')
+           end
+        else
+           local w = node_new(id_whatsit, sid_user)
+           setfield(w, 'next', hd)
+           setfield(w, 'user_id', DIR)
+           setfield(w, 'type', 110)
+           set_attr(w, attr_dir, v)
+           Dnode.write(w)
+        end
+        tex_set_attr('global', attr_icflag, 0)
+      end
+      tex_set_attr('global', attr_dir, 0)
+   end
+   luatexja.direction.set_list_direction = set_list_direction
 end
 
 -- ボックスに dir whatsit を追加
@@ -136,19 +135,37 @@ do
    luatexbase.add_to_callback('hpack_filter', 
                              create_dir_whatsit_hpack, 'ltj.create_dir_whatsit', 10000)
 
+   local wh = {}
+   local id_glue, sid_parskip = node.id('glue'), 3
    local function create_dir_whatsit_vbox(h, gc)
-      local hd= to_direct(h)
+      local hd = to_direct(h)
       ltjs.list_dir = get_dir_count()
-      if getid(hd)==id_whatsit and getsubtype(hd)==sid_user
-      and getfield(hd, 'user_id')==DIR then
-         ltjs.list_dir = has_attr(hd, attr_dir)
-         return h
-      elseif gc=='fin_row' or gc == 'preamble'  then
+      -- remove dir whatsit
+      for x in traverse_id(id_whatsit, hd) do
+        if getsubtype(x)==sid_user and getfield(x, 'user_id')==DIR then
+           wh[#wh+1]=x
+        end
+      end
+      if hd==wh[1] then
+        ltjs.list_dir = has_attr(hd,attr_dir)
+        local x = node_next(hd)
+        if getid(x)==id_glue and getsubtype(x)==sid_parskip then
+           node_remove(hd,x); node_free(x)
+        end
+      end
+      for i=1,#wh do  hd = node_remove(hd, wh[i]); node_free(wh[i]); wh[i] = nil end
+      if gc=='fin_row' or gc == 'preamble'  then
         if hd  then
            set_attr(hd, attr_icflag, PROCESSED_BEGIN_FLAG)
            tex_set_attr('global', attr_icflag, 0)
         end
-        return h
+        return to_node(hd)
+      elseif gc=='vtop' then
+        local w = create_dir_whatsit(hd, gc, ltjs.list_dir)
+        -- move  dir whatsit after hd
+        local n = getfield(hd, 'next')
+        setfield(hd, 'next', w); setfield(w, 'next', n)
+         return to_node(hd)
       else
          return to_node(create_dir_whatsit(hd, gc, ltjs.list_dir))
       end
@@ -158,14 +175,17 @@ do
 
    local function create_dir_whatsit_parbox(h, gc)
       stop_time_measure('tex_linebreak')
+      print('BEGIN POST_LINEBREAK', gc)
+      luatexja.ext_show_node_list(h, '   ', print)
       -- start 側は ltj-debug.lua に
       local new_dir, hd = ltjs.list_dir, to_direct(h)
       for line in traverse_id(id_hlist, hd) do
         set_attr(line, attr_dir, new_dir)
       end
+      tex_set_attr('global', attr_dir, 0)
       return to_node(create_dir_whatsit(hd, gc, new_dir))
    end
-   luatexbase.add_to_callback('post_linebreak_filter',
+   luatexbase.add_to_callback('post_linebreak_filter', 
                              create_dir_whatsit_parbox, 'ltj.create_dir_whatsit', 10000)
 
 end
@@ -270,20 +290,21 @@ do
       [dir_dtou] = { -- dtou を
         [dir_yoko] = { -- yoko 中で組む
            width  = get_h_d,
-           height = zero,
-           depth  = get_w,
+           height = get_w, 
+           depth  = zero,
            [id_hlist] = {
               { 'whatsit', sid_save },
               { 'rotate', '0 1 -1 0' },
-               { 'kern', get_w_neg },
+              { 'kern', zero },
               { 'box', get_h },
+              { 'kern', get_w_neg },
               { 'whatsit', sid_restore },
            },
            [id_vlist] = {
-               { 'kern', get_w },
+               { 'kern', zero },
               { 'whatsit', sid_save },
               { 'rotate', '0 1 -1 0' },
-              { 'box', zero },
+              { 'box', get_w_neg },
               { 'kern', get_h_d_neg },
               { 'whatsit', sid_restore },
            },
@@ -317,23 +338,26 @@ local function get_box_dir(b, default)
    local dir = has_attr(b, attr_dir) or 0
    local bh = getlist(b)
    local c
-   if bh and getid(bh)==id_whatsit
-   and getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then
-     c = bh
-      if dir==0 then
-        dir = has_attr(bh, attr_dir)
-        set_attr(b, attr_dir, dir)
-        tex_set_attr('global', attr_dir, 0)
+   for i=1,2 do
+      if bh and getid(bh)==id_whatsit
+      and getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then
+        c = bh
+        if dir==0 then
+           dir = has_attr(bh, attr_dir)
+           set_attr(b, attr_dir, dir)
+           tex_set_attr('global', attr_dir, 0)
+        end
       end
+      bh = node_next(bh)
    end
    return (dir==0 and default or dir), c
 end
 
 -- dir_node に包まれている「本来の中身」を取り出し,
 -- dir_node を全部消去
-local function unwrap_dir_node(b, head)
-   -- head: nil or nil-nil
-   -- if head is non-nil, return values are (new head), (next of b), (contents)
+local function unwrap_dir_node(b, head, box_dir)
+   -- b: dir_node, head: the head of list, box_dir: 
+   -- return values are (new head), (next of b), (contents), (dir of contents)
    local bh = getlist(b)
    local bc = node_next(node_next(node_next(bh)))
    local nh, nb
@@ -344,15 +368,24 @@ local function unwrap_dir_node(b, head)
       nh, nb = node_remove(nh, b)
       setfield(b, 'next', nil)
       setfield(b, 'head', nil)
-      luatexja.ext_show_node(to_node(b), ' ', print)
-      --node_free(b) -- TODO: これを入れると test51-vtest が途中で泊まる
+      node_free(b)
    end
-   local d, wh = get_box_dir(bc, 0)
+   local shift_old, b_dir, wh = nil, get_box_dir(bc, 0)
    if wh then
       Dnode.flush_list(getfield(wh, 'value'))
       setfield(wh, 'value', nil)
    end
-   return nh, nb, bc
+   -- recalc. info
+   local info = dir_node_aux[b_dir][box_dir%dir_node_auto][getid(bc)]
+   for _,v in ipairs(info) do 
+      if v[1]=='box' then
+        shift_old = v[2](
+           getfield(bc,'width'), getfield(bc, 'height'), getfield(bc, 'depth'))
+        break
+      end
+   end
+   setfield(bc, 'shift', getfield(bc, 'shift') - shift_old)
+   return nh, nb, bc, b_dir
 end
 
 -- is_manual: 寸法変更に伴うものか?
@@ -364,6 +397,7 @@ local function create_dir_node(b, b_dir, new_dir, is_manual)
    local db = node_new(getid(b))
    set_attr(db, attr_dir, 
            new_dir + (is_manual and dir_node_manual or dir_node_auto))
+   tex_set_attr('global', attr_dir, 0)
    set_attr(db, attr_icflag, PROCESSED)
    set_attr(b, attr_icflag, PROCESSED)
    setfield(db, 'dir', getfield(b, 'dir'))
@@ -388,19 +422,23 @@ do
       if box_dir==new_dir then
         return head, node_next(b), b, false
       elseif  box_dir%dir_node_auto == new_dir  then
--- TODO. we have to free  all other ...
+        local bc = node_next(node_next(node_next(bh)))
+        local _, dnc = get_box_dir(b, 0)
+        if dnc then -- free all other dir_node
+           Dnode.flush_list(getfield(dnc, 'value'))
+           setfield(dnc, 'value', nil)
+        end
         set_attr(b, attr_dir, box_dir%dir_node_auto + dir_node_auto)
         return head, node_next(b), b, true
       else
          local nh, nb, ret, flag
         if box_dir>= dir_node_auto then -- unwrap
-            nh, nb, ret = unwrap_dir_node(b, head)
-           head, b = nh, ret; 
-           bh = getlist(b); 
-           box_dir, dn =  get_box_dir(b, ltjs.list_dir)
-           if box_dir==new_dir then
-              return head, nb, b, fals
-           end
+           local b_dir
+            head, nb, b, b_dir = unwrap_dir_node(b, head, box_dir)
+           bh = getlist(b)
+           if b_dir==new_dir then -- no need to create new dir_node
+              return head, nb, b, false 
+           else box_dir = b_dir end
         end
             local db
             local dnh = getfield(dn, 'value')
@@ -410,6 +448,7 @@ do
                   db=x; break
                end
             end
+           Dnode.flush_list(dnh)
             db = db or create_dir_node(b, box_dir, new_dir, false)
             local w = getfield(b, 'width')
             local h = getfield(b, 'height')
@@ -501,10 +540,8 @@ do
          elseif b_dir%dir_node_auto==l_dir then
             setdimen('ltj@tempdima', getfield(s, key))
          else
-            get_box_dim_common(
-               key, 
-               node_next(node_next(node_next(getlist(s)))),
-               l_dir)
+            get_box_dim_common(key, 
+                              node_next(node_next(node_next(getlist(s)))), l_dir)
          end
       else
          setdimen('ltj@tempdima', 0)
@@ -566,6 +603,7 @@ do
         elseif b_dir%dir_node_auto == l_dir then
            setfield(s, key, tex.getdimen('ltj@tempdima'))
            if b_dir<dir_node_manual then
+              set_attr(s, attr_dir, b_dir%dir_node_auto + dir_node_manual)
            end
          else
            local sid, sl = getid(s), getlist(s)
@@ -582,7 +620,7 @@ do
            if set_box_dim_common(key, b, l_dir) then
               local bw, bh, bd 
                  = getfield(b,'width'), getfield(b, 'height'), getfield(b, 'depth')
-              -- re-calculate shifting info
+              -- re-calculate shift
               for i,v in ipairs(info[sid]) do 
                  if getid(sl)==id_kern then
                     setfield(sl, 'kern', v[2](bw,bh,bd) )
@@ -606,6 +644,29 @@ do
    luatexja.direction.set_box_dim = set_box_dim
 end
 
+-- \ifydir, \iftdir, \ifddir
+do
+   local cat_lp = luatexbase.catcodetables['latex-package']
+   local getbox = tex.getbox
+   local function dir_conditional(n, mode)
+      local s = getbox(n)
+      local res = false
+      if s then
+         s = to_direct(s)
+         local b_dir = get_box_dir(s, dir_yoko)
+         if b_dir<dir_node_auto then
+           res = (b_dir==mode)
+         else
+           local b_dir = get_box_dir(
+              node_next(node_next(node_next(getlist(s)))), dir_yoko)
+           res = (b_dir==mode)
+         end
+      end
+      tex.sprint(cat_lp, '\\if' .. tostring(res))
+   end
+   luatexja.direction.dir_conditional = dir_conditional
+end
+
 -- 縦書き用字形への変換テーブル
 local font_vert_table = {} -- key: fontnumber
 do