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
|
if not modules then modules = { } end modules ['font-cid'] = {
version = 1.001,
comment = "companion to font-otf.lua (cidmaps)",
author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
copyright = "PRAGMA ADE / ConTeXt Development Team",
license = "see context related readme files"
}
local format, match, lower = string.format, string.match, string.lower
local tonumber = tonumber
local P, S, R, C, V, lpegmatch = lpeg.P, lpeg.S, lpeg.R, lpeg.C, lpeg.V, lpeg.match
local fonts, logs, trackers = fonts, logs, trackers
local trace_loading = false trackers.register("otf.loading", function(v) trace_loading = v end)
local report_otf = logs.reporter("fonts","otf loading")
local cid = { }
fonts.cid = cid
local cidmap = { }
local cidmax = 10
-- original string parser: 0.109, lpeg parser: 0.036 seconds for Adobe-CNS1-4.cidmap
--
-- 18964 18964 (leader)
-- 0 /.notdef
-- 1..95 0020
-- 99 3000
local number = C(R("09","af","AF")^1)
local space = S(" \n\r\t")
local spaces = space^0
local period = P(".")
local periods = period * period
local name = P("/") * C((1-space)^1)
local unicodes, names = { }, { } -- we could use Carg now
local function do_one(a,b)
unicodes[tonumber(a)] = tonumber(b,16)
end
local function do_range(a,b,c)
c = tonumber(c,16)
for i=tonumber(a),tonumber(b) do
unicodes[i] = c
c = c + 1
end
end
local function do_name(a,b)
names[tonumber(a)] = b
end
local grammar = P { "start",
start = number * spaces * number * V("series"),
series = (spaces * (V("one") + V("range") + V("named")))^1,
one = (number * spaces * number) / do_one,
range = (number * periods * number * spaces * number) / do_range,
named = (number * spaces * name) / do_name
}
local function loadcidfile(filename)
local data = io.loaddata(filename)
if data then
unicodes, names = { }, { }
lpegmatch(grammar,data)
local supplement, registry, ordering = match(filename,"^(.-)%-(.-)%-()%.(.-)$")
return {
supplement = supplement,
registry = registry,
ordering = ordering,
filename = filename,
unicodes = unicodes,
names = names
}
end
end
cid.loadfile = loadcidfile -- we use the frozen variant
local template = "%s-%s-%s.cidmap"
local function locate(registry,ordering,supplement)
local filename = format(template,registry,ordering,supplement)
local hashname = lower(filename)
local found = cidmap[hashname]
if not found then
if trace_loading then
report_otf("checking cidmap, registry: %s, ordering: %s, supplement: %s, filename: %s",registry,ordering,supplement,filename)
end
local fullname = resolvers.findfile(filename,'cid') or ""
if fullname ~= "" then
found = loadcidfile(fullname)
if found then
if trace_loading then
report_otf("using cidmap file %s",filename)
end
cidmap[hashname] = found
found.usedname = file.basename(filename)
end
end
end
return found
end
-- cf Arthur R. we can safely scan upwards since cids are downward compatible
function cid.getmap(specification)
if not specification then
report_otf("invalid cidinfo specification (table expected)")
return
end
local registry = specification.registry
local ordering = specification.ordering
local supplement = specification.supplement
-- check for already loaded file
local filename = format(registry,ordering,supplement)
local found = cidmap[lower(filename)]
if found then
return found
end
if trace_loading then
report_otf("needed cidmap, registry: %s, ordering: %s, supplement: %s",registry,ordering,supplement)
end
found = locate(registry,ordering,supplement)
if not found then
local supnum = tonumber(supplement)
local cidnum = nil
-- next highest (alternatively we could start high)
if supnum < cidmax then
for s=supnum+1,cidmax do
local c = locate(registry,ordering,s)
if c then
found, cidnum = c, s
break
end
end
end
-- next lowest (least worse fit)
if not found and supnum > 0 then
for s=supnum-1,0,-1 do
local c = locate(registry,ordering,s)
if c then
found, cidnum = c, s
break
end
end
end
-- prevent further lookups -- somewhat tricky
registry = lower(registry)
ordering = lower(ordering)
if found and cidnum > 0 then
for s=0,cidnum-1 do
local filename = format(template,registry,ordering,s)
if not cidmap[filename] then
cidmap[filename] = found
end
end
end
end
return found
end
|