OSDN Git Service

support for not setting \ltj@{y,t}{a,k}blshift (unset -> 0pt)
[luatex-ja/luatexja.git] / src / ltj-jfmglue.lua
index b37b1ab..3018470 100644 (file)
@@ -3,7 +3,7 @@
 --
 luatexbase.provides_module({
   name = 'luatexja.jfmglue',
-  date = '2020-07-30',
+  date = '2022-08-18',
   description = 'Insertion process of JFM glues, [x]kanjiskip and others',
 })
 luatexja.jfmglue = luatexja.jfmglue or {}
@@ -19,23 +19,29 @@ local pairs = pairs
 --local to_node = node.direct.tonode
 --local to_direct = node.direct.todirect
 
-local setfield = node.direct.setfield
-local setglue = luatexja.setglue
 local getfield = node.direct.getfield
 local getid = node.direct.getid
 local getfont = node.direct.getfont
 local getlist = node.direct.getlist
 local getchar = node.direct.getchar
+local getglue = luatexja.getglue
 local getsubtype = node.direct.getsubtype
+local getshift = node.direct.getshift
+local getwidth = node.direct.getwidth
+local getdepth = node.direct.getdepth
+local getpenalty = node.direct.getpenalty
+local setfield = node.direct.setfield
+local setglue = luatexja.setglue
+local setshift = node.direct.setshift
 local if_lang_ja
 do
     local lang_ja = luatexja.lang_ja
     local getlang = node.direct.getlang
     -- glyph with font number 0 (\nullfont) is always considered an ALchar node
-    if_lang_ja = getlang 
-      and function (n) return (getlang(n)==lang_ja)and(getfont(n)~=0) end
-      or  function (n) return (getfield(n,'lang')==lang_ja)and(getfont(n)~=0) end
+    if_lang_ja = function (n) return (getlang(n)==lang_ja)and(getfont(n)~=0) end
 end
+local setpenalty = node.direct.setpenalty
+local setkern = node.direct.setkern
   
 local has_attr = node.direct.has_attribute
 local set_attr = node.direct.set_attribute
@@ -45,11 +51,12 @@ local node_next = node.direct.getnext
 local ltjd_make_dir_whatsit = ltjd.make_dir_whatsit
 local ltjf_font_metric_table = ltjf.font_metric_table
 local ltjf_find_char_class = ltjf.find_char_class
-local node_new = node.direct.new
+local node_new = luatexja.dnode_new
 local node_copy = node.direct.copy
 local node_tail = node.direct.tail
-local node_free = node.direct.free
+local node_free = node.direct.flush_node or node.direct.free
 local node_remove = node.direct.remove
+local node_inherit_attr = luatexja.node_inherit_attr
 
 local id_glyph = node.id 'glyph'
 local id_hlist = node.id 'hlist'
@@ -78,6 +85,7 @@ local FROM_JFM     = luatexja.icflag_table.FROM_JFM
 local PROCESSED    = luatexja.icflag_table.PROCESSED
 local IC_PROCESSED = luatexja.icflag_table.IC_PROCESSED
 local BOXBDD       = luatexja.icflag_table.BOXBDD
+local SPECIAL_JAGLUE = luatexja.icflag_table.SPECIAL_JAGLUE
 local PROCESSED_BEGIN_FLAG = luatexja.icflag_table.PROCESSED_BEGIN_FLAG
 
 local attr_icflag = luatexbase.attributes['ltj@icflag']
@@ -129,8 +137,6 @@ end
 -- penalty 値の計算
 local add_penalty
 do
-local setpenalty = node.direct.setpenalty or function(n, a) setfield(n,'penalty',a) end
-local getpenalty = node.direct.getpenalty or function(n) return getfield(n,'penalty') end
 function add_penalty(p,e)
    local pp = getpenalty(p)
    if (pp>-10000) and (pp<10000) then
@@ -204,7 +210,7 @@ local function check_box(box_ptr, box_end)
             if find_first_char then first_char = s; find_first_char = false end
             last_char = s; found_visible_node = true
          else
-            if getfield(p, 'shift')==0 then
+            if getshift(p)==0 then
                last_char = nil
                if check_box(getlist(p), nil) then found_visible_node = true end
                find_first_char = false
@@ -258,6 +264,8 @@ luatexbase.create_callback("luatexja.jfmglue.whatsit_getinfo", "data",
                            end)
 luatexbase.create_callback("luatexja.jfmglue.whatsit_after", "data",
                            function (stat, Nq, Np) return false end)
+luatexbase.create_callback("luatexja.jfmglue.whatsit_last_minute", "data",
+                           function (stat, Nq, Np) return false end)
 
 -- calc next Np
 local calc_np 
@@ -307,6 +315,8 @@ do -- 002 ---------------------------------------
    local attr_jchar_class = luatexbase.attributes['ltj@charclass']
    local attr_jchar_code = luatexbase.attributes['ltj@charcode']
    local font_getfont = font.getfont
+   local setwhd = node.direct.setwhd
+   local setdir = node.direct.setdir
    local function calc_np_notdef(lp)
       if not font_getfont(getfont(lp)).characters[getchar(lp)] then
          local ln = node_next(lp)
@@ -338,22 +348,21 @@ function calc_np_aux_glyph_common(lp, acc_flag)
       local first_glyph, last_glyph = lp
       set_attr(lp, attr_icflag, PROCESSED); Np.last = lp
       local y_adjust = has_attr(lp,attr_ablshift) or 0
-      local node_depth = getfield(lp, 'depth') + min(y_adjust, 0)
-      local adj_depth = (y_adjust>0) and (getfield(lp, 'depth') + y_adjust) or 0
+      local node_depth = getdepth(lp) + min(y_adjust, 0)
+      local adj_depth = (y_adjust>0) and (getdepth(lp) + y_adjust) or 0
       setfield(lp, 'yoffset', getfield(lp, 'yoffset') - y_adjust); lp = node_next(lp)
       local lx=lp
       while lx do
          local lai = get_attr_icflag(lx)
-         if lx==last or  lai>=PACKED then
-            lp=lx; break
+         if lx==last or  lai>=PACKED then break
          else
             local lid = getid(lx)
             if lid==id_glyph and not if_lang_ja(lx) then
                -- 欧文文字
                last_glyph = lx; set_attr(lx, attr_icflag, PROCESSED); Np.last = lx
                y_adjust = has_attr(lx,attr_ablshift) or 0
-               node_depth = max(getfield(lx, 'depth') + min(y_adjust, 0), node_depth)
-               adj_depth = (y_adjust>0) and max(getfield(lx, 'depth') + y_adjust, adj_depth) or adj_depth
+               node_depth = max(getdepth(lx) + min(y_adjust, 0), node_depth)
+               adj_depth = (y_adjust>0) and max(getdepth(lx) + y_adjust, adj_depth) or adj_depth
                setfield(lx, 'yoffset', getfield(lx, 'yoffset') - y_adjust); lx = node_next(lx)
             elseif lid==id_kern then
                local ls = getsubtype(lx)
@@ -363,26 +372,26 @@ function calc_np_aux_glyph_common(lp, acc_flag)
                   if getid(lx)==id_glyph then
                      setfield(lx, 'yoffset', getfield(lx, 'yoffset') - (has_attr(lx,attr_ablshift) or 0))
                   else -- アクセントは上下にシフトされている
-                     setfield(lx, 'shift', getfield(lx, 'shift') + (has_attr(lx,attr_ablshift) or 0))
+                     setshift(lx, getshift(lx) + (has_attr(lx,attr_ablshift) or 0))
                   end
-                  lx = node_next(node_next(lx))
+                  set_attr(lx, attr_icflag, PROCESSED)
+                  lx = node_next(lx); set_attr(lx, attr_icflag, PROCESSED)
+                  lx = node_next(lx); set_attr(lx, attr_icflag, PROCESSED)
                elseif ls==0  then
                   Np.last = lx; lx = node_next(lx)
                elseif (ls==3) or (lai==ITALIC) then
                   Np.last = lx; set_attr(lx, attr_icflag, IC_PROCESSED); lx = node_next(lx)
-               else
-                  lp=lx; break
+               else break
                end
-            else
-               lp=lx; break
+            else break
             end
          end
       end
+      lp=lx
       local r
       if adj_depth>node_depth then
-            r = node_new(id_rule,3)
-            setfield(r, 'width', 0); setfield(r, 'height', 0)
-            setfield(r, 'depth',adj_depth); setfield(r, 'dir', tex_dir)
+            r = node_new(id_rule,3,first_glyph)
+            setwhd(r, 0, 0, adj_depth); setdir(r, tex_dir)
             set_attr(r, attr_icflag, PROCESSED)
       end
       if last_glyph then
@@ -432,7 +441,7 @@ calc_np_auxtable = {
       head, lp, op, flag = ltjd_make_dir_whatsit(head, lp, list_dir, 'jfm hlist')
       set_attr(op, attr_icflag, PROCESSED)
       Np.first = Np.first or op; Np.last = op; Np.nuc = op;
-      if (flag or getfield(op, 'shift')~=0) then
+      if (flag or getshift(op)~=0) then
          Np.id = id_box_like
       else
          Np.id = id_hlist
@@ -457,7 +466,7 @@ calc_np_auxtable = {
       if lps==sid_user then
          if getfield(lp, 'user_id')==luatexja.userid_table.IHB then
             local lq = node_next(lp);
-            head = node_remove(head, lp); node_free(lp); non_ihb_flag = false
+            head = node_remove(head, lp); node_free(lp); non_ihb_flag = getfield(lp, 'value')~=1
             return false, lq;
          elseif getfield(lp, 'user_id')==luatexja.userid_table.JA_AL_BDD then
             local lq = node_next(lp);
@@ -497,7 +506,11 @@ calc_np_auxtable = {
    end,
    [id_glue] = function(lp)
       Np.first, Np.nuc, Np.last = (Np.first or lp), lp, lp;
-      Np.id = getid(lp); set_attr(lp, attr_icflag, PROCESSED)
+      Np.id = getid(lp); 
+      local f = luatexbase.call_callback("luatexja.jfmglue.special_jaglue", lp)
+      if f then
+         set_attr(lp, attr_icflag, PROCESSED)
+      end
       return true, node_next(lp)
    end,
    [id_disc] = function(lp)
@@ -514,7 +527,7 @@ calc_np_auxtable = {
          if getid(lp)==id_glyph then -- アクセント本体
             setfield(lp, 'yoffset', getfield(lp, 'yoffset') - (has_attr(lp,attr_ablshift) or 0))
          else -- アクセントは上下にシフトされている
-            setfield(lp, 'shift', getfield(lp, 'shift') + (has_attr(lp,attr_ablshift) or 0))
+            setshift(lp, getshift(lp) + (has_attr(lp,attr_ablshift) or 0))
          end
          set_attr(lp, attr_icflag, PROCESSED); lp = node_next(lp)
          set_attr(lp, attr_icflag, PROCESSED); lp = node_next(lp)
@@ -543,10 +556,13 @@ end
 function calc_np(last, lp)
    local k
    -- We assume lp = node_next(Np.last)
+   if Nq and Nq.id==id_pbox_w then
+      luatexbase.call_callback("luatexja.jfmglue.whatsit_last_minute", false, Nq, Np)
+   end
    Np, Nq, non_ihb_flag = Nq, Np, true
    -- We clear `predefined' entries of Np before pairs() loop,
    -- because using only pairs() loop is slower.
-   Np.post, Np.pre, Np.xspc = nil, nil, nil
+   Np.post, Np.pre, Np.xspc, Np.gk = nil, nil, nil, nil
    Np.first, Np.id, Np.last, Np.met, Np.class= nil, nil, nil, nil
    Np.auto_kspc, Np.auto_xspc, Np.char, Np.nuc = nil, nil, nil, nil
    -- auto_kspc, auto_xspc: normally true/false, 
@@ -557,7 +573,7 @@ function calc_np(last, lp)
    while lp ~= last  do
       local lpa = has_attr(lp, attr_icflag) or 0
       -- unbox 由来ノードの検出
-      if lpa>=PACKED then
+      if (lpa>=PACKED) and (lpa%PROCESSED_BEGIN_FLAG<=BOXBDD) then
          if lpa%PROCESSED_BEGIN_FLAG == BOXBDD then
             local lq = node_next(lp)
             head = node_remove(head, lp); node_free(lp); lp = lq
@@ -606,7 +622,8 @@ do
       Nx.post = table_current_stack[POST + c] or 0
       Nx.xspc = table_current_stack[XSP  + c] or 3
       Nx.kcat = table_current_stack[KCAT + c] or 0
-      Nx.auto_kspc, Nx.auto_xspc = (has_attr(x, attr_autospc)==1), (has_attr(x, attr_autoxspc)==1)
+      Nx.auto_kspc, Nx.auto_xspc 
+       = not has_attr(x, attr_autospc, 0), not has_attr(x, attr_autoxspc, 0)
       return m, mc, cls
    end
    function set_np_xspc_jachar_hbox(Nx, x)
@@ -618,7 +635,8 @@ do
       Nx.post = table_current_stack[POST + c] or 0
       Nx.xspc = table_current_stack[XSP  + c] or 3
       Nx.kcat = table_current_stack[KCAT + c] or 0
-      Nx.auto_kspc, Nx.auto_xspc = (has_attr(x, attr_autospc)==1), (has_attr(x, attr_autoxspc)==1)
+      Nx.auto_kspc, Nx.auto_xspc
+       = not has_attr(x, attr_autospc, 0), not has_attr(x, attr_autoxspc, 0)
    end
 
 -- 欧文文字のデータを取得
@@ -641,7 +659,7 @@ do
       end
       Nx.met = nil
       Nx.xspc = table_current_stack[XSP  + c] or 3
-      Nx.auto_xspc = (has_attr(x, attr_autoxspc)==1)
+      Nx.auto_xspc = not has_attr(x, attr_autoxspc, 0)
    end
    local set_np_xspc_alchar = set_np_xspc_alchar
    -- change the information for the next loop
@@ -679,9 +697,9 @@ local function handle_penalty_normal(post, pre, g)
    local a = (pre or 0) + (post or 0)
    if #Bp == 0 then
       if (a~=0 and not(g and getid(g)==id_kern)) then
-         local p = node_new(id_penalty)
+         local p = node_new(id_penalty, nil, Nq.nuc, Np.nuc)
          if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
-         setfield(p, 'penalty', a); head = insert_before(head, Np.first, p)
+         setpenalty(p, a); head = insert_before(head, Np.first, p)
          Bp[1]=p; set_attr(p, attr_icflag, KINSOKU)
       end
    else for _, v in pairs(Bp) do add_penalty(v,a) end
@@ -693,9 +711,9 @@ local function handle_penalty_always(post, pre, g)
    local a = (pre or 0) + (post or 0)
    if #Bp == 0 then
       if not (g and getid(g)==id_glue) or a~=0 then
-         local p = node_new(id_penalty)
+         local p = node_new(id_penalty, nil, Nq.nuc, Np.nuc)
          if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
-         setfield(p, 'penalty', a); head = insert_before(head, Np.first, p)
+         setpenalty(p, a); head = insert_before(head, Np.first, p)
          Bp[1]=p; set_attr(p, attr_icflag, KINSOKU)
       end
    else for _, v in pairs(Bp) do add_penalty(v,a) end
@@ -706,8 +724,8 @@ local function handle_penalty_suppress(post, pre, g)
    luatexbase.call_callback('luatexja.adjust_jfmglue', head, Nq, Np, Bp)
    if #Bp == 0 then
       if g and getid(g)==id_glue then
-         local p = node_new(id_penalty)
-         setfield(p, 'penalty', 10000); head = insert_before(head, Np.first, p)
+         local p = node_new(id_penalty, nil, Nq.nuc, Np.nuc)
+         setpenalty(p, 10000); head = insert_before(head, Np.first, p)
          Bp[1]=p; set_attr(p, attr_icflag, KINSOKU)
       end
    else 
@@ -720,9 +738,9 @@ local function handle_penalty_jwp()
    local a = table_current_stack[luatexja.stack_table_index.JWP]
    if #widow_Bp == 0 then
       if a~=0 then
-         local p = node_new(id_penalty)
+         local p = node_new(id_penalty, widow_Np.nuc)
          if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
-         setfield(p, 'penalty', a); head = insert_before(head, widow_Np.first, p)
+         setpenalty(p, a); head = insert_before(head, widow_Np.first, p)
          widow_Bp[1]=p; set_attr(p, attr_icflag, KINSOKU)
       end
    else for _, v in pairs(widow_Bp) do add_penalty(v,a) end
@@ -735,12 +753,14 @@ local function new_jfm_glue(mc, bc, ac)
    local g = mc[bc][ac]
    if g then
        if g[1] then
-           return node_copy(g[1]), g.ratio, false, false, false
+          local k = node_new(id_kern, 1); setkern(k, g[1]) 
+          set_attr(k, attr_icflag, FROM_JFM)
+          return k, g.ratio, false, false, false
        else
-         local f = node_new(id_glue)
-         set_attr(f, attr_icflag, g.priority)
-         setglue(f, g.width, g.stretch, g.shrink)
-         return f, g.ratio, g.kanjiskip_natural, g.kanjiskip_stretch, g.kanjiskip_shrink
+          local f = node_new(id_glue)
+          set_attr(f, attr_icflag, g.priority)
+          setglue(f, g.width, g.stretch, g.shrink)
+          return f, g.ratio, g.kanjiskip_natural, g.kanjiskip_stretch, g.kanjiskip_shrink
       end
    end
    return false, 0
@@ -749,8 +769,11 @@ end
 -- Nq.last (kern w) .... (glue/kern g) Np.first
 local function real_insert(g)
    if g then
-      head  = insert_before(head, Np.first, g)
-      Np.first = g
+      head, Np.first = insert_before(head, Np.first, node_inherit_attr(g, Nq.nuc, Np.nuc))
+      local ngk = Np.gk
+      if not ngk then Np.gk = g
+      elseif type(ngk)=="table" then ngk[#ngk+1]=g
+      else  Np.gk = { ngk, g } end
    end
 end
 
@@ -763,6 +786,7 @@ do
    local bg_ak = 2*id_glue - id_kern
    local bk_ag = 2*id_kern - id_glue
    local bk_ak = 2*id_kern - id_kern
+   local getkern = node.direct.getkern
 
    local function blend_diffmet(b, a, rb, ra)
       return round(luatexja.jfmglue.diffmet_rule((1-rb)*b+rb*a, (1-ra)*b+ra*a))
@@ -784,24 +808,24 @@ do
          db, da = 0, 1
       end
       if not gb then
-         if ga then gb = node_new(id_kern, 1); setfield(gb, 'kern', 0)
+         if ga then gb = node_new(id_kern, 1); setkern(gb, 0)
          else return nil end
       elseif not ga then
-         ga = node_new(id_kern, 1); setfield(ga, 'kern', 0)
+         ga = node_new(id_kern, 1); setkern(ga, 0)
       end
       local gbw, gaw, gbst, gast, gbsto, gasto, gbsh, gash, gbsho, gasho
       if getid(gb)==id_glue then
          gbw, gbst, gbsh, gbsto, gbsho = getglue(gb)
       else
-         gbw = getfield(gb, 'kern')
+         gbw = getkern(gb)
       end
       if getid(ga)==id_glue then
          gaw, gast, gash, gasto, gasho = getglue(ga)
       else
-         gaw = getfield(ga, 'kern')
+         gaw = getkern(ga)
       end
       if not (gbst or gast) then -- 両方とも kern
-         setfield(gb, 'kern', blend_diffmet(gbw, gaw, db, da))
+         setkern(gb, blend_diffmet(gbw, gaw, db, da))
          node_free(ga); return gb
       else
          local gr = gb
@@ -842,7 +866,7 @@ do
             local st = bp and (bp*getfield(kanji_skip, 'stretch')) or 0
             local sh = bh and (bh*getfield(kanji_skip, 'shrink')) or 0
             setglue(g,
-               bn and (bn*getfield(kanji_skip, 'width')) or 0,
+               bn and (bn*getwidth(kanji_skip)) or 0,
                st, sh, 
                (st==0) and 0 or getfield(kanji_skip, 'stretch_order'),
                (sh==0) and 0 or getfield(kanji_skip, 'shrink_order'))
@@ -926,13 +950,14 @@ do
          elseif flag then
             return node_copy(xkanji_skip)
          else
-            local g = node_new(id_glue);
+            local g = node_new(id_glue)
+            local w, st, sh, sto, sho = getglue(xkanji_skip) 
             setglue(g,
-               bn and (bn*getfield(xkanji_skip, 'width')) or 0,
-               bp and (bp*getfield(xkanji_skip, 'stretch')) or 0,
-               bh and (bh*getfield(xkanji_skip, 'shrink')) or 0,
-               bp and getfield(xkanji_skip, 'stretch_order') or 0,
-               bh and getfield(xkanji_skip, 'shrink_order') or 0)
+               bn and (bn*w) or 0,
+               bp and (bp*st) or 0,
+               bh and (bh*sh) or 0,
+               bp and sto or 0,
+               bh and sho or 0)
             set_attr(g, attr_icflag, XKANJI_SKIP_JFM)
             return g
          end
@@ -961,24 +986,20 @@ end
 -- NA, NB: alchar or math
 local function get_NA_skip()
    local pm = Np.met
-   local g, _, kn, kp, kh = new_jfm_glue(
-      pm.char_type,
-      fast_find_char_class(
-        (Nq.id == id_math and -1 or (Nq.xspc>=2 and 'alchar' or 'nox_alchar')), pm), 
-      Np.class)
-   local k = ((Nq.xspc>=2) and (Np.xspc%2==1) and combine_spc 'auto_xspc')
-       and get_xkanjiskip_low(false, pm, kn, kp, kh)
+   local qclass = fast_find_char_class(
+      (Nq.id == id_math and -1 or (Nq.xspc>=2 and 'alchar' or 'nox_alchar')), pm)
+   local g, _, kn, kp, kh = new_jfm_glue(pm.char_type, qclass, Np.class)
+   local k = g and (Nq.xspc>=2) and (Np.xspc%2==1) and combine_spc 'auto_xspc'
+      and get_kanjiskip_low(true, pm, kn, kp, kh)
    return g, k
 end
 local function get_NB_skip()
    local qm = Nq.met
-   local g, _, kn, kp, kh = new_jfm_glue(
-      qm.char_type, Nq.class,
-      fast_find_char_class(
-        (Np.id == id_math and -1 or (Np.xspc%2==1 and 'alchar' or 'nox_alchar')), qm)
-    )
-   local k = ((Nq.xspc>=2) and (Np.xspc%2==1) and combine_spc 'auto_xspc')
-         and get_xkanjiskip_low(false, qm, kn, kp, kh)
+   local pclass = fast_find_char_class(
+      (Np.id == id_math and -1 or (Np.xspc%2==1 and 'alchar' or 'nox_alchar')), qm)
+   local g, _, kn, kp, kh = new_jfm_glue(qm.char_type, Nq.class, pclass)
+   local k = g and (Nq.xspc>=2) and (Np.xspc%2==1) and combine_spc 'auto_xspc'
+      and get_kanjiskip_low(true, qm, kn, kp, kh)
    return g, k
 end
 
@@ -1023,8 +1044,7 @@ local function handle_np_jachar(mode)
       if not g then g = get_kanjiskip() end
       handle_penalty_normal(0, Np.pre, g); real_insert(g); real_insert(k)
    elseif Nq.pre then
-      local g, k
-      if non_ihb_flag then g, k = get_NA_skip() end -- N_A->X
+      local g, k; if non_ihb_flag then g, k = get_NA_skip() end -- N_A->X
       if not g then g = get_xkanjiskip(Np) end
       handle_penalty_normal((qid==id_hlist and 0 or Nq.post), Np.pre, g); 
       real_insert(g); real_insert(k)
@@ -1045,8 +1065,10 @@ end
 -- jachar .. (anything)
 local function handle_nq_jachar()
     if Np.pre then
-      local g = non_ihb_flag and get_NB_skip() or get_xkanjiskip(Nq) -- N_B->X
-      handle_penalty_normal(Nq.post, (Np.id==id_hlist and 0 or Np.pre), g); real_insert(g)
+      local g, k; if non_ihb_flag then g, k =  get_NB_skip()end -- N_B->X
+      if not g then g = get_xkanjiskip(Nq) end
+      handle_penalty_normal(Nq.post, (Np.id==id_hlist and 0 or Np.pre), g);
+      real_insert(g); real_insert(k)
    else
       local g =non_ihb_flag and  (get_OB_skip()) -- O_B
       if Np.id==id_glue then handle_penalty_normal(Nq.post, 0, g)
@@ -1086,13 +1108,17 @@ local adjust_nq
 do
    local adjust_nq_aux = {
       [id_glyph] = function() after_alchar(Nq) end, -- after_alchar(Nq)
-      [id_hlist]  = function() after_hlist(Nq) end,
+      [id_hlist] = function() after_hlist(Nq) end,
       [id_pbox]  = function() after_hlist(Nq) end,
       [id_disc]  = function() after_hlist(Nq) end,
-      [id_pbox_w]  = function()
-                        luatexbase.call_callback("luatexja.jfmglue.whatsit_after",
-                                                 false, Nq, Np)
-                     end,
+      [id_glue]  = function() 
+                      luatexbase.call_callback("luatexja.jfmglue.special_jaglue_after", Nq.nuc)
+                   end,
+      [id_pbox_w]= function()
+                      local hh = luatexbase.call_callback("luatexja.jfmglue.whatsit_after", false, Nq, Np, head)
+                      -- hh: new head of false (nott processed)
+                      if hh then head = hh end
+                   end,
    }
 
    adjust_nq = function()
@@ -1135,8 +1161,8 @@ local function handle_list_head(par_indented)
          if g then
             set_attr(g, attr_icflag, BOXBDD)
             if getid(g)==id_glue and #Bp==0 then
-               local h = node_new(id_penalty)
-               setfield(h, 'penalty', 10000); set_attr(h, attr_icflag, BOXBDD)
+               local h = node_new(id_penalty, nil, Np.nuc)
+               setpenalty(h, 10000); set_attr(h, attr_icflag, BOXBDD)
             end
             head = insert_before(head, Np.first, g)
          end
@@ -1161,10 +1187,10 @@ do
       {}, {}, {first=nil},
       { auto_kspc=nil, auto_xspc=nil, char=nil, class=nil,
         first=nil, id=nil, last=nil, met=nil, nuc=nil,
-        post=nil, pre=nil, xspc=nil, }, 
+        post=nil, pre=nil, xspc=nil, gk=nil }, 
       { auto_kspc=nil, auto_xspc=nil, char=nil, class=nil,
         first=nil, id=nil, last=nil, met=nil, nuc=nil,
-        post=nil, pre=nil, xspc=nil, },
+        post=nil, pre=nil, xspc=nil, gk=nil },
    }
    init_var = function (mode,dir)
       -- 1073741823: max_dimen
@@ -1179,18 +1205,15 @@ do
       attr_ablshift = is_dir_tate and attr_tablshift or attr_yablshift
       local TEMP = node_new(id_glue) 
       -- TEMP is a dummy node, which will be freed at the end of the callback. 
-      -- ithout this node, set_attr(kanji_skip, ...) somehow creates an "orphaned"  attribute list.
-
+      -- Without this node, set_attr(kanji_skip, ...) somehow creates an "orphaned"  attribute list.
       do
           kanji_skip, kanjiskip_jfm_flag = skip_table_to_glue(KSK)
           set_attr(kanji_skip, attr_icflag, KANJI_SKIP)
       end
-
       do
           xkanji_skip, xkanjiskip_jfm_flag = skip_table_to_glue(XSK)
           set_attr(xkanji_skip, attr_icflag, XKANJI_SKIP)
       end
-
       if mode then
          -- the current list is to be line-breaked:
          -- hbox from \parindent is skipped.
@@ -1201,7 +1224,7 @@ do
                or (lpi==id_local)) do
             if (lpi==id_hlist) and (lps==3) then
                Np.char, par_indented = 'parbdd', 'parbdd'
-               Np.width = getfield(lp, 'width')
+               Np.width = getwidth(lp)
             end
             lp=node_next(lp); lpi, lps = getid(lp), getsubtype(lp) end
          return lp, node_tail(head), par_indented, TEMP
@@ -1211,32 +1234,13 @@ do
    end
 end
 
-local ensure_tex_attr = ltjb.ensure_tex_attr
-local function cleanup(mode, TEMP)
-   -- luatexja.ext_show_node_list(to_node(head), '> ', print)
-   -- adjust attr_icflag for avoiding error
-   if tex.getattribute(attr_icflag)~=0 then ensure_tex_attr(attr_icflag, 0) end
-   node_free(kanji_skip); 
-   node_free(xkanji_skip); node_free(TEMP)
-   
-   if mode then
-      local h = node_next(head)
-      if getid(h) == id_penalty and getfield(h, 'penalty') == 10000 then
-         h = node_next(h)
-         if getid(h) == id_glue and getsubtype(h) == 15 and not node_next(h) then
-            return false
-         end
-      end
-   end
-   return head
-end
 -------------------- 外部から呼ばれる関数
 
+local ensure_tex_attr = ltjb.ensure_tex_attr
+local tex_getattr = tex.getattribute
 -- main interface
 function luatexja.jfmglue.main(ahead, mode, dir)
    if not ahead then return ahead end
-   -- luatexja.ext_show_node_list(node.direct.tonode(ahead ), '>B ', print)
-   -- print()
    head = ahead;
    local lp, last, par_indented, TEMP = init_var(mode,dir)
    lp = calc_np(last, lp)
@@ -1260,9 +1264,11 @@ function luatexja.jfmglue.main(ahead, mode, dir)
       end
       handle_list_tail(mode, last)
    end
-   --luatexja.ext_show_node_list(to_node(ahead ), '>A ', print)
-   --print()
-   return cleanup(mode, TEMP)
+   -- adjust attr_icflag for avoiding error
+   if tex_getattr(attr_icflag)~=0 then ensure_tex_attr(attr_icflag, 0) end
+   node_free(kanji_skip); 
+   node_free(xkanji_skip); node_free(TEMP)
+   return head
 end
 end
 
@@ -1273,14 +1279,20 @@ do
    local node_prev = node.direct.getprev
    local node_write = node.direct.write
 
-   -- \inhibitglue
-   function luatexja.jfmglue.create_inhibitglue_node()
+   -- \inhibitglue, \disinhibitglue
+   local function ihb_node(v)
       local tn = node_new(id_whatsit, sid_user)
       setfield(tn, 'user_id', IHB)
       setfield(tn, 'type', 100)
-      setfield(tn, 'value', 1)
+      setfield(tn, 'value', v)
       node_write(tn)
    end
+   function luatexja.jfmglue.create_inhibitglue_node()
+      ihb_node(1)
+   end
+   function luatexja.jfmglue.create_disinhibitglue_node()
+      ihb_node(0)
+   end
 
    -- Node for indicating beginning of a paragraph
    -- (for ltjsclasses)
@@ -1321,7 +1333,7 @@ do
       end
    end
 
-    local function whatsit_after_callback(s, Nq, Np)
+    local function whatsit_after_callback(s, Nq, Np, head)
        if not s and getfield(Nq.nuc, 'user_id') == BPAR then
          local x, y = node_prev(Nq.nuc), Nq.nuc
          Nq.first, Nq.nuc, Nq.last = x, x, x
@@ -1332,7 +1344,7 @@ do
             Nq.met = Np.met; Nq.pre = 0; Nq.post = 0; Nq.xspc = 0
             Nq.auto_xspc, Nq.auto_kspc = 0, 0
          end
-         head = node_remove(head, y)
+         s = node_remove(head, y)
          node_free(y)
        elseif not s and getfield(Nq.nuc, 'user_id') == BOXB then
          local x, y = node_prev(Nq.nuc), Nq.nuc
@@ -1344,7 +1356,7 @@ do
             Nq.met = Np.met; Nq.pre = 0; Nq.post = 0; Nq.xspc = 0
             Nq.auto_xspc, Nq.auto_kspc = 0, 0
          end
-         head = node_remove(head, y)
+         s = node_remove(head, y)
          node_free(y)
       end
       return s
@@ -1354,8 +1366,114 @@ do
                               "luatexja.beginpar.np_info", 1)
    luatexbase.add_to_callback("luatexja.jfmglue.whatsit_after", whatsit_after_callback,
                               "luatexja.beginpar.np_info_after", 1)
+end
 
+do
+   local node_prev = node.direct.getprev
+   local node_write = node.direct.write
+   local XKANJI_SKIP   = luatexja.icflag_table.XKANJI_SKIP
+   local XKANJI_SKIP_JFM   = luatexja.icflag_table.XKANJI_SKIP_JFM
+   local KANJI_SKIP   = luatexja.icflag_table.KANJI_SKIP
+   local KANJI_SKIP_JFM   = luatexja.icflag_table.KANJI_SKIP_JFM
+   local XSK  = luatexja.stack_table_index.XSK
+   local KSK  = luatexja.stack_table_index.KSK
+   local attr_yablshift = luatexbase.attributes['ltj@yablshift']
+   local attr_tablshift = luatexbase.attributes['ltj@tablshift']
+   local getcount, abs, scan_keyword = tex.getcount, math.abs, token.scan_keyword
+   local tex_nest = tex.nest
+   local tex_getattr = tex.getattribute
+   local get_current_jfont
+   do
+       local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
+       local attr_curtfnt = luatexbase.attributes['ltj@curtfnt']
+       local dir_tate = luatexja.dir_table.dir_tate
+       local get_dir_count = ltjd.get_dir_count        
+       function get_current_jfont()
+           return tex_getattr((get_dir_count()==dir_tate) and attr_curtfnt or attr_curjfnt)
+       end
+   end
+   -- \insertxkanjiskip
+   -- SPECIAL_JAGLUE のノード:
+   -- * (X)KANJI_SKIP(_JFM): その場で値が決まっている
+   -- * PROCESSED_BEGIN_FLAG + (X)KANJI_SKIP: 段落終了時に決める
+   local function insert_k_skip_common(ind, name, ica, icb)
+       if abs(tex_nest[tex_nest.ptr].mode) ~= ltjs.hmode then return end
+       local g = node_new(id_glue); set_attr(g, attr_icflag, SPECIAL_JAGLUE)
+       local is_late = scan_keyword("late")
+       if not is_late then
+           local st = ltjs.get_stack_skip(ind, getcount('ltj@@stack'))
+           if st.width==1073741823 then
+               local bk = ltjf_font_metric_table[get_current_jfont()][name]
+               if bk then
+                   setglue(g, bk[1] or 0, bk[2] or 0, bk[3] or 0, 0, 0)
+               end
+               set_attr(g, attr_yablshift, icb); node_write(g); return
+           end
+           setglue(g, st.width, st.stretch, st.shrink, st.stretch_order, st.shrink_order)
+           set_attr(g, attr_yablshift, ica)
+       else
+           set_attr(g, attr_yablshift, PROCESSED_BEGIN_FLAG + ica)
+           set_attr(g, attr_tablshift, get_current_jfont())               
+       end
+       node_write(g)
+   end
+   function luatexja.jfmglue.insert_xk_skip()
+       insert_k_skip_common(XSK, "xkanjiskip", XKANJI_SKIP, XKANJI_SKIP_JFM)
+   end
+   function luatexja.jfmglue.insert_k_skip()
+       insert_k_skip_common(KSK, "kanjiskip", KANJI_SKIP, KANJI_SKIP_JFM)
+   end
+   -- callback
+   local function special_jaglue(lx)
+       local lxi = get_attr_icflag(lx)
+       if lxi==SPECIAL_JAGLUE then
+           non_ihb_flag = false; return false
+       else
+           return lx
+       end
+   end
+   local function special_jaglue_after_inner(lx, lxi, lxi_jfm, kn, bk)
+       local w, st, sh, sto, sho = getglue(kn)
+       if w~=1073741823 then
+           setglue(lx, w, st, sh, sto, sho); set_attr(lx, attr_icflag, lxi)
+       else
+           local m = ltjf_font_metric_table[has_attr(lx, attr_tablshift)]
+           setglue(lx, bk[1], bk[2], bk[3], 0, 0)
+           set_attr(lx, attr_icflag, lxi_jfm)
+       end
+   end
+   local function special_jaglue_after(lx)
+       if get_attr_icflag(lx)==SPECIAL_JAGLUE then
+           lxi=has_attr(lx, attr_yablshift)
+           if lxi>=PROCESSED_BEGIN_FLAG then
+               lxi = lxi%PROCESSED_BEGIN_FLAG
+               if lxi == KANJI_SKIP then
+                   special_jaglue_after_inner(lx, lxi, KANJI_SKIP_JFM, kanji_skip, 
+                     ltjf_font_metric_table[has_attr(lx, attr_tablshift)].kanjiskip or null_skip_table)
+               else --  lxi == XKANJI_SKIP
+                   special_jaglue_after_inner(lx, lxi, XKANJI_SKIP_JFM, xkanji_skip, 
+                     ltjf_font_metric_table[has_attr(lx, attr_tablshift)].xkanjiskip or null_skip_table)
+               end
+           else
+               set_attr(lx, attr_icflag, lxi)
+           end
+           Np.first = lx
+           if node_prev(lx) then
+               local lxp = node_prev(lx)
+               if lxp and getid(lxp)==id_penalty and get_attr_icflag(lxp)==KINSOKU then
+                   Bp[#Bp+1]=lxp
+               end
+           end
+           non_ihb_flag = false; return false
+       end
+       return true
+   end
+   luatexbase.create_callback("luatexja.jfmglue.special_jaglue", "list",
+                              special_jaglue)
+   luatexbase.create_callback("luatexja.jfmglue.special_jaglue_after", "list",
+                              special_jaglue_after)
 end
 
+
 luatexja.jfmglue.after_hlist = after_hlist
 luatexja.jfmglue.check_box_high = check_box_high