OSDN Git Service

apply "implicit" vert/vrt2 features just before computing character class
[luatex-ja/luatexja.git] / src / ltj-jfmglue.lua
index d5b899e..106b98d 100644 (file)
@@ -66,6 +66,7 @@ local id_box_like  = 256 -- vbox, shifted hbox
 local id_pbox      = 257 -- already processed nodes (by \unhbox)
 local id_pbox_w    = 258 -- cluster which consists of a whatsit
 local sid_user = node.subtype('user_defined')
+local lang_ja = token.create('ltj@@japanese')[2]
 
 local sid_start_link = node.subtype('pdf_start_link')
 local sid_start_thread = node.subtype('pdf_start_thread')
@@ -88,10 +89,10 @@ local capsule_glyph
 local tex_dir
 local attr_ablshift
 local set_np_xspc_jachar
+local set_np_xspc_jachar_hbox
 
-local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
-local attr_dir = luatexbase.attributes['ltj@dir']
 local attr_icflag = luatexbase.attributes['ltj@icflag']
+local ltjs_orig_char_table = ltjs.orig_char_table
 
 local function get_attr_icflag(p)
    return (has_attr(p, attr_icflag) or 0)%PROCESSED_BEGIN_FLAG
@@ -99,10 +100,6 @@ end
 
 -------------------- Helper functions
 
-local function copy_attr(new, old)
-  -- 仕様が決まるまで off にしておく
-end
-
 -- This function is called only for acquiring `special' characters.
 local function fast_find_char_class(c,m)
    return m.chars[c] or 0
@@ -113,7 +110,7 @@ local slow_find_char_class
 do
    local start_time_measure = ltjb.start_time_measure
    local stop_time_measure = ltjb.stop_time_measure
-   slow_find_char_class = function (c, m, oc)
+   slow_find_char_class = function (c, m, oc,t )
       local cls = ltjf_find_char_class(oc, m)
       if oc~=c and cls==0 then
         return ltjf_find_char_class(-c, m), oc
@@ -173,8 +170,8 @@ local head -- the head of current list
 local Np, Nq, Bp
 local widow_Bp, widow_Np -- \jcharwidowpenalty 挿入位置管理用
 
-local ihb_flag -- JFM グルー挿入抑止用 flag
-               -- on: \inhibitglue 指定時,hlist の周囲
+local non_ihb_flag -- JFM グルー挿入抑止用 flag
+-- false: \inhibitglue 指定時 true: それ以外
 
 -------------------- hlist 内の文字の検索
 
@@ -234,7 +231,7 @@ local function check_box(box_ptr, box_end)
            first_char = p; find_first_char = false
         end
         last_char = p; found_visible_node = true
-      elseif pid==id_rule and get_attr_icflag(p)==PACKED then 
+      elseif pid==id_rule and get_attr_icflag(p)==PACKED then
         -- do nothing
       elseif not (pid==id_ins   or pid==id_mark
                  or pid==id_adjust or pid==id_whatsit
@@ -253,8 +250,8 @@ function check_box_high(Nx, box_ptr, box_end)
       local first_char = first_char
       if first_char then
          if getid(first_char)==id_glyph then
-           if getfont(first_char) == (has_attr(first_char, attr_curjfnt) or -1) then
-              set_np_xspc_jachar(Nx, first_char)
+           if getfield(first_char, 'lang') == lang_ja then
+              set_np_xspc_jachar_hbox(Nx, first_char)
            else
               set_np_xspc_alchar(Nx, getchar(first_char),first_char, 1)
            end
@@ -281,6 +278,7 @@ luatexbase.create_callback("luatexja.jfmglue.whatsit_after", "data",
 -- calc next Np
 do
 
+local traverse = Dnode.traverse
 local function set_attr_icflag_processed(p)
    if get_attr_icflag(p)<= ITALIC then
       set_attr(p, attr_icflag, PROCESSED)
@@ -303,7 +301,7 @@ local function calc_np_pbox(lp, last)
    while lp ~=last and (lpa>=PACKED) and (lpa<BOXBDD) do
       if getid(lp)==id_hlist or getid(lp)==id_vlist then
         head, lp, nc = ltjd_make_dir_whatsit(head, lp, list_dir, 'jfm pbox')
-        if first then Np.first = nc end
+        Np.first = first and nc or Np.first
       else
         nc, lp = lp, node_next(lp)
       end
@@ -311,29 +309,101 @@ local function calc_np_pbox(lp, last)
      -- get_attr_icflag() ではいけない!
    end
    Np.nuc = nc
-   return check_next_ickern(lp)
+   lp = check_next_ickern(lp)
+   Np.last_char = check_box_high(Np, Np.first, lp)
+   return lp
 end
 
 local ltjw_apply_ashift_math = ltjw.apply_ashift_math
+local ltjw_apply_ashift_disc = ltjw.apply_ashift_disc
+local min, max = math.min, math.max
 local function calc_np_aux_glyph_common(lp)
    Np.nuc = lp
    Np.id = npi
-   if (getfont(lp) == (has_attr(lp, attr_curjfnt) or -1)) then
+   if ltjs_orig_char_table[lp] then
       Np.id = id_jglyph
       set_np_xspc_jachar(Np, lp)
       local npi, npf
-      lp, head, npi, npf = capsule_glyph(lp, Np.met, Np.class, head, tex_dir)
+      lp, head, npi, npf = capsule_glyph(lp, Np.met, Np.class, head, tex_dir, lp)
       Np.first = (Np.first~=Np.nuc) and Np.first or npf or npi
       Np.nuc = npi
+      return true, check_next_ickern(lp);
    else
       Np.id = id_glyph
       set_np_xspc_alchar(Np, getchar(lp), lp, 1)
-      set_attr(lp, attr_icflag, PROCESSED)
-      setfield(lp, 'yoffset',
-              getfield(lp, 'yoffset') - (has_attr(lp,attr_ablshift) or 0))
+      -- loop
+      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
+      setfield(lp, 'yoffset', getfield(lp, 'yoffset') - y_adjust)
       lp = node_next(lp)
+      for lx in traverse(lp) do
+        local lai = get_attr_icflag(lx)
+        if lx==last or  lai>=PACKED then
+           lp=lx; break
+        else
+           local lid = getid(lx)
+           if lid==id_glyph and not ltjs_orig_char_table[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
+              setfield(lx, 'yoffset', getfield(lx, 'yoffset') - y_adjust)
+           elseif lid==id_kern then
+              local ls = getsubtype(lx)
+              if ls==2 then -- アクセント用の kern
+                 set_attr(lx, attr_icflag, PROCESSED)
+                 lx = node_next(lx) -- lp: アクセント本体
+                 setfield(lx, 'yoffset', getfield(lp, 'yoffset') - (has_attr(lx,attr_ablshift) or 0))
+                 lx = node_next(node_next(lx))
+              elseif ls==0  then
+                 Np.last = lx
+              elseif (ls==1 and lai==ITALIC) then
+                 Np.last = lx; set_attr(lx, attr_icflag, IC_PROCESSED)
+              else
+                 lp=lx; break
+              end
+           else
+              lp=lx; break
+           end
+        end
+      end
+      local r
+      if adj_depth>node_depth then
+           r = node_new(id_rule)
+           setfield(r, 'width', 0); setfield(r, 'height', 0)
+           setfield(r, 'depth',adj_depth); setfield(r, 'dir', tex_dir)
+           set_attr(r, attr_icflag, PROCESSED)
+      end
+      if last_glyph then
+        Np.last_char = last_glyph
+        if r then insert_after(head, first_glyph, r) end
+      else
+        local npn = Np.nuc
+        Np.last_char = npn
+        if r then
+           local nf, nc = getfont(npn), getchar(npn)
+           local ct = (font.getfont(nf) or font.fonts[nf] ).characters[nc]
+           if (ct.left_protruding or 0) == 0 then
+              head = insert_before(head, npn, r)
+              Np.first = (Np.first==npn) and r or npn
+           elseif (ct.right_protruding or 0) == 0 then
+              insert_after(head, npn, r); Np.last, lp = r, r
+           else
+              ltjb.package_warning_no_line(
+                 'luatexja',
+                 'Check depth of glyph node ' .. tostring(npn) .. '(font=' .. nf
+                    .. ', char=' .. nc .. '),    because its \\lpcode is ' .. tostring(ct.left_protruding)
+                    .. ' and its \\rpcode is ' .. tostring(ct.right_protruding)
+              ); node_free(r)
+           end
+        end
+      end
+      return true, lp
    end
-   return true, check_next_ickern(lp);
 end
 local calc_np_auxtable = {
    [id_glyph] = function (lp)
@@ -374,7 +444,7 @@ local 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); ihb_flag = true
+           head = node_remove(head, lp); node_free(lp); non_ihb_flag = false
            return false, lq;
         else
            set_attr(lp, attr_icflag, PROCESSED)
@@ -408,9 +478,16 @@ local calc_np_auxtable = {
       Np.last, Np.id = end_math, id_math;
       return true, node_next(end_math);
    end,
-   discglue = function(lp)
+   [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)
+      return true, node_next(lp)
+   end,
+   [id_disc] = function(lp)
       Np.first, Np.nuc, Np.last = (Np.first or lp), lp, lp;
       Np.id = getid(lp); set_attr(lp, attr_icflag, PROCESSED)
+      ltjw_apply_ashift_disc(lp, (list_dir==dir_tate), tex_dir)
+      Np.last_char = check_box_high(Np, getfield(lp, 'replace'), nil)
       return true, node_next(lp)
    end,
    [id_kern] = function(lp)
@@ -436,13 +513,11 @@ calc_np_auxtable[13]        = calc_np_auxtable.box_like
 calc_np_auxtable[id_ins]    = calc_np_auxtable.skip
 calc_np_auxtable[id_mark]   = calc_np_auxtable.skip
 calc_np_auxtable[id_adjust] = calc_np_auxtable.skip
-calc_np_auxtable[id_disc]   = calc_np_auxtable.discglue
-calc_np_auxtable[id_glue]   = calc_np_auxtable.discglue
 
 function calc_np(lp, last)
    local k
    -- We assume lp = node_next(Np.last)
-   Np, Nq, ihb_flag = Nq, Np, nil
+   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
@@ -487,13 +562,13 @@ do
 
 -- 和文文字のデータを取得
    local attr_jchar_class = luatexbase.attributes['ltj@charclass']
-   local attr_orig_char = luatexbase.attributes['ltj@origchar']
    local attr_autospc = luatexbase.attributes['ltj@autospc']
    local attr_autoxspc = luatexbase.attributes['ltj@autoxspc']
+   local ltjf_get_vert_glyph = ltjf.get_vert_glyph
    function set_np_xspc_jachar_yoko(Nx, x)
       local m = ltjf_font_metric_table[getfont(x)]
-      local cls, c = slow_find_char_class(has_attr(x, attr_orig_char), m, getchar(x))
-      Nx.met, Nx.char = m, c; Nx.class = cls;
+      local cls, c = slow_find_char_class(ltjs_orig_char_table[x], m, getchar(x))
+      Nx.met = m; Nx.class = cls
       if cls~=0 then set_attr(x, attr_jchar_class, cls) end
       Nx.pre  = table_current_stack[PRE + c]  or 0
       Nx.post = table_current_stack[POST + c] or 0
@@ -502,13 +577,12 @@ do
       Nx.auto_kspc, Nx.auto_xspc = (has_attr(x, attr_autospc)==1), (has_attr(x, attr_autoxspc)==1)
    end
    function set_np_xspc_jachar_tate(Nx, x)
-      local m = ltjf_font_metric_table[getfont(x)]
-      local cls, c
-      local c1, c2 = getchar(x), has_attr(x, attr_orig_char)
-      c = has_attr(x, attr_dir) or c1 or c2
-      cls = ltjf_find_char_class(c, m)
-      if cls==0 then cls = slow_find_char_class(c2, m, c1) end
-      Nx.met, Nx.char = m, c; Nx.class = cls;
+      local c, c_glyph = ltjs_orig_char_table[x], getchar(x)
+      local xf = getfont(x)
+      local m = ltjf_font_metric_table[xf]
+      local cls = slow_find_char_class(c, m, c_glyph)
+      setfield(x, 'char', ltjf_get_vert_glyph(xf, c_glyph) or c_glyph)
+      Nx.met = m; Nx.class = cls;
       if cls~=0 then set_attr(x, attr_jchar_class, cls) end
       Nx.pre  = table_current_stack[PRE + c]  or 0
       Nx.post = table_current_stack[POST + c] or 0
@@ -516,6 +590,16 @@ do
       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)
    end
+   function set_np_xspc_jachar_hbox(Nx, x)
+      local m = ltjf_font_metric_table[getfont(x)]
+      local c = getchar(x)
+      Nx.met = m; Nx.class = has_attr(x, attr_jchar_class) or 0;
+      Nx.pre  = table_current_stack[PRE + c]  or 0
+      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)
+   end
 
 -- 欧文文字のデータを取得
    local floor = math.floor
@@ -530,9 +614,8 @@ do
         Nx.pre  = table_current_stack[PRE + c]  or 0
         Nx.post = table_current_stack[POST + c] or 0
         Nx.xspc = table_current_stack[XSP  + c] or 3
-        Nx.char = 'jcharbdd'
       else
-        Nx.pre, Nx.post, Nx.char = 0, 0, -1
+        Nx.pre, Nx.post = 0, 0
          Nx.xspc = table_current_stack[XSP - 1] or 3
       end
       Nx.met = nil
@@ -540,26 +623,14 @@ do
    end
    local set_np_xspc_alchar = set_np_xspc_alchar
 
--- Np の情報取得メインルーチン
-   extract_np = function ()
-      local x, i = Np.nuc, Np.id;
---      if i ==  id_jglyph then return set_np_xspc_jachar(Np, x)
---      elseif i == id_glyph then return set_np_xspc_alchar(Np, getchar(x), x, 1)
---      if i == id_hlist then Np.last_char = check_box_high(Np, getlist(x), nil)
-      if i == id_pbox then Np.last_char = check_box_high(Np, Np.first, node_next(Np.last))
-      elseif i == id_disc then Np.last_char = check_box_high(Np, getfield(x, 'replace'), nil)
---      elseif i == id_math then return set_np_xspc_alchar(Np, -1, x)
-      end
-   end
-
    -- change the information for the next loop
    -- (will be done if Nx is an alphabetic character or a hlist)
    after_hlist = function (Nx)
       local s = Nx.last_char
       if s then
         if getid(s)==id_glyph then
-           if getfont(s) == (has_attr(s, attr_curjfnt) or -1) then
-              set_np_xspc_jachar(Nx, s)
+           if getfield(s, 'lang') == lang_ja then
+              set_np_xspc_jachar_hbox(Nx, s)
            else
               set_np_xspc_alchar(Nx, getchar(s), s, 2)
            end
@@ -572,7 +643,7 @@ do
    end
 
    after_alchar = function (Nx)
-      local x = Nx.nuc
+      local x = Nx.last_char
       return set_np_xspc_alchar(Nx, getchar(x), x, 2)
    end
 
@@ -762,22 +833,19 @@ do
 end
 
 local function calc_ja_ja_glue()
-   if  ihb_flag then return nil
+   local qm, pm = Nq.met, Np.met
+   if (qm.char_type==pm.char_type) and (qm.var==pm.var) then
+      return new_jfm_glue(qm, Nq.class, Np.class)
    else
-      local qm, pm = Nq.met, Np.met
-      if (qm.char_type==pm.char_type) and (qm.var==pm.var) then
-         return new_jfm_glue(qm, Nq.class, Np.class)
-      else
-         local npn, nqn = Np.nuc, Nq.nuc
-         local gb, db = new_jfm_glue(qm, Nq.class,
-                                    slow_find_char_class(has_attr(npn, attr_orig_char),
-                                                         qm, getchar(npn)))
-         local ga, da = new_jfm_glue(pm,
-                                    slow_find_char_class(has_attr(nqn, attr_orig_char),
-                                                         pm, getchar(nqn)),
-                               Np.class)
-         return calc_ja_ja_aux(gb, ga, db, da);
-      end
+      local npn, nqn = Np.nuc, Nq.nuc
+      local gb, db = new_jfm_glue(qm, Nq.class,
+                                 slow_find_char_class(ltjs_orig_char_table[npn],
+                                                      qm, getchar(npn)))
+      local ga, da = new_jfm_glue(pm,
+                                 slow_find_char_class(ltjs_orig_char_table[nqn],
+                                                      pm, getchar(nqn)),
+                                 Np.class)
+      return calc_ja_ja_aux(gb, ga, db, da);
    end
 end
 
@@ -820,36 +888,30 @@ end
 -------------------- 隣接した「塊」間の処理
 
 local function get_OA_skip()
-   if not ihb_flag then
-      local pm = Np.met
-      return new_jfm_glue(pm,
-        fast_find_char_class(((Nq.id == id_math and -1) or (type(Nq.char)=='string' and Nq.char or 'jcharbdd')), pm), Np.class)
-   else return nil
-   end
+   local pm = Np.met
+   return new_jfm_glue(pm,
+                      fast_find_char_class((Nq.id == id_math and -1 or 'jcharbdd'), pm), Np.class)
 end
 local function get_OB_skip()
-   if not ihb_flag then
-      local qm = Nq.met
-      return new_jfm_glue(qm, Nq.class,
-        fast_find_char_class(((Np.id == id_math and -1) or'jcharbdd'), qm))
-   else return nil
-   end
+   local qm = Nq.met
+   return new_jfm_glue(qm, Nq.class,
+                      fast_find_char_class((Np.id == id_math and -1 or'jcharbdd'), qm))
 end
 
 -- (anything) .. jachar
 local function handle_np_jachar(mode)
    local qid = Nq.id
    if qid==id_jglyph or ((qid==id_pbox or qid==id_pbox_w) and Nq.met) then
-      local g = calc_ja_ja_glue() or get_kanjiskip() -- M->K
+      local g = non_ihb_flag and calc_ja_ja_glue() or get_kanjiskip() -- M->K
       handle_penalty_normal(Nq.post, Np.pre, g); real_insert(g)
    elseif Nq.met then  -- qid==id_hlist
-      local g = get_OA_skip() or get_kanjiskip() -- O_A->K
+      local g = non_ihb_flag and get_OA_skip() or get_kanjiskip() -- O_A->K
       handle_penalty_normal(0, Np.pre, g); real_insert(g)
    elseif Nq.pre then
-      local g = get_OA_skip() or get_xkanjiskip(Np) -- O_A->X
+      local g = non_ihb_flag and get_OA_skip() or get_xkanjiskip(Np) -- O_A->X
       handle_penalty_normal((qid==id_hlist and 0 or Nq.post), Np.pre, g); real_insert(g)
    else
-      local g = get_OA_skip() -- O_A
+      local g = non_ihb_flag and get_OA_skip() -- O_A
       if qid==id_glue then handle_penalty_normal(0, Np.pre, g)
       elseif qid==id_kern then handle_penalty_suppress(0, Np.pre, g)
       else handle_penalty_always(0, Np.pre, g)
@@ -865,10 +927,10 @@ end
 -- jachar .. (anything)
 local function handle_nq_jachar()
     if Np.pre then
-      local g = get_OB_skip() or get_xkanjiskip(Nq) -- O_B->X
+      local g = non_ihb_flag and get_OB_skip() or get_xkanjiskip(Nq) -- O_B->X
       handle_penalty_normal(Nq.post, (Np.id==id_hlist and 0 or Np.pre), g); real_insert(g)
    else
-      local g = get_OB_skip() -- O_B
+      local g =non_ihb_flag and  get_OB_skip() -- O_B
       if Np.id==id_glue then handle_penalty_normal(Nq.post, 0, g)
       elseif Np.id==id_kern then handle_penalty_suppress(Nq.post, 0, g)
       else handle_penalty_always(Nq.post, 0, g)
@@ -881,7 +943,7 @@ end
 local function handle_np_ja_hlist()
    local qid = Nq.id
    if qid==id_jglyph or ((qid==id_pbox or Nq.id == id_pbox_w) and Nq.met) then
-      local g = get_OB_skip() or get_kanjiskip() -- O_B->K
+      local g = non_ihb_flag and get_OB_skip() or get_kanjiskip() -- O_B->K
       handle_penalty_normal(Nq.post, 0, g); real_insert(g)
    elseif Nq.met then  -- Nq.id==id_hlist
       local g = get_kanjiskip() -- K
@@ -904,10 +966,7 @@ end
 -- Nq が前側のクラスタとなることによる修正
 do
    local adjust_nq_aux = {
-      [id_glyph] = function()
-                     local x = Nq.nuc
-                     return set_np_xspc_alchar(Nq, getchar(x),x, 2)
-                  end, -- after_alchar(Nq)
+      [id_glyph] = function() after_alchar(Nq) end, -- after_alchar(Nq)
       [id_hlist]  = function() after_hlist(Nq) end,
       [id_pbox]  = function() after_hlist(Nq) end,
       [id_disc]  = function() after_hlist(Nq) end,
@@ -956,7 +1015,7 @@ end
 local function handle_list_head(par_indented)
    local npi, pm = Np.id, Np.met
    if npi ==  id_jglyph or (npi==id_pbox and pm) then
-      if noihb_flag then
+      if non_ihb_flag then
         local g = new_jfm_glue(pm, fast_find_char_class(par_indented, pm), Np.class)
         if g then
            set_attr(g, attr_icflag, BOXBDD)
@@ -1060,13 +1119,12 @@ function main(ahead, mode, dir)
    local lp, last, par_indented = init_var(mode,dir)
    lp = calc_np(lp, last)
    if Np then
-      extract_np(); handle_list_head(par_indented)
+      handle_list_head(par_indented)
    else
       return cleanup(mode)
    end
    lp = calc_np(lp, last)
    while Np do
-      extract_np();
       adjust_nq();
       local pid, pm = Np.id, Np.met
       -- 挿入部