luatexja.load_module('jfont'); local ltjf = luatexja.jfont
luatexja.load_module('jfmglue'); local ltjj = luatexja.jfmglue
+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 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 getlist = (Dnode ~= node) and Dnode.getlist or function(n) return n.head end
+local getid = (Dnode ~= node) and Dnode.getid or function(n) return n.id end
+local getfont = (Dnode ~= node) and Dnode.getfont or function(n) return n.font end
+local getsubtype = (Dnode ~= node) and Dnode.getsubtype or function(n) return n.subtype end
+
+local node_traverse_id = Dnode.traverse_id
+local node_new = Dnode.new
+local node_copy = Dnode.copy
+local node_hpack = Dnode.hpack
+local node_next = Dnode.getnext
+local node_free = Dnode.free
+local node_prev = Dnode.getprev
+local node_tail = Dnode.tail
+local has_attr = Dnode.has_attribute
+local set_attr = Dnode.set_attribute
+local insert_after = Dnode.insert_after
+
local id_glyph = node.id('glyph')
local id_kern = node.id('kern')
local id_hlist = node.id('hlist')
local id_glue = node.id('glue')
local id_glue_spec = node.id('glue_spec')
local id_whatsit = node.id('whatsit')
-local has_attr = node.has_attribute
-local set_attr = node.set_attribute
local attr_icflag = luatexbase.attributes['ltj@icflag']
local attr_jchar_class = luatexbase.attributes['ltj@charclass']
local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
-local node_copy = node.copy
-local node_next = node.next
-local node_free = node.free
local ltjf_font_metric_table = ltjf.font_metric_table
local spec_zero_glue = ltjj.spec_zero_glue
+local round = tex.round
local PACKED = luatexja.icflag_table.PACKED
local FROM_JFM = luatexja.icflag_table.FROM_JFM
local PROCESSED_BEGIN_FLAG = 32
local function get_attr_icflag(p)
- return (node.has_attribute(p, attr_icflag) or 0) % PROCESSED_BEGIN_FLAG
+ return (has_attr(p, attr_icflag) or 0) % PROCESSED_BEGIN_FLAG
end
-- box 内で伸縮された glue の合計値を計算
local function get_stretched(q, go, gs)
- local qs = q.spec
- if not qs.writable then return 0 end
+ local qs = getfield(q, 'spec')
+ if not getfield(qs, 'writable') then return 0 end
if gs == 1 then -- stretching
- if qs.stretch_order == go then return qs.stretch end
+ if getfield(qs, 'stretch_order') == go then
+ return getfield(qs, 'stretch')
+ end
else -- shrinking
- if qs.shrink_order == go then return qs.shrink end
+ if getfield(qs, 'shrink_order') == go then
+ return getfield(qs, 'shrink')
+ end
end
end
-- local new_ks, new_xs
local function get_total_stretched(p)
- local go, gf, gs = p.glue_order, p.glue_set, p.glue_sign
+ local go, gf, gs
+ = getfield(p, 'glue_order'), getfield(p, 'glue_set'), getfield(p, 'glue_sign')
local res = {
[0] = 0,
glue_set = gf, name = (gs==1) and 'stretch' or 'shrink'
}
+ local old_spec
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
- local head = p.head
- q = p.head
- --luatexja.ext_show_node_list(p.head, '>>> ', print)
- while q do
- if q.id==id_glue then
- local a, ic = get_stretched(q, go, gs), get_attr_icflag(q)
- if type(res[ic]) == 'number' then
- -- kanjiskip, xkanjiskip は段落内で spec を共有しているが,
- -- それはここでは望ましくないので,各 glue ごとに異なる spec を使う.
- -- JFM グルーはそれぞれ異なる glue_spec を用いているので,問題ない.
- res[ic] = res[ic] + a
- if ic == KANJI_SKIP or ic == XKANJI_SKIP then
- if q.spec ~= spec_zero_glue then
- local ts, g;
- q.spec, ts = node_copy(q.spec), q.spec
- g = node.copy(q); q.spec = ts
- node.insert_before(head, q, g);
- head = node.remove(head, q); node.free(q); q = g
- end
- end
- else
- res[0] = res[0] + a
- end
+ for q in node_traverse_id(getlist(p), id_glue) do
+ local a, ic = get_stretched(q, go, gs), get_attr_icflag(q)
+ if type(res[ic]) == 'number' then
+ -- kanjiskip, xkanjiskip は段落内で spec を共有しているが,
+ -- それはここでは望ましくないので,各 glue ごとに異なる spec を使う.
+ -- JFM グルーはそれぞれ異なる glue_spec を用いているので,問題ない.
+ res[ic] = res[ic] + a
+ if ic == KANJI_SKIP or ic == XKANJI_SKIP then
+ local qs = getfield(q, 'spec')
+ if qs ~= spec_zero_glue then
+ setfield(q, 'spec', node_copy(qs))
+ end
+ end
+ else
+ res[0] = res[0] + a
end
- q = node_next(q)
end
return res
end
local function clear_stretch(p, ic, name)
--print('clear ' .. ic)
- for q in node.traverse_id(id_glue, p.head) do
+ for q in node_traverse_id(id_glue, getlist(p)) do
if get_attr_icflag(q) == ic then
- local qs = q.spec
- if qs.writable then
- qs[name..'_order'], qs[name] = 0, 0
+ local qs = getfield(q, 'spec')
+ if getfield(qs, 'writable') then
+ setfield(qs, name..'_order', 0)
+ setfield(qs, name, 0)
end
end
end
for i,_ in pairs(set_stretch_table) do
set_stretch_table[i] = nil
end
- for q in node.traverse_id(id_glue, p.head) do
+ for q in node_traverse_id(id_glue, getlist(p)) do
if get_attr_icflag(q) == ic then
- local qs, do_flag = q.spec, true
+ local qs, do_flag = getfield(q, 'spec'), true
for i=1,#set_stretch_table do
if set_stretch_table[i]==qs then do_flag = false end
end
- if qs.writable and qs[name..'_order'] == 0 and do_flag then
- qs[name] = qs[name]*ratio;
+ if getfield(qs, 'writable') and getfield(qs, name..'_order')==0 and do_flag then
+ setfield(qs, name, getfield(qs, name)*ratio)
set_stretch_table[#set_stretch_table+1] = qs
end
end
-- step 1: 行末に kern を挿入(句読点,中点用)
local function aw_step1(p, res, total)
- local x = node.tail(p.head); if not x then return false end
- local x = node.prev(x) ; if not x then return false end
+ local head = getlist(p)
+ local x = node_tail(head); if not x then return false end
+ x = node_prev(x) ; if not x then return false end
-- 本当の行末の node を格納
- if x.id == id_glue and x.subtype == 15 then
+ if getid(x) == id_glue and getsubtype(x) == 15 then
-- 段落最終行のときは,\penalty10000 \parfillskip が入るので,
-- その前の node が本来の末尾文字となる
- x = node.prev(node.prev(x))
+ x = node_prev(node_prev(x))
end
- local xi, xc = x.id
- if xi == id_glyph and has_attr(x, attr_curjfnt) == x.font then
+ local xi, xc = getid(x)
+ if xi == id_glyph and has_attr(x, attr_curjfnt) == getfont(x) then
-- 和文文字
xc = x
elseif xi == id_hlist and get_attr_icflag(x) == PACKED then
-- packed JAchar
- xc = x.head
- while xc.id == id_whatsit do xc = node.next(xc) end
+ xc = getlist(x)
+ while getid(xc) == id_whatsit do xc = node_next(xc) end
else
return false-- それ以外は対象外.
end
- local xk = ltjf_font_metric_table[xc.font]
+ local xk = ltjf_font_metric_table[getfont(xc)]
xk = xk.char_type[has_attr(xc, attr_jchar_class) or 0]
xk = xk['end_' .. res.name] or 0
if xk>0 and total>=xk then
- --print("ADDED")
total = total - xk
- local kn = node.new(id_kern)
- kn.kern = (res.name=='shrink' and -1 or 1) * xk
+ local kn = node_new(id_kern)
+ setfield(kn, 'kern', (res.name=='shrink' and -1 or 1) * xk)
set_attr(kn, attr_icflag, FROM_JFM)
- node.insert_after(p.head, x, kn)
+ insert_after(head, x, kn)
return true
else return false
end
local function aw_step2(p, res, total, added_flag)
if total == 0 then -- もともと伸縮の必要なし
if added_flag then -- 行末に kern 追加したので,それによる補正
- local f = node.hpack(p.head, p.width, 'exactly')
- f.head, p.glue_set, p.glue_sign, p.glue_order
- = nil, f.glue_set, f.glue_sign, f.glue_order
- node.free(f); return
+ --local f = node_hpack(getlist(p), getfield(p, 'width'), 'exactly')
+ --setfield(f, 'head', nil)
+ setfield(p, 'glue_set', 0)
+ setfield(p, 'glue_order', 0)
+ setfield(p, 'glue_sign', 0)
+ --node_free(f)
+ return
end
elseif total <= res[0] then -- 和文処理グルー以外で足りる
for _,v in pairs(priority_table) do clear_stretch(p, v, res.name) end
- local f = node.hpack(p.head, p.width, 'exactly')
- f.head, p.glue_set, p.glue_sign, p.glue_order
- = nil, f.glue_set, f.glue_sign, f.glue_order
- node.free(f)
+ --local f = node_hpack(getlist(p), getfield(p, 'width'), 'exactly')
+ -- setfield(f, 'head', nil)
+ setfield(p, 'glue_set', total/res[0])
+ setfield(p, 'glue_order', 0)
+ setfield(p, 'glue_sign', res.name)
+ --node_free(f)
else
+ local orig_total, avail = total, res[0]
total, i = total - res[0], 1
while i <= #priority_table do
local v = priority_table[i]
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 -- ループから抜けさせたいため
end
- total, i= total - res[v], i+1
+ 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(p.head, p.width, 'exactly')
- f.head, p.glue_set, p.glue_sign, p.glue_order
- = nil, f.glue_set, f.glue_sign, f.glue_order
- node.free(f)
+ --local f = node_hpack(getlist(p), getfield(p, 'width'), 'exactly')
+ --setfield(f, 'head', nil)
+ setfield(p, 'glue_set', total / avail)
+ setfield(p, 'glue_order', 0)
+ setfield(p, 'glue_sign', res.name)
+ --node_free(f)
end
end
end
function adjust_width(head)
if not head then return head end
- for p in node.traverse_id(id_hlist, head) do
+ for p in node_traverse_id(id_hlist, to_direct(head)) do
local res = get_total_stretched(p)
--print(table.serialize(res))
if res then
if type(i)=='number' then
total = total + v
end
- end; total = tex.round(total * res.glue_set)
+ end; total = round(total * res.glue_set)
local added_flag = aw_step1(p, res, total)
--print(total, res[0], res[KANJI_SKIP], res[FROM_JFM])
aw_step2(p, res, total, added_flag)
end
end
- return head
+ return to_node(head)
end
local is_reg = false
local a = (pre or 0) + (post or 0)
if #Bp == 0 then
if (a~=0 and not(g and getid(g)==id_kern)) then
- local p = node_new(id_penalty); --copy_attr(p, Nq.nuc)
+ 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, Np.first, p)
local a = (pre or 0) + (post or 0)
if #Bp == 0 then
if not (g and getid(g)==id_glue) then
- local p = node_new(id_penalty); --copy_attr(p, Nq.nuc)
+ 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, Np.first, p)
local a = (pre or 0) + (post or 0)
if #Bp == 0 then
if g and getid(g)==id_glue then
- local p = node_new(id_penalty); --copy_attr(p, Nq.nuc)
+ local p = node_new(id_penalty)
setfield(p, 'penalty', 10000); head = insert_before(head, Np.first, p)
Bp[1]=p
set_attr(p, attr_icflag, KINSOKU)
local g, d = m.char_type[bc][ac], 0
local n
if g then
- n,d = node_copy(g[2]), g[3];
- if g[1] then setfield(n, 'spec', node_copy(getfield(n, 'spec'))) end
+ n,d = node_copy(g[2]), g[3]
+ if g[1] then
+ local f = node_new(id_glue)
+ set_attr(f, attr_icflag, g[4])
+ setfield(f, 'spec', n)
+ return f, d
+ end
end
return n, d
end
gb = node_new(id_kern); setfield(gb, 'kern', 0)
else return nil end
elseif not ga then
- ga = node_new(id_kern); gsetfield(ga, 'kern', 0)
+ ga = node_new(id_kern); setfield(ga, 'kern', 0)
end
local k = 2*getid(gb) - getid(ga)
local x, y = node_prev(Nq.nuc), Nq.nuc
Nq.first, Nq.nuc, Nq.last = x, x, x
head = node_remove(head, y)
+ node_free(y)
end
return s
end
luatexja.load_module('base'); local ltjb = luatexja.base
luatexja.load_module('charrange'); local ltjc = luatexja.charrange
+local mem_leak_glue, mem_leak_gs, mem_leak_kern = 0, 0, 0
+
local Dnode = node.direct or node
local setfield = (Dnode ~= node) and Dnode.setfield or function(n, i, c) n[i] = c end
defjfm_res = t
end
+local update_jfm_cache
do
local function mult_table(old,scale) -- modified from table.fastcopy
if old then
else return nil end
end
- function update_jfm_cache(j,sz)
+ update_jfm_cache = function (j,sz)
if metrics[j].size_cache[sz] then return end
local t = {}
metrics[j].size_cache[sz] = t
for i,v in pairs(t.char_type) do
if type(i) == 'number' then -- char_type
for k,w in pairs(v.glue) do
- local g, h = node_new(id_glue), node_new(id_glue_spec)
- v[k] = {true, g, (w[5] and w[5]/sz or 0)}
+ local h = node_new(id_glue_spec)
+mem_leak_gs = mem_leak_gs+1
+ v[k] = {true, h, (w[5] and w[5]/sz or 0), FROM_JFM + (w[4] and w[4]/sz or 0)}
setfield(h, 'width', w[1])
setfield(h, 'stretch', w[2])
setfield(h, 'shrink', w[3])
setfield(h, 'stretch_order', 0)
setfield(h, 'shrink_order', 0)
- setfield(g, 'subtype', 0)
- setfield(g, 'spec', h)
- set_attr(g, attr_icflag, FROM_JFM + (w[4] and w[4]/sz or 0));
end
for k,w in pairs(v.kern) do
local g = node_new(id_kern)
+mem_leak_kern = mem_leak_kern +1
setfield(g, 'kern', w[1])
setfield(g, 'subtype', 1)
set_attr(g, attr_icflag, FROM_JFM)
t.zh = round(metrics[j].zh*sz)
end
end
-local update_jfm_cache = update_jfm_cache
+
luatexbase.create_callback("luatexja.find_char_class", "data",
function (arg, fmtable, char)
return 0
return
end
update_jfm_cache(j, f.size)
+ --print('MEMORY LEAK (acc): ', mem_leak_glue, mem_leak_gs, mem_leak_kern)
local sz = metrics[j].size_cache[f.size]
local fmtable = { jfm = j, size = f.size, var = jfm_var,
zw = sz.zw, zh = sz.zh,
local MJT = luatexja.stack_table_index.MJT
local MJS = luatexja.stack_table_index.MJS
local MJSS = luatexja.stack_table_index.MJSS
-local capsule_glyph = ltjw.capsule_glyph
+local capsule_glyph_math = ltjw.capsule_glyph_math
local is_ucs_in_japanese_char = ltjc.is_ucs_in_japanese_char_direct
conv_jchar_to_hbox_A =
local k = has_attr(r,attr_ykblshift) or 0
set_attr(r, attr_ykblshift, 0)
-- ltj-setwidth 内で実際の位置補正はおこなうので,補正量を退避
- ltjw.head = r;
local met = ltjf_font_metric_table[f]
- capsule_glyph(r, tex.mathdir , true, met, ltjf_find_char_class(pc, met));
- setfield(q, 'head', ltjw.head); node_free(p); p=q;
- set_attr(getlist(q), attr_yablshift, k)
+ r = capsule_glyph_math(r, met, ltjf_find_char_class(pc, met));
+ setfield(q, 'head', r); node_free(p); p=q;
+ set_attr(r, attr_yablshift, k)
end
end
elseif pid == id_sub_box and getlist(p) then
local unset_attr = Dnode.unset_attribute
local node_insert_after = Dnode.insert_after
local node_write = Dnode.write
+local node_traverse_id = Dnode.traverse_id
local identifiers = fonts.hashes.identifiers
local function do_ivs_repr(head)
head = to_direct(head)
- local p = head
+ local p, r = head
while p do
local pid = getid(p)
if pid==id_glyph then
if qc>=0xE0100 then qc = qc - 0xE0100 end
local pt = font_ivs_table[pf]
pt = pt and pt[getchar(p)]; pt = pt and pt[qc]
- head = node_remove(head,q)
+ head, r = node_remove(head,q)
+ node_free(q)
if pt then
local np = ivs_jglyph(pt, p, pf,
(has_attr(p,attr_curjfnt) or 0)==pf and OTF or VSR)
head = node_insert_after(head, p, np)
head = node_remove(head,p)
- p = np
+ node_free(p)
end
+ p = r
+ else
+ p = q
end
+ else
+ p = node_next(p)
end
+ else
+ p = node_next(p)
end
- p = node_next(p)
end
return to_node(head)
end
end
end
-local ltjw = {}
+local head, dir
+local ltjw = {} --export
luatexja.setwidth = ltjw
luatexbase.create_callback("luatexja.set_width", "data",
local fshift = { down = 0, left = 0}
-- mode: true iff p will be always encapsuled by a hbox
-local function capsule_glyph(p, dir, mode, met, class)
+local function capsule_glyph(p, met, class)
local char_data = met.char_type[class]
if not char_data then return node_next(p) end
local fwidth, pwidth = char_data.width, getfield(p, 'width')
fshift.down = char_data.down; fshift.left = char_data.left
fshift = call_callback("luatexja.set_width", fshift, met, class)
local fheight, fdepth = char_data.height, char_data.depth
- if (mode or pwidth ~= fwidth or getfield(p, 'height') ~= fheight or getfield(p, 'depth') ~= fdepth) then
+ 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 q
- ltjw.head, q = node_remove(ltjw.head, p)
+ head, q = node_remove(head, p)
setfield(p, 'yoffset', -fshift.down); setfield(p, 'next', nil)
- if ca~='left' then
- setfield(p, 'xoffset', getfield(p, 'xoffset') - fshift.left
- + (((ca=='right') and fwidth - pwidth) or round((fwidth - pwidth)*0.5)))
- else
- setfield(p, 'xoffset', getfield(p, 'xoffset') - fshift.left)
- end
+ 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(box, 'width', fwidth)
setfield(box, 'height', fheight)
setfield(box, 'depth', fdepth)
setfield(box, 'head', p)
setfield(box, 'shift', y_shift)
- setfield(box, 'dir', dir or 'TLT')
+ setfield(box, 'dir', dir)
set_attr(box, attr_icflag, PACKED + get_pr_begin_flag(p))
- ltjw.head = q and node_insert_before(ltjw.head, q, box)
- or node_insert_after(ltjw.head, node_tail(ltjw.head), box)
+ head = q and node_insert_before(head, q, box)
+ or node_insert_after(head, node_tail(head), box)
return q
else
set_attr(p, attr_icflag, PROCESSED + get_pr_begin_flag(p))
setfield(p, 'xoffset', getfield(p, 'xoffset') - fshift.left)
- setfield(p, 'yoffset', getfield(p, 'yoffset') - (has_attr(p, attr_ykblshift) or 0) - fshift.down)
+ setfield(p, 'yoffset', getfield(p, 'yoffset')
+ - (has_attr(p, attr_ykblshift) or 0) - fshift.down)
return node_next(p)
end
end
luatexja.setwidth.capsule_glyph = capsule_glyph
-function luatexja.setwidth.set_ja_width(ahead, dir)
- local p = ahead; ltjw.head = p
+local function capsule_glyph_math(p, met, class)
+ local char_data = met.char_type[class]
+ if not char_data then return nil end
+ local fwidth, pwidth = char_data.width, getfield(p, 'width')
+ fwidth = (fwidth ~= 'prop') and fwidth or pwidth
+ fshift.down = char_data.down; fshift.left = char_data.left
+ fshift = call_callback("luatexja.set_width", fshift, met, class)
+ local fheight, fdepth = char_data.height, char_data.depth
+ local y_shift, ca
+ = - getfield(p, 'yoffset') + (has_attr(p,attr_ykblshift) or 0), char_data.align
+ setfield(p, 'yoffset', -fshift.down)
+ if ca~='left' then
+ setfield(p, 'xoffset', getfield(p, 'xoffset') - fshift.left
+ + (((ca=='right') and fwidth - pwidth) or round((fwidth - pwidth)*0.5)))
+ else
+ setfield(p, 'xoffset', getfield(p, 'xoffset') - fshift.left)
+ end
+ local box = node_new(id_hlist);
+ setfield(box, 'width', fwidth)
+ setfield(box, 'height', fheight)
+ setfield(box, 'depth', fdepth)
+ setfield(box, 'head', p)
+ setfield(box, 'shift', y_shift)
+ setfield(box, 'dir', tex.mathdir)
+ set_attr(box, attr_icflag, PACKED + get_pr_begin_flag(p))
+ return box
+end
+luatexja.setwidth.capsule_glyph_math = capsule_glyph_math
+
+function luatexja.setwidth.set_ja_width(ahead, adir)
+ local p = ahead; head = p; dir = adir or 'TLT'
local m = false -- is in math mode?
while p do
local pid = getid(p)
and ((has_attr(p, attr_icflag) or 0)%PROCESSED_BEGIN_FLAG)<=0 then
local pf = getfont(p)
if pf == has_attr(p, attr_curjfnt) then
- p = capsule_glyph(p, dir, false, ltjf_font_metric_table[pf],
+ p = capsule_glyph(p, ltjf_font_metric_table[pf],
has_attr(p, attr_jchar_class))
else
set_attr(p, attr_icflag, PROCESSED + get_pr_begin_flag(p))
end
-- adjust attr_icflag
tex.setattribute('global', attr_icflag, 0)
- return ltjw.head
+ return head
end