OSDN Git Service

get rid of attr_orig_char
[luatex-ja/luatexja.git] / src / ltj-direction.lua
index 4057de5..e29503b 100644 (file)
@@ -30,7 +30,7 @@ local node_remove = Dnode.remove
 local node_next = (Dnode ~= node) and Dnode.getnext or node.next
 local traverse = Dnode.traverse
 local traverse_id = Dnode.traverse_id
-local start_time_measure, stop_time_measure 
+local start_time_measure, stop_time_measure
    = ltjb.start_time_measure, ltjb.stop_time_measure
 local abs = math.abs
 
@@ -83,7 +83,7 @@ do
       if h then
         if h.id==id_whatsit and h.subtype==sid_user and h.user_id==DIR then
               local ic = node.has_attribute(h, attr_icflag) or 0
-              return (ic<PROCESSED_BEGIN_FLAG) 
+              return (ic<PROCESSED_BEGIN_FLAG)
                  and (node.has_attribute(h,attr_dir)%dir_node_auto) or 0
         else
            return 0
@@ -127,7 +127,7 @@ do
    local IHB = luatexja.userid_table.IHB
 
    local function test_list(h, lv)
-      if not h then 
+      if not h then
         return 2 -- need to create dir_whatsit
       else
         local flag = 2 -- need to create dir_whatsit
@@ -148,16 +148,38 @@ do
               flag = 0; break
            end
         end
-        if flag==1 then -- move dir_whatsit w
-           return 1,w -- TODO
-        else 
+        if flag==1 then -- dir_whatsit already exists
+           return 1,w
+        else
            return flag
         end
       end
    end
+   function luatexja.direction.set_list_direction_hook(v)
+      local lv = tex_nest.ptr -- must be >= 1
+      if not v then
+         v = get_dir_count()
+        if abs(tex_nest[lv-1].mode) == ltjs.mmode and v == dir_tate then
+           v = dir_utod
+        end
+      elseif v=='adj' then
+         v = get_adjust_dir_count()
+      end
+      local h = to_direct(tex_nest[lv].head)
+      local w = node_new(id_whatsit, sid_user)
+      setfield(w, 'next', nil)
+      setfield(w, 'user_id', DIR)
+      setfield(w, 'type', 110)
+      set_attr(w, attr_dir, v)
+      insert_after(h, h, w)
+      tex_nest[lv].tail = to_node(node_tail(w))
+      tex_set_attr('global', attr_icflag, 0)
+      tex_set_attr('global', attr_dir, 0)
+   end
+
    local function set_list_direction(v, name)
       local lv = tex_nest.ptr
-      if not v then 
+      if not v then
          v,name  = get_dir_count(), nil
         if lv>=1 and abs(tex_nest[lv-1].mode) == ltjs.mmode and v == dir_tate then
            v = dir_utod
@@ -184,7 +206,7 @@ do
                  'Direction change command by LuaTeX-ja is available\n'
                    .. 'only when the current list is null.')
            end
-        elseif flag==1 then 
+        elseif flag==1 then
            node_set_attr(w, attr_dir, v)
            if lv==0 then page_direction = v end
         else
@@ -205,9 +227,9 @@ end
 
 -- ボックスに dir whatsit を追加
 local function create_dir_whatsit(hd, gc, new_dir)
-   if getid(hd)==id_whatsit and 
+   if getid(hd)==id_whatsit and
            getsubtype(hd)==sid_user and getfield(hd, 'user_id')==DIR then
-      set_attr(hd, attr_icflag, 
+      set_attr(hd, attr_icflag,
               get_attr_icflag(hd) + PROCESSED_BEGIN_FLAG)
       tex_set_attr('global', attr_icflag, 0)
       return hd
@@ -218,8 +240,8 @@ local function create_dir_whatsit(hd, gc, new_dir)
       setfield(w, 'type', 110)
       set_attr(w, attr_dir, new_dir)
       set_attr(w, attr_icflag, PROCESSED_BEGIN_FLAG)
-      set_attr(hd, attr_icflag, 
-              (has_attr(hd, attr_icflag) or 0)%PROCESSED_BEGIN_FLAG 
+      set_attr(hd, attr_icflag,
+              (has_attr(hd, attr_icflag) or 0)%PROCESSED_BEGIN_FLAG
                  + PROCESSED_BEGIN_FLAG)
       tex_set_attr('global', attr_dir, 0)
       tex_set_attr('global', attr_icflag, 0)
@@ -244,7 +266,7 @@ do
       end
    end
 
-   luatexbase.add_to_callback('hpack_filter', 
+   luatexbase.add_to_callback('hpack_filter',
                              create_dir_whatsit_hpack, 'ltj.create_dir_whatsit', 10000)
 end
 
@@ -256,12 +278,12 @@ do
       for line in traverse_id(id_hlist, hd) do
          local nh = getlist(line)
         setfield(line, 'head', create_dir_whatsit(nh, gc, new_dir) )
-        set_attr(line, attr_dir, new_dir)
+        --set_attr(line, attr_dir, new_dir)
       end
       tex_set_attr('global', attr_dir, 0)
-      return h 
+      return h
    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
 
@@ -284,8 +306,8 @@ do
            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 
+      for i=1,#wh do
+        hd = node_remove(hd, wh[i]); node_free(wh[i]); wh[i] = nil
       end
       if gc=='fin_row' then -- gc == 'preamble' case is treated in dir_adjust_vpack
         if hd  then
@@ -323,7 +345,7 @@ do
    local get_w =function (w,h,d) return w end
    local zero = function() return 0 end
    dir_node_aux = {
-      [dir_yoko] = { -- yoko を 
+      [dir_yoko] = { -- yoko を
         [dir_tate] = { -- tate 中で組む
            width  = get_h_d,
            height = get_w_half,
@@ -410,7 +432,7 @@ do
       [dir_dtou] = { -- dtou を
         [dir_yoko] = { -- yoko 中で組む
            width  = get_h_d,
-           height = get_w, 
+           height = get_w,
            depth  = zero,
            [id_hlist] = {
               { 'whatsit', sid_save },
@@ -443,9 +465,9 @@ do
            [id_vlist] = {
               { 'whatsit', sid_save },
               { 'rotate', ' -1 0 0 -1' },
-              { 'kern', function (w,h,d,nw,nh,nd) return -nh-nd end }, 
+              { 'kern', function (w,h,d,nw,nh,nd) return -nh-nd end },
               { 'box', get_w_neg },
-              { 'kern', function (w,h,d,nw,nh,nd) return nh+nd-h-d end }, 
+              { 'kern', function (w,h,d,nw,nh,nd) return nh+nd-h-d end },
               { 'whatsit', sid_restore },
            },
         },
@@ -458,73 +480,102 @@ end
 local function get_box_dir(b, default)
    start_time_measure('get_box_dir')
    local dir = has_attr(b, attr_dir) or 0
-   local bh = getfield(b,'head') 
+   local bh = getfield(b,'head')
    -- b は insert node となりうるので getlist() は使えない
    local c
-   for i=1,2 do
-      if bh and getid(bh)==id_whatsit
-      and getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then
+   for bh in traverse_id(id_whatsit, bh) do
+      if getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then
         c = bh
-        dir = (dir==0) and has_attr(bh, attr_dir) or dir
+        dir = (dir==0) and has_attr(bh, attr_dir) or dir
       end
-      bh = node_next(bh)
    end
+   -- 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
+   --   dir = (dir==0) and has_attr(bh, attr_dir) or dir
+   --    end
+   --    bh = node_next(bh)
+   -- end
    stop_time_measure('get_box_dir')
    return (dir==0 and default or dir), c
 end
 
 do
    local getbox = tex.getbox
-   local function check_dir(reg_num)
+   local dir_backup
+   function luatexja.direction.unbox_check_dir(is_copy)
       start_time_measure('box_primitive_hook')
       local list_dir = get_dir_count()%dir_math_mod
       local b = getbox(tex_getcount('ltj@tempcnta'))
       if b then
         local box_dir = get_box_dir(to_direct(b), dir_yoko)
         if box_dir%dir_math_mod ~= list_dir then
-          --  print('NEST', tex_nest.ptr, tex_getcount('ltj@tempcnta'))
-          --  luatexja.ext_show_node_list(
-           --     (tex_nest.ptr==0) and tex.lists.page_head or tex_nest[tex_nest.ptr].head,
-           --     'LIST' .. tostring(list_dir) .. '> ', print)
-          -- luatexja.ext_show_node_list(b, 'BOX' .. tostring(box_dir) .. '> ', print)
            ltjb.package_error(
               'luatexja',
               "Incompatible direction list can't be unboxed",
               'I refuse to unbox a box in differrent direction.')
+            tex.sprint(cat_lp, '\\@gobbletwo')
+        else
+           dir_backup = nil
+           local bd = to_direct(b)
+           local hd = getlist(bd)
+           local nh = hd
+           while hd do
+              if getid(hd)==id_whatsit and getsubtype(hd)==sid_user
+                 and getfield(hd, 'user_id')==DIR then
+                    local d = hd
+                    nh, hd = node_remove(nh, hd)
+                    if is_copy and (not dir_backup) then
+                       dir_backup = d
+                       setfield(dir_backup, 'next', nil)
+                    else
+                       node_free(d)
+                    end
+              else
+                 hd = node_next(hd)
+              end
+           end
+           setfield(bd, 'head', nh)
         end
       end
-      if luatexja.global_temp and tex.globaldefs~=luatexja.global_temp then 
+      if luatexja.global_temp and tex.globaldefs~=luatexja.global_temp then
         tex.globaldefs = luatexja.global_temp
       end
       stop_time_measure('box_primitive_hook')
    end
-   luatexja.direction.check_dir = check_dir
+   function luatexja.direction.uncopy_restore_whatsit()
+      local b = getbox(tex_getcount('ltj@tempcnta'))
+      if b then
+        local bd = to_direct(b)
+        if dir_backup then
+           setfield(dir_backup, 'next', getlist(bd))
+           setfield(bd, 'head', dir_backup)
+           dir_backup = nil
+        end
+      end
+   end
 end
 
 -- dir_node に包まれている「本来の中身」を取り出し,
 -- dir_node を全部消去
 local function unwrap_dir_node(b, head, box_dir)
-   -- b: dir_node, head: the head of list, 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
-   node_remove(bh, bc); 
-   Dnode.flush_list(bh)
    if head then
-      nh = insert_before(head, b, bc)
+      nh = insert_before(head, b, bh)
       nh, nb = node_remove(nh, b)
       setfield(b, 'next', nil)
-      setfield(b, 'head', nil)
       node_free(b)
    end
-   local shift_old, b_dir, wh = nil, get_box_dir(bc, 0)
+   local shift_old, b_dir, wh = nil, get_box_dir(bh, 0)
    if wh then
       Dnode.flush_list(getfield(wh, 'value'))
       setfield(wh, 'value', nil)
    end
-   setfield(bc, 'shift', 0)
-   return nh, nb, bc, b_dir
+   return nh, nb, bh, b_dir
 end
 
 -- is_manual: 寸法変更に伴うものか?
@@ -534,7 +585,7 @@ local function create_dir_node(b, b_dir, new_dir, is_manual)
    local h = getfield(b, 'height')
    local d = getfield(b, 'depth')
    local db = node_new(getid(b)) -- dir_node
-   set_attr(db, attr_dir, 
+   set_attr(db, attr_dir,
            new_dir + (is_manual and dir_node_manual or dir_node_auto))
    set_attr(db, attr_icflag, PROCESSED)
    set_attr(b, attr_icflag, PROCESSED)
@@ -564,7 +615,6 @@ do
       if box_dir%dir_math_mod==new_dir then
         if box_dir>=dir_node_auto then
            -- dir_node としてカプセル化されている
-           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'))
@@ -585,7 +635,7 @@ do
            bh = getlist(b)
            if b_dir%dir_math_mod==new_dir then
               -- dir_node の中身が周囲の組方向とあっている
-              return head, nb, b, false 
+              return head, nb, b, false
            else box_dir = b_dir end
         end
         box_dir = box_dir%dir_math_mod
@@ -598,6 +648,7 @@ do
            end
         end
         Dnode.flush_list(getfield(dn, 'value'))
+        setfield(dn, 'value', nil)
         db = db or create_dir_node(b, box_dir, new_dir, false)
         local w = getfield(b, 'width')
         local h = getfield(b, 'height')
@@ -607,30 +658,8 @@ do
         local dn_d = getfield(db, 'depth')
         nh, nb =  insert_before(head, b, db), nil
         nh, nb = node_remove(nh, b)
-        local db_head, db_tail  = nil
-        for _,v in ipairs(dir_node_aux[box_dir][new_dir][getid(b)]) do
-           local cmd, arg, nn = v[1], v[2]
-           if cmd=='kern' then
-              nn = node_new(id_kern)
-              setfield(nn, 'kern', arg(w, h, d, dn_w, dn_h, dn_d))
-           elseif cmd=='whatsit' then
-              nn = node_new(id_whatsit, arg)
-           elseif cmd=='rotate' then
-              nn = node_new(id_whatsit, sid_matrix)
-              setfield(nn, 'data', arg)
-           elseif cmd=='box' then
-              nn = b; setfield(b, 'next', nil)
-              setfield(nn, 'shift', arg(w, h, d, dn_w, dn_h, dn_d))
-           end
-           if db_head then
-              insert_after(db_head, db_tail, nn)
-              db_tail = nn
-           else
-              db_head, db_tail = nn, nn
-           end
-           setfield(db, 'head', db_head)
-           ret, flag = db, true
-        end
+         setfield(b, 'next', nil); setfield(db, 'head', b)
+         ret, flag = db, true
         return nh, nb, ret, flag
       end
    end
@@ -698,7 +727,7 @@ do
             local w = getfield(s, 'width')
             local h = getfield(s, 'height')
             local d = getfield(s, 'depth')
-            setdimen('ltj@tempdima', 
+            setdimen('ltj@tempdima',
                          dir_node_aux[s_dir][l_dir][key](w,h,d))
          end
       else
@@ -717,8 +746,7 @@ do
          elseif b_dir%dir_math_mod==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, getlist(s), l_dir)
          end
       else
          setdimen('ltj@tempdima', 0)
@@ -754,7 +782,7 @@ do
          setfield(s, key, tex.getdimen('ltj@tempdima'))
         if wh then
            -- change dimension of dir_nodes which are created "automatically"
-              local bw, bh, bd 
+              local bw, bh, bd
                  = getfield(s,'width'), getfield(s, 'height'), getfield(s, 'depth')
            for x in traverse(getfield(wh, 'value')) do
               local x_dir = has_attr(x, attr_dir)
@@ -784,41 +812,14 @@ do
            if b_dir<dir_node_manual then
               set_attr(s, attr_dir, b_dir%dir_node_auto + dir_node_manual)
            end
-           -- re-calculate shift and kern (TODO)
-           local sid, sl = getid(s), getlist(s)
-           local b = node_next(node_next(node_next(sl))) -- 本来の box
-           local info = dir_node_aux[get_box_dir(b,dir_yoko)%dir_math_mod][b_dir%dir_node_auto]
-           local bw, bh, bd 
-              = getfield(b,'width'), getfield(b, 'height'), getfield(b, 'depth')
-           local sw, sh, sd 
-              = getfield(s,'width'), getfield(s, 'height'), getfield(s, 'depth')
-           -- re-calculate shift and kern
-           for i,v in ipairs(info[sid]) do 
-              if getid(sl)==id_kern then
-                 setfield(sl, 'kern', v[2](bw,bh,bd,sw,sh,sd) )
-              elseif getid(sl)==sid then
-                 setfield(sl, 'shift', v[2](bw,bh,bd,sw,sh,sd) )
-              end
-              sl = node_next(sl)
-           end
          else
-           local sid, sl = getid(s), getlist(s)
-           local b = node_next(node_next(node_next(sl))) -- 本来の box
+           local sid, b = getid(s), getlist(s)
            local info = dir_node_aux[get_box_dir(b,dir_yoko)%dir_math_mod][b_dir%dir_node_auto]
-           local bw, bh, bd 
+           local bw, bh, bd
               = getfield(b,'width'), getfield(b, 'height'), getfield(b, 'depth')
-           local sw, sh, sd 
+           local sw, sh, sd
               = getfield(s,'width'), getfield(s, 'height'), getfield(s, 'depth')
-           if set_box_dim_common(key, b, l_dir) then
-              -- re-calculate shift and kern
-              for i,v in ipairs(info[sid]) do 
-                 if getid(sl)==id_kern then
-                    setfield(sl, 'kern', v[2](bw,bh,bd,sw,sh,sd) )
-                 elseif getid(sl)==sid then
-                    setfield(sl, 'shift', v[2](bw,bh,bd,sw,sh,sd) )
-                 end
-                 sl = node_next(sl)
-              end
+           if set_box_dim_common(key, b, l_dir) and b_dir<dir_node_manual then
               -- re-calculate dimension of s, if s is created "automatically"
               if b_dir<dir_node_manual then
                  setfield(s, 'width',  info.width(bw,bh,bd))
@@ -865,11 +866,9 @@ do
         local box_dir = get_box_dir(sd, dir_yoko)
         if box_dir%dir_math_mod ~= list_dir then
            setbox(
-              'ltj@afbox', 
-              to_node(
-                 copy_list(make_dir_whatsit(sd, sd, list_dir, 'box_move'))
-                 -- without copy_list, we get a segfault
-              )
+              'ltj@afbox',
+              to_node(copy_list(make_dir_whatsit(sd, sd, list_dir, 'box_move')))
+              -- copy_list しないとリストの整合性が崩れる……?
            )
         end
       end
@@ -882,30 +881,65 @@ end
 do
    local function glyph_from_packed(h)
       local b = getlist(h)
-      return (getid(b)==id_kern
-        and node_next(node_next(node_next(node_next(b)))) or b
+      return (getid(b)==id_kern or (getid(b)==id_whatsit and getsubtype(b)==sid_save) )
+        and node_next(node_next(node_next(b))) or b
    end
    luatexja.direction.glyph_from_packed = glyph_from_packed
 end
 
--- adjust and insertion
-local id_adjust = node.id('adjust')
-function luatexja.direction.check_adjust_direction()
-   start_time_measure('box_primitive_hook')
-   local list_dir = get_adjust_dir_count()
-   local a = tex_nest[tex_nest.ptr].tail
-   local ad = to_direct(a)
-   if a and getid(ad)==id_adjust then
-      local adj_dir = get_box_dir(ad)
-      if list_dir~=adj_dir then
-         ltjb.package_error(
-                 'luatexja',
-                 'Direction Incompatible',
-                 "\\vadjust's argument and outer vlist must have same direction.")
-         Dnode.last_node()
+-- adjust
+do
+   local id_adjust = node.id('adjust')
+   function luatexja.direction.check_adjust_direction()
+      start_time_measure('box_primitive_hook')
+      local list_dir = get_adjust_dir_count()
+      local a = tex_nest[tex_nest.ptr].tail
+      local ad = to_direct(a)
+      if a and getid(ad)==id_adjust then
+        local adj_dir = get_box_dir(ad)
+        if list_dir~=adj_dir then
+           ltjb.package_error(
+              'luatexja',
+              'Direction Incompatible',
+              "\\vadjust's argument and outer vlist must have same direction.")
+           Dnode.last_node()
+        end
       end
+      stop_time_measure('box_primitive_hook')
+   end
+end
+
+-- insert
+do
+   local id_ins = node.id('ins')
+   local id_rule = node.id('rule')
+   function luatexja.direction.populate_insertion_dir_whatsit()
+      start_time_measure('box_primitive_hook')
+      local list_dir = get_dir_count()
+      local a = tex_nest[tex_nest.ptr].tail
+      local ad = to_direct(a)
+      if a and getid(ad)==id_ins then
+        local h = getfield(ad, 'head')
+        if getid(h)==id_whatsit and
+           getsubtype(h)==sid_user and getfield(h, 'user_id')==DIR then
+              local n = h; h = node_remove(h,h)
+              node_free(n)
+        end
+        for box_rule in traverse(h) do
+           if getid(box_rule)<id_rule then
+              local w = node_new(id_whatsit, sid_user)
+              setfield(w, 'next', nil)
+              setfield(w, 'user_id', DIR)
+              setfield(w, 'type', 110)
+              set_attr(w, attr_dir, list_dir)
+              h = insert_before(h, box_rule, w)
+           end
+        end
+        tex_set_attr('global', attr_dir, 0)
+        setfield(ad, 'head', h)
+      end
+      stop_time_measure('box_primitive_hook')
    end
-   stop_time_measure('box_primitive_hook')
 end
 
 -- vsplit
@@ -919,14 +953,19 @@ do
         hd = create_dir_whatsit_vbox(hd, gc)
         split_dir_whatsit = hd
       elseif gc=='split_off'  then
-        local bh=hd
-        for i=1,2 do
-           if bh and getid(bh)==id_whatsit
-           and getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then
+        for  bh in traverse_id(id_whatsit, hd) do
+           if getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then
               ltjs.list_dir  = has_attr(bh, attr_dir); break
            end
-           bh = node_next(bh)
         end
+        -- local bh=hd
+        -- for i=1,2 do
+        --    if bh and getid(bh)==id_whatsit
+        --    and getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then
+        --       ltjs.list_dir  = has_attr(bh, attr_dir); break
+        --    end
+        --    bh = node_next(bh)
+        -- end
         if split_dir_whatsit then
            -- adjust direction of 'split_keep'
            set_attr(split_dir_whatsit, attr_dir, ltjs.list_dir)
@@ -967,7 +1006,7 @@ do
    end
 end
 
--- 
+-- buildpage filter
 do
    local function dir_adjust_buildpage(info)
       if info=='box' then
@@ -975,9 +1014,9 @@ do
         local nb
         if head then
            head, _, nb
-              = make_dir_whatsit(head, 
+              = make_dir_whatsit(head,
                                  node_tail(head),
-                                 get_dir_count(), 
+                                 get_dir_count(),
                                  'buildpage')
            tex.lists.contrib_head = to_node(head)
         end
@@ -987,3 +1026,76 @@ do
                              dir_adjust_buildpage,
                              'ltj.direction', 10000)
 end
+
+-- finalize (executed just before \shipout)
+-- we supply correct pdfsavematrix nodes etc. inside dir_node
+do
+   local finalize_inner
+   local function finalize_dir_node(db,new_dir)
+      local b = getlist(db)
+      finalize_inner(b)
+      local box_dir = get_box_dir(b, dir_yoko)%dir_math_mod
+      setfield(db, 'head', nil)
+      local w = getfield(b, 'width')
+      local h = getfield(b, 'height')
+      local d = getfield(b, 'depth')
+      local dn_w = getfield(db, 'width')
+      local dn_h = getfield(db, 'height')
+      local dn_d = getfield(db, 'depth')
+      local db_head, db_tail  = nil
+      for _,v in ipairs(dir_node_aux[box_dir][new_dir][getid(b)]) do
+         local cmd, arg, nn = v[1], v[2]
+         if cmd=='kern' then
+            nn = node_new(id_kern)
+            setfield(nn, 'kern', arg(w, h, d, dn_w, dn_h, dn_d))
+         elseif cmd=='whatsit' then
+            nn = node_new(id_whatsit, arg)
+         elseif cmd=='rotate' then
+            nn = node_new(id_whatsit, sid_matrix)
+            setfield(nn, 'data', arg)
+         elseif cmd=='box' then
+            nn = b; setfield(b, 'next', nil)
+            setfield(nn, 'shift', arg(w, h, d, dn_w, dn_h, dn_d))
+         end
+         if db_head then
+            insert_after(db_head, db_tail, nn)
+            db_tail = nn
+         else
+            db_head, db_tail = nn, nn
+         end
+         setfield(db, 'head', db_head)
+      end
+   end
+
+   local shipout_temp =  node_new(id_hlist)
+   set_attr(shipout_temp, attr_dir, dir_yoko)
+   tex_set_attr('global', attr_dir, 0)
+
+   finalize_inner = function (box)
+      for n in traverse(getlist(box)) do
+         local nid = getid(n)
+         if (nid==id_hlist or nid==id_vlist) then
+            local ndir = get_box_dir(n, dir_yoko)
+            if ndir>=dir_node_auto then -- n is dir_node
+               finalize_dir_node(n, ndir%dir_math_mod)
+            else
+               finalize_inner(n)
+            end
+        end
+      end
+   end
+   local getbox = tex.getbox
+   local setbox, copy = Dnode.setbox, Dnode.copy
+   function luatexja.direction.finalize()
+      local a = to_direct(tex.getbox("AtBeginShipoutBox"))
+      local a_dir = get_box_dir(a, dir_yoko)
+      if a_dir~=dir_yoko then
+         local b = create_dir_node(a, a_dir, dir_yoko, false)
+         setfield(b, 'head', a); a = b
+      end
+      setfield(shipout_temp, 'head', a)
+      finalize_inner(shipout_temp)
+      setbox('global', "AtBeginShipoutBox", copy(getlist(shipout_temp)))
+      setfield(shipout_temp, 'head',nil)
+   end
+end