X-Git-Url: http://git.osdn.net/view?a=blobdiff_plain;f=src%2Fltj-direction.lua;h=7dd0dee906166e447dfea73f70852d9900f29f26;hb=35abc8d5257bf4a8dd76354b821b22fb8fb5e135;hp=fb3c5419045f5a92a153fa53be10e87f4ec62c81;hpb=77736c93df2de8812680c8839f6ad22305022854;p=luatex-ja%2Fluatexja.git diff --git a/src/ltj-direction.lua b/src/ltj-direction.lua index fb3c541..7dd0dee 100644 --- a/src/ltj-direction.lua +++ b/src/ltj-direction.lua @@ -10,26 +10,24 @@ local attr_dir = luatexbase.attributes['ltj@dir'] local attr_icflag = luatexbase.attributes['ltj@icflag'] local cat_lp = luatexbase.catcodetables['latex-package'] -local Dnode = node.direct or node -local nullfunc = function (n) return n end -local to_node = (Dnode ~= node) and Dnode.tonode or nullfunc -local to_direct = (Dnode ~= node) and Dnode.todirect or nullfunc -local has_attr = Dnode.has_attribute -local set_attr = Dnode.set_attribute -local insert_before = Dnode.insert_before -local insert_after = Dnode.insert_after -local getid = (Dnode ~= node) and Dnode.getid or function(n) return n.id end -local getsubtype = (Dnode ~= node) and Dnode.getsubtype or function(n) return n.subtype end -local getlist = (Dnode ~= node) and Dnode.getlist or function(n) return n.head end -local setfield = (Dnode ~= node) and Dnode.setfield or function(n, i, c) n[i] = c end -local getfield = (Dnode ~= node) and Dnode.getfield or function(n, i) return n[i] end -local node_new = Dnode.new -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 to_node = node.direct.tonode +local to_direct = node.direct.todirect +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 getid = node.direct.getid +local getsubtype = node.direct.getsubtype +local getlist = node.direct.getlist +local setfield = node.direct.setfield +local getfield = node.direct.getfield +local node_new = node.direct.new +local node_tail = node.direct.tail +local node_free = node.direct.free +local node_remove = node.direct.remove +local node_next = node.direct.getnext +local traverse = node.direct.traverse +local traverse_id = node.direct.traverse_id local start_time_measure, stop_time_measure = ltjb.start_time_measure, ltjb.stop_time_measure local abs = math.abs @@ -45,7 +43,7 @@ local sid_user = node.subtype('user_defined') local tex_nest = tex.nest local tex_getcount = tex.getcount -local tex_set_attr = tex.setattribute +local ensure_tex_attr = ltjb.ensure_tex_attr local PROCESSED = luatexja.icflag_table.PROCESSED local PROCESSED_BEGIN_FLAG = luatexja.icflag_table.PROCESSED_BEGIN_FLAG local PACKED = luatexja.icflag_table.PACKED @@ -63,6 +61,21 @@ end local page_direction -- +local dir_pool +do + local node_copy = node.direct.copy + dir_pool = {} + for _,i in pairs({dir_tate, dir_yoko, dir_dtou, dir_utod}) do + local w = node_new(id_whatsit, sid_user) + set_attr(w, attr_dir, i) + setfield(w, 'user_id', DIR) + setfield(w, 'type', 110) + setfield(w, 'next', nil) + dir_pool[i] = function () return node_copy(w) end + end +end + +-- local function adjust_badness(hd) if not node_next(hd) and getid(hd)==id_whatsit and getsubtype(hd)==sid_user and getfield(hd, 'user_id')==DIR then @@ -93,14 +106,14 @@ do end end function get_dir_count() - for i=tex_nest.ptr, 1, -1 do - local h = tex_nest[i].head.next - if h then - local t = get_dir_count_inner(h) - if t~=0 then return t end - end - end - return page_direction + for i=tex_nest.ptr, 1, -1 do + local h = tex_nest[i].head.next + if h then + local t = get_dir_count_inner(h) + if t~=0 then return t end + end + end + return page_direction end function get_adjust_dir_count() for i=tex_nest.ptr, 1, -1 do @@ -125,6 +138,8 @@ do local node_traverse = node.traverse local STCK = luatexja.userid_table.STCK local IHB = luatexja.userid_table.IHB + local id_local = node.id('local_par') + local id_dir = node.id('dir') local function test_list(h, lv) if not h then @@ -134,27 +149,48 @@ do local w for p in node_traverse(h) do if p.id==id_whatsit then - if p.subtype==sid_user then + local ps = p.subtype + if ps==sid_user then local uid= p.user_id if uid==DIR then flag = 1; w = w or p -- found elseif not(uid==IHB or uid==STCK) then flag = 0; break -- error end - else - flag = 0; break end - else + elseif p.id~=id_local and p.id~=id_dir then flag = 0; break end end - if flag==1 then -- move dir_whatsit w - return 1,w -- TODO + if flag==1 then -- dir_whatsit already exists + return 1,w else return flag end end end + local node_next_node, node_tail_node = node.next, node.tail + local insert_after_node = node.insert_after + function luatexja.direction.set_list_direction_hook(v) + local lv = tex_nest.ptr -- must be >= 1 + if not v then + v = get_dir_count() + if abs(tex_nest[lv-1].mode) == ltjs.mmode and v == dir_tate then + v = dir_utod + end + elseif v=='adj' then + v = get_adjust_dir_count() + end + local h = tex_nest[lv].head + local hn = node.next(h) + hn = (hn and hn.id==id_local) and hn or h + local w = to_node(dir_pool[v]()) + insert_after_node(h, hn, w) + tex_nest[lv].tail = node_tail_node(w) + ensure_tex_attr(attr_icflag, 0) + ensure_tex_attr(attr_dir, 0) + end + local function set_list_direction(v, name) local lv = tex_nest.ptr if not v then @@ -165,19 +201,29 @@ do elseif v=='adj' then v,name = get_adjust_dir_count(), nil end + local current_nest = tex_nest[lv] if tex.currentgrouptype==6 then ltjb.package_error( 'luatexja', "You can't use `\\" .. name .. "' in an align", - "To change direction in an align, \n" - .. "you shold use \\hbox or \\vbox.") + "To change the direction in an align, \n" + .. "you shold use \\hbox or \\vbox.") + elseif current_nest.mode == ltjs.hmode or abs(current_nest.mode) == ltjs.mmode then + ltjb.package_error( + 'luatexja', + "Improper `\\" .. name .. "'", + 'You cannot change the direction in unrestricted horizontal mode \n' + .. 'nor math modes.') else - local h = (lv==0) and tex.lists.page_head or tex_nest[lv].head.next + local h = (lv==0) and tex.lists.page_head or current_nest.head.next local flag,w = test_list(h,lv) if flag==0 then if lv==0 and not page_direction then page_direction = v -- for first call of \yoko (in luatexja-core.sty) else + if luatexja.debug then + luatexja.ext_show_node_list(node.direct.tonode(h),'>> ', texio.write_nl) + end ltjb.package_error( 'luatexja', "Use `\\" .. tostring(name) .. "' at top of list", @@ -187,18 +233,19 @@ do elseif flag==1 then node_set_attr(w, attr_dir, v) if lv==0 then page_direction = v end - else - local w = node_new(id_whatsit, sid_user) - setfield(w, 'next', nil) - setfield(w, 'user_id', DIR) - setfield(w, 'type', 110) - set_attr(w, attr_dir, v) - Dnode.write(w) - if lv==0 then page_direction = v end + elseif lv==0 then + page_direction = v + else -- flag == 2: need to create dir whatsit. + local h = current_nest.head + local hn = node.next(h) + hn = (hn and hn.id==id_local) and hn or h + local w = to_node(dir_pool[v]()) + insert_after_node(h,hn,w) + current_nest.tail = node_tail_node(w) end - tex_set_attr('global', attr_icflag, 0) + ensure_tex_attr(attr_icflag, 0) end - tex_set_attr('global', attr_dir, 0) + ensure_tex_attr(attr_dir, 0) end luatexja.direction.set_list_direction = set_list_direction end @@ -209,59 +256,65 @@ local function create_dir_whatsit(hd, gc, new_dir) getsubtype(hd)==sid_user and getfield(hd, 'user_id')==DIR then set_attr(hd, attr_icflag, get_attr_icflag(hd) + PROCESSED_BEGIN_FLAG) - tex_set_attr('global', attr_icflag, 0) + local n =node_next(hd) + if n then + set_attr(n, attr_icflag, + get_attr_icflag(n) + PROCESSED_BEGIN_FLAG) + end + ensure_tex_attr(attr_icflag, 0) return hd else - local w = node_new(id_whatsit, sid_user) + local w = dir_pool[new_dir]() setfield(w, 'next', hd) - setfield(w, 'user_id', DIR) - setfield(w, 'type', 110) - set_attr(w, attr_dir, new_dir) set_attr(w, attr_icflag, PROCESSED_BEGIN_FLAG) set_attr(hd, attr_icflag, - (has_attr(hd, attr_icflag) or 0)%PROCESSED_BEGIN_FLAG - + PROCESSED_BEGIN_FLAG) - tex_set_attr('global', attr_dir, 0) - tex_set_attr('global', attr_icflag, 0) + get_attr_icflag(hd) + PROCESSED_BEGIN_FLAG) + ensure_tex_attr(attr_icflag, 0) + ensure_tex_attr(attr_dir, 0) return w end end -- hpack_filter, vpack_filter, post_line_break_filter -- の結果を組方向を明示するため,先頭に dir_node を設置 +local get_box_dir do local function create_dir_whatsit_hpack(h, gc) local hd = to_direct(h) - if gc=='fin_row' or gc == 'preamble' then + if gc=='fin_row' then if hd then + for p in traverse_id(15, hd) do -- unset + if get_box_dir(p, 0)==0 then + setfield(p, 'head', create_dir_whatsit(getlist(p), 'fin_row', ltjs.list_dir)) + end + end set_attr(hd, attr_icflag, PROCESSED_BEGIN_FLAG) - tex_set_attr('global', attr_icflag, 0) + ensure_tex_attr(attr_icflag, 0) end return h + elseif gc == 'preamble' then else adjust_badness(hd) return to_node(create_dir_whatsit(hd, gc, ltjs.list_dir)) end end - luatexbase.add_to_callback('hpack_filter', + ltjb.add_to_callback('hpack_filter', create_dir_whatsit_hpack, 'ltj.create_dir_whatsit', 10000) end do local function create_dir_whatsit_parbox(h, gc) - stop_time_measure('tex_linebreak') + 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 - local nh = getlist(line) - setfield(line, 'head', create_dir_whatsit(nh, gc, new_dir) ) - set_attr(line, attr_dir, new_dir) + local new_dir = ltjs.list_dir + for line in traverse_id(id_hlist, to_direct(h)) do + setfield(line, 'head', create_dir_whatsit(getlist(line), gc, new_dir) ) end - tex_set_attr('global', attr_dir, 0) + ensure_tex_attr(attr_dir, 0) return h end - luatexbase.add_to_callback('post_linebreak_filter', + ltjb.add_to_callback('post_linebreak_filter', create_dir_whatsit_parbox, 'ltj.create_dir_whatsit', 10000) end @@ -290,7 +343,7 @@ do if gc=='fin_row' then -- gc == 'preamble' case is treated in dir_adjust_vpack if hd then set_attr(hd, attr_icflag, PROCESSED_BEGIN_FLAG) - tex_set_attr('global', attr_icflag, 0) + ensure_tex_attr(attr_icflag, 0) end return hd else @@ -455,20 +508,28 @@ end -- 1st ret val: b の組方向 -- 2nd ret val はその DIR whatsit -local function get_box_dir(b, default) +function get_box_dir(b, default) start_time_measure('get_box_dir') local dir = has_attr(b, attr_dir) or 0 local bh = getfield(b,'head') -- b は insert node となりうるので getlist() は使えない local c - for i=1,2 do - if bh and getid(bh)==id_whatsit - and getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then - c = bh - dir = (dir==0) and has_attr(bh, attr_dir) or dir + if bh~=0 then -- bh != nil + for bh in traverse_id(id_whatsit, bh) do + if getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then + c = bh + dir = (dir==0) and has_attr(bh, attr_dir) or dir + end end - bh = node_next(bh) end + -- for i=1,2 do + -- if bh and getid(bh)==id_whatsit + -- and getsubtype(bh)==sid_user and getfield(bh, 'user_id')==DIR then + -- c = bh + -- dir = (dir==0) and has_attr(bh, attr_dir) or dir + -- end + -- bh = node_next(bh) + -- end stop_time_measure('get_box_dir') return (dir==0 and default or dir), c end @@ -480,7 +541,7 @@ do start_time_measure('box_primitive_hook') local list_dir = get_dir_count()%dir_math_mod local b = getbox(tex_getcount('ltj@tempcnta')) - if b then + if b and getlist(to_direct(b)) then local box_dir = get_box_dir(to_direct(b), dir_yoko) if box_dir%dir_math_mod ~= list_dir then ltjb.package_error( @@ -544,7 +605,7 @@ local function unwrap_dir_node(b, head, box_dir) end local shift_old, b_dir, wh = nil, get_box_dir(bh, 0) if wh then - Dnode.flush_list(getfield(wh, 'value')) + node.direct.flush_list(getfield(wh, 'value')) setfield(wh, 'value', nil) end return nh, nb, bh, b_dir @@ -561,8 +622,8 @@ local function create_dir_node(b, b_dir, new_dir, is_manual) new_dir + (is_manual and dir_node_manual or dir_node_auto)) set_attr(db, attr_icflag, PROCESSED) set_attr(b, attr_icflag, PROCESSED) - tex_set_attr('global', attr_dir, 0) - tex_set_attr('global', attr_icflag, 0) + ensure_tex_attr(attr_dir, 0) + ensure_tex_attr(attr_icflag, 0) setfield(db, 'dir', getfield(b, 'dir')) setfield(db, 'shift', 0) setfield(db, 'width', info.width(w,h,d)) @@ -583,13 +644,16 @@ do local bh = getlist(b) local box_dir, dn = get_box_dir(b, ltjs.list_dir) -- 既に b の中身にあるwhatsit - + if (box_dir=dir_node_auto then -- dir_node としてカプセル化されている local _, dnc = get_box_dir(b, 0) if dnc then -- free all other dir_node - Dnode.flush_list(getfield(dnc, 'value')) + node.direct.flush_list(getfield(dnc, 'value')) setfield(dnc, 'value', nil) end set_attr(b, attr_dir, box_dir%dir_math_mod + dir_node_auto) @@ -619,7 +683,8 @@ do db=x; break end end - Dnode.flush_list(getfield(dn, 'value')) + node.direct.flush_list(getfield(dn, 'value')) + setfield(dn, 'value', nil) db = db or create_dir_node(b, box_dir, new_dir, false) local w = getfield(b, 'width') local h = getfield(b, 'height') @@ -649,7 +714,8 @@ do end -- lastbox - local node_prev = (Dnode~=node) and Dnode.getprev or node.prev + local node_prev = (node.direct~=node) and node.direct.getprev or node.prev + local id_glue = node.id('glue') local function lastbox_hook() start_time_measure('box_primitive_hook') local bn = tex_nest[tex_nest.ptr].tail @@ -657,6 +723,14 @@ do local b, head = to_direct(bn), to_direct(tex_nest[tex_nest.ptr].head) local bid = getid(b) if bid==id_hlist or bid==id_vlist then + local p = getlist(b) + -- alignment の各行の中身が入ったボックス + if p and getid(p)==id_glue and getsubtype(p)==12 then -- tabskip + local np = node_next(p); local npid = getid(np) + if npid==id_hlist or npid==id_vlist then + setfield(b, 'head', create_dir_whatsit(p, 'align', get_box_dir(np, 0))) + end + end local box_dir = get_box_dir(b, 0) if box_dir>= dir_node_auto then -- unwrap dir_node local p = node_prev(b) @@ -667,7 +741,7 @@ do end local _, wh = get_box_dir(b, 0) -- clean dir_node attached to the box if wh then - Dnode.flush_list(getfield('value', wh)) + node.direct.flush_list(getfield('value', wh)) setfield(wh, 'value', nil) end end @@ -722,11 +796,14 @@ do else setdimen('ltj@tempdima', 0) end + tex.sprint(cat_lp, '\\ltj@tempdima') tex.globaldefs = gt end luatexja.direction.get_box_dim = get_box_dim -- return value: (changed dimen of box itself?) + local scan_dimen, scan_int = token.scan_dimen, token.scan_int + local scan_keyword = token.scan_keyword local function set_box_dim_common(key, s, l_dir) local s_dir, wh = get_box_dir(s, dir_yoko) s_dir = s_dir%dir_math_mod @@ -747,10 +824,10 @@ do setfield(db, 'next', dnh) setfield(wh, 'value',to_node(db)) end - setfield(db, key, tex.getdimen('ltj@tempdima')) + setfield(db, key, scan_dimen()) return false else - setfield(s, key, tex.getdimen('ltj@tempdima')) + setfield(s, key, scan_dimen()) if wh then -- change dimension of dir_nodes which are created "automatically" local bw, bh, bd @@ -769,8 +846,7 @@ do end end local function set_box_dim(key) - local n = tex_getcount('ltj@tempcnta') - local s = getbox(n) + local s = getbox(scan_int()); scan_keyword('=') if s then local l_dir = (get_dir_count())%dir_math_mod s = to_direct(s) @@ -779,7 +855,7 @@ do set_box_dim_common(key, s, l_dir) elseif b_dir%dir_math_mod == l_dir then -- s is dir_node - setfield(s, key, tex.getdimen('ltj@tempdima')) + setfield(s, key, scan_dimen()) if b_dirlua_mem_kb+20480 then + -- collectgarbage(); lua_mem_kb = collectgarbage('count') + --end + --print('Lua Memory Usage', lua_mem_kb) end end