OSDN Git Service

Merge branch 'kitagawa_cid' into kitagawa_test
[luatex-ja/luatexja.git] / src / luatexja.lua
1
2 local floor = math.floor
3
4 require('lualibs')
5
6 ------------------------------------------------------------------------
7 -- naming:
8 --    ext_... : called from \directlua{}
9 --    int_... : called from other Lua codes, but not from \directlua{}
10 --    (other)     : only called from this file
11 function luatexja.load_module(name)
12    if not package.loaded['luatexja.' .. name] then
13       local fn = 'ltj-' .. name .. '.lua'
14       local found = kpse.find_file(fn, 'tex')
15       if not found then
16          tex.error("LuaTeX-ja error: File `" .. fn .. "' not found", 
17                         {'This file ' .. fn .. ' is required for LuaTeX-ja.', 
18                          'Please check your installation.'})
19       else 
20          texio.write_nl('(' .. found .. ')')
21          require(found) -- 2度読み防止; これでいいのか?
22       end
23    end
24 end
25 function luatexja.load_lua(fn)
26    local found = kpse.find_file(fn, 'tex')
27    if not found then
28       tex.error("LuaTeX-ja error: File `" .. fn .. "' not found")
29    else 
30       texio.write_nl('(' .. found .. ')')
31       dofile(found)
32    end
33 end
34
35 --- 以下は全ファイルで共有される定数
36 local icflag_table = {}
37 luatexja.icflag_table = icflag_table
38 icflag_table.ITALIC       = 1
39 icflag_table.PACKED       = 2
40 icflag_table.KINSOKU      = 3
41 icflag_table.FROM_JFM     = 6
42 -- FROM_JFM: 4, 5, 6, 7, 8 →優先度高
43 -- 6 が標準
44 icflag_table.KANJI_SKIP   = 9
45 icflag_table.XKANJI_SKIP  = 10
46 icflag_table.PROCESSED    = 11
47 icflag_table.IC_PROCESSED = 12
48 icflag_table.BOXBDD       = 15
49 icflag_table.PROCESSED_BEGIN_FLAG = 32
50
51 local stack_table_index = {}
52 luatexja.stack_table_index = stack_table_index
53 stack_table_index.PRE  = 0x200000 -- characterごと
54 stack_table_index.POST = 0x400000 -- characterごと
55 stack_table_index.KCAT = 0x600000 -- characterごと
56 stack_table_index.XSP  = 0x800000 -- characterごと
57 stack_table_index.JWP  = 0 -- 0のみ
58 stack_table_index.MJT  = 0x100 -- 0--255
59 stack_table_index.MJS  = 0x200 -- 0--255
60 stack_table_index.MJSS = 0x300 -- 0--255
61 stack_table_index.KSJ  = 0x400 -- 0--9
62
63 local userid_table = {}
64 luatexja.userid_table = userid_table
65 userid_table.IHB  = 30111 -- \inhibitglue
66 userid_table.STCK = 30112 -- スタック管理
67 userid_table.OTF  = 30113 -- luatexja-otf
68 userid_table.BPAR = 30114 -- 「段落始め」
69
70
71 --- 定義終わり
72
73 local load_module = luatexja.load_module
74 load_module('base');      local ltjb = luatexja.base
75 load_module('rmlgbm');    local ltjr = luatexja.rmlgbm -- must be 1st
76 load_module('charrange'); local ltjc = luatexja.charrange
77 load_module('jfont');     local ltjf = luatexja.jfont
78 load_module('inputbuf');  local ltji = luatexja.inputbuf
79 load_module('stack');     local ltjs = luatexja.stack
80 load_module('pretreat');  local ltjp = luatexja.pretreat
81 load_module('jfmglue');   local ltjj = luatexja.jfmglue
82 load_module('setwidth');  local ltjw = luatexja.setwidth
83 load_module('math');      local ltjm = luatexja.math
84 load_module('tangle');    local ltjb = luatexja.base
85
86
87 local node_type = node.type
88 local node_new = node.new
89 local node_prev = node.prev
90 local node_next = node.next
91 local has_attr = node.has_attribute
92 local node_insert_before = node.insert_before
93 local node_insert_after = node.insert_after
94 local node_hpack = node.hpack
95
96 local id_penalty = node.id('penalty')
97 local id_glyph = node.id('glyph')
98 local id_glue_spec = node.id('glue_spec')
99 local id_glue = node.id('glue')
100 local id_kern = node.id('kern')
101 local id_hlist = node.id('hlist')
102 local id_vlist = node.id('vlist')
103 local id_rule = node.id('rule')
104 local id_math = node.id('math')
105 local id_whatsit = node.id('whatsit')
106 local sid_user = node.subtype('user_defined')
107
108 local attr_jchar_class = luatexbase.attributes['ltj@charclass']
109 local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
110 local attr_yablshift = luatexbase.attributes['ltj@yablshift']
111 local attr_icflag = luatexbase.attributes['ltj@icflag']
112 local attr_uniqid = luatexbase.attributes['ltj@uniqid']
113 local cat_lp = luatexbase.catcodetables['latex-package']
114
115 -- Three aux. functions, bollowed from tex.web
116 local unity=65536
117 local function print_scaled(s)
118    local out=''
119    local delta=10
120    if s<0 then 
121       out=out..'-'; s=-s
122    end
123    out=out..tostring(floor(s/unity)) .. '.'
124    s=10*(s%unity)+5
125    repeat
126       if delta>unity then s=s+32768-50000 end
127       out=out .. tostring(floor(s/unity)) 
128       s=10*(s%unity)
129       delta=delta*10
130    until s<=delta
131    return out
132 end
133
134 local function print_glue(d,order)
135    local out=print_scaled(d)
136    if order>0 then
137       out=out..'fi'
138       while order>1 do
139          out=out..'l'; order=order-1
140       end
141    else 
142       out=out..'pt'
143    end
144    return out
145 end
146
147 function print_spec(p)
148    local out=print_scaled(p.width)..'pt'
149    if p.stretch~=0 then
150       out=out..' plus '..print_glue(p.stretch,p.stretch_order)
151    end
152    if p.shrink~=0 then
153       out=out..' minus '..print_glue(p.shrink,p.shrink_order)
154    end
155 return out
156 end
157
158
159 ---- table: charprop_stack_table [stack_level].{pre|post|xsp}[chr_code]
160
161 ------------------------------------------------------------------------
162 -- CODE FOR GETTING/SETTING PARAMETERS 
163 ------------------------------------------------------------------------
164
165 -- EXT: print parameters that don't need arguments
166 function luatexja.ext_get_parameter_unary(k)
167    local t = tex.getcount('ltj@@stack')
168    if k == 'yalbaselineshift' then
169       tex.write(print_scaled(tex.getattribute('ltj@yablshift'))..'pt')
170    elseif k == 'yjabaselineshift' then
171       tex.write(print_scaled(tex.getattribute('ltj@ykblshift'))..'pt')
172    elseif k == 'kanjiskip' then
173       tex.write(print_spec(ltjs.get_skip_table('kanjiskip', t)))
174    elseif k == 'xkanjiskip' then
175       tex.write(print_spec(ltjs.get_skip_table('xkanjiskip', t)))
176    elseif k == 'jcharwidowpenalty' then
177       tex.write(ltjs.get_penalty_table(stack_table_index.JWP, 0, t))
178    elseif k == 'autospacing' then
179       tex.write(tex.getattribute('ltj@autospc'))
180    elseif k == 'autoxspacing' then
181       tex.write(tex.getattribute('ltj@autoxspc'))
182    elseif k == 'differentjfm' then
183       if luatexja.jfmglue.diffmet_rule == math.max then
184          tex.write('large')
185       elseif luatexja.jfmglue.diffmet_rule == math.min then
186          tex.write('small')
187       elseif luatexja.jfmglue.diffmet_rule == math.two_average then
188          tex.write('average')
189       elseif luatexja.jfmglue.diffmet_rule == math.two_paverage then
190          tex.write('paverage')
191       elseif luatexja.jfmglue.diffmet_rule == math.two_pleft then
192          tex.write('pleft')
193       elseif luatexja.jfmglue.diffmet_rule == math.two_pright then
194          tex.write('pright')
195       elseif luatexja.jfmglue.diffmet_rule == math.two_add then
196          tex.write('both')
197       else -- This can't happen.
198          tex.write('???')
199       end
200    end
201 end
202
203
204 -- EXT: print parameters that need arguments
205 function luatexja.ext_get_parameter_binary(k,c)
206    local t = tex.getcount('ltj@@stack')
207    if type(c)~='number' then
208       ltjb.package_error('luatexja',
209                          'invalid the second argument (' .. tostring(c) .. ')',
210                          'I changed this one to zero.')
211       c=0
212    end
213    if k == 'jacharrange' then
214       if c>=7*ltjc.ATTR_RANGE then 
215          ltjb.package_error('luatexja',
216                             'invalid character range number (' .. c .. ')',
217                             'A character range number should be in the range 0..'
218                                .. 7+ATTR_RANGE-1 .. ",\n"..
219                              'So I changed this one to zero.')
220          c=0
221       end
222       -- 負の値は <U+0080 の文字の文字範囲,として出てくる.この時はいつも欧文文字なので 1 を返す
223       tex.write( (c<0) and -1 or ltjc.get_range_setting(c))
224    else
225       if c<0 or c>0x10FFFF then
226          ltjb.package_error('luatexja',
227                             'bad character code (' .. c .. ')',
228                             'A character number must be between -1 and 0x10ffff.\n'..
229                                "(-1 is used for denoting `math boundary')\n"..
230                                'So I changed this one to zero.')
231          c=0
232       end
233       if k == 'prebreakpenalty' then
234          tex.write(ltjs.get_penalty_table(stack_table_index.PRE + c, 0, t))
235       elseif k == 'postbreakpenalty' then
236          tex.write(ltjs.get_penalty_table(stack_table_index.POST+ c, 0, t))
237       elseif k == 'kcatcode' then
238          tex.write(ltjs.get_penalty_table(stack_table_index.KCAT+ c, 0, t))
239       elseif k == 'chartorange' then 
240          tex.write(ltjc.char_to_range(c))
241       elseif k == 'jaxspmode' or k == 'alxspmode' then
242          tex.write(ltjs.get_penalty_table(stack_table_index.XSP + c, 3, t))
243       end
244    end
245 end
246
247 -- EXT: print \global if necessary
248 function luatexja.ext_print_global()
249    if luatexja.isglobal=='global' then tex.sprint(cat_lp, '\\global') end
250 end
251
252 -- main process
253 -- mode = true iff main_process is called from pre_linebreak_filter
254 local function main_process(head, mode, dir)
255    local p = head
256    p = ltjj.main(p,mode)
257    if p then p = ltjw.set_ja_width(p, dir) end
258    return p
259 end
260
261 -- callbacks
262
263 luatexbase.add_to_callback('pre_linebreak_filter', 
264    function (head,groupcode)
265       return main_process(head, true, tex.textdir)
266    end,'ltj.pre_linebreak_filter',
267    luatexbase.priority_in_callback('pre_linebreak_filter',
268                                    'luaotfload.pre_linebreak_filter') + 1)
269 luatexbase.add_to_callback('hpack_filter', 
270   function (head,groupcode,size,packtype, dir)
271      return main_process(head, false, dir)
272   end,'ltj.hpack_filter',
273    luatexbase.priority_in_callback('hpack_filter',
274                                    'luaotfload.hpack_filter') + 1)
275
276 -- debug
277 local function get_attr_icflag(p)
278    return (has_attr(p, attr_icflag) or 0) % icflag_table.PROCESSED_BEGIN_FLAG
279 end
280
281 local debug_depth
282
283 local function debug_show_node_X(p,print_fn)
284    local k = debug_depth
285    local s
286    local pt=node_type(p.id)
287    local base = debug_depth .. string.format('%X', get_attr_icflag(p))
288    .. ' ' .. pt .. ' ' .. tostring(p.subtype) .. ' '
289    if pt == 'glyph' then
290       s = base .. ' ' .. utf.char(p.char) .. ' '  .. tostring(p.font)
291          .. ' (' .. print_scaled(p.height) .. '+' 
292          .. print_scaled(p.depth) .. ')x' .. print_scaled(p.width)
293       print_fn(s)
294    elseif pt=='hlist' or pt=='vlist' then
295       s = base .. '(' .. print_scaled(p.height) .. '+' 
296          .. print_scaled(p.depth) .. ')x' .. print_scaled(p.width) .. p.dir
297       if p.shift~=0 then
298          s = s .. ', shifted ' .. print_scaled(p.shift)
299       end
300       if p.glue_sign >= 1 then 
301          s = s .. ' glue set '
302          if p.glue_sign == 2 then s = s .. '-' end
303          s = s .. tostring(floor(p.glue_set*10000)/10000)
304          if p.glue_order == 0 then 
305             s = s .. 'pt' 
306          else 
307             s = s .. 'fi'
308             for i = 2,  p.glue_order do s = s .. 'l' end
309          end
310       end
311       if get_attr_icflag(p) == icflag_table.PACKED then
312          s = s .. ' (packed)'
313       end
314       print_fn(s)
315       local q = p.head
316       debug_depth=debug_depth.. '.'
317       while q do 
318          debug_show_node_X(q, print_fn); q = node_next(q)
319       end
320       debug_depth=k
321    elseif pt == 'glue' then
322       s = base .. ' ' ..  print_spec(p.spec)
323       if get_attr_icflag(p)>icflag_table.KINSOKU 
324          and get_attr_icflag(p)<icflag_table.KANJI_SKIP then
325          s = s .. ' (from JFM: priority ' .. get_attr_icflag(p)-icflag_table.FROM_JFM .. ')'
326       elseif get_attr_icflag(p)==icflag_table.KANJI_SKIP then
327          s = s .. ' (kanjiskip)'
328       elseif get_attr_icflag(p)==icflag_table.XKANJI_SKIP then
329          s = s .. ' (xkanjiskip)'
330       end
331       print_fn(s)
332    elseif pt == 'kern' then
333       s = base .. ' ' .. print_scaled(p.kern) .. 'pt'
334       if p.subtype==2 then
335          s = s .. ' (for accent)'
336       elseif get_attr_icflag(p)==icflag_table.IC_PROCESSED then
337          s = s .. ' (italic correction)'
338          -- elseif get_attr_icflag(p)==ITALIC then
339          --    s = s .. ' (italic correction)'
340       elseif get_attr_icflag(p)>icflag_table.KINSOKU 
341          and get_attr_icflag(p)<icflag_table.KANJI_SKIP then
342          s = s .. ' (from JFM: priority ' .. get_attr_icflag(p)-icflag_table.FROM_JFM .. ')'
343       end
344       print_fn(s)
345    elseif pt == 'penalty' then
346       s = base .. ' ' .. tostring(p.penalty)
347       if get_attr_icflag(p)==icflag_table.KINSOKU then
348          s = s .. ' (for kinsoku)'
349       end
350       print_fn(s)
351    elseif pt == 'whatsit' then
352       s = base .. ' subtype: ' ..  tostring(p.subtype)
353       if p.subtype==sid_user then
354          if p.type ~= 110 then 
355             s = s .. ' user_id: ' .. p.user_id .. ' ' .. p.value
356             print_fn(s)
357          else
358             s = s .. ' user_id: ' .. p.user_id .. ' (node list)'
359             print_fn(s)
360             local q = p.value
361             debug_depth=debug_depth.. '.'
362             while q do 
363                debug_show_node_X(q, print_fn); q = node_next(q)
364             end
365             debug_depth=k
366          end
367       else
368          s = s .. node.subtype(p.subtype); print_fn(s)
369       end
370    -------- math node --------
371    elseif pt=='noad' then
372       s = base ; print_fn(s)
373       if p.nucleus then
374          debug_depth = k .. 'N'; debug_show_node_X(p.nucleus, print_fn); 
375       end
376       if p.sup then
377          debug_depth = k .. '^'; debug_show_node_X(p.sup, print_fn); 
378       end
379       if p.sub then
380          debug_depth = k .. '_'; debug_show_node_X(p.sub, print_fn); 
381       end
382       debug_depth = k;
383    elseif pt=='math_char' then
384       s = base .. ' fam: ' .. p.fam .. ' , char = ' .. utf.char(p.char)
385       print_fn(s)
386    elseif pt=='sub_box' then
387       print_fn(base)
388       if p.head then
389          debug_depth = k .. '.'; debug_show_node_X(p.head, print_fn); 
390       end
391    else
392       print_fn(base)
393    end
394    p=node_next(p)
395 end
396 function luatexja.ext_show_node_list(head,depth,print_fn)
397    debug_depth = depth
398    if head then
399       while head do
400          debug_show_node_X(head, print_fn); head = node_next(head)
401       end
402    else
403       print_fn(debug_depth .. ' (null list)')
404    end
405 end
406 function luatexja.ext_show_node(head,depth,print_fn)
407    debug_depth = depth
408    if head then
409       debug_show_node_X(head, print_fn)
410    else
411       print_fn(debug_depth .. ' (null list)')
412    end
413 end