From 72dd4273df6e03d84f45bb73e10c827d5742e0bd Mon Sep 17 00:00:00 2001 From: Hironori Kitagawa Date: Fri, 16 May 2014 11:22:45 +0900 Subject: [PATCH] Changed use of DIR whatsit. * attr_dir: direction of box * value: node list of "dir_node". --- src/ltj-debug.lua | 3 +- src/ltj-direction.lua | 305 ++++++++++++++++++++++++++++---------------------- src/ltj-jfmglue.lua | 19 ++-- src/ltj-plain.sty | 4 +- src/ltj-pretreat.lua | 16 +-- src/ltj-setwidth.lua | 4 +- src/luatexja-core.sty | 12 +- src/luatexja.lua | 29 +++-- test/test51-vtest.pdf | Bin 94164 -> 114447 bytes test/test51-vtest.tex | 105 ++++++++++++++++- 10 files changed, 320 insertions(+), 177 deletions(-) diff --git a/src/ltj-debug.lua b/src/ltj-debug.lua index 5125d55..c9704c1 100644 --- a/src/ltj-debug.lua +++ b/src/ltj-debug.lua @@ -88,6 +88,7 @@ ltjdbg.pformat = pformat -------------------- 所要時間合計 require("socket") do + local max = math.max local gettime = socket.gettime local time_stat = {} local function start_time_measure(n) @@ -100,7 +101,7 @@ do end local function stop_time_measure(n) local t = time_stat[n] - t[2] = t[2] + gettime() + t[2] = max(t[2] + gettime(), 0) end local function print_measure() diff --git a/src/ltj-direction.lua b/src/ltj-direction.lua index b8b4076..042470a 100644 --- a/src/ltj-direction.lua +++ b/src/ltj-direction.lua @@ -28,6 +28,7 @@ local node_tail = Dnode.tail local node_free = Dnode.free local node_remove = Dnode.remove local node_next = (Dnode ~= node) and Dnode.getnext or node.next +local traverse = Dnode.traverse local traverse_id = Dnode.traverse_id local start_time_measure, stop_time_measure = ltjb.start_time_measure, ltjb.stop_time_measure @@ -44,11 +45,10 @@ local sid_user = node.subtype('user_defined') local PROCESSED = luatexja.icflag_table.PROCESSED local PROCESSED_BEGIN_FLAG = luatexja.icflag_table.PROCESSED_BEGIN_FLAG local PACKED = luatexja.icflag_table.PACKED -local DIR = luatexja.stack_table_index.DIR local STCK = luatexja.userid_table.STCK -local wh_DIR = luatexja.userid_table.DIR -local dir_tate = 3 -local dir_yoko = 4 +local DIR = luatexja.userid_table.DIR +local dir_tate = luatexja.dir_table.dir_tate +local dir_yoko = luatexja.dir_table.dir_yoko local get_dir_count @@ -66,16 +66,18 @@ do 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==wh_DIR then - w.value = v + 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')==wh_DIR then - setfield(w, 'value', v) - else + and getfield(w, 'user_id')==DIR then + set_attr(w, attr_dir, v) + tex.setattribute('global', attr_dir, 0) + else ltjb.package_error( 'luatexja', "Use `\\" .. name .. "' at top of list", @@ -85,75 +87,81 @@ do else local w = node_new(id_whatsit, sid_user) setfield(w, 'next', hd) - setfield(w, 'user_id', wh_DIR) - setfield(w, 'type', 100) - setfield(w, 'value', v) + setfield(w, 'user_id', DIR) + setfield(w, 'type', 110) + set_attr(w, attr_dir, v) Dnode.write(w) + tex.setattribute('global', attr_dir, 0) end + tex.setattribute('global', attr_icflag, 0) end end luatexja.direction.set_list_direction = set_list_direction end -- ボックスに dir whatsit を追加 +local function create_dir_whatsit(hd, gc, new_dir) + 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, new_dir) + tex.setattribute('global', attr_dir, 0) + set_attr(w, attr_icflag, PROCESSED_BEGIN_FLAG) + set_attr(hd, attr_icflag, (has_attr(hd, attr_icflag) or 0) + PROCESSED_BEGIN_FLAG) + tex.setattribute('global', attr_icflag, 0) + return w +end + do local tex_getcount = tex.getcount - local function set_dir_flag(h, gc) + local function create_dir_whatsit_hpack(h, gc) + local hd = to_direct(h) if gc=='fin_row' or gc == 'preamble' then - local hd = to_direct(h) if hd then set_attr(hd, attr_icflag, PROCESSED_BEGIN_FLAG) tex.setattribute('global', attr_icflag, 0) end return h else - local hd = to_direct(h) - if hd and getid(hd)==id_whatsit and getsubtype(hd)==sid_user - and getfield(hd, 'user_id')==wh_DIR then - set_attr(hd, attr_icflag, PROCESSED_BEGIN_FLAG) - tex.setattribute('global', attr_icflag, 0) - hd = node_next(hd) - if hd then - set_attr(hd, attr_icflag, (has_attr(hd, attr_icflag) or 0) + PROCESSED_BEGIN_FLAG) - tex.setattribute('global', attr_icflag, 0) - end - return h - else - local w = node_new(id_whatsit, sid_user) - setfield(w, 'next', hd) - setfield(w, 'user_id', wh_DIR) - setfield(w, 'type', 100) - setfield(w, 'value', ltjs.list_dir) - set_attr(w, attr_icflag, PROCESSED_BEGIN_FLAG) - set_attr(hd, attr_icflag, (has_attr(hd, attr_icflag) or 0) + PROCESSED_BEGIN_FLAG) - tex.setattribute('global', attr_icflag, 0) - return to_node(w) - end + return to_node(create_dir_whatsit(hd, gc, ltjs.list_dir)) end end - luatexbase.add_to_callback('hpack_filter', set_dir_flag, 'ltj.set_dir_flag', 10000) - local function set_dir_flag_vbox(h, gc) - local w = to_direct(h) + + luatexbase.add_to_callback('hpack_filter', + create_dir_whatsit_hpack, 'ltj.create_dir_whatsit', 10000) + + local function create_dir_whatsit_vbox(h, gc) + local hd= to_direct(h) ltjs.list_dir = get_dir_count() - if getid(w)==id_whatsit and getsubtype(w)==sid_user - and getfield(w, 'user_id')==wh_DIR then - ltjs.list_dir = getfield(w, 'value') + 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 + if hd then + set_attr(hd, attr_icflag, PROCESSED_BEGIN_FLAG) + tex.setattribute('global', attr_icflag, 0) + end + return h else - return set_dir_flag(h, gc) + return to_node(create_dir_whatsit(hd, gc, ltjs.list_dir)) end end - luatexbase.add_to_callback('vpack_filter', set_dir_flag_vbox, 'ltj.set_dir_flag', 1) + luatexbase.add_to_callback('vpack_filter', + create_dir_whatsit_vbox, 'ltj.create_dir_whatsit', 1) + + local function create_dir_whatsit_parbox(h, gc) + stop_time_measure('tex_linebreak') + -- start 側は ltj-debug.lua に + local new_dir, hd = ltjs.list_dir, to_direct(h) + for line in traverse_id(id_hlist, hd) do + set_attr(line, attr_dir, new_dir) + end + return to_node(create_dir_whatsit(hd, gc, new_dir)) + end luatexbase.add_to_callback('post_linebreak_filter', - function (h, gc) - stop_time_measure('tex_linebreak') - -- start 側は ltj-debug.lua に - local new_dir = ltjs.list_dir - for line in traverse_id(id_hlist, to_direct(h)) do - set_attr(line, attr_dir, new_dir) - end - return set_dir_flag(h, gc) - end, 'ltj.set_dir_flag', 100) + create_dir_whatsit_parbox, 'ltj.create_dir_whatsit', 10000) end @@ -170,67 +178,95 @@ do local get_w_neg =function (w,h,d) return -w end local get_w =function (w,h,d) return w end dir_node_aux = { - [dir_yoko] = { -- yoko を tate 中で組む - width = get_h_d, - height = get_w_half, - depth = get_w_half, - [id_hlist] = { - { 'kern', get_h }, - { 'whatsit', sid_save }, - { 'rotate', '0 1 -1 0' }, - { 'kern', get_w_neg_half }, - { 'box' }, - { 'kern', get_w_neg_half }, - { 'whatsit', sid_restore }, - }, - [id_vlist] = { - { 'kern', get_w}, - { 'whatsit', sid_save }, - { 'rotate', '0 1 -1 0' }, - { 'box' }, - { 'kern', get_h_neg}, - { 'whatsit', sid_restore }, + [dir_yoko] = { -- yoko を + [dir_tate] = { -- tate 中で組む + width = get_h_d, + height = get_w_half, + depth = get_w_half, + [id_hlist] = { + { 'kern', get_h }, + { 'whatsit', sid_save }, + { 'rotate', '0 1 -1 0' }, + { 'kern', get_w_neg_half }, + { 'box' }, + { 'kern', get_w_neg_half }, + { 'whatsit', sid_restore }, + }, + [id_vlist] = { + { 'kern', get_w}, + { 'whatsit', sid_save }, + { 'rotate', '0 1 -1 0' }, + { 'box' }, + { 'kern', get_h_neg}, + { 'whatsit', sid_restore }, + }, }, }, - [dir_tate] = { -- tate を yoko 中で組む - width = get_h_d, - height = get_w, - depth = function() return 0 end, - [id_hlist] = { - { 'kern', get_d }, - { 'whatsit', sid_save }, - { 'rotate', '0 -1 1 0' }, - { 'kern', get_w_neg }, - { 'box' }, - { 'whatsit', sid_restore }, - }, - [id_vlist] = { - { 'whatsit', sid_save }, - { 'rotate', '0 -1 1 0' }, - { 'kern', get_h_neg }, - { 'kern', get_d_neg }, - { 'box' }, - { 'whatsit', sid_restore }, + [dir_tate] = { -- tate を + [dir_yoko] = { -- yoko 中で組む + width = get_h_d, + height = get_w, + depth = function() return 0 end, + [id_hlist] = { + { 'kern', get_d }, + { 'whatsit', sid_save }, + { 'rotate', '0 -1 1 0' }, + { 'kern', get_w_neg }, + { 'box' }, + { 'whatsit', sid_restore }, + }, + [id_vlist] = { + { 'whatsit', sid_save }, + { 'rotate', '0 -1 1 0' }, + { 'kern', get_h_neg }, + { 'kern', get_d_neg }, + { 'box' }, + { 'whatsit', sid_restore }, + }, }, }, } end -local function clean_dir_whatsit(b) +local function get_box_dir(b, default) + -- b に DIR whatsit があればその内容を attr_dir にうつす (1st ret val) + local dir = has_attr(b, attr_dir) or 0 local bh = getlist(b) - local dir = has_attr(b, attr_dir) - for x in traverse_id(id_whatsit, bh) do - if getsubtype(x)==sid_user and getfield(x, 'user_id')==wh_DIR then - local nh = node_remove(bh, x) - setfield(b, 'head', nh) - dir = getfield(bh, 'value') + 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) - node_free(x); break + tex.setattribute('global', attr_dir, 0) end end - return dir + return (dir==0 and default or dir), c end -luatexja.direction.clean_dir_whatsit = clean_dir_whatsit + +local function unwrap_dir_node(b, head) + -- head: nil or nil-nil + -- if head is non-nil, return values are (new head), (next of b), (contents) + local bh = getlist(b) + local bc = node_next(node_next(node_next(node_next(bh)))) + local nh, nb + node_remove(bh, bc); + if head then + nh = insert_before(head, b, bc) + nh, nb = node_remove(nh, b) + end + setfield(b, 'list', nil); Dnode.flush_list(bh) + local d, wh = get_box_dir(bc, 0) + if not wh then + wh = create_dir_whatsit(getlist(bc), 'unwrap', d) + end + local h = getfield(wh, 'value') + if h then setfield(b, 'next', h) end + setfield(wh, 'value', to_node(b)) + return nh, nb, bc +end + -- \wd, \ht, \dp の代わり do @@ -240,12 +276,22 @@ do local s = getbox(n) if s then s = to_direct(s) - local s_dir, l_dir = clean_dir_whatsit(s), get_dir_count() + local s_dir, wh = get_box_dir(s, dir_yoko) + local l_dir = get_dir_count() if s_dir ~= l_dir then - local w = getfield(s, 'width') - local h = getfield(s, 'height') - local d = getfield(s, 'depth') - tex.setdimen('ltj@tempdima', dir_node_aux[s_dir][key](w,h,d)) + local not_found = true + for x in traverse(getfield(wh, 'value')) do + if l_dir == -has_attr(x, attr_dir) then + tex.setdimen('ltj@tempdima', getfield(x, key)) + not_found = false; break + end + end + if not_found then + local w = getfield(s, 'width') + local h = getfield(s, 'height') + local d = getfield(s, 'depth') + tex.setdimen('ltj@tempdima', dir_node_aux[s_dir][l_dir][key](w,h,d)) + end else tex.setdimen('ltj@tempdima', getfield(s, key)) end @@ -260,49 +306,40 @@ do local s = getbox(n) if s then s = to_direct(s) - local s_dir, l_dir = clean_dir_whatsit(s), get_dir_count() + local s_dir, wh = get_box_dir(s, dir_yoko) + local l_dir = get_dir_count() if s_dir ~= l_dir then print('setting ' .. key .. ' of different direction box is not supported') + -- TODO else setfield(s, key, tex.getdimen('ltj@tempdima')) end end end + luatexja.direction.set_box_dim = set_box_dim end -local make_dir_node +local make_dir_whatsit do - make_dir_node = function (head, b, new_dir, origin) + make_dir_whatsit = function (head, b, new_dir, origin) -- head: list head, b: box -- origin: コール元 (for debug) -- return value: (new head), (next of b), (new b), (is_b_dir_node) -- (new b): b か dir_node に被せられた b - local old_dir = has_attr(b, attr_dir) or 0 + local box_dir = has_attr(b, attr_dir) or 0 local bh = getlist(b) - if old_dir ==0 then - if getsubtype(bh)==sid_user and getfield(bh, 'user_id')==wh_DIR then - old_dir = getfield(bh, 'value') - set_attr(b, attr_dir, old_dir) - local nh = node_remove(bh, bh) - setfield(b, 'head', nh) - end - if old_dir ==0 then old_dir = ltjs.list_dir end - end - if old_dir==new_dir then + local box_dir, dn = get_box_dir(b, ltjs.list_dir) + -- 既に b の中身にあるwhatsit + if box_dir==new_dir then return head, node_next(b), b, false - elseif -old_dir == new_dir then + elseif -box_dir == new_dir then return head, node_next(b), b, true else local nh, nb, ret, flag - if old_dir < 0 then + if box_dir < 0 then -- b itself is a dir node; just unwrap - local bc = node_next(node_next( - node_next(node_next(bh)))) - node_remove(bh, bc); - nh, nb = insert_before(head, b, bc), nil - nh, nb = node_remove(head, b) - setfield(b, 'next', nil); Dnode.flush_list(b) - ret, flag = bc, false + nh, nb, ret = unwrap_dir_node(b,head) + flag = false else local bid = getid(b) local db = node_new(bid) -- dir node @@ -311,7 +348,7 @@ do local w = getfield(b, 'width') local h = getfield(b, 'height') local d = getfield(b, 'depth') - local info = dir_node_aux[old_dir] + local info = dir_node_aux[box_dir][new_dir] set_attr(db, attr_dir, -new_dir) set_attr(b, attr_icflag, PROCESSED) set_attr(db, attr_icflag, PROCESSED) @@ -355,7 +392,7 @@ do local xid = getid(x) if (xid==id_hlist and has_attr(x, attr_icflag)%PROCESSED_BEGIN_FLAG~=PACKED) or xid==id_vlist then - h, x = make_dir_node(h, x, new_dir, 'process_dir_node:' .. gc) + h, x = make_dir_whatsit(h, x, new_dir, 'process_dir_node:' .. gc) else x = node_next(x) end @@ -363,9 +400,9 @@ do stop_time_measure('direction_vpack') return to_node(h) end - luatexja.direction.make_dir_node = make_dir_node + luatexja.direction.make_dir_whatsit = make_dir_whatsit luatexbase.add_to_callback('vpack_filter', - process_dir_node, 'ltj.dir_node', 10001) + process_dir_node, 'ltj.dir_whatsit', 10001) end -- 縦書き用字形への変換テーブル diff --git a/src/ltj-jfmglue.lua b/src/ltj-jfmglue.lua index bca2b79..ea78b52 100644 --- a/src/ltj-jfmglue.lua +++ b/src/ltj-jfmglue.lua @@ -35,7 +35,7 @@ local insert_before = Dnode.insert_before local insert_after = Dnode.insert_after local node_next = (Dnode ~= node) and Dnode.getnext or node.next local round = tex.round -local ltjd_make_dir_node = ltjd.make_dir_node +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 = Dnode.new @@ -45,9 +45,6 @@ local node_tail = Dnode.tail local node_free = Dnode.free local node_end_of_math = Dnode.end_of_math -local dir_tate = 3 -local dir_yoko = 4 - local id_glyph = node.id('glyph') local id_hlist = node.id('hlist') local id_vlist = node.id('vlist') @@ -303,7 +300,12 @@ local function calc_np_pbox(lp, last) local lpa, nc = KINSOKU, nil set_attr(lp, attr_icflag, get_attr_icflag(lp)); while lp ~=last and (lpa>=PACKED) and (lpa= 1 then @@ -445,18 +449,19 @@ local function debug_show_node_X(p,print_fn) end print_fn(s) elseif pt == 'whatsit' then - s = base -- .. '(' .. node.whatsits()[p.subtype] .. ') ' + s = base if p.subtype==sid_user then + local t = tostring(p.user_id) .. ' (' .. + luatexbase.get_user_whatsit_name(p.user_id) .. ') ' if p.type ~= 110 then - s = s .. ' userid: ' .. p.user_id .. ' ' .. p.value + s = s .. ' userid:' .. t .. p.value print_fn(s) else - s = s .. ' userid: ' .. p.user_id .. ' (node list)' + s = s .. ' userid:' .. t .. '(node list)' print_fn(s) - local q = p.value debug_depth=debug_depth.. '.' - while q do - debug_show_node_X(q, print_fn); q = node_next(q) + for q in node.traverse(p.value) do + debug_show_node_X(q, print_fn) end debug_depth=k end diff --git a/test/test51-vtest.pdf b/test/test51-vtest.pdf index c956354817b229fcd28e8af0faf53cef19dd5a22..d92a08e6ffce26dd5076968c0e7f8e3ed68bc234 100644 GIT binary patch delta 62380 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