1 ------------------------------------------------------------------------
2 -- MAIN PROCESS STEP 3: insert \xkanjiskip (prefix: none)
3 ------------------------------------------------------------------------
5 local node_type = node.type
6 local node_new = node.new
7 local node_prev = node.prev
8 local node_next = node.next
9 local node_copy = node.copy
10 local has_attr = node.has_attribute
11 local set_attr = node.set_attribute
12 local node_insert_before = node.insert_before
13 local node_insert_after = node.insert_after
14 local node_hpack = node.hpack
15 local round = tex.round
17 local id_penalty = node.id('penalty')
18 local id_glyph = node.id('glyph')
19 local id_glue = node.id('glue')
20 local id_glue_spec = node.id('glue_spec')
21 local id_kern = node.id('kern')
22 local id_hlist = node.id('hlist')
23 local id_ins = node.id('ins')
24 local id_mark = node.id('mark')
25 local id_adjust = node.id('adjust')
26 local id_math = node.id('math')
27 local id_whatsit = node.id('whatsit')
29 local attr_icflag = luatexbase.attributes['ltj@icflag']
30 local attr_autospc = luatexbase.attributes['ltj@autospc']
31 local attr_autoxspc = luatexbase.attributes['ltj@autoxspc']
32 local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
33 local max_dimen = 1073741823
47 -- (glyph_node nr) ... (node nq) <GLUE> ,,, (node np)
48 local np, nq, nrc, nrf
52 local after_wchar = 2 -- nr is a Japanese glyph_node
53 local insert_skip = no_skip
56 local function is_japanese_glyph_node(p)
57 return p and (p.id==id_glyph)
58 and (p.font==has_attr(p,attr_curjfnt))
61 local function get_zero_glue()
62 local g = node_new(id_glue_spec)
63 g.width = 0; g.stretch_order = 0; g.stretch = 0
64 g.shrink_order = 0; g.shrink = 0
68 local function skip_table_to_spec(n)
69 local g = node_new(id_glue_spec)
70 local st = luatexja.stack.get_skip_table(n, ltj.box_stack_level)
71 g.width = st.width; g.stretch = st.stretch; g.shrink = st.shrink
72 g.stretch_order = st.stretch_order; g.shrink_order = st.shrink_order
76 local function add_glue_spec(g,h)
78 g.width = g.width + h.width
79 if g.stretch_order<h.stretch_order then
80 g.stretch_order = h.stretch_order
82 elseif g.stretch_order==h.stretch_order then
83 g.stretch = g.stretch + h.stretch
85 if g.shrink_order<h.shrink_order then
86 g.shrink_order = h.shrink_order
88 elseif g.shrink_order==h.shrink_order then
89 g.shrink = g.shrink + h.shrink
93 -- lowest part of \xkanjiskip
94 local function get_xkanji_skip_from_jfm(pf)
96 local px = { ltj.font_metric_table[pf].size,
97 ltj.font_metric_table[pf].jfm }
98 local i = ltj.metrics[px[2]].xkanjiskip
100 return { round(i[1]*px[1]), round(i[2]*px[1]), round(i[3]*px[1]) }
107 local function insert_xkanjiskip_node(q, f, p)
108 if nr_spc[2] or np_spc[2] then
109 local g = node_new(id_glue); g.subtype = 0
110 if xkanji_skip.width==max_dimen then -- use xkanjiskip from JFM
111 local gx = node_new(id_glue_spec)
112 gx.stretch_order = 0; gx.shrink_order = 0
113 local ak = get_xkanji_skip_from_jfm(f)
115 gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
116 else gx = get_zero_glue() -- fallback
119 else g.spec=node_copy(xkanji_skip)
121 local h = node_prev(p)
122 if h and has_attr(h, attr_icflag)==TEMPORARY then
123 if h.id==id_kern then
124 g.spec.width = g.spec.width + h.kern
125 set_attr(g,attr_icflag,XKANJI_SKIP)
126 node_insert_after(head, q, g)
127 head = node.remove(head, h)
130 add_glue_spec(h.spec, g.spec)
131 node.free(g.spec); node.free(g)
134 set_attr(g,attr_icflag,XKANJI_SKIP)
135 node_insert_after(head, q, g)
140 local function insert_ascii_kanji_xkskip(q, p)
141 if luatexja.stack.get_penalty_table('xsp', p.char, 3, ltj.box_stack_level)<=1 then return end
142 insert_xkanjiskip_node(q, p.font, p)
145 local function insert_kanji_ascii_xkskip(q, p)
148 while p.components and p.subtype
149 and math.floor(p.subtype/2)%2==1 do
150 p = p.components; c = p.char
152 if luatexja.stack.get_penalty_table('xsp', c, 3, ltj.box_stack_level)%2 == 1 then
153 if luatexja.stack.get_penalty_table('xsp', nrc, 3, ltj.box_stack_level)%2 == 0 then g = false end
156 if g then insert_xkanjiskip_node(q, nrf, p) end
159 local function set_insert_skip_after_achar(p)
161 while p.components and p.subtype
162 and math.floor(p.subtype/2)%2 == 1 do
163 p=node.tail(p.components); c = p.char
165 if luatexja.stack.get_penalty_table('xsp', c, 3, ltj.box_stack_level)>=2 then
166 insert_skip = after_schar
168 insert_skip = no_skip
172 -- lowest part of \kanjiskip
173 local function get_kanji_skip_from_jfm(pf)
175 local px = { ltj.font_metric_table[pf].size,
176 ltj.font_metric_table[pf].jfm }
177 local i = ltj.metrics[px[2]].kanjiskip
179 return { round(i[1]*px[1]), round(i[2]*px[1]), round(i[3]*px[1]) }
186 local function insert_kanji_skip(ope, p)
187 local g = node_new(id_glue); g.subtype=0
188 if nr_spc[1] or np_spc[1] then
189 if kanji_skip.width==max_dimen then -- use kanjiskip from JFM
190 local gx = node_new(id_glue_spec);
191 gx.stretch_order = 0; gx.shrink_order = 0
192 local bk = get_kanji_skip_from_jfm(nrf)
193 local ak = get_kanji_skip_from_jfm(p.font)
196 gx.width = round(ltj.ja_diffmet_rule(bk[1], ak[1]))
197 gx.stretch = round(ltj.ja_diffmet_rule(bk[2], ak[2]))
198 gx.shrink = -round(ltj.ja_diffmet_rule(-bk[3], -ak[3]))
200 gx.width = bk[1]; gx.stretch = bk[2]; gx.shrink = bk[3]
203 gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
204 else gx = get_zero_glue() -- fallback
207 else g.spec=node_copy(kanji_skip)
209 else g.spec = get_zero_glue()
211 local h = node_prev(p)
212 if h and has_attr(h, attr_icflag)==TEMPORARY then
213 if h.id==id_kern then
214 g.spec.width = g.spec.width + h.kern
215 head = node.remove(head, h)
217 set_attr(g,attr_icflag,KANJI_SKIP)
220 add_glue_spec(h.spec, g.spec)
221 node.free(g.spec); node.free(g)
224 set_attr(g,attr_icflag,KANJI_SKIP)
229 -- When p is a glyph_node ...
230 local function insks_around_char()
231 if is_japanese_glyph_node(np) then
232 if insert_skip==after_wchar then
233 insert_kanji_skip(node_insert_before, np)
234 elseif insert_skip==after_schar then
235 insert_ascii_kanji_xkskip(nq, np)
237 insert_skip=after_wchar
238 nrc = np.char; nrf = np.font; nr_spc = np_spc
240 if insert_skip==after_wchar then
241 insert_kanji_ascii_xkskip(nq, np)
243 set_insert_skip_after_achar(np); nr_spc = np_spc
248 -- Return first and last glyph nodes in a hbox
249 local first_char = nil
250 local last_char = nil
251 local find_first_char = nil
252 local function check_box(box_ptr)
253 local p = box_ptr; local found_visible_node = false
255 find_first_char = false; first_char = nil; last_char = nil
259 if p.id==id_glyph then
261 if find_first_char then
262 first_char = p; find_first_char = false
264 last_char = p; found_visible_node = true; p=node_next(p)
265 if not p then return found_visible_node end
268 if p.id==id_hlist then
269 if has_attr(p, attr_icflag)==PACKED then
270 for q in node.traverse_id(id_glyph, p.head) do
271 if find_first_char then
272 first_char = q; find_first_char = false
274 last_char = q; found_visible_node = true
278 if check_box(p.head) then found_visible_node = true end
279 else if find_first_char then
280 find_first_char = false
286 elseif p.id==id_ins or p.id==id_mark
287 or p.id==id_adjust or p.id==id_whatsit
288 or p.id==id_penalty then
291 found_visible_node = true
292 if find_first_char then
293 find_first_char = false
300 return found_visible_node
303 -- When np is a hlist_node ...
304 local function insks_around_hbox()
306 find_first_char = true; first_char = nil; last_char = nil
307 if check_box(np.head) then
309 if is_japanese_glyph_node(first_char) then
310 nrc = first_char.char; nrf = first_char.font
311 if insert_skip==after_schar then
312 insert_ascii_kanji_xkskip(nq, first_char)
313 elseif insert_skip==after_wchar then
314 np_spc = { has_attr(first_char, attr_autospc)==1,
315 has_attr(first_char, attr_autoxspc)==1 }
316 insert_kanji_skip(node_insert_before, np)
318 insert_skip = after_wchar
319 elseif first_char then
320 if insert_skip==after_wchar then
321 insert_kanji_ascii_xkskip(nq, first_char)
323 set_insert_skip_after_achar(first_char)
326 if is_japanese_glyph_node(last_char) then
327 insert_skip = after_wchar
328 nrc = last_char.char; nrf = last_char.font
329 nr_spc = { has_attr(last_char, attr_autospc)==1,
330 has_attr(last_char, attr_autoxspc)==1 }
331 if is_japanese_glyph_node(node_next(np)) then
332 insert_kanji_skip(node_insert_after, np)
334 elseif last_char then
335 set_insert_skip_after_achar(last_char)
336 nr_spc = { has_attr(last_char, attr_autospc)==1,
337 has_attr(last_char, attr_autoxspc)==1 }
338 else insert_skip = no_skip
340 else insert_skip = no_skip
342 else insert_skip = no_skip
347 -- When np is a penalty ...
348 local function insks_around_penalty()
352 -- When np is a kern ...
354 local function insks_around_kern()
355 if np.subtype==1 then -- \kern or \/
356 local i = has_attr(np, attr_icflag)
357 if not i or i==FROM_JFM then -- \kern
358 insert_skip = no_skip
359 elseif i==ITALIC or i==LINE_END or i==TEMPORARY then
362 elseif np.subtype==2 then
363 -- (np = kern from \accent) .. (accent char) .. (kern from \accent) .. (glyph)
364 np = node_next(node_next(np))
365 else -- kern from TFM
370 -- When np is a math_node ...
371 local function insks_around_math()
372 local g = { char = -1 }
373 if (np.subtype==0) and (insert_skip==after_wchar) then
374 insert_kanji_ascii_xkskip(nq, g)
375 insert_skip = no_skip
377 nq = np; set_insert_skip_after_achar(g); nr_spc = np_spc
381 function ltj.int_insert_kanji_skip(ahead)
382 kanji_skip=skip_table_to_spec('kanjiskip')
383 xkanji_skip=skip_table_to_spec('xkanjiskip')
385 np = head; nq = nil; insert_skip = no_skip
387 np_spc = { (has_attr(np, attr_autospc)==1),
388 (has_attr(np, attr_autoxspc)==1) }
389 if np.id==id_glyph then
391 np_spc = { has_attr(np, attr_autospc)==1,
392 has_attr(np, attr_autoxspc)==1 }
393 insks_around_char(); np=node_next(np)
394 until (not np) or np.id~=id_glyph
396 if np.id==id_hlist then
398 elseif np.id==id_penalty then
399 insks_around_penalty()
400 elseif np.id==id_kern then
402 elseif np.id==id_math then
404 elseif np.id==id_ins or np.id==id_mark
405 or np.id==id_adjust or np.id==id_whatsit then
409 -- rule, disc, glue, margin_kern
410 insert_skip = no_skip