OSDN Git Service

Moved some Lua codes to avoid circular dependencies
[luatex-ja/luatexja.git] / src / ltj-jfont.lua
1 --
2 -- luatexja/jfont.lua
3 --
4 luatexbase.provides_module({
5   name = 'luatexja.jfont',
6   date = '2014/08/12',
7   description = 'Loader for Japanese fonts',
8 })
9 module('luatexja.jfont', package.seeall)
10
11 luatexja.load_module('base');      local ltjb = luatexja.base
12 luatexja.load_module('charrange'); local ltjc = luatexja.charrange
13 luatexja.load_module('rmlgbm');    local ltjr = luatexja.rmlgbm
14 luatexja.load_module('direction'); local ltjd = luatexja.direction
15
16
17 local Dnode = node.direct or node
18
19 local setfield = (Dnode ~= node) and Dnode.setfield or function(n, i, c) n[i] = c end
20 local getid = (Dnode ~= node) and Dnode.getid or function(n) return n.id end
21 local getfont = (Dnode ~= node) and Dnode.getfont or function(n) return n.font end
22 local getchar = (Dnode ~= node) and Dnode.getchar or function(n) return n.char end
23
24 local nullfunc = function(n) return n end
25 local to_direct = (Dnode ~= node) and Dnode.todirect or nullfunc
26
27 local node_new = Dnode.new
28 local node_free = Dnode.free
29 local has_attr = Dnode.has_attribute
30 local set_attr = Dnode.set_attribute
31 local node_write = Dnode.write
32 local round = tex.round
33 local font_getfont = font.getfont
34
35 local attr_icflag = luatexbase.attributes['ltj@icflag']
36 local attr_curjfnt = luatexbase.attributes['ltj@curjfnt']
37 local attr_curtfnt = luatexbase.attributes['ltj@curtfnt']
38 local id_glyph = node.id('glyph')
39 local id_kern = node.id('kern')
40 local id_glue_spec = node.id('glue_spec')
41 local id_glue = node.id('glue')
42 local cat_lp = luatexbase.catcodetables['latex-package']
43 local ITALIC       = luatexja.icflag_table.ITALIC
44 local FROM_JFM     = luatexja.icflag_table.FROM_JFM
45
46 ------------------------------------------------------------------------
47 -- LOADING JFM
48 ------------------------------------------------------------------------
49
50 metrics={} -- this table stores all metric informations
51 font_metric_table={} -- [font number] -> jfm_name, jfm_var, size
52
53 luatexbase.create_callback("luatexja.load_jfm", "data", function (ft, jn) return ft end)
54
55 local jfm_file_name, jfm_var
56 local defjfm_res
57 local jfm_dir
58
59 function define_jfm(t)
60    local real_char -- Does current character class have the 'real' character?
61    if t.dir~=jfm_dir then
62       defjfm_res= nil; return
63    elseif type(t.zw)~='number' or type(t.zh)~='number' then
64       defjfm_res= nil; return
65    end
66    t.char_type = {}; t.chars = {}
67    for i,v in pairs(t) do
68       if type(i) == 'number' then -- char_type
69          if not v.chars then
70             if i ~= 0 then defjfm_res= nil; return  end
71             real_char = true
72          else
73             real_char = false
74             for j,w in pairs(v.chars) do
75                if type(w) == 'number' and w~=-1 then
76                   real_char = true;
77                elseif type(w) == 'string' and utf.len(w)==1 then
78                   real_char = true; w = utf.byte(w)
79                elseif type(w) == 'string' and utf.len(w)==2 and utf.sub(w,2) == '*' then
80                   real_char = true; w = utf.byte(utf.sub(w,1,1))
81                   if not t.chars[-w] then
82                      t.chars[-w] = i
83                   else
84                      defjfm_res= nil; return
85                   end
86                end
87                if not t.chars[w] then
88                   t.chars[w] = i
89                else
90                   defjfm_res= nil; return
91                end
92             end
93             if type(v.align)~='string' then
94                v.align = 'left' -- left
95             end
96             if real_char then
97                if type(v.width)~='number' and v.width~='prop' then
98                   defjfm_res= nil; return
99                else
100                   if v.width=='prop' and jfm_dir=='tate' then
101                      v.width = 1.0
102                   end
103                   if type(v.height)~='number' then
104                      v.height = 0.0
105                   end
106                   if type(v.depth)~='number' then
107                      v.depth = 0.0
108                   end
109                   if type(v.italic)~='number' then
110                      v.italic = 0.0
111                   end
112                   if type(v.left)~='number' then
113                      v.left = 0.0
114                   end
115                   if type(v.down)~='number' then
116                      v.down = 0.0
117                   end
118                end
119             end
120             v.chars = nil
121          end
122          v.kern = v.kern or {}; v.glue = v.glue or {}
123          for j in pairs(v.glue) do
124             if v.kern[j] then defjfm_res= nil; return end
125          end
126          for j,x in pairs(v.kern) do
127             if type(x)=='number' then
128                v.kern[j] = {x, 0}
129             elseif type(x)=='table' then
130                v.kern[j] = {x[1], x[2] or 0}
131             end
132          end
133          t.char_type[i] = v
134          t[i] = nil
135       end
136    end
137    t = luatexbase.call_callback("luatexja.load_jfm", t, jfm_file_name)
138    t.size_cache = {}
139    defjfm_res = t
140 end
141
142 local update_jfm_cache
143 do
144    local function mult_table(old,scale) -- modified from table.fastcopy
145       if old then
146          local new = { }
147          for k,v in next, old do
148             if type(v) == "table" then
149                new[k] = mult_table(v,scale)
150             elseif type(v) == "number" then
151                new[k] = round(v*scale)
152             else
153                new[k] = v
154             end
155          end
156          return new
157       else return nil end
158    end
159
160    update_jfm_cache = function (j,sz)
161       if metrics[j].size_cache[sz] then return end
162       local t = {}
163       metrics[j].size_cache[sz] = t
164       t.chars = metrics[j].chars
165       t.char_type = mult_table(metrics[j].char_type, sz)
166       for i,v in pairs(t.char_type) do
167          v.align = (v.align=='left') and 0 or
168             ((v.align=='right') and 1 or 0.5)
169          if type(i) == 'number' then -- char_type
170             for k,w in pairs(v.glue) do
171                local h = node_new(id_glue_spec)
172                v[k] = {true, h, (w[5] and w[5]/sz or 0), FROM_JFM + (w[4] and w[4]/sz or 0)}
173                setfield(h, 'width', w[1])
174                setfield(h, 'stretch', w[2])
175                setfield(h, 'shrink', w[3])
176                setfield(h, 'stretch_order', 0)
177                setfield(h, 'shrink_order', 0)
178             end
179             for k,w in pairs(v.kern) do
180                local g = node_new(id_kern)
181                setfield(g, 'kern', w[1])
182                setfield(g, 'subtype', 1)
183                set_attr(g, attr_icflag, FROM_JFM)
184                v[k] = {false, g, w[2]/sz}
185             end
186          end
187          v.glue, v.kern = nil, nil
188       end
189       t.kanjiskip = mult_table(metrics[j].kanjiskip, sz)
190       t.xkanjiskip = mult_table(metrics[j].xkanjiskip,sz)
191       t.zw = round(metrics[j].zw*sz)
192       t.zh = round(metrics[j].zh*sz)
193    end
194 end
195
196 luatexbase.create_callback("luatexja.find_char_class", "data",
197                            function (arg, fmtable, char)
198                               return 0
199                            end)
200
201 function find_char_class(c,m)
202 -- c: character code, m:
203    if not m then return 0 end
204    return m.chars[c] or
205       luatexbase.call_callback("luatexja.find_char_class", 0, m, c)
206 end
207
208
209 ------------------------------------------------------------------------
210 -- LOADING JAPANESE FONTS
211 ------------------------------------------------------------------------
212
213 do
214    local cstemp
215    local global_flag -- true if \globaljfont, false if \jfont
216    local function load_jfont_metric()
217       if jfm_file_name=='' then
218          ltjb.package_error('luatexja',
219                             'no JFM specified',
220                             'To load and define a Japanese font, a JFM must be specified.'..
221                             "The JFM 'ujis' will be  used for now.")
222          jfm_file_name='ujis'
223       end
224       for j,v in ipairs(metrics) do
225          if v.name==jfm_file_name then return j end
226       end
227       luatexja.load_lua('jfm-' .. jfm_file_name .. '.lua')
228       if defjfm_res then
229          defjfm_res.name = jfm_file_name
230          table.insert(metrics, defjfm_res)
231          return #metrics
232       else
233          return nil
234       end
235    end
236
237 -- EXT
238    function jfontdefX(g)
239       local t = token.get_next()
240       cstemp=token.csname_name(t)
241       global_flag = g and '\\global' or ''
242       tex.sprint(cat_lp, '\\expandafter\\font\\csname ', cstemp, '\\endcsname')
243    end
244
245    luatexbase.create_callback("luatexja.define_jfont", "data", function (ft, fn) return ft end)
246
247 -- EXT
248    local identifiers = fonts.hashes.identifiers
249    function jfontdefY(dir)
250       jfm_dir = dir
251       local j = load_jfont_metric(dir)
252       local fn = font.id(cstemp)
253       local f = font_getfont(fn)
254       if not j then
255          ltjb.package_error('luatexja',
256                             "bad JFM `" .. jfm_file_name .. "'",
257                             'The JFM file you specified is not valid JFM file.\n'..
258                                'So defining Japanese font is cancelled.')
259          tex.sprint(cat_lp, global_flag, '\\expandafter\\let\\csname ', cstemp,
260                        '\\endcsname=\\relax')
261          return
262       end
263       update_jfm_cache(j, f.size)
264       local ad = identifiers[fn].parameters
265       local sz = metrics[j].size_cache[f.size]
266       local fmtable = { jfm = j, size = f.size, var = jfm_var,
267                         zw = sz.zw, zh = sz.zh,
268                         ascent = ad.ascender,
269                         descent = ad.descender,
270                         chars = sz.chars, char_type = sz.char_type,
271                         kanjiskip = sz.kanjiskip, xkanjiskip = sz.xkanjiskip,
272       }
273
274       fmtable = luatexbase.call_callback("luatexja.define_jfont", fmtable, fn)
275       font_metric_table[fn]=fmtable
276       tex.sprint(cat_lp, global_flag, '\\protected\\expandafter\\def\\csname ',
277                     cstemp , '\\endcsname{\\ltj@cur'..
278                     (dir == 'yoko' and 'j' or 't') .. 'fnt', fn, '\\relax}')
279    end
280 end
281
282 do
283    local get_dir_count = ltjd.get_dir_count
284    local dir_tate = luatexja.dir_table.dir_tate
285    local tex_get_attr = tex.getattribute
286    -- PUBLIC function
287    function get_zw()
288       local a = font_metric_table[
289          tex_get_attr((get_dir_count()==dir_tate) and attr_curtfnt or attr_curjfnt)]
290       return a and a.zw or 0
291    end
292    function get_zh()
293       local a = font_metric_table[
294          tex_get_attr((get_dir_count()==dir_tate) and attr_curtfnt or attr_curjfnt)]
295       return a and a.zw or 0
296    end
297 end
298
299 do
300    -- extract jfm_file_name and jfm_var
301    -- normalize position of 'jfm=' and 'jfmvar=' keys
302    local function extract_metric(name)
303       jfm_file_name = ''; jfm_var = ''
304       local tmp, index = name:sub(1, 5), 1
305       if tmp == 'file:' or tmp == 'name:' or tmp == 'psft:' then
306          index = 6
307       end
308       local p = name:find(":", index); index = p and (p+1) or index
309       while index do
310          local l = name:len()+1
311          local q = name:find(";", index+1) or l
312          if name:sub(index, index+3)=='jfm=' and q>index+4 then
313             jfm_file_name = name:sub(index+4, q-1)
314             if l~=q then
315                name = name:sub(1,index-1) .. name:sub(q+1)
316             else
317                name = name:sub(1,index-1)
318                index = nil
319             end
320          elseif name:sub(index, index+6)=='jfmvar=' and q>index+6 then
321             jfm_var = name:sub(index+7, q-1)
322             if l~=q then
323                name = name:sub(1,index-1) .. name:sub(q+1)
324             else
325                name = name:sub(1,index-1)
326                index = nil
327             end
328          else
329             index = (l~=q) and (q+1) or nil
330          end
331       end
332       if jfm_file_name~='' then
333          local l = name:sub(-1)
334          name = name 
335             .. ((l==':' or l==';') and '' or ';')
336             .. 'jfm=' .. jfm_file_name
337          if jfm_var~='' then
338             name = name .. 'jfmvar=' .. jfm_var
339          end
340       end
341       return name
342    end
343
344    -- define_font callback
345    local otfl_fdr = fonts.definers.read
346    local ltjr_font_callback = ltjr.font_callback
347    function luatexja.font_callback(name, size, id)
348       local new_name = extract_metric(name)
349       local res =  ltjr_font_callback(new_name, size, id, otfl_fdr)
350       luatexbase.call_callback('luatexja.define_font', res, new_name, size, id)
351       return res
352    end
353    luatexbase.create_callback('luatexja.define_font', 'simple', function (n) return n end)
354    luatexbase.add_to_callback('define_font',luatexja.font_callback,"luatexja.font_callback", 1)
355 end
356
357 ------------------------------------------------------------------------
358 -- LATEX INTERFACE
359 ------------------------------------------------------------------------
360 do
361    -- these function are called from ltj-latex.sty
362    local kyenc_list, ktenc_list = {}, {}
363    function add_kyenc_list(enc) kyenc_list[enc] = 'true ' end
364    function add_ktenc_list(enc) ktenc_list[enc] = 'true ' end
365    function is_kyenc(enc)
366       tex.sprint(cat_lp, '\\let\\ifin@\\if' .. (kyenc_list[enc] or 'false '))
367    end
368    function is_ktenc(enc)
369       tex.sprint(cat_lp, '\\let\\ifin@\\if' .. (ktenc_list[enc] or 'false '))
370    end
371    function is_kenc(enc)
372       tex.sprint(cat_lp, '\\let\\ifin@\\if'
373                  .. (kyenc_list[enc] or ktenc_list[enc] or 'false '))
374    end
375
376    local kfam_list, Nkfam_list = {}, {}
377    function add_kfam_list(enc, fam)
378       if not kfam_list[enc] then kfam_list[enc] = {} end
379       kfam_list[enc][fam] = 'true '
380    end
381    function add_Nkfam_list(enc, fam)
382       if not Nkfam_list[enc] then Nkfam_list[enc] = {} end
383       Nkfam_list[enc][fam] = 'true '
384    end
385    function is_kfam(enc, fam)
386       tex.sprint(cat_lp, '\\let\\ifin@\\if'
387                  .. (kfam_list[enc] and kfam_list[enc][fam] or 'false ')) end
388    function is_Nkfam(enc, fam)
389       tex.sprint(cat_lp, '\\let\\ifin@\\if'
390                  .. (Nkfam_list[enc] and Nkfam_list[enc][fam] or 'false ')) end
391
392    local ffam_list, Nffam_list = {}, {}
393    function add_ffam_list(enc, fam)
394       if not ffam_list[enc] then ffam_list[enc] = {} end
395       ffam_list[enc][fam] = 'true '
396    end
397    function add_Nffam_list(enc, fam)
398       if not Nffam_list[enc] then Nffam_list[enc] = {} end
399       Nffam_list[enc][fam] = 'true '
400    end
401    function is_ffam(enc, fam)
402       tex.sprint(cat_lp, '\\let\\ifin@\\if'
403                  .. (ffam_list[enc] and ffam_list[enc][fam] or 'false ')) end
404    function is_Nffam(enc, fam)
405       tex.sprint(cat_lp, '\\let\\ifin@\\if'
406                  .. (Nffam_list[enc] and Nffam_list[enc][fam] or 'false ')) end
407 end
408 ------------------------------------------------------------------------
409 -- ALTERNATE FONTS
410 ------------------------------------------------------------------------
411 alt_font_table = {}
412 local alt_font_table = alt_font_table
413 local attr_curaltfnt = {}
414 local ucs_out = 0x110000
415
416 ------ for TeX interface
417 -- EXT
418 function set_alt_font(b,e,ind,bfnt)
419    -- ind: 新フォント, bfnt: 基底フォント
420    if b>e then b, e = e, b end
421    if b*e<=0 then
422       ltjb.package_error('luatexja',
423                         'bad character range ([' .. b .. ',' .. e .. ']). ' ..
424                            'I take the intersection with [0x80, 0x10ffff].')
425       b, e = math.max(0x80,b),math.min(ucs_out-1,e)
426    elseif e<0 then -- b<e<0
427       -- do nothing
428    elseif b<0x80 or e>=ucs_out then
429       ltjb.package_warning('luatexja',
430                            'bad character range ([' .. b .. ',' .. e .. ']). ' ..
431                               'I take the intersection with [0x80, 0x10ffff].')
432       b, e = math.max(0x80,b), math.min(ucs_out-1,e)
433    end
434    if not alt_font_table[bfnt] then alt_font_table[bfnt]={} end
435    local t = alt_font_table[bfnt]
436    local ac = font_getfont(ind).characters
437    if bfnt==ind then ind = nil end -- ind == bfnt の場合はテーブルから削除
438    if e>=0 then -- character range
439       for i=b, e do
440          if ac[i]then  t[i]=ind end
441       end
442    else
443       b, e = -e, -b
444       local tx = font_metric_table[bfnt].chars
445       for i,v in pairs(tx) do
446          if b<=v and v<=e and ac[i] then t[i]=ind end
447       end
448    end
449 end
450
451 -- EXT
452 function clear_alt_font(bfnt)
453    if alt_font_table[bfnt] then
454       local t = alt_font_table[bfnt]
455       for i,_ in pairs(t) do t[i]=nil; end
456    end
457 end
458
459 ------ used in ltjp.suppress_hyphenate_ja callback
460 function replace_altfont(pf, pc)
461    local a = alt_font_table[pf]
462    return a and a[pc] or pf
463 end
464
465 ------ for LaTeX interface
466
467 local alt_font_table_latex = {}
468
469 -- EXT
470 function clear_alt_font_latex(bbase)
471    local t = alt_font_table_latex[bbase]
472    if t then
473       for j,v in pairs(t) do t[j] = nil end
474    end
475 end
476
477 -- EXT
478 function set_alt_font_latex(b,e,ind,bbase)
479    -- ind: Alt font の enc/fam/ser/shape, bbase: 基底フォントの enc/fam/ser/shape
480    if b>e then b, e = e, b end
481    if b*e<=0 then
482       ltjb.package_error('luatexja',
483                         'bad character range ([' .. b .. ',' .. e .. ']). ' ..
484                            'I take the intersection with [0x80, 0x10ffff].')
485       b, e = math.max(0x80,b),math.min(ucs_out-1,e)
486    elseif e<0 then -- b<e<0
487       -- do nothing
488    elseif b<0x80 or e>=ucs_out then
489       ltjb.package_warning('luatexja',
490                            'bad character range ([' .. b .. ',' .. e .. ']). ' ..
491                               'I take the intersection with [0x80, 0x10ffff].')
492       b, e = math.max(0x80,b), math.min(ucs_out-1,e)
493    end
494
495    if not alt_font_table_latex[bbase] then alt_font_table_latex[bbase]={} end
496    local t = alt_font_table_latex[bbase]
497    if not t[ind] then t[ind] = {} end
498    for i=b, e do
499       for j,v in pairs(t) do
500          if v[i] then -- remove old entry
501             if j~=ind then v[i]=nil end; break
502          end
503       end
504       t[ind][i]=true
505    end
506    -- remove the empty tables
507    for j,v in pairs(t) do
508       local flag_clear = true
509       for k,_ in pairs(v) do flag_clear = false; break end
510       if flag_clear then t[j]=nil end
511    end
512    if ind==bbase  then t[bbase] = nil end
513 end
514
515 -- ここから先は 新 \selectfont の内部でしか実行されない
516 do
517    local alt_font_base, alt_font_base_num
518    local aftl_base
519    -- EXT
520    function does_alt_set(bbase)
521       aftl_base = alt_font_table_latex[bbase]
522       tex.sprint(cat_lp, '\\if' .. (aftl_base and 'true' or 'false'))
523    end
524    -- EXT
525    function print_aftl_address()
526       tex.sprint(cat_lp, ';ltjaltfont' .. tostring(aftl_base):sub(8))
527    end
528
529 -- EXT
530    function output_alt_font_cmd(dir, bbase)
531       alt_font_base = bbase
532       if dir == 't' then
533          alt_font_base_num = tex.getattribute(attr_curtfnt)
534       else
535          alt_font_base_num = tex.getattribute(attr_curjfnt)
536       end           
537       local t = alt_font_table[alt_font_base_num]
538       if t then
539          for i,_ in pairs(t) do t[i]=nil end
540       end
541       t = alt_font_table_latex[bbase]
542       if t then
543        for i,_ in pairs(t) do
544             tex.sprint(cat_lp, '\\ltj@pickup@altfont@aux' .. dir .. '{' .. i .. '}')
545          end
546       end
547    end
548
549 -- EXT
550    function pickup_alt_font_a(size_str)
551       local t = alt_font_table_latex[alt_font_base]
552       if t then
553          for i,v in pairs(t) do
554             tex.sprint(cat_lp, '\\expandafter\\ltj@pickup@altfont@copy'
555                           .. '\\csname ' .. i .. '/' .. size_str .. '\\endcsname{' .. i .. '}')
556          end
557       end
558    end
559
560    local function pickup_alt_font_class(class, afnt_num, afnt_chars)
561       local t  = alt_font_table[alt_font_base_num]
562       local tx = font_metric_table[alt_font_base_num].chars
563       for i,v in pairs(tx) do
564          if v==class and afnt_chars[i] then t[i]=afnt_num end
565       end
566    end
567
568 -- EXT
569    function pickup_alt_font_b(afnt_num, afnt_base)
570       local t = alt_font_table[alt_font_base_num]
571       local ac = font_getfont(afnt_num).characters
572       if not t then t = {}; alt_font_table[alt_font_base_num] = t end
573       for i,v in pairs(alt_font_table_latex[alt_font_base]) do
574          if i == afnt_base then
575             for j,_ in pairs(v) do
576                if j>=0 then
577                   if ac[j] then t[j]=afnt_num end
578                else  -- -n (n>=1) means that the character class n,
579                      -- which is defined in the JFM
580                   pickup_alt_font_class(-j, afnt_num, ac)
581                end
582             end
583             return
584          end
585       end
586    end
587
588 end
589
590
591 ------------------------------------------------------------------------
592 -- 縦書き用字形への変換テーブル
593 ------------------------------------------------------------------------
594 local font_vert_table = {} -- key: fontnumber
595 do
596    local font_vert_basename = {} -- key: basename
597    local function add_feature_table(tname, src, dest)
598       for i,v in pairs(src) do
599          if type(v.slookups)=='table' then
600             local s = v.slookups[tname]
601             if s and not dest[i] then
602                dest[i] = s
603             end
604          end
605       end
606    end
607
608    local function prepare_vert_data(n, id)
609       -- test if already loaded
610       if type(id)=='number' then -- sometimes id is an integer
611          font_vert_table[n] = font_vert_table[id]; return
612       elseif (not id) or font_vert_table[n]  then return
613       end
614       local fname = id.filename
615       local bname = file.basename(fname)
616       if not fname then
617          font_vert_table[n] = {}; return
618       elseif font_vert_basename[bname] then
619          font_vert_table[n] = font_vert_basename[bname]; return
620       end
621       local vtable = {}
622       local a = id.resources.sequences
623       if a then
624          local s = id.shared.rawdata.descriptions
625          for i,v in pairs(a) do
626             if v.features.vert or v.features.vrt2 then
627                add_feature_table(v.subtables[1], s, vtable)
628             end
629          end
630       end
631       font_vert_basename[bname] = vtable
632       font_vert_table[n] = vtable
633    end
634    -- 縦書き用字形への変換
635    function get_vert_glyph(n, chr)
636       local fn = font_vert_table[n]
637       return fn and fn[chr] or chr
638    end
639    luatexbase.add_to_callback('luatexja.define_font',
640                               function (res, name, size, id)
641                                  prepare_vert_data(id, res)
642                               end,
643                               'prepare_vert_data', 1)
644
645    local function a (n, dat) font_vert_table[n] = dat end
646    ltjr.vert_addfunc = a
647
648 end
649
650 ------------------------------------------------------------------------
651 -- MISC
652 ------------------------------------------------------------------------
653 do
654    local is_ucs_in_japanese_char = ltjc.is_ucs_in_japanese_char_direct
655    local tex_set_attr = tex.setattribute
656    -- EXT: italic correction
657    function append_italic()
658       local p = to_direct(tex.nest[tex.nest.ptr].tail)
659       if p and getid(p)==id_glyph then
660          local f = getfont(p)
661          local g = node_new(id_kern)
662          setfield(g, 'subtype', 1)
663          set_attr(g, attr_icflag, ITALIC)
664          if is_ucs_in_japanese_char(p) then
665             f = has_attr(p, attr_curjfnt)
666             local j = font_metric_table[f]
667             setfield(g, 'kern', j.char_type[find_char_class(getchar(p), j)].italic)
668          else
669             local h = font_getfont(f)
670             if h then
671                setfield(g, 'kern', h.characters[getchar(p)].italic)
672             else
673                tex_set_attr(attr_icflag, 0)
674                return node_free(g)
675             end
676          end
677          node_write(g)
678          tex_set_attr(attr_icflag, 0)
679       end
680    end
681 end