1if not modules then modules = { } end modules ['good-ini'] = {
2 version = 1.000,
3 comment = "companion to font-lib.mkiv",
4 author = "Hans Hagen, PRAGMA-ADE, Hasselt NL",
5 copyright = "PRAGMA ADE / ConTeXt Development Team",
6 license = "see context related readme files"
7}
8
9
10
11local type, next = type, next
12local gmatch = string.gmatch
13local sortedhash, insert = table.sortedhash, table.insert
14
15local fonts = fonts
16
17local trace_goodies = false trackers.register("fonts.goodies", function(v) trace_goodies = v end)
18local report_goodies = logs.reporter("fonts","goodies")
19
20local allocate = utilities.storage.allocate
21local implement = interfaces.implement
22local findfile = resolvers.findfile
23local formatters = string.formatters
24
25local otf = fonts.handlers.otf
26local afm = fonts.handlers.afm
27local tfm = fonts.handlers.tfm
28
29local registerotffeature = otf.features.register
30local registerafmfeature = afm.features.register
31local registertfmfeature = tfm.features.register
32
33local addotffeature = otf.enhancers.addfeature
34
35local fontgoodies = fonts.goodies or { }
36fonts.goodies = fontgoodies
37
38local data = fontgoodies.data or { }
39fontgoodies.data = data
40
41local list = fontgoodies.list or { }
42fontgoodies.list = list
43
44fontgoodies.suffixes = { "lfg", "lua" }
45
46local contextsetups = fonts.specifiers.contextsetups
47
48function fontgoodies.report(what,trace,goodies)
49 if trace_goodies or trace then
50 local whatever = goodies[what]
51 if whatever then
52 report_goodies("goodie %a found in %a",what,goodies.name)
53 end
54 end
55end
56
57local function locate(filename)
58 local suffixes = fontgoodies.suffixes
59 for i=1,#suffixes do
60 local suffix = suffixes[i]
61 local fullname = findfile(file.addsuffix(filename,suffix))
62 if fullname and fullname ~= "" then
63 return fullname
64 end
65 end
66end
67
68local function loadgoodies(filename)
69 local goodies = data[filename]
70 if goodies ~= nil then
71
72 elseif type(filename) == "string" then
73 local fullname = locate(filename)
74 if not fullname or fullname == "" then
75 report_goodies("goodie file %a is not found (suffixes: % t)",filename,fontgoodies.suffixes)
76 data[filename] = false
77 else
78 goodies = dofile(fullname) or false
79 if not goodies then
80 report_goodies("goodie file %a is invalid",fullname)
81 return nil
82 elseif trace_goodies then
83 report_goodies("goodie file %a is loaded",fullname)
84 end
85 goodies.name = goodies.name or "no name"
86 for i=1,#list do
87 local g = list[i]
88 if trace_goodies then
89 report_goodies("handling goodie %a",g[1])
90 end
91 g[2](goodies)
92 end
93 goodies.initialized = true
94 data[filename] = goodies
95 end
96 end
97 return goodies
98end
99
100function fontgoodies.register(name,fnc,prepend)
101 for i=1,#list do
102 local g = list[i]
103 if g[1] == name then
104 g[2] = fnc
105 return
106 end
107 end
108 local g = { name, fnc }
109 if prepend then
110 insert(list,g,prepend == true and 1 or prepend)
111 else
112 insert(list,g)
113 end
114end
115
116fontgoodies.load = loadgoodies
117
118if implement then
119
120 implement {
121 name = "loadfontgoodies",
122 actions = loadgoodies,
123 arguments = "string",
124 overload = true,
125 }
126
127end
128
129
130
131local function setgoodies(tfmdata,value)
132 local goodies = tfmdata.goodies
133 if not goodies then
134 goodies = { }
135 tfmdata.goodies = goodies
136 end
137 for filename in gmatch(value,"[^, ]+") do
138
139 local ok = loadgoodies(filename)
140 if ok then
141 if trace_goodies then
142 report_goodies("assigning goodie %a",filename)
143 end
144 goodies[#goodies+1] = ok
145 end
146 end
147end
148
149
150
151local function flattenedfeatures(t,tt)
152
153 local tt = tt or { }
154 for i=1,#t do
155 local ti = t[i]
156 local ty = type(ti)
157 if ty == "table" then
158 flattenedfeatures(ti,tt)
159 elseif ty == "string" then
160 local set = contextsetups[ti]
161 if set then
162 for k, v in next, set do
163 if k ~= "number" then
164 tt[k] = v or nil
165 end
166 end
167 else
168
169 end
170 elseif tt[ti] == nil then
171 tt[ti] = true
172 end
173 end
174 for k, v in next, t do
175 if type(k) ~= "number" then
176 if type(v) == "table" then
177 flattenedfeatures(v,tt)
178 elseif tt[k] == nil then
179 tt[k] = v
180 end
181 end
182 end
183 return tt
184end
185
186
187
188local function prepare_features(goodies,name,set)
189 if set then
190 local ff = flattenedfeatures(set)
191 local fullname = goodies.name .. "::" .. name
192 local n, s = fonts.specifiers.presetcontext(fullname,"",ff)
193 goodies.featuresets[name] = s
194 if trace_goodies then
195 report_goodies("feature set %a gets number %a and name %a",name,n,fullname)
196 end
197 return n
198 end
199end
200
201fontgoodies.prepare_features = prepare_features
202
203local function initialize(goodies)
204 local featuresets = goodies.featuresets
205 if featuresets then
206 if trace_goodies then
207 report_goodies("checking featuresets in %a",goodies.name)
208 end
209 for name, set in next, featuresets do
210 prepare_features(goodies,name,set)
211 end
212 end
213end
214
215fontgoodies.register("featureset",initialize)
216
217local function setfeatureset(tfmdata,set,features)
218 local goodies = tfmdata.goodies
219 if goodies then
220 local properties = tfmdata.properties
221 local what
222 for i=1,#goodies do
223
224 local g = goodies[i]
225 what = g.featuresets and g.featuresets[set] or what
226 end
227 if what then
228 for feature, value in next, what do
229 if features[feature] == nil then
230 features[feature] = value
231 end
232 end
233 properties.mode = what.mode or properties.mode
234 end
235 end
236end
237
238
239
240function fontgoodies.registerpostprocessor(tfmdata,f,prepend)
241 local postprocessors = tfmdata.postprocessors
242 if not postprocessors then
243 tfmdata.postprocessors = { f }
244 elseif prepend then
245 insert(postprocessors,f,prepend == true and 1 or prepend)
246 else
247 insert(postprocessors,f)
248 end
249end
250
251local function setpostprocessor(tfmdata,processor)
252 local goodies = tfmdata.goodies
253 if goodies and type(processor) == "string" then
254 local found = { }
255 local asked = utilities.parsers.settings_to_array(processor)
256 for i=1,#goodies do
257 local g = goodies[i]
258 local p = g.postprocessors
259 if p then
260 for i=1,#asked do
261 local a = asked[i]
262 local f = p[a]
263 if type(f) == "function" then
264 found[a] = f
265 end
266 end
267 end
268 end
269 local postprocessors = tfmdata.postprocessors or { }
270 for i=1,#asked do
271 local a = asked[i]
272 local f = found[a]
273 if f then
274 postprocessors[#postprocessors+1] = f
275 end
276 end
277 if #postprocessors > 0 then
278 tfmdata.postprocessors = postprocessors
279 end
280 end
281end
282
283local function setextrafeatures(tfmdata)
284 local goodies = tfmdata.goodies
285 if goodies then
286 for i=1,#goodies do
287 local g = goodies[i]
288 local f = g.features
289 if f then
290 local rawdata = tfmdata.shared.rawdata
291 local done = { }
292
293 for i=1,#f do
294 local specification = f[i]
295 local feature = specification.name
296 if feature then
297 addotffeature(rawdata,feature,specification)
298 registerotffeature {
299 name = feature,
300 description = formatters["extra: %s"](feature)
301 }
302 end
303 done[i] = true
304 end
305
306 for feature, specification in sortedhash(f) do
307 if not done[feature] then
308 feature = specification.name or feature
309 specification.name = feature
310 addotffeature(rawdata,feature,specification)
311 registerotffeature {
312 name = feature,
313 description = formatters["extra: %s"](feature)
314 }
315 end
316 end
317 end
318 end
319 end
320end
321
322local function setextensions(tfmdata)
323 local goodies = tfmdata.goodies
324 if goodies then
325 for i=1,#goodies do
326 local g = goodies[i]
327 local e = g.extensions
328 if e then
329 local goodie = g.name or "unknown"
330 for i=1,#e do
331 local name = "extension-" .. i
332
333 otf.enhancers.addfeature(tfmdata.shared.rawdata,name,e[i])
334 end
335 end
336 end
337 end
338end
339
340
341
342local goodies_specification = {
343 name = "goodies",
344 description = "goodies on top of built in features",
345 initializers = {
346 position = 1,
347 base = setgoodies,
348 node = setgoodies,
349 }
350}
351
352registerotffeature(goodies_specification)
353registerafmfeature(goodies_specification)
354registertfmfeature(goodies_specification)
355
356
357
358registerotffeature {
359 name = "extrafeatures",
360 description = "extra features",
361 default = true,
362 initializers = {
363 position = 2,
364 base = setextrafeatures,
365 node = setextrafeatures,
366 }
367}
368
369registerotffeature {
370 name = "extensions",
371 description = "extensions to features",
372 default = true,
373 initializers = {
374 position = 2,
375 base = setextensions,
376 node = setextensions,
377 }
378}
379
380registerotffeature {
381 name = "featureset",
382 description = "goodie feature set",
383 initializers = {
384 position = 3,
385 base = setfeatureset,
386 node = setfeatureset,
387 }
388}
389
390registerotffeature {
391 name = "postprocessor",
392 description = "goodie postprocessor",
393 initializers = {
394 base = setpostprocessor,
395 node = setpostprocessor,
396 }
397}
398 |