X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=src%2Fltj-jfmglue.lua;h=ef05a671686e642c88e09be9292193557f128f6a;hb=d177010c46e52e722b4752eded1ae4a6807953df;hp=490d3e7a0e1b88e81dc3c4f7b1908ecf9db20c8b;hpb=0e8b59d4e986bb2c1e1af9746d649389325db9a1;p=luatex-ja%2Fluatexja.git diff --git a/src/ltj-jfmglue.lua b/src/ltj-jfmglue.lua index 490d3e7..ef05a67 100644 --- a/src/ltj-jfmglue.lua +++ b/src/ltj-jfmglue.lua @@ -3,7 +3,7 @@ -- luatexbase.provides_module({ name = 'luatexja.jfmglue', - date = '2016/04/03', + date = '2017/05/05', description = 'Insertion process of JFM glues and kanjiskip', }) module('luatexja.jfmglue', package.seeall) @@ -28,22 +28,28 @@ local getfont = node.direct.getfont local getlist = node.direct.getlist local getchar = node.direct.getchar local getsubtype = node.direct.getsubtype - +local if_lang_ja +do + local lang_ja = luatexja.lang_ja + local getlang = node.direct.getlang + if_lang_ja = getlang + and function (n) return getlang(n)==lang_ja end + or function (n) return getfield(n,'lang')==lang_ja end +end + local has_attr = node.direct.has_attribute local set_attr = node.direct.set_attribute local insert_before = node.direct.insert_before local insert_after = node.direct.insert_after local node_next = node.direct.getnext -local round = tex.round 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_copy = node.direct.copy -local node_remove = node.direct.remove local node_tail = node.direct.tail local node_free = node.direct.free -local node_end_of_math = node.direct.end_of_math +local node_remove = node.direct.remove local id_glyph = node.id('glyph') local id_hlist = node.id('hlist') @@ -64,12 +70,6 @@ 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 = luatexja.lang_ja - -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 = luatexja.icflag_table.ITALIC local PACKED = luatexja.icflag_table.PACKED @@ -122,25 +122,29 @@ end local function skip_table_to_glue(n) local g, st = node_new(id_glue), ltjs.fast_get_stack_skip(n) setglue(g, st.width, st.stretch, st.shrink, st.stretch_order, st.shrink_order) - -- luatexja.ext_show_node(to_node(g), 'sg ',print) return g, (st.width==1073741823) end -- penalty 値の計算 -local function add_penalty(p,e) - local pp = getfield(p, 'penalty') - if pp>=10000 then - if e<=-10000 then setfield(p, 'penalty', 0) end - elseif pp<=-10000 then - if e>=10000 then setfield(p, 'penalty', 0) end - else - pp = pp + e - if pp>=10000 then setfield(p, 'penalty', 10000) - elseif pp<=-10000 then setfield(p, 'penalty', -10000) - else setfield(p, 'penalty', pp) end +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 + if e>=10000 then setpenalty(p, 10000) + elseif e<=-10000 then setpenalty(p, -10000) + else + pp = pp + e + if pp>=10000 then setpenalty(p, 10000) + elseif pp<=-10000 then setpenalty(p, -10000) + else setpenalty(p, pp) end + end end end +end -- 「異なる JFM」の間の調整方法 diffmet_rule = math.two_paverage @@ -208,6 +212,7 @@ local function check_box(box_ptr, box_end) if getfield(p, 'shift')==0 then last_char = nil if check_box(getlist(p), nil) then found_visible_node = true end + find_first_char = false else find_first_char = false; last_char = nil end @@ -236,7 +241,7 @@ 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 getfield(first_char, 'lang') == lang_ja then + if if_lang_ja(first_char) then set_np_xspc_jachar_hbox(Nx, first_char) else set_np_xspc_alchar(Nx, getchar(first_char),first_char, 1) @@ -267,12 +272,12 @@ do local traverse = node.direct.traverse local function check_next_ickern(lp) - if lp and getid(lp) == id_kern and ( getsubtype(lp)==3 or ITALIC == get_attr_icflag(lp)) then - set_attr(lp, attr_icflag, IC_PROCESSED); - Np.last = lp; return node_next(lp) - else - Np.last = Np.nuc; return lp + local lx = Np.nuc + while lp and getid(lp) == id_kern and ( getsubtype(lp)==3 or ITALIC == get_attr_icflag(lp)) do + set_attr(lp, attr_icflag, IC_PROCESSED); + lx, lp = lp, node_next(lp) end + Np.last = lx; return lp end local function calc_np_pbox(lp, last) @@ -302,10 +307,10 @@ 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) +local function calc_np_aux_glyph_common(lp, acc_flag) Np.nuc = lp Np.first= (Np.first or lp) - if getfield(lp, 'lang') == lang_ja then + if if_lang_ja(lp) then Np.id = id_jglyph local m, mc, cls = set_np_xspc_jachar(Np, lp) local npi, npf @@ -330,7 +335,7 @@ local function calc_np_aux_glyph_common(lp) lp=lx; break else local lid = getid(lx) - if lid==id_glyph and getfield(lx, 'lang') ~= lang_ja then + 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 @@ -380,7 +385,7 @@ local function calc_np_aux_glyph_common(lp) node_free(r) elseif (ct.left_protruding or 0) == 0 then head = insert_before(head, npn, r) - Np.first = (Np.first==npn) and r or npn + Np.first = acc_flag and Np.first or ((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 @@ -396,7 +401,15 @@ local function calc_np_aux_glyph_common(lp) return true, lp end end -local calc_np_auxtable = { +local calc_np_auxtable +do +local node_end_of_math = node.direct.end_of_math +local dir_tate = luatexja.dir_table.dir_tate +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') +calc_np_auxtable = { [id_glyph] = calc_np_aux_glyph_common, [id_hlist] = function(lp) local op, flag @@ -423,10 +436,6 @@ local calc_np_auxtable = { Np.id = id_box_like; return true, node_next(lp) end, - skip = function(lp) - set_attr(lp, attr_icflag, PROCESSED) - return false, node_next(lp) - end, [id_whatsit] = function(lp) local lps = getsubtype(lp) if lps==sid_user then @@ -490,7 +499,7 @@ local calc_np_auxtable = { set_attr(lp, attr_icflag, PROCESSED); lp = node_next(lp) set_attr(lp, attr_icflag, PROCESSED); lp = node_next(lp) set_attr(lp, attr_icflag, PROCESSED); - return calc_np_aux_glyph_common(lp) + return calc_np_aux_glyph_common(lp, true) else Np.first = Np.first or lp Np.id = id_kern; set_attr(lp, attr_icflag, PROCESSED) @@ -502,13 +511,13 @@ local calc_np_auxtable = { return false, node_next(lp) end, } +end calc_np_auxtable[id_rule] = calc_np_auxtable.box_like calc_np_auxtable[15] = 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 -if node.id('local_par') then - calc_np_auxtable[node.id('local_par')] = calc_np_auxtable.skip + +local function calc_np_aux_skip (lp) + set_attr(lp, attr_icflag, PROCESSED) + return false, node_next(lp) end function calc_np(last, lp) @@ -534,7 +543,7 @@ function calc_np(last, lp) return calc_np_pbox(lp, last) end -- id_pbox else - k, lp = calc_np_auxtable[getid(lp)](lp) + k, lp = (calc_np_auxtable[getid(lp)] or calc_np_aux_skip)(lp) if k then return lp end end end @@ -560,16 +569,17 @@ do local attr_jchar_code = luatexbase.attributes['ltj@charcode'] local attr_autospc = luatexbase.attributes['ltj@autospc'] local attr_autoxspc = luatexbase.attributes['ltj@autoxspc'] + local getcomponents = node.direct.getcomponents --local ltjf_get_vert_glyph = ltjf.get_vert_glyph function set_np_xspc_jachar(Nx, x) local m = ltjf_font_metric_table[getfont(x)] - local c, c_glyph = ltjs_orig_char_table[x], getchar(x) + local c, c_glyph = (not getcomponents(x) and ltjs_orig_char_table[x]), getchar(x) + if c and c~=c_glyph then set_attr(x, attr_jchar_code, c) end c = c or c_glyph local cls = slow_find_char_class(c, m, c_glyph) Nx.met, Nx.class, Nx.char = m, cls, c; local mc = m.char_type; Nx.char_type = mc if cls~=0 then set_attr(x, attr_jchar_class, cls) end - if c~=c_glyph then set_attr(x, attr_jchar_code, c) end 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 @@ -594,19 +604,18 @@ do function set_np_xspc_alchar(Nx, c,x, lig) if c~=-1 then local f = (lig ==1) and nullfunc or node_tail - local xc, xs = getfield(x, 'components'), getsubtype(x) + local xc, xs = getcomponents(x), getsubtype(x) while xc and xs and xs%4>=2 do - x = f(xc); xc, xs = getfield(x, 'components'), getsubtype(x) + x = f(xc); xc, xs = getcomponents(x), getsubtype(x) end c = getchar(x) 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 else Nx.pre, Nx.post = 0, 0 - Nx.xspc = table_current_stack[XSP - 1] or 3 end Nx.met = nil + Nx.xspc = table_current_stack[XSP + c] or 3 Nx.auto_xspc = (has_attr(x, attr_autoxspc)==1) end local set_np_xspc_alchar = set_np_xspc_alchar @@ -617,7 +626,7 @@ do local s = Nx.last_char if s then if getid(s)==id_glyph then - if getfield(s, 'lang') == lang_ja then + if if_lang_ja(s) then set_np_xspc_jachar_hbox(Nx, s) else set_np_xspc_alchar(Nx, getchar(s), s, 2) @@ -639,8 +648,11 @@ end -------------------- 最下層の処理 +luatexbase.create_callback('luatexja.adjust_jfmglue', 'simple', nullfunc) + -- change penalties (or create a new penalty, if needed) local function handle_penalty_normal(post, pre, g) + luatexbase.call_callback('luatexja.adjust_jfmglue', head, Nq, Np, Bp) local a = (pre or 0) + (post or 0) if #Bp == 0 then if (a~=0 and not(g and getid(g)==id_kern)) then @@ -656,6 +668,7 @@ local function handle_penalty_normal(post, pre, g) end local function handle_penalty_always(post, pre, g) + luatexbase.call_callback('luatexja.adjust_jfmglue', head, Nq, Np, Bp) local a = (pre or 0) + (post or 0) if #Bp == 0 then if not (g and getid(g)==id_glue) or a~=0 then @@ -671,7 +684,7 @@ local function handle_penalty_always(post, pre, g) end local function handle_penalty_suppress(post, pre, g) - local a = (pre or 0) + (post or 0) + 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) @@ -679,7 +692,24 @@ local function handle_penalty_suppress(post, pre, g) Bp[1]=p set_attr(p, attr_icflag, KINSOKU) end - else for _, v in pairs(Bp) do add_penalty(v,a) end + else + local a = (pre or 0) + (post or 0) + for _, v in pairs(Bp) do add_penalty(v,a) end + end +end + +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) + 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) + widow_Bp[1]=p; + set_attr(p, attr_icflag, KINSOKU) + end + else for _, v in pairs(widow_Bp) do add_penalty(v,a) end end end @@ -712,6 +742,7 @@ end -------------------- 和文文字間空白量の決定 local calc_ja_ja_aux do + local round = tex.round local bg_ag = 2*id_glue - id_glue local bg_ak = 2*id_glue - id_kern local bk_ag = 2*id_kern - id_glue @@ -727,10 +758,10 @@ do end if not gb then if ga then - gb = node_new(id_kern); setfield(gb, 'kern', 0) + gb = node_new(id_kern, 1); setfield(gb, 'kern', 0) else return nil end elseif not ga then - ga = node_new(id_kern); setfield(ga, 'kern', 0) + ga = node_new(id_kern, 1); setfield(ga, 'kern', 0) end local k = 2*getid(gb) - getid(ga) @@ -808,7 +839,9 @@ do end get_kanjiskip = function() - if Np.auto_kspc or Nq.auto_kspc then + if Np.auto_kspc==0 or Nq.auto_kspc==0 then + return nil + elseif Np.auto_kspc or Nq.auto_kspc then local pm, qm = Np.met, Nq.met if (pm.char_type==qm.char_type) and (qm.var==pm.var) then return get_kanjiskip_low(true, qm, 1, 1, 1) @@ -817,7 +850,7 @@ do local ga = get_kanjiskip_low(true, pm, 1, 1, 1) return calc_ja_ja_aux(gb, ga, 0, 1) end - else + else local g = node_new(id_glue) set_attr(g, attr_icflag, kanjiskip_jfm_flag and KANJI_SKIP_JFM or KANJI_SKIP) return g @@ -888,7 +921,9 @@ do end get_xkanjiskip = function(Nn) - if (Nq.xspc>=2) and (Np.xspc%2==1) and (Nq.auto_xspc or Np.auto_xspc) then + if Np.auto_xspc==0 or Nq.auto_xspc==0 then + return nil + elseif (Nq.xspc>=2) and (Np.xspc%2==1) and (Nq.auto_xspc or Np.auto_xspc) then return get_xkanjiskip_low(true, Nn.met, 1, 1, 1) else local g = node_new(id_glue) @@ -900,18 +935,44 @@ end -------------------- 隣接した「塊」間の処理 +local function combine_spc(name) + return (Np[name] or Nq[name]) and ((Np[name]~=0) and (Nq[name]~=0)) +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) + 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) + return g, k +end + local function get_OA_skip(is_kanji) 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 'jcharbdd'), pm), + fast_find_char_class( + (((Nq.id==id_glue)or(Nq.id==id_kern)) and 'glue' or 'jcharbdd'), pm), Np.class) local k if is_kanji==0 then - k = (Np.auto_kspc or Nq.auto_kspc) and get_kanjiskip_low(false, pm, kn, kp, kh) - elseif is_kanji==1 then - k = ((Nq.xspc>=2) and (Np.xspc%2==1) and (Nq.auto_xspc or Np.auto_xspc)) - and get_xkanjiskip_low(false, pm, kn, kp, kh) + k = combine_spc('auto_kspc') and get_kanjiskip_low(false, pm, kn, kp, kh) end return g, k end @@ -919,13 +980,11 @@ local function get_OB_skip(is_kanji) 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'jcharbdd'), qm)) + fast_find_char_class( + (((Np.id==id_glue)or(Np.id==id_kern)) and 'glue' or 'jcharbdd'), qm)) local k if is_kanji==0 then - k = (Np.auto_kspc or Nq.auto_kspc) and get_kanjiskip_low(false, qm, kn, kp, kh) - elseif is_kanji==1 then - k = ((Nq.xspc>=2) and (Np.xspc%2==1) and (Nq.auto_xspc or Np.auto_xspc)) - and get_xkanjiskip_low(false, qm, kn, kp, kh) + k = combine_spc('auto_kspc') and get_kanjiskip_low(false, qm, kn, kp, kh) end return g, k end @@ -946,7 +1005,7 @@ local function handle_np_jachar(mode) 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_OA_skip(1) end -- O_A->X + 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) @@ -967,7 +1026,7 @@ end -- jachar .. (anything) local function handle_nq_jachar() if Np.pre then - local g = non_ihb_flag and get_OB_skip(1) or get_xkanjiskip(Nq) -- O_B->X + 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) else local g =non_ihb_flag and (get_OB_skip()) -- O_B @@ -982,7 +1041,7 @@ end -- (anything) .. (和文文字で始まる hlist) 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 + if qid==id_jglyph or ((qid==id_pbox or qid == id_pbox_w) and Nq.met) then local g = non_ihb_flag and get_OB_skip(0) or get_kanjiskip() -- O_B->K handle_penalty_normal(Nq.post, 0, g); real_insert(g) elseif Nq.met then -- Nq.id==id_hlist @@ -1025,19 +1084,16 @@ end -------------------- 開始・終了時の処理 do - +local node_prev = node.direct.getprev -- リスト末尾の処理 -local JWP = luatexja.stack_table_index.JWP -local function handle_list_tail(mode) - adjust_nq(); Np = Nq +local function handle_list_tail(mode, last) + adjust_nq() if mode then -- the current list is to be line-breaked. -- Insert \jcharwidowpenalty - Bp = widow_Bp; Np = widow_Np - if Np.first then - handle_penalty_normal(0, table_current_stack[JWP] or 0) - end + if widow_Np.first then handle_penalty_jwp() end else + Np=Nq -- the current list is the contents of a hbox local npi, pm = Np.id, Np.met if npi == id_jglyph or (npi==id_pbox and pm) then @@ -1137,6 +1193,7 @@ 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); @@ -1158,6 +1215,8 @@ end -- main interface function main(ahead, mode, dir) if not ahead then return ahead end + --luatexja.ext_show_node_list(to_node(ahead ), '>B ', print) + --print() head = ahead; local lp, last, par_indented, TEMP = init_var(mode,dir) lp = calc_np(last, lp) @@ -1179,8 +1238,10 @@ function main(ahead, mode, dir) end lp = calc_np(last,lp) end - handle_list_tail(mode) + handle_list_tail(mode, last) end + --luatexja.ext_show_node_list(to_node(ahead ), '>A ', print) + --print() return cleanup(mode, TEMP) end end @@ -1188,6 +1249,7 @@ end do local IHB = luatexja.userid_table.IHB local BPAR = luatexja.userid_table.BPAR + local BOXB = luatexja.userid_table.BOXB local node_prev = node.direct.getprev local node_write = node.direct.write @@ -1210,11 +1272,32 @@ do node_write(tn) end + -- Node for indicating a head/end of a box + function create_boxbdd_node() + local tn = node_new(id_whatsit, sid_user) + setfield(tn, 'user_id', BOXB) + setfield(tn, 'type', 100) + setfield(tn, 'value', 1) + node_write(tn) + end + local function whatsit_callback(Np, lp, Nq) if Np and Np.nuc then return Np elseif Np and getfield(lp, 'user_id') == BPAR then Np.first = lp; Np.nuc = lp; Np.last = lp return Np + elseif Np and getfield(lp, 'user_id') == BOXB then + Np.first = lp; Np.nuc = lp; Np.last = lp + if Nq then + if Nq.met then + Np.class = fast_find_char_class('boxbdd', Nq.met) + end + Np.met = Nq.met; Np.pre = 0; Np.post = 0; Np.xspc = 0 + Np.auto_xspc, Np.auto_kspc = 0, 0 + end + return Np + else + return Np end end @@ -1227,7 +1310,19 @@ do Nq.class = fast_find_char_class('parbdd', Np.met) end Nq.met = Np.met; Nq.pre = 0; Nq.post = 0; Nq.xspc = 0 - Nq.auto_xspc = false + Nq.auto_xspc, Nq.auto_kspc = 0, 0 + end + head = 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 + Nq.first, Nq.nuc, Nq.last = x, x, x + if Np then + if Np.met then + Nq.class = fast_find_char_class('boxbdd', Np.met) + end + 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) node_free(y)