OSDN Git Service

671daa0c7ca18e595f38cf915c47acfd698ae22f
[luatex-ja/luatexja.git] / src / luatexja-xkanji.lua
1 ------------------------------------------------------------------------
2 -- MAIN PROCESS STEP 3: insert \xkanjiskip (prefix: none)
3 ------------------------------------------------------------------------
4
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 has_attr = node.has_attribute
10 local node_insert_before = node.insert_before
11 local node_insert_after = node.insert_after
12 local node_hpack = node.hpack
13
14 local id_penalty = node.id('penalty')
15 local id_glyph = node.id('glyph')
16 local id_glue = node.id('glue')
17 local id_glue_spec = node.id('glue_spec')
18 local id_kern = node.id('kern')
19 local id_hlist = node.id('hlist')
20 local id_ins = node.id('ins')
21 local id_mark = node.id('mark')
22 local id_adjust = node.id('adjust')
23 local id_math = node.id('math')
24 local id_whatsit = node.id('whatsit')
25
26 local attr_icflag = luatexbase.attributes['ltj@icflag']
27 local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
28
29 local kanji_skip
30 local xkanji_skip
31 local no_skip = 0
32 local after_schar = 1
33 local after_wchar = 2
34 local insert_skip = no_skip
35
36 -- (glyph_node nr) ... (node nq) <GLUE> ,,, (node np)
37 local np, nq, nrc
38 local no_skip = 0 
39 local after_schar = 1
40 local after_wchar = 2 -- nr is a Japanese glyph_node
41 local insert_skip = no_skip
42
43 local cstb_get_inhibit_xsp_table = ltj.int_get_inhibit_xsp_table
44
45 local function is_japanese_glyph_node(p)
46    return p and (p.id==id_glyph) 
47    and (p.font==has_attr(p,attr_curjfnt))
48 end
49
50 -- the following 2 functions are the lowest part.
51 -- cx: the Kanji code of np
52 local function insert_ascii_kanji_xkskip(head,q,cx)
53    if cstb_get_inhibit_xsp_table(cx)<=1 then return end
54    local g = node_new(id_glue)
55    g.subtype = 0; g.spec = node.copy(xkanji_skip)
56    node_insert_after(head, q, g)
57 end
58
59 local function insert_kanji_ascii_xkskip(head,q,p)
60    local g=true
61    local c = p.char
62    while p.components and p.subtype 
63       and math.floor(p.subtype/2)%2==1 do
64       p = p.components; c = p.char
65    end
66    if cstb_get_inhibit_xsp_table(c)%2 == 1 then
67       if cstb_get_inhibit_xsp_table(nrc)%2 == 0 then g = false end
68    else g = false
69    end
70    if g then
71       g = node_new(id_glue)
72       g.subtype = 0; g.spec = node.copy(xkanji_skip)
73       node_insert_after(head, q, g)
74    end
75 end
76
77
78 local function set_insert_skip_after_achar(p)
79    local c = p.char
80    while p.components and p.subtype 
81       and math.floor(p.subtype/2)%2 == 1 do
82       p=node.tail(p.components); c = p.char
83    end
84   if cstb_get_inhibit_xsp_table(c)>=2 then
85      insert_skip = after_schar
86   else
87      insert_skip = no_skip
88   end
89 end
90
91 -- When p is a glyph_node ...
92 local function insks_around_char(head)
93    if is_japanese_glyph_node(np) then
94       if insert_skip==after_wchar then
95          local g = node_new(id_glue)
96          g.subtype=0; g.spec=node.copy(kanji_skip)
97          node_insert_before(head, np, g)
98       elseif insert_skip==after_schar then
99          insert_ascii_kanji_xkskip(head, nq, np.char)
100       end
101       insert_skip=after_wchar; nrc = np.char
102    else
103       if insert_skip==after_wchar then
104          insert_kanji_ascii_xkskip(head, nq, np)
105       end
106       set_insert_skip_after_achar(np)
107    end
108    nq = np
109 end
110
111 -- Return first and last glyph nodes in a hbox
112 local first_char = nil
113 local last_char = nil
114 local find_first_char = nil
115 local function check_box(box_ptr)
116    local p = box_ptr; local found_visible_node = false
117    while p do
118       if p.id==id_glyph then
119          repeat 
120             if find_first_char then
121                first_char = p; find_first_char = false
122             end
123             last_char = p; found_visible_node = true; p=node_next(p)
124             if not p then return found_visible_node end
125          until p.id~=id_glyph
126       end
127       if p.id==id_hlist then
128          found_visible_node = true
129          if p.shift==0 then
130             if check_box(p.head) then found_visible_node = true end
131          else if find_first_char then 
132                find_first_char = false
133             else 
134                last_char = nil
135             end
136          end
137       elseif p.id==id_ins    or p.id==id_mark
138           or p.id==id_adjust or p.id==id_whatsit
139           or p.id==id_penalty then
140          p=p
141       else
142          found_visible_node = true
143          if find_first_char then 
144             find_first_char = false
145          else 
146             last_char = nil
147          end
148       end
149       p = node_next(p)
150    end
151    return found_visible_node
152 end 
153
154 -- When np is a hlist_node ...
155 local function insks_around_hbox(head)
156    if np.shift==0 then
157       find_first_char = true; first_char = nil; last_char = nil
158       if check_box(np.head) then
159          -- first char
160          if is_japanese_glyph_node(first_char) then
161             nrc = first_char.char
162             if insert_skip==after_schar then 
163                insert_ascii_kanji_xkskip(head, nq, first_char.char)
164             elseif insert_skip==after_wchar then
165                local g = node_new(id_glue)
166                g.subtype = 0; g.spec = node.copy(kanji_skip)
167                node_insert_before(head, np, g)
168             end
169             insert_skip = after_wchar
170          elseif first_char then
171             if insert_skip==after_wchar then
172                insert_kanji_ascii_xkskip(head, nq, first_char)
173             end
174             set_insert_skip_after_achar(first_char)
175          end
176          -- last char
177          if is_japanese_glyph_node(last_char) then
178             if is_japanese_glyph_node(node_next(np)) then
179                local g = node_new(id_glue)
180                g.subtype = 0; g.spec = node.copy(kanji_skip)
181                node_insert_after(head, np, g)
182             end
183             insert_skip = after_wchar; nrc = last_char.char
184          elseif last_char then
185             set_insert_skip_after_achar(last_char)
186          else insert_skip = no_skip
187          end
188       else insert_skip = no_skip
189       end
190    else insert_skip = no_skip
191    end
192    nq = np
193 end
194
195 -- When np is a penalty ...
196 local function insks_around_penalty(head)
197    nq = np
198 end
199
200 -- When np is a kern ...
201 -- 
202 local function insks_around_kern(head)
203    if np.subtype==1 then -- \kern or \/
204       local i = has_attr(np, attr_icflag)
205       if not i then -- \kern
206          insert_skip = no_skip
207       elseif i==1 then
208          nq = np
209       end
210    elseif np.subtype==2 then 
211       -- (np = kern from \accent) .. (accent char) .. (kern from \accent) .. (glyph)
212       np = node_next(node_next(np))
213    end
214 end
215
216 -- When np is a math_node ...
217 local function insks_around_math(head)
218    local g = { char = -1 }
219    if (np.subtype==0) and (insert_skip==after_wchar) then
220       insert_kanji_ascii_xkskip(head, nq, g)
221       insert_skip = no_skip
222    else
223       nq = np; set_insert_skip_after_achar(g)
224    end
225 end
226
227 function ltj.int_insert_kanji_skip(head)
228    if ltj.auto_spacing then
229       kanji_skip=tex.skip['kanjiskip']
230    else
231       kanji_skip=node_new(id_glue_spec)
232       kanji_skip.width=0;  kanji_skip.stretch=0; kanji_skip.shrink=0
233    end
234    if ltj.auto_xspacing then
235       xkanji_skip=tex.skip['xkanjiskip']
236    else
237       xkanji_skip=node_new(id_glue_spec)
238       xkanji_skip.width=0;  xkanji_skip.stretch=0; xkanji_skip.shrink=0
239    end
240    np = head; nq = nil; insert_skip = no_skip
241    while np do
242       if np.id==id_glyph then
243          repeat 
244             insks_around_char(head); np=node_next(np)
245          until (not np) or np.id~=id_glyph
246       else
247          if np.id==id_hlist then
248             insks_around_hbox(head)
249          elseif np.id==id_penalty then
250             insks_around_penalty(head)
251          elseif np.id==id_kern then
252             insks_around_kern(head)
253          elseif np.id==id_math then
254             insks_around_math(head)
255          elseif np.id==id_ins    or np.id==id_mark
256              or np.id==id_adjust or np.id==id_whatsit then
257             -- do nothing
258             np = np
259          else
260             -- rule, disc, glue, margin_kern
261             insert_skip = no_skip
262          end
263          np = node_next(np)
264       end
265    end
266    return head
267 end