OSDN Git Service

Fix ticket #29140/
[luatex-ja/luatexja.git] / src / ltj-jfmglue.lua
index 228d376..0659fd0 100644 (file)
@@ -3,8 +3,8 @@
 --
 luatexbase.provides_module({
   name = 'luatexja.jfmglue',
-  date = '2012/04/02',
-  version = '0.3',
+  date = '2012/04/25',
+  version = '0.4',
   description = 'Insertion process of JFM glues and kanjiskip',
 })
 module('luatexja.jfmglue', package.seeall)
@@ -52,6 +52,11 @@ local id_pbox = node.id('hlist') + 512        -- already processed nodes (by \un
 local id_pbox_w = node.id('hlist') + 513      -- cluster which consists of a whatsit
 local sid_user = node.subtype('user_defined')
 
+local sid_start_link = node.subtype('pdf_start_link')
+local sid_start_thread = node.subtype('pdf_start_thread')
+local sid_end_link = node.subtype('pdf_end_link')
+local sid_end_thread = node.subtype('pdf_end_thread')
+
 local ITALIC = 1
 local PACKED = 2
 local KINSOKU = 3
@@ -178,12 +183,8 @@ local function check_box(box_ptr, box_end)
    end
    while p and p~=box_end do
       local pid = p.id
-      if pid==id_kern then
-        if p.subtype==2 then
-           p = node_next(node_next(node_next(p))); pid = p.id
-        elseif has_attr(p, attr_icflag)==IC_PROCESSED then
-           p = node_next(p); pid = p.id
-        end
+      if pid==id_kern and p.subtype==2 then
+           p = node_next(node_next(node_next(p))); pid = p.id -- p must be glyph_node
       end
       if pid==id_glyph then
         repeat 
@@ -193,8 +194,11 @@ local function check_box(box_ptr, box_end)
            last_char = p; found_visible_node = true; p=node_next(p)
            if (not p) or p==box_end then return found_visible_node end
         until p.id~=id_glyph
+        pid = p.id -- p must be non-nil
       end
-      if pid==id_hlist then
+      if pid==id_kern and has_attr(p, attr_icflag)==IC_PROCESSED then
+        p = node_next(p); 
+      elseif pid==id_hlist then
         if has_attr(p, attr_icflag)==PACKED then
            for q in node.traverse_id(id_glyph, p.head) do
               if find_first_char then
@@ -272,7 +276,7 @@ end
 
 local function calc_np_pbox()
    local uid = has_attr(lp, attr_uniqid)
-   Np.first = lp; Np.id = id_pbox
+   Np.first = Np.first or lp; Np.id = id_pbox
    lpa = KINSOKU -- dummy=
    while lp~=last and lpa>=PACKED and lpa~=BOXBDD
       and has_attr(lp, attr_uniqid) == uid do
@@ -284,17 +288,17 @@ end
 
 local calc_np_auxtable = {
    [id_glyph] = function() 
-                  Np.first = lp
+                  Np.first = Np.first or lp
                   if lp.font == has_attr(lp, attr_curjfnt) then 
                      Np.id = id_jglyph 
                   else 
                      Np.id = id_glyph 
                   end
-                  Np.first = lp; Np.nuc = lp; set_attr_icflag_processed(lp)
+                  Np.nuc = lp; set_attr_icflag_processed(lp)
                   lp = node_next(lp); check_next_ickern(); return true
                end,
    [id_hlist] = function() 
-                  Np.first = lp; Np.last = lp; Np.nuc = lp; 
+                  Np.first = Np.first or lp; Np.last = lp; Np.nuc = lp; 
                   set_attr_icflag_processed(lp)
                   if lp.shift~=0 then 
                      Np.id = id_box_like
@@ -304,12 +308,12 @@ local calc_np_auxtable = {
                   lp = node_next(lp); return true
                end,
    [id_vlist] = function()
-                  Np.first = lp; Np.nuc = lp; Np.last = lp;
+                  Np.first = Np.first or lp; Np.nuc = lp; Np.last = lp;
                   Np.id = id_box_like; set_attr_icflag_processed(lp); 
                   lp = node_next(lp); return true
                end,
    [id_rule] = function()
-                 Np.first = lp; Np.nuc = lp; Np.last = lp;
+                 Np.first = Np.first or lp; Np.nuc = lp; Np.last = lp;
                  Np.id = id_box_like; set_attr_icflag_processed(lp); 
                  lp = node_next(lp); return true
               end,
@@ -326,30 +330,37 @@ local calc_np_auxtable = {
                    return false
                 end,
    [id_disc] = function()
-                 Np.first = lp; Np.nuc = lp; set_attr_icflag_processed(lp); 
+                 Np.first = Np.first or lp; 
+          Np.nuc = lp; set_attr_icflag_processed(lp); 
                  Np.last = lp; Np.id = id_disc; lp = node_next(lp); return true
               end,
    [id_whatsit] = function() 
                  if lp.subtype==sid_user then
-             if lp.user_id==30111 then
-                local lq = node_next(lp)
-                head = node_remove(head, lp); node_free(lp); lp = lq; ihb_flag = true
-             else
-                set_attr_icflag_processed(lp)
-                luatexbase.call_callback("luatexja.jfmglue.whatsit_getinfo"
-                                        , Np, lp, Nq, box_stack_level)
-                lp = node_next(lp)
-                if Np.nuc then 
-                   Np.id = id_pbox_w; Np.first = Np.nuc; Np.last = Np.nuc; return true
-                end
+                    if lp.user_id==30111 then
+                       local lq = node_next(lp)
+                       head = node_remove(head, lp); node_free(lp); lp = lq; ihb_flag = true
+                    else
+                       set_attr_icflag_processed(lp)
+                       luatexbase.call_callback("luatexja.jfmglue.whatsit_getinfo"
+                                                , Np, lp, Nq, box_stack_level)
+                       lp = node_next(lp)
+                       if Np.nuc then 
+                          Np.id = id_pbox_w; Np.first = Np.nuc; Np.last = Np.nuc; return true
+                       end
+                    end
+                 else
+             -- we do special treatment for these whatsit nodes.
+             if lp.subtype == sid_start_link or lp.subtype == sid_start_thread then
+                Np.first = lp 
+             elseif lp.subtype == sid_end_link or lp.subtype == sid_end_thread then
+                Nq.last = lp; Np.first = nil
              end
-          else
-            set_attr_icflag_processed(lp)
+                    set_attr_icflag_processed(lp); lp = node_next(lp)
                  end
                  return false
                  end,
    [id_math] = function()
-                 Np.first = lp; Np.nuc = lp; 
+                 Np.first = Np.first or lp; Np.nuc = lp; 
                  set_attr_icflag_processed(lp); lp  = node_next(lp) 
                  while lp.id~=id_math do 
                     set_attr_icflag_processed(lp); lp  = node_next(lp) 
@@ -359,11 +370,11 @@ local calc_np_auxtable = {
                  return true
               end,
    [id_glue] = function()
-                 Np.first = lp; Np.nuc = lp; set_attr_icflag_processed(lp); 
+                 Np.first = Np.first or lp; Np.nuc = lp; set_attr_icflag_processed(lp); 
                  Np.last = lp; Np.id = id_glue; lp = node_next(lp); return true
               end,
    [id_kern] = function() 
-                 Np.first = lp
+                 Np.first = Np.first or lp
                  if lp.subtype==2 then
                     set_attr_icflag_processed(lp); lp = node_next(lp)
                     set_attr_icflag_processed(lp); lp = node_next(lp)
@@ -386,7 +397,7 @@ local calc_np_auxtable = {
                     lp = node_next(lp); return false
                  end,
    [13] = function()
-                 Np.first = lp; Np.nuc = lp; Np.last = lp;
+                 Np.first = Np.first or lp; Np.nuc = lp; Np.last = lp;
                  Np.id = id_box_like; set_attr_icflag_processed(lp); 
                  lp = node_next(lp); return true
               end,
@@ -461,8 +472,9 @@ function set_np_xspc_alchar(Nx, c,x, lig)
       end
       Nx.pre = ltjs_get_penalty_table('pre', c, 0, box_stack_level)
       Nx.post = ltjs_get_penalty_table('post', c, 0, box_stack_level)
+      Nx.char = 'jcharbdd'
    else
-      Nx.pre = 0; Nx.post = 0
+      Nx.pre = 0; Nx.post = 0; Nx.char = -1
    end
    Nx.met = nil
    local y = ltjs_get_penalty_table('xsp', c, 3, box_stack_level)
@@ -737,16 +749,14 @@ end
 
 local function get_OA_skip()
    if not ihb_flag then
-      local c
-      if Nq.id == id_math then c = -1 else c = 'jcharbdd' end
+      local c = Nq.char or 'jcharbdd'
       return new_jfm_glue(Np, fast_find_char_class(c,Np.met), Np.class)
    else return nil
    end
 end
 local function get_OB_skip()
    if not ihb_flag then
-      local c
-      if Np.id == id_math then c = -1 else c = 'jcharbdd' end
+      local c = Np.char or 'jcharbdd'
       return new_jfm_glue(Nq, Nq.class, fast_find_char_class(c,Nq.met))
    else return nil
    end
@@ -764,6 +774,7 @@ local function handle_np_jachar()
       handle_penalty_normal(0, Np.pre, g); real_insert(0, g)
    elseif Nq.pre then 
       g = get_OA_skip() or get_xkanjiskip(Np) -- O_A->X
+      if Nq.id==id_hlist then Nq.post = 0 end
       handle_penalty_normal(Nq.post, Np.pre, g); real_insert(0, g)
    else
       g = get_OA_skip() -- O_A
@@ -784,6 +795,7 @@ end
 local function handle_nq_jachar()
    local g
    if Np.pre then 
+      if Np.id==id_hlist then Np.pre = 0 end
       g = get_OB_skip() or get_xkanjiskip(Nq) -- O_B->X
       g = lineend_fix(g)
       handle_penalty_normal(Nq.post, Np.pre, g); real_insert(Nq.lend, g)
@@ -822,11 +834,21 @@ local function handle_nq_ja_hlist()
    end
 end
 
+-- Nq が前側のクラスタとなることによる修正
+local function adjust_nq()
+   if Nq.id==id_glyph then after_alchar(Nq)
+   elseif Nq.id==id_hlist or Nq.id==id_pbox or Nq.id==id_disc then after_hlist(Nq)
+   elseif Nq.id == id_pbox_w then 
+      luatexbase.call_callback("luatexja.jfmglue.whatsit_after",
+                              false, Nq, Np, box_stack_level)
+   end
+end
+
 -------------------- 開始・終了時の処理
 
 -- リスト末尾の処理
 local function handle_list_tail()
-   Np = Nq
+   adjust_nq(); Np = Nq
    if mode then
       -- the current list is to be line-breaked:
       if Np.id == id_jglyph or (Np.id==id_pbox and Np.met) then 
@@ -851,9 +873,7 @@ local function handle_list_tail()
            head = node_insert_after(head, Np.last, g)
         end
       end
-      head = node_remove(head, last); node_free(last);-- remove the sentinel
    end
-   node_free(kanji_skip); node_free(xkanji_skip)
 end
 
 -- リスト先頭の処理
@@ -913,13 +933,22 @@ local function init_var()
    end
 end
 
--- Nq が前側のクラスタとなることによる修正
-local function adjust_nq()
-   if Nq.id==id_glyph then after_alchar(Nq)
-   elseif Nq.id==id_hlist or Nq.id==id_pbox or Nq.id==id_disc then after_hlist(Nq)
-   elseif Nq.id == id_pbox_w then 
-      luatexbase.call_callback("luatexja.jfmglue.whatsit_after",
-                              false, Nq, Np, box_stack_level)
+local function cleanup()
+   -- adjust attr_icflag for avoiding error
+   tex.attribute[attr_icflag] = -(0x7FFFFFFF)
+   node_free(kanji_skip); node_free(xkanji_skip)
+   if mode then
+      local h = node_next(head)
+      if h.id == id_penalty and h.penalty == 10000 then
+        h = h.next
+        if h.id == id_glue and h.subtype == 15 and not h.next then
+           return false
+        end
+      end
+      return head
+   else
+      head = node_remove(head, last); node_free(last);-- remove the sentinel
+      return head
    end
 end
 -------------------- 外部から呼ばれる関数
@@ -931,8 +960,7 @@ function main(ahead, amode)
    if Np then 
       extract_np(); handle_list_head()
    else
-      if not mode then head = node_remove(head, last); node_free(last) end
-      return head
+      return cleanup()
    end
    calc_np()
    while Np do
@@ -950,15 +978,49 @@ function main(ahead, amode)
       calc_np()
    end
    handle_list_tail()
-   -- adjust attr_icflag
-   tex.attribute[attr_icflag] = -(0x7FFFFFFF)
-   return head
+   return cleanup()
 end
 
 -- \inhibitglue
-local inhibitglue_node=node_new(id_whatsit, sid_user)
-inhibitglue_node.user_id=30111; inhibitglue_node.type=100; inhibitglue_node.value=1
 
 function create_inhibitglue_node()
-   node.write(node.copy(inhibitglue_node))
+   local tn = node_new(id_whatsit, sid_user)
+   tn.user_id=30111; tn.type=100; tn.value=1
+   node.write(tn)
+end
+
+-- Node for indicating beginning of a paragraph
+-- (for ltjsclasses)
+function create_beginpar_node()
+   local tn = node_new(id_whatsit, sid_user)
+   tn.user_id=30114; tn.type=100; tn.value=1
+   node.write(tn)
 end
+
+local function whatsit_callback(Np, lp, Nq, bsl)
+   if Np and Np.nuc then return Np 
+   elseif Np and lp.user_id == 30114 then
+      Np.first = lp; Np.nuc = lp; Np.last = lp
+      Np.char = 'parbdd'
+      Np.met = nil
+      Np.pre = 0; Np.post = 0
+      Np.xspc_before = false
+      Np.xspc_after  = false
+      Np.auto_xspc = false
+      return Np
+   end
+end
+local function whatsit_after_callback(s, Nq, Np, bsl)
+   if not s and Nq.nuc.user_id == 30114 then
+      local x, y = node.prev(Nq.nuc), Nq.nuc
+      Nq.first, Nq.nuc, Nq.last = x, x, x
+      head = node_remove(head, y)
+   end
+   return s
+end
+
+luatexbase.add_to_callback("luatexja.jfmglue.whatsit_getinfo", whatsit_callback,
+                           "luatexja.beginpar.np_info", 1)
+luatexbase.add_to_callback("luatexja.jfmglue.whatsit_after", whatsit_after_callback,
+                           "luatexja.beginpar.np_info_after", 1)
+