OSDN Git Service

unhbox and unvbox.
[luatex-ja/luatexja.git] / src / ltj-direction.lua
index f3d6cc4..75517f0 100644 (file)
@@ -56,51 +56,55 @@ 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
+   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(lv.head)
+        if w then
+           w = to_direct(w)
+           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
+
+function luatexja.direction.freeze_list_dir()
+   local w = to_direct(tex.nest[tex.nest.ptr].tail)
+   set_attr(w, attr_dir, -has_attr(w, attr_dir))
 end
 
 -- ボックスに dir whatsit を追加
@@ -136,19 +140,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
@@ -163,9 +185,10 @@ do
       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
@@ -316,20 +339,38 @@ end
 -- 2nd ret val はその DIR whatsit
 local function get_box_dir(b, default)
    local dir = has_attr(b, attr_dir) or 0
-   local bh = getlist(b)
+   local bh = getfield(b,'head') 
+   -- b は insert node となりうるので getlist() は使えない
    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
 
+function luatexja.direction.check_dir(reg_num)
+   local list_dir = get_dir_count()
+   local b = tex.getbox(reg_num)
+   if b then
+      local box_dir = get_box_dir(to_direct(b), dir_yoko)
+      if box_dir%dir_node_auto ~= list_dir%dir_node_auto then
+        ltjb.package_error(
+                 'luatexja',
+                 "Incompatible direction list can't be unboxed",
+                'I refuse to unbox a box in differrent direction.')
+      end
+   end
+end
+
 -- dir_node に包まれている「本来の中身」を取り出し,
 -- dir_node を全部消去
 local function unwrap_dir_node(b, head, box_dir)
@@ -374,6 +415,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'))
@@ -580,7 +622,6 @@ do
            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)
-              tex_set_attr('global', attr_dir, 0)
            end
          else
            local sid, sl = getid(s), getlist(s)
@@ -621,6 +662,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
@@ -688,3 +752,21 @@ do
    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()
+   local list_dir = tex_getcount('ltj@adjdir@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
+end