From a693b63eadfcabe5f4f513a4cc90302f2360b18b Mon Sep 17 00:00:00 2001 From: Hironori Kitagawa Date: Sat, 1 Feb 2014 22:10:21 +0900 Subject: [PATCH] Added luatexja.node_remove and luatexja.Dnode_remove ("safe node.remove") --- src/ltj-adjust.lua | 95 +++++++++++++++++++++++++++------------------------ src/ltj-jfmglue.lua | 9 +++-- src/ltj-jfont.lua | 16 +++++---- src/ltj-otf.lua | 2 +- src/ltj-pretreat.lua | 2 +- src/ltj-setwidth.lua | 14 +++----- src/luatexja-core.sty | 6 ++-- src/luatexja.lua | 38 +++++++++++++++++++++ 8 files changed, 114 insertions(+), 68 deletions(-) diff --git a/src/ltj-adjust.lua b/src/ltj-adjust.lua index efa8072..09125a1 100644 --- a/src/ltj-adjust.lua +++ b/src/ltj-adjust.lua @@ -3,7 +3,7 @@ -- luatexbase.provides_module({ name = 'luatexja.adjust', - date = '2014/01/26', + date = '2014/02/01', description = 'Advanced line adjustment for LuaTeX-ja', }) module('luatexja.adjust', package.seeall) @@ -49,7 +49,7 @@ local attr_curjfnt = luatexbase.attributes['ltj@curjfnt'] local ltjf_font_metric_table = ltjf.font_metric_table local spec_zero_glue = ltjj.spec_zero_glue -local round = tex.round +local round, pairs = tex.round, pairs local PACKED = luatexja.icflag_table.PACKED local FROM_JFM = luatexja.icflag_table.FROM_JFM @@ -57,7 +57,6 @@ local KANJI_SKIP = luatexja.icflag_table.KANJI_SKIP local KANJI_SKIP_JFM = luatexja.icflag_table.KANJI_SKIP_JFM local XKANJI_SKIP = luatexja.icflag_table.XKANJI_SKIP local XKANJI_SKIP_JFM = luatexja.icflag_table.XKANJI_SKIP_JFM -local PROCESSED_BEGIN_FLAG = luatexja.icflag_table.PROCESSED_BEGIN_FLAG local priority_table = { FROM_JFM + 2, @@ -69,8 +68,12 @@ local priority_table = { KANJI_SKIP } -local function get_attr_icflag(p) - return (has_attr(p, attr_icflag) or 0) % PROCESSED_BEGIN_FLAG +local get_attr_icflag +do + local PROCESSED_BEGIN_FLAG = luatexja.icflag_table.PROCESSED_BEGIN_FLAG + get_attr_icflag = function(p) + return (has_attr(p, attr_icflag) or 0) % PROCESSED_BEGIN_FLAG + end end -- box 内で伸縮された glue の合計値を計算 @@ -90,37 +93,43 @@ local function get_stretched(q, go, gs) end local res = {} -local function get_total_stretched(p) +local gs_used_line = {} +local function get_total_stretched(p, line) local go, gf, gs = getfield(p, 'glue_order'), getfield(p, 'glue_set'), getfield(p, 'glue_sign') + if go ~= 0 then return nil end res[0], res.glue_set, res.name = 0, gf, (gs==1) and 'stretch' or 'shrink' for i=1,#priority_table do res[priority_table[i]]=0 end - if go ~= 0 then return nil end - if gs ~= 1 and gs ~= 2 then return res end + if gs ~= 1 and gs ~= 2 then return res, 0 end + local total = 0 for q in node_traverse_id(id_glue, getlist(p)) do local a, ic = get_stretched(q, go, gs), get_attr_icflag(q) if type(res[ic]) == 'number' then -- kanjiskip, xkanjiskip は段落内で spec を共有しているが, -- それはここでは望ましくないので,各 glue ごとに異なる spec を使う. - -- (この仮定でメモリリークを起こしている!) + -- 本当は各行ごとに glue_spec を共有させたかったが,安直にやると + -- ref_count が 0 なので Double-free が発生する.どうする? -- JFM グルーはそれぞれ異なる glue_spec を用いているので,問題ない. if (ic == KANJI_SKIP or ic == XKANJI_SKIP) and getsubtype(q)==0 then local qs = getfield(q, 'spec') if qs ~= spec_zero_glue then - local f = node_new(id_glue) - setfield(f, 'spec', qs) - setfield(q, 'spec', node_copy(qs)) - node_free(f) + if (gs_used_line[qs] or 0) 0 then - --print (ic, before, after) local ratio = after/before for i,_ in pairs(set_stretch_table) do set_stretch_table[i] = nil @@ -171,6 +179,11 @@ local function aw_step1(p, res, total) -- その前の node が本来の末尾文字となる x = node_prev(node_prev(x)) end + -- local xi = getid(x) + -- while (get_attr_icflag(x) == PACKED) + -- and ((xi == id_penalty) or (xi == id_kern) or (xi == id_kern)) do + -- x = node_prev(x); xi = getid(x) + -- end local xi, xc = getid(x) if xi == id_glyph and has_attr(x, attr_curjfnt) == getfont(x) then -- 和文文字 @@ -213,33 +226,28 @@ local function aw_step2(p, res, total, added_flag) for _,v in pairs(priority_table) do clear_stretch(p, v, res.name) end local f = node_hpack(getlist(p), getfield(p, 'width'), 'exactly') setfield(f, 'head', nil) - setfield(p, 'glue_set', getfield(f, 'glue_set')) - setfield(p, 'glue_order', getfield(f, 'glue_order')) - setfield(p, 'glue_sign', getfield(f, 'glue_sign')) + setfield(p, 'glue_set', getfield(f, 'glue_set')) + setfield(p, 'glue_order', getfield(f, 'glue_order')) + setfield(p, 'glue_sign', getfield(f, 'glue_sign')) node_free(f) else - local orig_total, avail = total, res[0] - total, i = total - res[0], 1 - while i <= #priority_table do + total = total - res[0] + for i = 1, #priority_table do local v = priority_table[i] if total <= res[v] then for j = i+1,#priority_table do clear_stretch(p, priority_table[j], res.name) end - set_stretch(p, total, res[v], v, res.name) - avail = avail + total - i = #priority_table + 9 -- ループから抜けさせたいため + set_stretch(p, total, res[v], v, res.name); break end - total, i, avail = total - res[v], i+1, avail + res[v] - end - if i == #priority_table + 10 or added_flag then - local f = node_hpack(getlist(p), getfield(p, 'width'), 'exactly') - setfield(f, 'head', nil) - setfield(p, 'glue_set', getfield(f, 'glue_set')) - setfield(p, 'glue_order', getfield(f, 'glue_order')) - setfield(p, 'glue_sign', getfield(f, 'glue_sign')) - node_free(f) + total = total - res[v] end + local f = node_hpack(getlist(p), getfield(p, 'width'), 'exactly') + setfield(f, 'head', nil) + setfield(p, 'glue_set', getfield(f, 'glue_set')) + setfield(p, 'glue_order', getfield(f, 'glue_order')) + setfield(p, 'glue_sign', getfield(f, 'glue_sign')) + node_free(f) end end @@ -247,20 +255,19 @@ end local ltjs_fast_get_stack_skip = ltjs.fast_get_stack_skip local function adjust_width(head) if not head then return head end + local line = 1 for p in node_traverse_id(id_hlist, to_direct(head)) do - local res = get_total_stretched(p) + line = line + 1 + local res, total = get_total_stretched(p, line) -- this is the same table as the table which is def'd in l. 92 - if res then - -- 調整量の合計 - local total = 0 - for i,v in pairs(res) do - if type(i)=='number' then - total = total + v - end - end; total = round(total * res.glue_set) + if res and res.glue_set<1 then + total = round(total * res.glue_set) aw_step2(p, res, total, aw_step1(p, res, total)) end end + for i,_ in pairs(gs_used_line) do + gs_used_line[i] = nil + end return to_node(head) end diff --git a/src/ltj-jfmglue.lua b/src/ltj-jfmglue.lua index d78c971..8946027 100644 --- a/src/ltj-jfmglue.lua +++ b/src/ltj-jfmglue.lua @@ -3,7 +3,7 @@ -- luatexbase.provides_module({ name = 'luatexja.jfmglue', - date = '2014/1/21', + date = '2014/02/01', description = 'Insertion process of JFM glues and kanjiskip', }) module('luatexja.jfmglue', package.seeall) @@ -37,7 +37,7 @@ local ltjf_font_metric_table = ltjf.font_metric_table local ltjf_find_char_class = ltjf.find_char_class local node_new = Dnode.new local node_copy = Dnode.copy -local node_remove = Dnode.remove +local node_remove = luatexja.Dnode_remove -- Dnode.remove local node_tail = Dnode.tail local node_free = Dnode.free local node_end_of_math = Dnode.end_of_math @@ -189,7 +189,9 @@ local function check_box(box_ptr, box_end) pid = getid(p) -- p must be non-nil end if pid==id_kern then - if get_attr_icflag(p)==IC_PROCESSED then + local pa = get_attr_icflag(p) + --if pa==IC_PROCESSED or pa == PACKED then + if pa==IC_PROCESSED then -- do nothing elseif getsubtype(p)==2 then p = node_next(node_next(p)); @@ -216,6 +218,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 -- do nothing elseif not (pid==id_ins or pid==id_mark or pid==id_adjust or pid==id_whatsit or pid==id_penalty) then diff --git a/src/ltj-jfont.lua b/src/ltj-jfont.lua index d58f4de..7e10815 100644 --- a/src/ltj-jfont.lua +++ b/src/ltj-jfont.lua @@ -3,7 +3,7 @@ -- luatexbase.provides_module({ name = 'luatexja.jfont', - date = '2014/01/23', + date = '2014/02/01', description = 'Loader for Japanese fonts', }) module('luatexja.jfont', package.seeall) @@ -158,6 +158,8 @@ do t.chars = metrics[j].chars t.char_type = mult_table(metrics[j].char_type, sz) for i,v in pairs(t.char_type) do + v.align = (v.align=='left') and 0 or + ((v.align=='right') and 1 or 0.5) if type(i) == 'number' then -- char_type for k,w in pairs(v.glue) do local h = node_new(id_glue_spec) @@ -268,15 +270,14 @@ do end do --- EXT: zw, zh - function load_zw() + -- PUBLIC function + function get_zw() local a = font_metric_table[tex.attribute[attr_curjfnt]] - tex.setdimen('ltj@zw', a and a.zw or 0) + return a and a.zw or 0 end - - function load_zh() + function get_zh() local a = font_metric_table[tex.attribute[attr_curjfnt]] - tex.setdimen('ltj@zh', a and a.zh or 0) + return a and a.zw or 0 end end @@ -320,6 +321,7 @@ end -- LATEX INTERFACE ------------------------------------------------------------------------ do + -- these function are called from ltj-latex.sty local kyenc_list, ktenc_list = {}, {} function add_kyenc_list(enc) kyenc_list[enc] = 'true ' end function add_ktenc_list(enc) ktenc_list[enc] = 'true ' end diff --git a/src/ltj-otf.lua b/src/ltj-otf.lua index 4de28c1..0904854 100644 --- a/src/ltj-otf.lua +++ b/src/ltj-otf.lua @@ -28,7 +28,7 @@ local to_node = (Dnode ~= node) and Dnode.tonode or nullfunc local to_direct = (Dnode ~= node) and Dnode.todirect or nullfunc local node_new = Dnode.new -local node_remove = Dnode.remove +local node_remove = luatexja.Dnode_remove -- Dnode.remove local node_next = Dnode.getnext local node_free = Dnode.free local has_attr = Dnode.has_attribute diff --git a/src/ltj-pretreat.lua b/src/ltj-pretreat.lua index b641ce3..387fcc8 100644 --- a/src/ltj-pretreat.lua +++ b/src/ltj-pretreat.lua @@ -24,7 +24,7 @@ local floor = math.floor local has_attr = Dnode.has_attribute local set_attr = Dnode.set_attribute local node_traverse = Dnode.traverse -local node_remove = Dnode.remove +local node_remove =luatexja.Dnode_remove -- Dnode.remove local node_next = Dnode.getnext local node_free = Dnode.free local node_end_of_math = Dnode.end_of_math diff --git a/src/ltj-setwidth.lua b/src/ltj-setwidth.lua index 7e264ad..ebd7393 100644 --- a/src/ltj-setwidth.lua +++ b/src/ltj-setwidth.lua @@ -6,7 +6,6 @@ luatexja.load_module('base'); local ltjb = luatexja.base luatexja.load_module('jfont'); local ltjf = luatexja.jfont local Dnode = node.direct or node - 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 getid = (Dnode ~= node) and Dnode.getid or function(n) return n.id end @@ -17,7 +16,7 @@ local getsubtype = (Dnode ~= node) and Dnode.getsubtype or function(n) return n. local node_traverse = Dnode.traverse local node_new = Dnode.new -local node_remove = Dnode.remove +local node_remove = luatexja.Dnode_remove -- Dnode.remove local node_tail = Dnode.tail local node_next = Dnode.getnext local has_attr = Dnode.has_attribute @@ -77,16 +76,13 @@ local function capsule_glyph(p, met, class) fshift = call_callback("luatexja.set_width", fshift, met, class) local fheight, fdepth = char_data.height, char_data.depth if (pwidth ~= fwidth or getfield(p, 'height') ~= fheight or getfield(p, 'depth') ~= fdepth) then - local y_shift, ca - = - getfield(p, 'yoffset') + (has_attr(p,attr_ykblshift) or 0), char_data.align + local y_shift + = - getfield(p, 'yoffset') + (has_attr(p,attr_ykblshift) or 0) local q head, q = node_remove(head, p) setfield(p, 'yoffset', -fshift.down); setfield(p, 'next', nil) - ca = (ca~='left') - and -fshift.left + (((ca=='right') and fwidth-pwidth) or round((fwidth-pwidth)*0.5)) - or -fshift.left - setfield(p, 'xoffset', getfield(p, 'xoffset') + ca) - local box = node_new(id_hlist); + setfield(p, 'xoffset', getfield(p, 'xoffset') + char_data.align*(fwidth-pwidth)) + local box = node_new(id_hlist) setfield(box, 'width', fwidth) setfield(box, 'height', fheight) setfield(box, 'depth', fdepth) diff --git a/src/luatexja-core.sty b/src/luatexja-core.sty index 46a4dcd..db94c78 100644 --- a/src/luatexja-core.sty +++ b/src/luatexja-core.sty @@ -65,7 +65,7 @@ \expandafter\let\csname ifltj@in@latex\expandafter\endcsname \csname iftrue\endcsname \NeedsTeXFormat{LaTeX2e} - \ProvidesPackage{luatexja-core}[2014/01/24 Core of LuaTeX-ja] + \ProvidesPackage{luatexja-core}[2014/02/01 Core of LuaTeX-ja] \fi % %% Load prerequisite packages. @@ -200,8 +200,8 @@ \def\ltj@@jfont{\directlua{luatexja.jfont.jfontdefY()}} %%%%%%%% \zw, \zh -\protected\def\zw{\directlua{luatexja.jfont.load_zw()}\ltj@zw} -\protected\def\zh{\directlua{luatexja.jfont.load_zh()}\ltj@zh} +\protected\def\zw{\directlua{tex.setdimen('ltj@zw', luatexja.jfont.get_zw())}\ltj@zw} +\protected\def\zh{\directlua{tex.setdimen('ltj@zh', luatexja.jfont.get_zh())}\ltj@zh} %%%%%%%% \inhibitglue \protected\def\ltj@reset@globaldefs{% diff --git a/src/luatexja.lua b/src/luatexja.lua index b205460..d935235 100644 --- a/src/luatexja.lua +++ b/src/luatexja.lua @@ -57,6 +57,44 @@ userid_table.IHB = luatexbase.newuserwhatsitid('inhibitglue', 'luatexja') -- \ userid_table.STCK = luatexbase.newuserwhatsitid('stack_marker', 'luatexja') -- スタック管理 userid_table.BPAR = luatexbase.newuserwhatsitid('begin_par', 'luatexja') -- 「段落始め」 +do + local node_remove, node_next, node_prev = node.remove, node.next, node.prev + function luatexja.node_remove (head, current) + if head==current then + local q, r = node_next(current), node_prev(current) + current.next = nil + if q then q.prev = r end + if r and node_next(r)==current then + -- r is "real prev" + r.next = q + end + return q, node_next(q) + else + return node_remove(head, current) + end + end + + local Dnode = node.direct or node + local Dnode_remove, Dnode_next, Dnode_prev = Dnode.remove, Dnode.getnext, Dnode.getprev + local getfield = (Dnode ~= node) and Dnode.getfield or function(n, i) return n[i] end + local setfield = (Dnode ~= node) and Dnode.setfield or function(n, i, c) n[i] = c end + function luatexja.Dnode_remove (head, current) + if head==current then + local q, r = Dnode_next(current), Dnode_prev(current) + setfield(current, 'next', nil) + if q then setfield(q, 'prev', r) end + if r and Dnode_next(r) == current then + -- r is "real prev" + setfield(r, 'next', q) + end + return q, Dnode_next(q) + else + return Dnode_remove(head, current) + end + end + +end + --- 定義終わり local load_module = luatexja.load_module -- 2.11.0