OSDN Git Service

Changed encoding from EUC-JP to UTF-8.
[luatex-ja/luatexja.git] / src / luatexja-jfont.lua
1 local has_attr = node.has_attribute
2 local jfmfname
3
4 --====== METRIC
5 jfm={}; jfm.char_type={}; jfm.glue={}; jfm.kern={}
6
7 function jfm.define_char_type(t,lt) 
8    if not jfm.char_type[t] then jfm.char_type[t]={} end
9    jfm.char_type[t].chars=lt 
10 end
11 function jfm.define_type_dim(t,l,x,w,h,d,i)
12    if not jfm.char_type[t] then jfm.char_type[t]={} end
13    jfm.char_type[t].width=w; jfm.char_type[t].height=h;
14    jfm.char_type[t].depth=d; jfm.char_type[t].italic=i; 
15    jfm.char_type[t].left=l; jfm.char_type[t].down=x
16 end
17 function jfm.define_glue(b,a,w,st,sh)
18    local j=b*0x800+a
19    if not jfm.glue[j] then jfm.glue[j]={} end
20    jfm.glue[j].width=w; jfm.glue[j].stretch=st; 
21    jfm.glue[j].shrink=sh
22 end
23 function jfm.define_kern(b,a,w)
24    local j=b*0x800+a
25    if not jfm.kern[j] then jfm.kern[j]=w end
26 end
27
28 -- procedures for \loadjfontmetric
29 ltj.metrics={} -- this table stores all metric informations
30 ltj.font_metric_table={}
31
32 local function search_metric(key)
33    for i,v in ipairs(ltj.metrics) do 
34       if v.name==key then return i end
35    end
36    return nil
37 end
38
39 -- return nil iff ltj.metrics[ind] is a bad metric
40 local function consistency_check(ind)
41    local t = ltj.metrics[ind]
42    local r = ind
43    if t.dir~='yoko' then -- TODO: tate?
44       r=nil
45    elseif type(t.zw)~='number' or type(t.zh)~='number' then 
46       r=nil -- .zw, .zh must be present
47    else
48       local lbt = ltj.find_char_type('lindend',ind)
49       if lbt~=0 and t.char_type[lbt].chars~={'linebdd'} then
50          r=nil -- 'linebdd' must be isolated char_type
51       end
52    end
53    if not r then ltj.metrics[ind] = nil end
54    return r
55 end
56
57 function ltj.load_jfont_metric()
58    if jfmfname=='' then 
59       ltj.error('no JFM specified', 
60                 {[1]='To load and define a Japanese font, the name of JFM must be specified.',
61                  [2]="The JFM 'ujis' will be  used for now."})
62       jfmfname='ujis'
63    end
64    jfm.name=jfmfname .. ':' .. ltj.jfmvar
65    local i = search_metric(jfm.name)
66    local t = {}
67    if i then  return i end
68    jfm.char_type={}; jfm.glue={}; jfm.kern={}
69    ltj.loadlua('jfm-' .. jfmfname .. '.lua')
70    t.name=jfm.name
71    t.dir=jfm.dir; t.zw=jfm.zw; t.zh=jfm.zh
72    t.char_type=jfm.char_type
73    t.glue=jfm.glue; t.kern=jfm.kern
74    table.insert(ltj.metrics,t)
75    return consistency_check(#ltj.metrics)
76 end
77
78 function ltj.find_char_type(c,m)
79 -- c: character code, m
80    if not ltj.metrics[m] then return 0 end
81    for i, v in pairs(ltj.metrics[m].char_type) do
82       if i~=0 then
83         for j,w in pairs(v.chars) do
84            if w==c then return i end
85         end
86       end
87    end
88    return 0
89 end
90
91
92 --====== \setjfont\CS={...:...;jfm=metric;...}
93
94 function ltj.jfontdefX(g)
95   local t = token.get_next()
96   ltj.cstemp=token.csname_name(t)
97   if g then ltj.is_global = '\\global' else ltj.is_global = '' end
98   tex.sprint('\\expandafter\\font\\csname ' .. ltj.cstemp .. '\\endcsname')
99 end
100
101 function ltj.jfontdefY() -- for horizontal font
102    local j=ltj.load_jfont_metric()
103    local fn=font.id(ltj.cstemp)
104    local f = font.fonts[fn]
105    if not j then 
106      ltj.error("bad JFM '" .. jfmfname .. "'",
107                {[1]='The JFM file you specified is not valid JFM file.',
108                 [2]='Defining Japanese font is cancelled.'})
109      tex.sprint(ltj.is_global .. '\\expandafter\\let\\csname '
110                 .. ltj.cstemp .. '\\endcsname=\\relax')
111      return 
112    end
113    ltj.font_metric_table[fn]={}
114    ltj.font_metric_table[fn].jfm=j; ltj.font_metric_table[fn].size=f.size
115    tex.sprint(ltj.is_global .. '\\protected\\expandafter\\def\\csname '
116               .. ltj.cstemp .. '\\endcsname'
117               .. '{\\csname luatexja@curjfnt\\endcsname=' .. fn
118               .. ' \\zw=' .. tex.round(f.size*ltj.metrics[j].zw) .. 'sp'
119               .. '\\zh=' .. tex.round(f.size*ltj.metrics[j].zh) .. 'sp\\relax}')
120 end
121
122 local dr_orig = fonts.define.read
123 function fonts.define.read(name, size, id)
124    ltj.extract_metric(name)
125    -- In the present imple., we don't remove "jfm=..." from name.
126    local fontdata = dr_orig(name, size, id)
127    return fontdata
128 end
129
130 -- extract jfmfname and ltj.jfmvar
131 function ltj.extract_metric(name)
132    local basename=name
133    local tmp = utf.sub(basename, 1, 5)
134    jfmfname = ''
135    ltj.jfmvar = ''
136    if tmp == 'file:' or tmp == 'name:' or tmp == 'psft:' then
137       basename = utf.sub(basename, 6)
138    end
139
140    local p = utf.find(basename, ":")
141    if p then 
142       basename = utf.sub(basename, p+1)
143    else return 
144    end
145
146    p=1
147    while p do
148       local q= utf.find(basename, ";",p+1) or utf.len(basename)+1
149       if utf.sub(basename,p,p+3)=='jfm=' and q>p+4 then
150          jfmfname = utf.sub(basename,p+4,q-1)
151       elseif utf.sub(basename,p,p+6)=='jfmvar=' and q>p+6 then
152          ltj.jfmvar = utf.sub(basename,p+7,q-1)
153       end
154       if utf.len(basename)+1==q then p=nil else p=q+1 end
155    end
156    return
157 end
158
159
160 --====== Range of Japanese characters.
161 -- jcr_table_main[chr_code] = index
162 -- index : internal 0, 1, 2, ..., 216               0: 'other'
163 --         external    1  2       216, (out of range): 'other'
164
165 -- init: 
166 local ucs_out = 0x110000
167 local jcr_table_main = {}
168 local jcr_cjk = 0
169 local jcr_noncjk = 1
170
171 for i=0x80,0xFF do
172    jcr_table_main[i]=1
173 end
174 for i=0x100,ucs_out-1 do
175    jcr_table_main[i]=0
176 end
177
178 function ltj.def_char_range(b,e,ind) -- ind: external range number
179    if ind<0 or ind>216 then 
180       ltj.error('Invalid range number (' .. ind .. '), should be in the range 1..216.',
181                 {}); return
182    end
183    for i=math.max(0x80,b),math.min(ucs_out-1,e) do
184       jcr_table_main[i]=ind
185    end
186 end
187
188 local function get_char_jcrcode(p) -- for internal use
189    local i
190    local c = p.char
191    if c<0x80 then return jcr_noncjk else i=jcr_table_main[c] end
192    return math.floor(has_attr(p,
193          luatexbase.attributes['luatexja@kcat'..math.floor(i/31)])
194          /math.pow(2, i%31))%2
195 end
196
197 function ltj.get_char_jcrnumber(c) -- return the (external) range number
198    if c<0x80 or c>=ucs_out then return -1
199    else 
200       local i = jcr_table_main[c] or 0
201       if i==0 then return 217 else return i end
202    end
203 end
204
205 function ltj.get_jcr_setting(i) -- i: internal range number
206    return math.floor(tex.getattribute(luatexbase.attributes['luatexja@kcat'..math.floor(i/31)])
207          /math.pow(2, i%31))%2
208 end
209
210 --  和文文字と認識する unicode の範囲
211 function ltj.is_ucs_in_japanese_char(p)
212    return (get_char_jcrcode(p)~=jcr_noncjk) 
213 end
214
215 function ltj.set_jchar_range(g, i) -- i: external range number
216    if i==0 then return 
217    else
218       local kc
219       if i>0 then kc=0 else kc=1; i=-i end
220       if i>216 then i=0 end
221       local attr = luatexbase.attributes['luatexja@kcat'..math.floor(i/31)]
222       local a = tex.getattribute(attr)
223       local k = math.pow(2, i%31)
224       tex.setattribute(g,attr,(math.floor(a/k/2)*2+kc)*k+a%k)
225    end
226 end