1if not modules then modules = { } end modules ['s-fonts-features'] = {
2 version = 1.001,
3 comment = "companion to s-fonts-features.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
9moduledata.fonts = moduledata.fonts or { }
10moduledata.fonts.features = moduledata.fonts.features or { }
11
12
13
14local rawget = rawget
15local insert, remove, sortedhash = table.insert, table.remove, table.sortedhash
16
17local v_yes = interfaces.variables.yes
18local v_no = interfaces.variables.no
19local c_name = interfaces.constants.name
20
21local context = context
22local NC, NR, bold = context.NC, context.NR, context.bold
23
24function moduledata.fonts.features.showused(specification)
25
26 specification = interfaces.checkedspecification(specification)
27
28
29
30 context.starttabulate { "|T|T|T|T|T|" }
31
32 context.HL()
33
34 NC() bold("feature")
35 NC()
36 NC() bold("description")
37 NC() bold("value")
38 NC() bold("internal")
39 NC() NR()
40
41 context.HL()
42
43 local usedfeatures = fonts.handlers.otf.statistics.usedfeatures
44 local features = fonts.handlers.otf.tables.features
45 local descriptions = fonts.handlers.otf.features.descriptions
46
47 for feature, keys in sortedhash(usedfeatures) do
48
49 local done = false
50 for k, v in sortedhash(keys) do
51 if done then
52 NC()
53 NC()
54 NC()
55 elseif rawget(descriptions,feature) then
56 NC() context(feature)
57 NC() context("+")
58 NC() context.escaped(descriptions[feature])
59 done = true
60 elseif rawget(features,feature) then
61 NC() context(feature)
62 NC()
63 NC() context.escaped(features[feature])
64 done = true
65 else
66 NC() context(feature)
67 NC() context("-")
68 NC()
69 done = true
70 end
71 NC() context(k)
72 NC() context(tostring(v))
73 NC() NR()
74 end
75
76 end
77
78 context.HL()
79
80 context.stoptabulate()
81
82end
83
84local function collectkerns(tfmdata,feature)
85 local combinations = { }
86 local resources = tfmdata.resources
87 local characters = tfmdata.characters
88 local sequences = resources.sequences
89 local lookuphash = resources.lookuphash
90 local feature = feature or "kern"
91 if sequences then
92 for i=1,#sequences do
93 local sequence = sequences[i]
94 if sequence.features and sequence.features[feature] then
95 local steps = sequence.steps
96 for i=1,#steps do
97 local step = steps[i]
98 local format = step.format
99 for unicode, hash in table.sortedhash(step.coverage) do
100 local kerns = combinations[unicode]
101 if not kerns then
102 kerns = { }
103 combinations[unicode] = kerns
104 end
105 for otherunicode, kern in table.sortedhash(hash) do
106 if format == "pair" then
107 local f = kern[1]
108 local s = kern[2]
109 if f then
110 if s then
111
112 else
113 if not kerns[otherunicode] and f[3] ~= 0 then
114 kerns[otherunicode] = f[3]
115 end
116 end
117 elseif s then
118
119 end
120 elseif format == "kern" then
121 if not kerns[otherunicode] and kern ~= 0 then
122 kerns[otherunicode] = kern
123 end
124 end
125 end
126 end
127 end
128 end
129 end
130 end
131
132 return combinations
133end
134
135local showkernpair = context.showkernpair
136
137function moduledata.fonts.features.showbasekerns(specification)
138
139 specification = interfaces.checkedspecification(specification)
140 local id, cs = fonts.definers.internal(specification,"<module:fonts:features:font>")
141 local tfmdata = fonts.hashes.identifiers[id]
142 local done = false
143 for unicode, character in sortedhash(tfmdata.characters) do
144 local kerns = character.kerns
145 if kerns then
146 context.par()
147 for othercode, kern in sortedhash(kerns) do
148 showkernpair(unicode,kern,othercode)
149 end
150 context.par()
151 done = true
152 end
153 end
154 if not done then
155 context("no kern pairs found")
156 context.par()
157 end
158end
159
160function moduledata.fonts.features.showallkerns(specification)
161 specification = interfaces.checkedspecification(specification)
162 local id, cs = fonts.definers.internal(specification,"<module:fonts:features:font>")
163 local tfmdata = fonts.hashes.identifiers[id]
164 local allkerns = collectkerns(tfmdata)
165 local characters = tfmdata.characters
166 local hfactor = tfmdata.parameters.hfactor
167 if next(allkerns) then
168 for first, pairs in sortedhash(allkerns) do
169 context.par()
170 for second, kern in sortedhash(pairs) do
171
172
173
174
175 showkernpair(first,kern*hfactor,second)
176 end
177 context.par()
178 end
179 else
180 context("no kern pairs found")
181 context.par()
182 end
183end
184
185function moduledata.fonts.features.showfeatureset(specification)
186 specification = interfaces.checkedspecification(specification)
187 local name = specification[c_name]
188 if name then
189 local s = fonts.specifiers.contextsetups[name]
190 if s then
191 local t = table.copy(s)
192 t.number = nil
193 if t and next(t) then
194 context.starttabulate { "|T|T|" }
195 for k, v in sortedhash(t) do
196 NC() context(k) NC() context(v == true and v_yes or v == false and v_no or tostring(v)) NC() NR()
197 end
198 context.stoptabulate()
199 end
200 end
201 end
202end
203
204
205
206local function collectligatures(tfmdata)
207 local sequences = tfmdata.resources.sequences
208
209 if not sequences then
210 return
211 end
212
213
214
215 local series = { }
216 local stack = { }
217 local max = 0
218
219 local function add(v)
220 local n = #stack
221 if n > max then
222 max = n
223 end
224 series[#series+1] = { v, unpack(stack) }
225 end
226
227 local function make(tree)
228 for k, v in sortedhash(tree) do
229 if k == "ligature" then
230 add(v)
231 elseif tonumber(v) then
232 insert(stack,k)
233 add(v)
234 remove(stack)
235 else
236 insert(stack,k)
237 make(v)
238 remove(stack)
239 end
240 end
241 end
242
243 for i=1,#sequences do
244 local sequence = sequences[i]
245 if sequence.type == "gsub_ligature" then
246 local steps = sequence.steps
247 for i=1,#steps do
248 local step = steps[i]
249 local coverage = step.coverage
250 if coverage then
251 make(coverage)
252 end
253 end
254 end
255 end
256
257 return series, max
258end
259
260function moduledata.fonts.features.showallligatures(specification)
261 specification = interfaces.checkedspecification(specification)
262 local id, cs = fonts.definers.internal(specification,"<module:fonts:features:font>")
263 local tfmdata = fonts.hashes.identifiers[id]
264 local allligatures,
265 max = collectligatures(tfmdata)
266 local characters = tfmdata.characters
267 local descriptions = tfmdata.descriptions
268 if #allligatures > 0 then
269 context.starttabulate { "|T|" .. string.rep("|",max) .. "|T|T|" }
270 for i=1,#allligatures do
271 local s = allligatures[i]
272 local n = #s
273 local u = s[1]
274 local c = characters[u]
275 local d = descriptions[u]
276 NC()
277 context("%U",u)
278 NC()
279 context("\\setfontid%i\\relax",id)
280 context.char(u)
281 NC()
282 context("\\setfontid%i\\relax",id)
283 for i=2,n do
284 context.char(s[i])
285 NC()
286 end
287 for i=n+1,max do
288 NC()
289 end
290 context(d.name)
291 NC()
292 context(c.tounicode)
293 NC()
294 NR()
295 end
296 context.stoptabulate()
297 else
298 context("no ligatures found")
299 context.par()
300 end
301end
302
303
304function moduledata.fonts.features.showallfeatures(specification)
305 specification = interfaces.checkedspecification(specification)
306 local id, cs = fonts.definers.internal(specification,"<module:fonts:features:font>")
307 local tfmdata = fonts.hashes.identifiers[id]
308 local sequences = tfmdata.resources.sequences
309
310 context.starttabulate { "|T|T|Tc|T|T|Tp|" }
311
312 NC() bold("\\letterhash")
313 NC() bold("type")
314 NC() bold("\\letterhash steps")
315 NC() bold("feature")
316 NC() bold("script")
317 NC() bold("language")
318 NC() NR()
319 context.HL()
320
321 for i=1,#sequences do
322 local s = sequences[i]
323 local features = s.features
324 if features then
325 local done1 = false
326 NC() context(i)
327 NC() context(s.type)
328 NC() context(s.nofsteps)
329 for feature, scripts in table.sortedhash(features) do
330 NC()
331 if done1 then
332 NC() NC() NC()
333 else
334 context(feature)
335 done1 = true
336 end
337 local done2 = false
338 for script, languages in table.sortedhash(scripts) do
339 if done2 then
340 NC() NC() NC() NC()
341 else
342 done2 = true
343 end
344 NC() context(script)
345 NC() context("% t",table.sortedkeys(languages))
346 NC() NR()
347 end
348 end
349 else
350 NC() context(i)
351 NC() context(s.type)
352 NC() context(s.nofsteps)
353 NC() NC() NC() NC() NR()
354 end
355 end
356
357 context.stoptabulate()
358end
359
360local function collect(tfmdata,id,specification,feature)
361 local validlookups, lookuplist = fonts.handlers.otf.collectlookups(
362 tfmdata.shared.rawdata,
363 feature,
364 specification.script or "math",
365 specification.language or "dflt"
366 )
367 if lookuplist then
368 local descriptions = tfmdata.descriptions
369 for i=1,#lookuplist do
370 local lookup = lookuplist[i]
371 if lookup.type == "gsub_single" then
372 local steps = lookup.steps
373 context.startsubject { title = feature }
374 context.starttabulate { "|T|||T|" }
375 for i=1,lookup.nofsteps do
376 local c = steps[i].coverage
377 for k, v in table.sortedhash(c) do
378 NC() context(descriptions[k].name)
379 NC() context.showfontidchar(id,k)
380 NC() context.showfontidchar(id,v)
381 NC() context(descriptions[v].name)
382 NC() NR()
383 end
384 end
385 context.stoptabulate()
386 context.stopsubject()
387 elseif lookup.type == "gsub_alternate" then
388 local steps = lookup.steps
389 context.startsubject { title = feature }
390 context.starttabulate { "|T|||Tp|" }
391 for i=1,lookup.nofsteps do
392 local c = steps[i].coverage
393 for k, v in table.sortedhash(c) do
394 NC() context(descriptions[k].name)
395 NC() context.showfontidchar(id,k)
396 NC()
397 for i=1,#v do
398 if i > 1 then context(" ") end
399 context.showfontidchar(id,v[i])
400 end
401 NC()
402 for i=1,#v do
403 if i > 1 then context(" ") end
404 context(descriptions[v[i]].name)
405 end
406 NC() NR()
407 end
408 end
409 context.stoptabulate()
410 context.stopsubject()
411 end
412 end
413 end
414end
415
416function moduledata.fonts.features.showsubstitutions(specification)
417 specification = interfaces.checkedspecification(specification)
418 local id, cs = fonts.definers.internal(specification,"<module:fonts:features:font>")
419 local tfmdata = fonts.hashes.identifiers[id]
420 local feature = specification.feature
421 if feature == "*" then
422 local features = tfmdata.shared.rawdata.resources.features
423 for k in table.sortedhash(features.gsub) do
424 collect(tfmdata,id,specification,k)
425 end
426 else
427 collect(tfmdata,id,specification,feature)
428 end
429end
430
431
432
433
434 |