local node_insert_before = node.insert_before
local node_insert_after = node.insert_after
local round = tex.round
+local table_insert = table.insert
local id_glyph = node.id('glyph')
local id_hlist = node.id('hlist')
local attr_autoxspc = luatexbase.attributes['ltj@autoxspc']
local max_dimen = 1073741823
-
+local ltjs_get_penalty_table = ltjs.get_penalty_table
+local ltjs_get_skip_table = ltjs.get_skip_table
+local ltjf_find_char_class = ltjf.find_char_class
+local ltjf_font_metric_table = ltjf.font_metric_table
+local ltjf_metrics = ltjf.metrics
+local box_stack_level
+local par_indented -- is the paragraph indented?
-------------------- Helper functions
-local function find_char_class(c,m)
+-- This function is called only for acquiring `special' characters.
+local function fast_find_char_class(c,m)
return m.chars[c] or 0
end
+local spec_zero_glue = node_new(id_glue_spec)
+ spec_zero_glue.width = 0; spec_zero_glue.stretch_order = 0; spec_zero_glue.stretch = 0
+ spec_zero_glue.shrink_order = 0; spec_zero_glue.shrink = 0
+
local function get_zero_glue()
- local g = node_new(id_glue_spec)
- g.width = 0; g.stretch_order = 0; g.stretch = 0
- g.shrink_order = 0; g.shrink = 0
- return g
+ return node_copy(spec_zero_glue)
end
local function skip_table_to_spec(n)
local g = node_new(id_glue_spec)
- local st = ltjs.get_skip_table(n, ltjp.box_stack_level)
+ local st = ltjs_get_skip_table(n, box_stack_level)
g.width = st.width; g.stretch = st.stretch; g.shrink = st.shrink
g.stretch_order = st.stretch_order; g.shrink_order = st.shrink_order
return g
-- 実際の glue は Np.last, Nq.first の間に挿入される
-- Bp: Np.last, Nq.first の間の penalty node 達の配列
+-- Np, Nq, Bp, widow_Bp について
+-- Np, Nq は別々のテーブル.
+-- 1回のループごとに Nq = Np, Np = (new table) となるのは効率が悪いので,
+-- Np <-> Nq 入れ替え,その後 Np をクリアすることでテーブルを再利用.
+-- 同様の関係は Bp, widow_Bp にも.
+
+
-- 核の定義:
-- node x が non-char node のときは,x のみ
-- x が char_node のときは,
local function calc_np()
-- We assume lp = node_next(Np.last)
- local pBp = Bp; local lpi, lpa
- Nq = Np; Bp = {}; Bp[0] = 0; Np = {}; ihb_flag = false
+ local lpi, lpa, Nr
+ Nr = Nq; for k in pairs(Nr) do Nr[k] = nil end
+ Nq = Np; Np = Nr
+ for k in pairs(Bp) do Bp[k] = nil end
+ ihb_flag = false
while true do
lpi = lp.id; lpa = has_attr(lp, attr_icflag) or 0
if lp==last then Np = nil; return
elseif lpa>=PACKED then
if lpa == BOXBDD then
local lq = node_next(lp)
- head = node_remove(head, lp); lp = lq
+ head = node_remove(head, lp); node_free(lp); lp = lq
else calc_np_pbox(); return end -- id_pbox
elseif lpi == id_ins or lpi == id_mark or lpi == id_adjust then
set_attr_icflag_processed(lp); lp = node_next(lp)
elseif lpi == id_penalty then
- table.insert(Bp, lp); Bp[0] = Bp[0] + 1
- set_attr_icflag_processed(lp); lp = node_next(lp)
+ table_insert(Bp, lp); set_attr_icflag_processed(lp); lp = node_next(lp)
elseif lpi == id_whatsit then
if lp.subtype==sid_user and lp.user_id==30111 then
local lq = node_next(lp)
- head = node_remove(head, lp); lp = lq; ihb_flag = true
+ head = node_remove(head, lp); node_free(lp); lp = lq; ihb_flag = true
else
set_attr_icflag_processed(lp); lp = node_next(lp)
end
-- "Np is not a character" otherwise.
-- 和文文字のデータを取得
-local function set_np_xspc_jachar(c,x)
- Np.class = has_attr(x, attr_jchar_class)
- Np.char = c
- local z = ltjf.font_metric_table[x.font]
+local function set_np_xspc_jachar(x)
+ local z = ltjf_font_metric_table[x.font]
+ local cls = ltjf_find_char_class(x.char, z)
+ set_attr(x, attr_jchar_class, cls)
+ Np.class = cls
+ Np.char = x.char
Np.size= z.size
- Np.met = ltjf.metrics[z.jfm]
+ Np.met = ltjf_metrics[z.jfm]
Np.var = z.var
- Np.pre = ltjs.get_penalty_table('pre', c, 0, ltjp.box_stack_level)
- Np.post = ltjs.get_penalty_table('post', c, 0, ltjp.box_stack_level)
- z = find_char_class('lineend', Np.met)
+ Np.pre = ltjs_get_penalty_table('pre', x.char, 0, box_stack_level)
+ Np.post = ltjs_get_penalty_table('post', x.char, 0, box_stack_level)
+ z = fast_find_char_class('lineend', Np.met)
local y = Np.met.size_cache[Np.size].char_type[Np.class]
if y.kern and y.kern[z] then
Np.lend = y.kern[z]
else
Np.lend = 0
end
- y = ltjs.get_penalty_table('xsp', c, 3, ltjp.box_stack_level)
- Np.xspc_before = (y>=2)
- Np.xspc_after = (y%2==1)
+ y = ltjs_get_penalty_table('xsp', x.char, 3, box_stack_level)
+ Np.xspc_before = (y%2==1)
+ Np.xspc_after = (y>=2)
Np.auto_kspc = (has_attr(x, attr_autospc)==1)
Np.auto_xspc = (has_attr(x, attr_autoxspc)==1)
end
x = node_tail(x.components); c = x.char
end
end
- Np.pre = ltjs.get_penalty_table('pre', c, 0, ltjp.box_stack_level)
- Np.post = ltjs.get_penalty_table('post', c, 0, ltjp.box_stack_level)
+ Np.pre = ltjs_get_penalty_table('pre', c, 0, box_stack_level)
+ Np.post = ltjs_get_penalty_table('post', c, 0, box_stack_level)
else
Np.pre = 0; Np.post = 0
end
Np.met = nil
- local y = ltjs.get_penalty_table('xsp', c, 3, ltjp.box_stack_level)
+ local y = ltjs_get_penalty_table('xsp', c, 3, box_stack_level)
Np.xspc_before = (y%2==1)
Np.xspc_after = (y>=2)
Np.auto_xspc = (has_attr(x, attr_autoxspc)==1)
local function extract_np()
local x = Np.nuc
if Np.id == id_jglyph then
- set_np_xspc_jachar(x.char, x)
+ set_np_xspc_jachar(x)
elseif Np.id == id_glyph then
set_np_xspc_alchar(x.char, x, ligature_head)
elseif Np.id == id_hlist then
if check_box(x.head, nil) then
if first_char then
if first_char.font == has_attr(first_char, attr_curjfnt) then
- set_np_xspc_jachar(first_char.char,first_char)
+ set_np_xspc_jachar(first_char)
else
set_np_xspc_alchar(first_char.char,first_char, ligature_head)
end
if check_box(Np.first, node_next(Np.last)) then
if first_char then
if first_char.font == has_attr(first_char, attr_curjfnt) then
- set_np_xspc_jachar(first_char.char,first_char)
+ set_np_xspc_jachar(first_char)
else
set_np_xspc_alchar(first_char.char,first_char, ligature_head)
end
if check_box(x.replace, nil) then
if first_char then
if first_char.font == has_attr(first_char, attr_curjfnt) then
- set_np_xspc_jachar(first_char.char,first_char)
+ set_np_xspc_jachar(first_char)
else
set_np_xspc_alchar(first_char.char,first_char, ligature_head)
end
local function after_hlist()
if last_char then
if last_char.font == has_attr(last_char, attr_curjfnt) then
- set_np_xspc_jachar(last_char.char,last_char, ligature_after)
+ set_np_xspc_jachar(last_char, ligature_after)
else
set_np_xspc_alchar(last_char.char,last_char, ligature_after)
end
local function lineend_fix(g)
if g and g.id==id_kern then
Nq.lend = 0
- elseif Nq.lend and Nq.lend~=0 then
+ elseif Nq.lend~=0 then
if not g then
g = node_new(id_kern); g.subtype = 1
g.kern = -Nq.lend; set_attr(g, attr_icflag, LINEEND)
-- change penalties (or create a new penalty, if needed)
local function handle_penalty_normal(post, pre, g)
local a = (pre or 0) + (post or 0)
- if Bp[0] == 0 then
- if (a~=0 and not(g and g.id==id_kern)) or (Nq.lend and Nq.lend~=0) then
+ if #Bp == 0 then
+ if (a~=0 and not(g and g.id==id_kern)) or Nq.lend~=0 then
local p = node_new(id_penalty)
if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
p.penalty = a
head = node_insert_before(head, Np.first, p)
- Bp[1] = p; Bp[0] = 1; set_attr(p, attr_icflag, KINSOKU)
+ table_insert(Bp, p); set_attr(p, attr_icflag, KINSOKU)
end
- else for i, v in ipairs(Bp) do add_penalty(v,a) end
+ else for i, v in pairs(Bp) do add_penalty(v,a) end
end
end
local function handle_penalty_always(post, pre, g)
local a = (pre or 0) + (post or 0)
- if Bp[0] == 0 then
- if not (g and g.id==id_glue) or (Nq.lend and Nq.lend~=0) then
+ if #Bp == 0 then
+ if not (g and g.id==id_glue) or Nq.lend~=0 then
local p = node_new(id_penalty)
if a<-10000 then a = -10000 elseif a>10000 then a = 10000 end
p.penalty = a
head = node_insert_before(head, Np.first, p)
- Bp[1] = p; Bp[0] = 1; set_attr(p, attr_icflag, KINSOKU)
+ table_insert(Bp, p); set_attr(p, attr_icflag, KINSOKU)
end
- else for i, v in ipairs(Bp) do add_penalty(v,a) end
+ else for i, v in pairs(Bp) do add_penalty(v,a) end
end
end
local function handle_penalty_suppress(post, pre, g)
local a = (pre or 0) + (post or 0)
- if Bp[0] == 0 then
+ if #Bp == 0 then
if g and g.id==id_glue then
local p = node_new(id_penalty)
p.penalty = 10000; head = node_insert_before(head, Np.first, p)
- Bp[1] = p; Bp[0] = 1; set_attr(p, attr_icflag, KINSOKU)
+ table_insert(Bp, p); set_attr(p, attr_icflag, KINSOKU)
end
- else for i, v in ipairs(Bp) do add_penalty(v,a) end
+ else for i, v in pairs(Bp) do add_penalty(v,a) end
end
end
if w~=0 then
local h = node_new(id_kern)
set_attr(h, attr_icflag, LINE_END)
- h.kern = Nq.lend; h.subtype = 1
+ h.kern = w; h.subtype = 1
head = node_insert_after(head, Nq.last, h)
end
if g then
end
elseif ak then
gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
- else gx = get_zero_glue() -- fallback
+ else node_free(gx); gx = get_zero_glue() -- fallback
end
g.spec = gx
- else g.spec=node_copy(kanji_skip) end
+ else g.spec=node_copy(kanji_skip); node_free(gx) end
else
- local gx = get_zero_glue()
- g.spec = gx
+ g.spec = get_zero_glue(); node_free(gx)
end
set_attr(g, attr_icflag, KANJI_SKIP)
return g
return new_jfm_glue(Nq, Nq.class, Np.class)
else
local g = new_jfm_glue(Nq, Nq.class,
- find_char_class('diffmet',Nq.met))
- local h = new_jfm_glue(Np, find_char_class('diffmet',Np.met),
+ fast_find_char_class('diffmet',Nq.met))
+ local h = new_jfm_glue(Np, fast_find_char_class('diffmet',Np.met),
Np.class)
return calc_ja_ja_aux(g,h)
end
local bk = get_xkanji_skip_from_jfm(Nn)
if bk then
gx.width = bk[1]; gx.stretch = bk[2]; gx.shrink = bk[3]
- else gx = get_zero_glue() -- fallback
+ else node_free(gx); gx = get_zero_glue() -- fallback
end
g.spec = gx
else g.spec=node_copy(xkanji_skip) end
else
- local gx = get_zero_glue()
- g.spec = gx
+ g.spec = get_zero_glue()
end
set_attr(g, attr_icflag, XKANJI_SKIP)
return g
local function get_OA_skip()
if not ihb_flag then
- return new_jfm_glue(Np, find_char_class('jcharbdd',Np.met), Np.class)
+ local c
+ if Nq.id == id_math then c = -1 else c = 'jcharbdd' end
+ return new_jfm_glue(Np, fast_find_char_class(c,Np.met), Np.class)
else return nil
end
end
local function get_OB_skip()
if not ihb_flag then
- return new_jfm_glue(Nq, Nq.class, find_char_class('jcharbdd',Nq.met))
+ local c
+ if Np.id == id_math then c = -1 else c = 'jcharbdd' end
+ return new_jfm_glue(Nq, Nq.class, fast_find_char_class(c,Nq.met))
else return nil
end
end
-- (anything) .. jachar
local function handle_np_jachar()
- local g = nil
+ local g
if Nq.id==id_jglyph or (Nq.id==id_pbox and Nq.met) then
g = calc_ja_ja_glue() or get_kanjiskip() -- M->K
g = lineend_fix(g)
real_insert(0, g)
end
-- \jcharwidowpenalty 挿入予定箇所更新
- if ltjs.get_penalty_table('kcat', Np.char, 0, ltjp.box_stack_level)%2~=1 then
- widow_Np = Np; widow_Bp = Bp
+ if mode and ltjs_get_penalty_table('kcat', Np.char, 0, box_stack_level)%2~=1 then
+ widow_Np.first = Np.first;
+ local Bpr = widow_Bp; widow_Bp = Bp; Bp = Bpr
end
end
-- jachar .. (anything)
local function handle_nq_jachar()
- local g = nil
+ local g
if Np.pre then
g = get_OB_skip() or get_xkanjiskip(Nq) -- O_B->X
g = lineend_fix(g)
-- (anything) .. (和文文字で終わる hlist)
local function handle_np_ja_hlist()
- local g = nil
+ local g
if Nq.id==id_jglyph or (Nq.id==id_pbox and Nq.met) then
g = get_OB_skip() or get_kanjiskip() -- O_B->K
g = lineend_fix(g)
end
end
-- Insert \jcharwidowpenalty
- Bp = widow_Bp; Np = widow_Np
- if Np then
+ Bp = widow_Bp; Np = widow_Np; Nq.lend = 0
+ if Np.first then
handle_penalty_normal(0,
- ltjs.get_penalty_table('jwp', 0, 0, ltjp.box_stack_level))
+ ltjs_get_penalty_table('jwp', 0, 0, box_stack_level))
end
else
-- the current list is the contents of a hbox
if Np.id == id_jglyph or (Np.id==id_pbox and Np.met) then
- local g = new_jfm_glue(Np, Np.class, find_char_class('boxbdd',Np.met))
+ local g = new_jfm_glue(Np, Np.class, fast_find_char_class('boxbdd',Np.met))
if g then
set_attr(g, attr_icflag, BOXBDD)
head = node_insert_after(head, Np.last, g)
end
end
- head = node_remove(head, last) -- remove the sentinel
+ head = node_remove(head, last); node_free(last);-- remove the sentinel
end
+ node_free(kanji_skip); node_free(xkanji_skip)
end
-- リスト先頭の処理
local function handle_list_head()
if Np.id == id_jglyph or (Np.id==id_pbox and Np.met) then
- local g = new_jfm_glue(Np, find_char_class('boxbdd',Np.met), Np.class)
- if g then
- set_attr(g, attr_icflag, BOXBDD)
- if g.id==id_glue and Bp[0]==0 then
- local h = node_new(id_penalty)
- h.penalty = 10000; set_attr(h, attr_icflag, BOXBDD)
+ if not ihb_flag then
+ local g
+ if par_indented then
+ g = new_jfm_glue(Np, fast_find_char_class('parbdd',Np.met), Np.class)
+ else
+ g = new_jfm_glue(Np, fast_find_char_class('boxbdd',Np.met), Np.class)
+ end
+ if g then
+ set_attr(g, attr_icflag, BOXBDD)
+ if g.id==id_glue and #Bp==0 then
+ local h = node_new(id_penalty)
+ h.penalty = 10000; set_attr(h, attr_icflag, BOXBDD)
+ end
+ head = node_insert_before(head, Np.first, g)
end
- head = node_insert_before(head, Np.first, g)
end
end
end
-- initialize
local function init_var()
- lp = head; widow_Bp = nil; widow_Np = nil
+ lp = head; Bp = {}; widow_Bp = {}; widow_Np = {first = nil}
+ par_indented = false
+ box_stack_level = ltjp.box_stack_level
kanji_skip=skip_table_to_spec('kanjiskip')
xkanji_skip=skip_table_to_spec('xkanjiskip')
+ Np = {
+ auto_kspc=nil, auto_xspc=nil, char=nil, class=nil,
+ first=nil, id=nil, last=nil, lend=0, met=nil, nuc=nil,
+ post=nil, pre=nil, var=nil, xspc_after=nil, xspc_before=nil,
+ }
+ Nq = {
+ auto_kspc=nil, auto_xspc=nil, char=nil, class=nil,
+ first=nil, id=nil, last=nil, lend=0, met=nil, nuc=nil,
+ post=nil, pre=nil, var=nil, xspc_after=nil, xspc_before=nil,
+ }
if mode then
-- the current list is to be line-breaked:
-- hbox from \parindent is skipped.
- while lp and (lp.id==id_whatsit or ((lp.id==id_hlist) and (lp.subtype==3))) do
+ while lp and ((lp.id==id_whatsit and lp.subtype~=sid_user)
+ or ((lp.id==id_hlist) and (lp.subtype==3))) do
+ if (lp.id==id_hlist) and (lp.subtype==3) then par_indented = true end
lp=node_next(lp) end
last=node.tail(head)
else
elseif Np.id==id_hlist or Np.id==id_pbox or Np.id==id_disc then after_hlist()
end
else
- if not mode then head = node_remove(head, last) end
+ if not mode then head = node_remove(head, last); node_free(last) end
return head
end
calc_np()
end
-- \inhibitglue
+local inhibitglue_node=node_new(id_whatsit, sid_user)
+inhibitglue_node.user_id=30111; inhibitglue_node.type=100; inhibitglue_node.value=1
+
function create_inhibitglue_node()
- local g=node_new(id_whatsit, sid_user)
- g.user_id=30111; g.type=100; g.value=1; node.write(g)
+ node.write(node.copy(inhibitglue_node))
end