1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
|
--
-- ltj-rmlgbm.lua
--
luatexja.load_module 'base'; local ltjb = luatexja.base
local get_modtime
do
local find_file = kpse.find_file
local lfs = require"lfs"
local file_attributes = lfs.attributes
get_modtime = function (f)
f = f and find_file(f, 'cmap files')
return f and file_attributes(f, 'modification')
end
end
local cidfont_data = {}
local cache_chars = {}
local cache_ver = 14
local sub = string.sub
local identifiers = fonts.hashes.identifiers
local cid_reg, cid_order, cid_supp, cid_name
local cid_replace = {
["Adobe-Japan1"] = {"UniJIS2004-UTF32", 23059, 7,
function (i)
if (231<=i and i<=632) or (8718<=i and i<=8719)
or (12063<=i and i<=12087) then
return 327680 -- 655360/2
elseif 9758<=i and i<=9778 then
return 218453 -- 655360/3
elseif 9738<=i and i<=9757 then
return 163840 -- 655360/4
end
end},
-- 基本的には JIS X 0213:2004 に沿ったマッピング
["Adobe-Korea1"] = {"UniKS-UTF32", 18351, 2,
function (i)
if 8094<=i and i<=8100 then
return 327680 -- 655360/2
end
end},
["Adobe-GB1"] = {"UniGB-UTF32", 30571, 6,
function (i)
if (814<=i and i<=939) or (i==7716)
or (22355<=i and i<=22357) then
return 327680 -- 655360/2
end
end},
["Adobe-CNS1"] = {"UniCNS-UTF32", 19178, 7,
function (i)
if (13648<=i and i<=13742) or (i==17603) then
return 327680 -- 655360/2
end
end},
["Adobe-KR"] = {"UniAKR-UTF32", 22896, 9,
function (i)
if i==3057 then
return 655360*2
elseif i==3058 then
return 655360*3
elseif i==12235 or i==12236 then
return 163840 -- 655360/4
end
end},
}
-- reading CID maps
local make_cid_font
do
local line, fh -- line, file handler
local tt,cidm -- characters, cid->(Unicode)
local function load_cid_char(cid_dec, mke)
local cid, ucs, ucsa
line = fh:read("*l")
while line do
if string.find(line, "end...?char") then
line = fh:read("*l"); return
else -- WMA l is in the form "<%x+>%s%d+"
ucs, cid = string.match(line, "<(%x+)>%s+<?(%x+)>?")
cid = cid_dec(cid); ucs = tonumber(ucs, 16);
if not tt[ucs] then
tt[ucs] = mke(cid); cidm[cid]=ucs
end
end
line = fh:read("*l")
end
end
local function load_cid_range(inc, cid_dec, mke)
local bucs, eucs, cid
line = fh:read("*l")
while line do
if string.find(line, "end...?range") then
line = fh:read("*l"); return
else -- WMA l is in the form "<%x+>%s+<%x+>"
bucs, eucs, cid = string.match(line, "<(%x+)>%s+<(%x+)>%s+<?(%x+)>?")
cid = cid_dec(cid);
bucs = tonumber(bucs, 16); eucs = tonumber(eucs, 16)
for ucs = bucs, eucs do
if not tt[ucs] then
tt[ucs] = mke(cid); cidm[cid]=ucs
end
cid = inc(cid)
end
end
line = fh:read("*l")
end
end
local function open_cmap_file(name, inc, cid_dec, mke)
local fn = kpse.find_file(name, 'cmap files')
if fn then
fh = io.open(fn, "r")
line = fh:read("*l")
while line do
if string.find(line, "%x+%s+begin...?char") then
load_cid_char(cid_dec, mke)
elseif string.find(line, "%x+%s+begin...?range") then
load_cid_range(inc, cid_dec, mke)
else
line = fh:read("*l")
end
end
fh:close();
end
end
local function increment(a) return a+1 end
local function entry(a)
return {index = a}
end
local feat_dummy_vert = { gsub={vert={dflt={dflt=true}}} }
local seq_dummy_vert={{
features={vert={dflt={dflt=true}}},
--flags={false,false,false,false},
--index=1, name="s_s_0", skiphash=false, steps={coverage={},index=1},
["type"]="gsub_single", order='vert',
}}
make_cid_font = function ()
local kx = cid_replace[cid_name]
if not kx then return end
local k = {
cidinfo = { ordering=cid_order, registry=cid_reg, supplement=kx[3] },
encodingbytes = 2, extend=1000, format = 'opentype',
direction = 0, characters = {}, parameters = {
ascender = 655360*0.88,
descender = 655360*0.12,
},
embedding = "no", cache = "yes", factor = 0, hfactor = 0, vfactor = 0,
tounicode = 1, filename="",
properties = { language = "dflt", script = "dflt" },
}
cidfont_data[cid_name] = k
-- CID => Unicode 符号空間
local tth, cidmo = {}, {}
tt, cidm = tth, cidmo
for i = 0,kx[2] do cidm[i] = -1 end
open_cmap_file(kx[1] .. "-H", increment, tonumber, entry)
k.characters = tth
-- Unicode にマップされなかった文字の処理
-- これらは TrueType フォントを使って表示するときはおかしくなる
local ttu, pricode = {}, 0xF0000
for i,v in ipairs(cidmo) do
if v==-1 then
tth[pricode], cidmo[i], pricode
= { index = i }, pricode, pricode+1;
end
ttu[i] = cidmo[i]
ttu[cid_order .. '.' .. i] = cidmo[i]
end
-- shared
k.shared = {
otfdata = {
cidinfo= k.cidinfo, verbose = false,
shared = { featuredata = {}, },
},
dynamics = {}, processes = {},
rawdata = {}, features={},
}
k.resources = {
unicodes = ttu,
features = feat_dummy_vert,
sequences = seq_dummy_vert,
}
k.descriptions = {}
cache_chars[cid_name] = { [655360] = k.characters }
-- 縦書用字形
tt, cidm = {}, {}
local ttv = {}; k.ltj_vert_table = ttv
for i = 0,kx[2] do cidm[i] = -1 end
open_cmap_file(kx[1] .. "-V", increment, tonumber, entry)
for i,v in pairs(tt) do
ttv[i] = cidmo[v.index] -- "unicode" of vertical variant
end
-- tounicode エントリ
local cidp = {nil, nil}; tt, ttu, cidm = {}, {}, {}
open_cmap_file(cid_name .. "-UCS2",
function(a)
a[2] = a[2] +1 ; return a
end,
function(a)
cidp[1] = string.upper(string.sub(a,1,string.len(a)-4))
cidp[2] = tonumber(string.sub(a,-4),16)
return cidp
end,
function(a) return a[1] ..string.format('%04X',a[2]) end)
-- tt は cid -> tounicode になっているので cidm -> tounicode に変換
local kxf = kx[4]
for i,v in ipairs(cidmo) do
k.characters[v].width = kxf(i)
if v>=0xF0000 then
k.characters[v].tounicode = tt[i]
end
end
-- Save
if k and k.characters and k.characters[46] then
k.characters[46].width = math.floor(655360/14);
end
ltjb.save_cache("ltj-cid-auto-" .. string.lower(cid_name),
{version = cache_ver,
cid2ucs_modtime = get_modtime(cid_name..'-UCS2'),
ucs2cid = kx[1]..'-H',
ucs2cid_modtime = get_modtime(kx[1]..'-H'),
k})
k.shared.rawdata.resources=k.resources
k.shared.rawdata.descriptions=k.descriptions
end
end
--
local cidf_vert_processor
do
local traverse_glyph, is_node = node.direct.traverse_glyph, node.is_node
local to_direct = node.direct.todirect
local id_glyph = node.id 'glyph'
local getfont = node.direct.getfont
local getchar = node.direct.getchar
local setchar = node.direct.setchar
local font_getfont = font.getfont
cidf_vert_processor = {
function (head, fnum)
local fontdata = font_getfont(fnum)
if head and luatexja.jfont.font_metric_table[fnum] and luatexja.jfont.font_metric_table[fnum].vert_activated then
local vt = fontdata.ltj_vert_table
local nh = is_node(head) and to_direct(head) or head
for n in traverse_glyph(head) do
local c = getchar(n)
if getfont(n)==fnum then setchar(n, vt[c] or c) end
end
return head, false
end
end
}
end
local dummy_vht, dummy_vorg = {}, {}
setmetatable(dummy_vht, {__index = function () return 1 end } )
setmetatable(dummy_vorg, {__index = function () return 0.88 end } )
local function cid_cache_outdated(t)
return (t.version~=cache_ver)
or (t.cid2ucs_modtime ~= get_modtime(cid_name..'-UCS2'))
or (t.ucs2cid_modtime ~= get_modtime(t.ucs2cid))
end
local function read_cid_font()
local dat = ltjb.load_cache("ltj-cid-auto-" .. string.lower(cid_name),
cid_cache_outdated)
if dat then
dat[1].shared.rawdata.resources=dat[1].resources
dat[1].shared.rawdata.descriptions=dat[1].descriptions
cidfont_data[cid_name] = dat[1]
cache_chars[cid_name] = { [655360] = cidfont_data[cid_name].characters }
else
-- Now we must create the virtual metrics from CMap.
make_cid_font()
end
if cidfont_data[cid_name] then
cidfont_data[cid_name].shared.processes = cidf_vert_processor
cidfont_data[cid_name].resources.ltj_extra
= { ind_to_uni = cidfont_data[cid_name].resources.unicodes,
vheight = dummy_vht, vorigin = dummy_vorg }
for i,v in pairs(cidfont_data[cid_name].characters) do
if not v.width then v.width = 655360 end
v.height, v.depth = 576716.8, 78643.2 -- optimized for jfm-ujis.lua
end
return cidfont_data[cid_name]
else
return nil
end
end
-- High-level
local function prepare_cid_font(reg, ord)
cid_reg, cid_order, cid_name, cid_supp = reg, ord, reg .. '-' .. ord
return cidfont_data[cid_name] or read_cid_font()
end
local definers = fonts.definers
local function mk_rml(name, size, id)
local specification = definers.analyze(name,size)
--specification = definers.resolve(specification) (not needed)
specification.detail = specification.detail or ''
do
local n = specification.name
if sub(n,1,1)=="{" then n=sub(n,2) end
if sub(n,-1)=="}" then n=sub(n,1,-2) end
specification.name=n
end
local fontdata = {}
local cachedata = {}
local s = cidfont_data[cid_name]
for k, v in pairs(s) do
fontdata[k] = v
cachedata[k] = v
end
fontdata.characters = nil
cachedata.characters = nil
fontdata.shared = nil
cachedata.shared = nil
if s.shared then
cachedata.shared = {}
local shared = cachedata.shared
for k, v in pairs(s.shared) do
shared[k] = v
end
end
-- characters & scaling
if size < 0 then size = -size * 655.36 end
local scale = size / 655360
do
local def_height = 0.88 * size
-- character's default height (optimized for jfm-ujis.lua)
local def_depth = 0.12 * size -- and depth.
if not cache_chars[cid_name][size] then
cache_chars[cid_name][size] = {}
for k, v in pairs(cache_chars[cid_name][655360]) do
cache_chars[cid_name][size][k] = {
index = v.index, width = v.width * scale,
height = def_height, depth = def_depth, tounicode = v.tounicode,
}
end
end
fontdata.characters = cache_chars[cid_name][size]
cachedata.characters = cache_chars[cid_name][size]
end
luatexja.rmlgbm.vert_addfunc(id, fontdata)
-- other parameters
do
local parameters = {}
for k, v in pairs(s.parameters) do parameters[k] = v * scale end
fontdata.parameters = parameters; fontdata.size = size; fontdata.resources = s.resources
cachedata.parameters = parameters; cachedata.size = size; cachedata.resources = s.resources
end
-- no embedding
local var = ''
local s = string.match(specification.detail, 'slant=([+-]*%d*%.?%d)')
if s and e~=0 then
s = s * 1000
var, fontdata.slant = var .. 's' .. tostring(s), s
end
local e = string.match(specification.detail, 'extend=([+-]*%d*%.?%d)')
if e and e~=1 then
e = e * 1000
var, fontdata.extend = var .. 'x' .. tostring(e), e
end
fontdata.name = specification.name .. size .. var; cachedata.name = fontdata.name
fontdata.fullname = specification.name .. var; cachedata.fullname = fontdata.fullname
fontdata.psname = specification.name; cachedata.psname = fontdata.psname
identifiers[id] = cachedata
return fontdata
end
local function font_callback(name, size, id, fallback)
if sub(name,1,1)=="{" and sub(name,-1)=="}" then name = sub(name,2,-2) end
local p = name:find(":") or 0
if sub(name,1, p-1) == 'psft' then
local s = "Adobe-Japan1-7"
local basename = sub(name,p+1)
local p = basename:find(":")
local q = basename:find("/[BI][BI]?")
if q and p and q<=p then
basename = basename:gsub('/[BI][BI]?', '', 1)
p = basename:find(":")
end
if p then
local xname = sub(basename,p+1)
p = 1
while p do
local q = xname:find(";", p+1) or xname:len()+1
if sub(xname,p, p+3)=='cid=' and q>p+4 then
s = sub(xname,p+4, q-1)
end
if xname:len()+1==q then p = nil else p = q + 1 end
end
end
cid_reg, cid_order = string.match(s, "^(.-)%-(.-)%-(%d-)$")
if not cid_reg then
cid_reg, cid_order = string.match(s, "^(.-)%-(.-)$")
end
if not prepare_cid_font(cid_reg, cid_order) then
ltjb.package_error('luatexja',
"bad cid key `" .. s .. "'",
"I couldn't find any non-embedded font information for the CID\n" ..
'`' .. s .. "'. For now, I'll use `Adobe-Japan1-6'.\n"..
'Please contact the LuaTeX-ja project team.')
cid_name = "Adobe-Japan1"
end
return mk_rml(basename, size, id)
else
local fontdata=fallback(name, size, id)
if type (fontdata) == "table" and fontdata.encodingbytes == 2 then
luatexbase.call_callback ("luaotfload.patch_font", fontdata, name, id)
else
luatexbase.call_callback ("luaotfload.patch_font_unsafe", fontdata, name, id)
end
return fontdata
end
end
luatexja.rmlgbm = {
prepare_cid_font = prepare_cid_font,
cidfont_data = cidfont_data,
font_callback = font_callback,
vert_addfunc = function () end, -- dummy, set in ltj-direction.lua
}
prepare_cid_font('Adobe', 'Japan1')
|