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 node_insert_before = node.insert_before
12 local node_insert_after = node.insert_after
13 local node_hpack = node.hpack
14 local round = tex.round
16 local id_penalty = node.id('penalty')
17 local id_glyph = node.id('glyph')
18 local id_glue = node.id('glue')
19 local id_glue_spec = node.id('glue_spec')
20 local id_kern = node.id('kern')
21 local id_hlist = node.id('hlist')
22 local id_ins = node.id('ins')
23 local id_mark = node.id('mark')
24 local id_adjust = node.id('adjust')
25 local id_math = node.id('math')
26 local id_whatsit = node.id('whatsit')
28 local attr_icflag = luatexbase.attributes['ltj@icflag']
29 local attr_autospc = luatexbase.attributes['ltj@autospc']
30 local attr_autoxspc = luatexbase.attributes['ltj@autoxspc']
31 local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
32 local max_dimen = 1073741823
45 -- (glyph_node nr) ... (node nq) <GLUE> ,,, (node np)
46 local np, nq, nrc, nrf
50 local after_wchar = 2 -- nr is a Japanese glyph_node
51 local insert_skip = no_skip
54 local cstb_get_inhibit_xsp_table = ltj.int_get_inhibit_xsp_table
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 get_kanji_skip_from_jfm(pf)
70 local px = { ltj.font_metric_table[pf].size,
71 ltj.font_metric_table[pf].jfm }
72 local i = ltj.metrics[px[2]].kanjiskip
74 return { round(i[1]*px[1]), round(i[2]*px[1]), round(i[3]*px[1]) }
81 local function get_xkanji_skip_from_jfm(pf)
83 local px = { ltj.font_metric_table[pf].size,
84 ltj.font_metric_table[pf].jfm }
85 local i = ltj.metrics[px[2]].xkanjiskip
87 return { round(i[1]*px[1]), round(i[2]*px[1]), round(i[3]*px[1]) }
94 -- the following 2 functions are the lowest part.
95 -- cx: the Kanji code of np
96 local function insert_ascii_kanji_xkskip(q, cx)
97 if cstb_get_inhibit_xsp_table(cx)<=1 then return end
98 local g = node_new(id_glue)
99 g.subtype = 0; g.spec = node.copy(xkanji_skip)
100 node_insert_after(head, q, g)
103 local function insert_kanji_ascii_xkskip(q, p)
106 while p.components and p.subtype
107 and math.floor(p.subtype/2)%2==1 do
108 p = p.components; c = p.char
110 if cstb_get_inhibit_xsp_table(c)%2 == 1 then
111 if cstb_get_inhibit_xsp_table(nrc)%2 == 0 then g = false end
115 g = node_new(id_glue); g.subtype = 0
116 if nr_spc[1] or np_spc[1] then
117 if xkanji_skip.width==max_dimen then -- use kanjiskip from JFM
118 local gx = node_new(id_glue_spec);
119 gx.stretch_order = 0; gx.shrink_order = 0
120 local ak = get_xkanji_skip_from_jfm(p.font)
122 gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
123 else gx = get_zero_glue() -- fallback
126 else g.spec=node.copy(xkanji_skip)
128 else g.spec = get_zero_glue()
130 local h = node_prev(p)
131 if h and has_attr(h, attr_icflag)==TEMPORARY then
132 if h.id==id_kern then
133 g.spec.width = g.spec.width + h.kern
134 node.set_attribute(g,attr_icflag,XKANJI_SKIP)
135 node_insert_after(head, q, g)
136 head = node.remove(head, h)
138 h.spec.width = g.spec.width + h.spec.width
139 h.spec.stretch = g.spec.stretch + h.spec.stretch
140 h.spec.shrink = g.spec.shrink + h.spec.shrink
143 node.set_attribute(g,attr_icflag,XKANJI_SKIP)
144 node_insert_after(head, q, g)
150 local function set_insert_skip_after_achar(p)
152 while p.components and p.subtype
153 and math.floor(p.subtype/2)%2 == 1 do
154 p=node.tail(p.components); c = p.char
156 if cstb_get_inhibit_xsp_table(c)>=2 then
157 insert_skip = after_schar
159 insert_skip = no_skip
163 local function insert_kanji_skip()
164 local g = node_new(id_glue); g.subtype=0
165 if nr_spc[1] or np_spc[1] then
166 if kanji_skip.width==max_dimen then -- use kanjiskip from JFM
167 local gx = node_new(id_glue_spec);
168 gx.stretch_order = 0; gx.shrink_order = 0
169 local bk = get_kanji_skip_from_jfm(nrf)
170 local ak = get_kanji_skip_from_jfm(np.font)
173 gx.width = round(ltj.ja_diffmet_rule(bk[1], ak[1]))
174 gx.stretch = round(ltj.ja_diffmet_rule(bk[2], ak[2]))
175 gx.shrink = -round(ltj.ja_diffmet_rule(-bk[3], -ak[3]))
177 gx.width = bk[1]; gx.stretch = bk[2]; gx.shrink = bk[3]
180 gx.width = ak[1]; gx.stretch = ak[2]; gx.shrink = ak[3]
181 else gx = get_zero_glue() -- fallback
184 else g.spec=node.copy(kanji_skip)
186 else g.spec = get_zero_glue()
188 local h = node_prev(np)
189 if h and has_attr(h, attr_icflag)==TEMPORARY then
190 if h.id==id_kern then
191 g.spec.width = g.spec.width + h.kern
192 head = node.remove(head, h)
193 node.set_attribute(g,attr_icflag,KANJI_SKIP)
194 node_insert_before(head, np, g)
196 h.spec.width = g.spec.width + h.spec.width
197 h.spec.stretch = g.spec.stretch + h.spec.stretch
198 h.spec.shrink = g.spec.shrink + h.spec.shrink
201 node.set_attribute(g,attr_icflag,KANJI_SKIP)
202 node_insert_before(head, np, g)
206 -- When p is a glyph_node ...
207 local function insks_around_char()
208 if is_japanese_glyph_node(np) then
209 if insert_skip==after_wchar then
211 elseif insert_skip==after_schar then
212 insert_ascii_kanji_xkskip(nq, np.char)
214 insert_skip=after_wchar
215 nrc = np.char; nrf = np.font; nr_spc = np_spc
217 if insert_skip==after_wchar then
218 insert_kanji_ascii_xkskip(nq, np)
220 set_insert_skip_after_achar(np); nr_spc = np_spc
225 -- Return first and last glyph nodes in a hbox
226 local first_char = nil
227 local last_char = nil
228 local find_first_char = nil
229 local function check_box(box_ptr)
230 local p = box_ptr; local found_visible_node = false
232 if p.id==id_glyph then
234 if find_first_char then
235 first_char = p; find_first_char = false
237 last_char = p; found_visible_node = true; p=node_next(p)
238 if not p then return found_visible_node end
241 if p.id==id_hlist then
242 found_visible_node = true
244 if check_box(p.head) then found_visible_node = true end
245 else if find_first_char then
246 find_first_char = false
251 elseif p.id==id_ins or p.id==id_mark
252 or p.id==id_adjust or p.id==id_whatsit
253 or p.id==id_penalty then
256 found_visible_node = true
257 if find_first_char then
258 find_first_char = false
265 return found_visible_node
268 -- When np is a hlist_node ...
269 local function insks_around_hbox()
271 find_first_char = true; first_char = nil; last_char = nil
272 if check_box(np.head) then
274 if is_japanese_glyph_node(first_char) then
275 nrc = first_char.char; nrf = first_char.font
276 if insert_skip==after_schar then
277 insert_ascii_kanji_xkskip(nq, first_char.char)
278 elseif insert_skip==after_wchar then
279 np_spc = { has_attr(first_char, attr_autospc)==1,
280 has_attr(first_char, attr_autoxspc)==1 }
283 insert_skip = after_wchar
284 elseif first_char then
285 if insert_skip==after_wchar then
286 insert_kanji_ascii_xkskip(nq, first_char)
288 set_insert_skip_after_achar(first_char)
291 if is_japanese_glyph_node(last_char) then
292 if is_japanese_glyph_node(node_next(np)) then
293 local g = node_new(id_glue)
294 g.subtype = 0; g.spec = node.copy(kanji_skip)
295 node_insert_after(head, np, g)
297 insert_skip = after_wchar
298 nrc = last_char.char; nrf = last_char.font
299 nr_spc = { has_attr(last_char, attr_autospc)==1,
300 has_attr(last_char, attr_autoxspc)==1 }
301 elseif last_char then
302 set_insert_skip_after_achar(last_char)
303 nr_spc = { has_attr(last_char, attr_autospc)==1,
304 has_attr(last_char, attr_autoxspc)==1 }
305 else insert_skip = no_skip
307 else insert_skip = no_skip
309 else insert_skip = no_skip
314 -- When np is a penalty ...
315 local function insks_around_penalty()
319 -- When np is a kern ...
321 local function insks_around_kern()
322 if np.subtype==1 then -- \kern or \/
323 local i = has_attr(np, attr_icflag)
324 if not i or i==FROM_JFM then -- \kern
325 insert_skip = no_skip
326 elseif i==ITALIC or i==LINE_END or i==TEMPORARY then
329 elseif np.subtype==2 then
330 -- (np = kern from \accent) .. (accent char) .. (kern from \accent) .. (glyph)
331 np = node_next(node_next(np))
335 -- When np is a math_node ...
336 local function insks_around_math()
337 local g = { char = -1 }
338 if (np.subtype==0) and (insert_skip==after_wchar) then
339 insert_kanji_ascii_xkskip(nq, g)
340 insert_skip = no_skip
342 nq = np; set_insert_skip_after_achar(g); nr_spc = np_spc
346 function ltj.int_insert_kanji_skip(ahead)
347 kanji_skip=tex.skip['kanjiskip']
348 xkanji_skip=tex.skip['xkanjiskip']
350 np = head; nq = nil; insert_skip = no_skip
352 np_spc = { (has_attr(np, attr_autospc)==1),
353 (has_attr(np, attr_autoxspc)==1) }
354 if np.id==id_glyph then
356 np_spc = { has_attr(np, attr_autospc)==1,
357 has_attr(np, attr_autoxspc)==1 }
358 insks_around_char(); np=node_next(np)
359 until (not np) or np.id~=id_glyph
361 if np.id==id_hlist then
363 elseif np.id==id_penalty then
364 insks_around_penalty()
365 elseif np.id==id_kern then
367 elseif np.id==id_math then
369 elseif np.id==id_ins or np.id==id_mark
370 or np.id==id_adjust or np.id==id_whatsit then
374 -- rule, disc, glue, margin_kern
375 insert_skip = no_skip