1if not modules then modules = { } end modules [ ' font-imp-quality ' ] = {
2 version = 1 . 001 ,
3 comment = " companion to font-ini.mkiv and hand-ini.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
9if not context then return end
10
11local next , type , tonumber = next , type , tonumber
12
13local fonts = fonts
14local utilities = utilities
15
16local handlers = fonts . handlers
17local otf = handlers . otf
18local afm = handlers . afm
19local registerotffeature = otf . features . register
20local registerafmfeature = afm . features . register
21
22local allocate = utilities . storage . allocate
23local getparameters = utilities . parsers . getparameters
24
25local implement = interfaces and interfaces . implement
26
27local trace_protrusion = false trackers . register ( " fonts.protrusion " , function ( v ) trace_protrusion = v end )
28local trace_expansion = false trackers . register ( " fonts.expansion " , function ( v ) trace_expansion = v end )
29
30local report_expansions = logs . reporter ( " fonts " , " expansions " )
31local report_protrusions = logs . reporter ( " fonts " , " protrusions " )
32
33
34
35
36
37local function get_class_and_vector ( tfmdata , value , where )
38 local g_where = tfmdata . goodies and tfmdata . goodies [ where ]
39 local f_where = fonts [ where ]
40 local g_classes = g_where and g_where . classes
41 local f_classes = f_where and f_where . classes
42 local class = ( g_classes and g_classes [ value ] ) or ( f_classes and f_classes [ value ] )
43 if class then
44 local class_vector = class . vector
45 local g_vectors = g_where and g_where . vectors
46 local f_vectors = f_where and f_where . vectors
47 local vector = ( g_vectors and g_vectors [ class_vector ] ) or ( f_vectors and f_vectors [ class_vector ] )
48 return class , vector
49 end
50end
51
52
53
54
55
56local expansions = fonts . expansions or allocate ( )
57
58fonts . expansions = expansions
59
60local classes = expansions . classes or allocate ( )
61local vectors = expansions . vectors or allocate ( )
62
63expansions . classes = classes
64expansions . vectors = vectors
65
66classes . preset = {
67 stretch = 2 ,
68 shrink = 2 ,
69 step = . 5 ,
70 factor = 1 ,
71}
72
73classes [ ' quality ' ] = {
74 stretch = 2 ,
75 shrink = 2 ,
76 step = . 5 ,
77 vector = ' default ' ,
78 factor = 1 ,
79}
80
81vectors [ ' default ' ] = {
82 [ 0x0041 ] = 0 . 5 ,
83 [ 0x0042 ] = 0 . 7 ,
84 [ 0x0043 ] = 0 . 7 ,
85 [ 0x0044 ] = 0 . 5 ,
86 [ 0x0045 ] = 0 . 7 ,
87 [ 0x0046 ] = 0 . 7 ,
88 [ 0x0047 ] = 0 . 5 ,
89 [ 0x0048 ] = 0 . 7 ,
90 [ 0x004B ] = 0 . 7 ,
91 [ 0x004D ] = 0 . 7 ,
92 [ 0x004E ] = 0 . 7 ,
93 [ 0x004F ] = 0 . 5 ,
94 [ 0x0050 ] = 0 . 7 ,
95 [ 0x0051 ] = 0 . 5 ,
96 [ 0x0052 ] = 0 . 7 ,
97 [ 0x0053 ] = 0 . 7 ,
98 [ 0x0055 ] = 0 . 7 ,
99 [ 0x0057 ] = 0 . 7 ,
100 [ 0x005A ] = 0 . 7 ,
101 [ 0x0061 ] = 0 . 7 ,
102 [ 0x0062 ] = 0 . 7 ,
103 [ 0x0063 ] = 0 . 7 ,
104 [ 0x0064 ] = 0 . 7 ,
105 [ 0x0065 ] = 0 . 7 ,
106 [ 0x0067 ] = 0 . 7 ,
107 [ 0x0068 ] = 0 . 7 ,
108 [ 0x006B ] = 0 . 7 ,
109 [ 0x006D ] = 0 . 7 ,
110 [ 0x006E ] = 0 . 7 ,
111 [ 0x006F ] = 0 . 7 ,
112 [ 0x0070 ] = 0 . 7 ,
113 [ 0x0071 ] = 0 . 7 ,
114 [ 0x0073 ] = 0 . 7 ,
115 [ 0x0075 ] = 0 . 7 ,
116 [ 0x0077 ] = 0 . 7 ,
117 [ 0x007A ] = 0 . 7 ,
118 [ 0x0032 ] = 0 . 7 ,
119 [ 0x0033 ] = 0 . 7 ,
120 [ 0x0036 ] = 0 . 7 ,
121 [ 0x0038 ] = 0 . 7 ,
122 [ 0x0039 ] = 0 . 7 ,
123}
124
125vectors [ ' quality ' ] = vectors [ ' default ' ]
126
127local function initialize ( tfmdata , value )
128 if value then
129 local class , vector = get_class_and_vector ( tfmdata , value , " expansions " )
130 if class then
131 if vector then
132 local stretch = class . stretch or 0
133 local shrink = class . shrink or 0
134 local step = class . step or 0
135 local factor = class . factor or 1
136 if trace_expansion then
137 report_expansions ( " setting class %a, vector %a, factor %a, stretch %a, shrink %a, step %a " ,
138 value , class . vector , factor , stretch , shrink , step )
139 end
140 tfmdata . parameters . expansion = {
141 stretch = 10 * stretch ,
142 shrink = 10 * shrink ,
143 step = 10 * step ,
144 factor = factor ,
145 }
146 local data = characters and characters . data
147 for i , chr in next , tfmdata . characters do
148 local v = vector [ i ]
149 if data and not v then
150 local d = data [ i ]
151 if d then
152 local s = d . shcode
153 if not s then
154
155 elseif type ( s ) = = " table " then
156 v = ( ( vector [ s [ 1 ] ] or 0 ) + ( vector [ s [ # s ] ] or 0 ) ) / 2
157 else
158 v = vector [ s ] or 0
159 end
160 end
161 end
162 if v and v ~ = 0 then
163 chr . expansion_factor = v * factor
164 else
165 chr . expansion_factor = factor
166 end
167 end
168 elseif trace_expansion then
169 report_expansions ( " unknown vector %a in class %a " , class . vector , value )
170 end
171 elseif trace_expansion then
172 report_expansions ( " unknown class %a " , value )
173 end
174 end
175end
176
177local specification = {
178 name = " expansion " ,
179 description = " apply hz optimization " ,
180 initializers = {
181 base = initialize ,
182 node = initialize ,
183 }
184}
185
186registerotffeature ( specification )
187registerafmfeature ( specification )
188
189fonts . goodies . register ( " expansions " , function ( ... ) return fonts . goodies . report ( " expansions " , trace_expansion , ... ) end )
190
191implement {
192 name = " setupfontexpansion " ,
193 arguments = " 2 strings " ,
194 actions = function ( class , settings ) getparameters ( classes , class , ' preset ' , settings ) end
195}
196
197
198
199
200
201fonts . protrusions = allocate ( )
202local protrusions = fonts . protrusions
203
204protrusions . classes = allocate ( )
205protrusions . vectors = allocate ( )
206
207local classes = protrusions . classes
208local vectors = protrusions . vectors
209
210
211
212classes . preset = {
213 factor = 1 ,
214 left = 1 ,
215 right = 1 ,
216}
217
218classes [ ' pure ' ] = { vector = ' pure ' , factor = 1 }
219classes [ ' punctuation ' ] = { vector = ' punctuation ' , factor = 1 }
220classes [ ' alpha ' ] = { vector = ' alpha ' , factor = 1 }
221classes [ ' quality ' ] = { vector = ' quality ' , factor = 1 }
222
223vectors [ ' pure ' ] = {
224
225 [ 0x002C ] = { 0 , 1 } ,
226 [ 0x002E ] = { 0 , 1 } ,
227 [ 0x003A ] = { 0 , 1 } ,
228 [ 0x003B ] = { 0 , 1 } ,
229 [ 0x002D ] = { 0 , 1 } ,
230 [ 0x00AD ] = { 0 , 1 } ,
231 [ 0x2013 ] = { 0 , 0 . 50 } ,
232 [ 0x2014 ] = { 0 , 0 . 33 } ,
233 [ 0x3001 ] = { 0 , 1 } ,
234 [ 0x3002 ] = { 0 , 1 } ,
235 [ 0x060C ] = { 0 , 1 } ,
236 [ 0x061B ] = { 0 , 1 } ,
237 [ 0x06D4 ] = { 0 , 1 } ,
238
239}
240
241vectors [ ' punctuation ' ] = {
242
243 [ 0x003F ] = { 0 , 0 . 20 } ,
244 [ 0x00BF ] = { 0 . 20 , 0 } ,
245 [ 0x0021 ] = { 0 , 0 . 20 } ,
246 [ 0x00A1 ] = { 0 . 20 , 0 , } ,
247 [ 0x0028 ] = { 0 . 05 , 0 } ,
248 [ 0x0029 ] = { 0 , 0 . 05 } ,
249 [ 0x005B ] = { 0 . 05 , 0 } ,
250 [ 0x005D ] = { 0 , 0 . 05 } ,
251 [ 0x002C ] = { 0 , 0 . 70 } ,
252 [ 0x002E ] = { 0 , 0 . 70 } ,
253 [ 0x003A ] = { 0 , 0 . 50 } ,
254 [ 0x003B ] = { 0 , 0 . 50 } ,
255 [ 0x002D ] = { 0 , 0 . 70 } ,
256 [ 0x00AD ] = { 0 , 0 . 70 } ,
257 [ 0x2013 ] = { 0 , 0 . 30 } ,
258 [ 0x2014 ] = { 0 , 0 . 20 } ,
259 [ 0x060C ] = { 0 , 0 . 70 } ,
260 [ 0x061B ] = { 0 , 0 . 50 } ,
261 [ 0x06D4 ] = { 0 , 0 . 70 } ,
262 [ 0x061F ] = { 0 , 0 . 20 } ,
263
264
265
266 [ 0x2039 ] = { 0 . 70 , 0 . 70 } ,
267 [ 0x203A ] = { 0 . 70 , 0 . 70 } ,
268 [ 0x00AB ] = { 0 . 50 , 0 . 50 } ,
269 [ 0x00BB ] = { 0 . 50 , 0 . 50 } ,
270
271 [ 0x2018 ] = { 0 . 70 , 0 . 70 } ,
272 [ 0x2019 ] = { 0 , 0 . 70 } ,
273 [ 0x201A ] = { 0 . 70 , 0 } ,
274 [ 0x201B ] = { 0 . 70 , 0 } ,
275 [ 0x201C ] = { 0 . 50 , 0 . 50 } ,
276 [ 0x201D ] = { 0 , 0 . 50 } ,
277 [ 0x201E ] = { 0 . 50 , 0 } ,
278 [ 0x201F ] = { 0 . 50 , 0 } ,
279
280}
281
282vectors [ ' alpha ' ] = {
283
284 [ 0x0041 ] = { . 05 , . 05 } ,
285 [ 0x0046 ] = { 0 , . 05 } ,
286 [ 0x004A ] = { . 05 , 0 } ,
287 [ 0x004B ] = { 0 , . 05 } ,
288 [ 0x004C ] = { 0 , . 05 } ,
289 [ 0x0054 ] = { . 05 , . 05 } ,
290 [ 0x0056 ] = { . 05 , . 05 } ,
291 [ 0x0057 ] = { . 05 , . 05 } ,
292 [ 0x0058 ] = { . 05 , . 05 } ,
293 [ 0x0059 ] = { . 05 , . 05 } ,
294
295 [ 0x006B ] = { 0 , . 05 } ,
296 [ 0x0072 ] = { 0 , . 05 } ,
297 [ 0x0074 ] = { 0 , . 05 } ,
298 [ 0x0076 ] = { . 05 , . 05 } ,
299 [ 0x0077 ] = { . 05 , . 05 } ,
300 [ 0x0078 ] = { . 05 , . 05 } ,
301 [ 0x0079 ] = { . 05 , . 05 } ,
302
303}
304
305vectors [ ' quality ' ] = table . merged (
306 vectors [ ' punctuation ' ] ,
307 vectors [ ' alpha ' ]
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
334classes [ ' double ' ] = {
335 factor = 2 ,
336 left = 1 ,
337 right = 1 ,
338}
339
340local function map_opbd_onto_protrusion ( tfmdata , value , opbd )
341 local characters = tfmdata . characters
342 local descriptions = tfmdata . descriptions
343 local properties = tfmdata . properties
344 local parameters = tfmdata . parameters
345 local resources = tfmdata . resources
346 local rawdata = tfmdata . shared . rawdata
347 local lookuphash = rawdata . lookuphash
348 local lookuptags = resources . lookuptags
349 local script = properties . script
350 local language = properties . language
351 local units = parameters . units
352 local done , factor , left , right = false , 1 , 1 , 1
353 local class = classes [ value ]
354 if class then
355 factor = class . factor or 1
356 left = class . left or 1
357 right = class . right or 1
358 else
359 factor = tonumber ( value ) or 1
360 end
361 local lfactor = left * factor
362 local rfactor = right * factor
363 if trace_protrusion then
364 report_protrusions ( " left factor %0.3F, right factor %0.3F " , lfactor , rfactor )
365 end
366 tfmdata . parameters . protrusion = {
367 factor = factor ,
368 left = left ,
369 right = right ,
370 }
371 if opbd ~ = " right " then
372 local validlookups , lookuplist = otf . collectlookups ( rawdata , " lfbd " , script , language )
373 if validlookups then
374 for i = 1 , # lookuplist do
375 local lookup = lookuplist [ i ]
376 local steps = lookup . steps
377 if steps then
378 if trace_protrusion then
379 report_protrusions ( " setting left using lfbd " )
380 end
381 for i = 1 , # steps do
382 local step = steps [ i ]
383 local coverage = step . coverage
384 if coverage then
385 for k , v in next , coverage do
386 if v = = true then
387
388 else
389 local w = descriptions [ k ] . width
390 local d = - v [ 1 ]
391 if w = = 0 or d = = 0 then
392
393 else
394 local p = lfactor * d / units
395 characters [ k ] . left_protruding = p
396 if trace_protrusion then
397 report_protrusions ( " lfbd -> %0.3F %C " , p , k )
398 end
399 end
400 end
401 end
402 end
403 end
404 done = true
405 end
406 end
407 end
408 end
409 if opbd ~ = " left " then
410 local validlookups , lookuplist = otf . collectlookups ( rawdata , " rtbd " , script , language )
411 if validlookups then
412 for i = 1 , # lookuplist do
413 local lookup = lookuplist [ i ]
414 local steps = lookup . steps
415 if steps then
416 if trace_protrusion then
417 report_protrusions ( " setting right using rtbd " )
418 end
419 for i = 1 , # steps do
420 local step = steps [ i ]
421 local coverage = step . coverage
422 if coverage then
423 for k , v in next , coverage do
424 if v = = true then
425
426 else
427 local w = descriptions [ k ] . width
428 local d = - v [ 3 ]
429 if w = = 0 or d = = 0 then
430
431 else
432 local p = rfactor * d / units
433 characters [ k ] . right_protruding = p
434 if trace_protrusion then
435 report_protrusions ( " rtbd -> %0.3F %C " , p , k )
436 end
437 end
438 end
439 end
440 end
441 end
442 end
443 done = true
444 end
445 end
446 end
447end
448
449
450
451
452
453local function initialize ( tfmdata , value )
454 if value then
455 local opbd = tfmdata . shared . features . opbd
456 if opbd then
457
458 map_opbd_onto_protrusion ( tfmdata , value , opbd )
459 else
460 local class , vector = get_class_and_vector ( tfmdata , value , " protrusions " )
461 if class then
462 if vector then
463 local factor = class . factor or 1
464 local left = class . left or 1
465 local right = class . right or 1
466 if trace_protrusion then
467 report_protrusions ( " setting class %a, vector %a, factor %a, left %a, right %a " ,
468 value , class . vector , factor , left , right )
469 end
470 local data = characters . data
471 local lfactor = left * factor
472 local rfactor = right * factor
473 if trace_protrusion then
474 report_protrusions ( " left factor %0.3F, right factor %0.3F " , lfactor , rfactor )
475 end
476 tfmdata . parameters . protrusion = {
477 factor = factor ,
478 left = left ,
479 right = right ,
480 }
481 for i , chr in next , tfmdata . characters do
482 local v = vector [ i ]
483 local pl = nil
484 local pr = nil
485 if v then
486 pl = v [ 1 ]
487 pr = v [ 2 ]
488 else
489 local d = data [ i ]
490 if d then
491 local s = d . shcode
492 if not s then
493
494 elseif type ( s ) = = " table " then
495 local vl = vector [ s [ 1 ] ]
496 local vr = vector [ s [ # s ] ]
497 if vl then pl = vl [ 1 ] end
498 if vr then pr = vr [ 2 ] end
499 else
500 v = vector [ s ]
501 if v then
502 pl = v [ 1 ]
503 pr = v [ 2 ]
504 end
505 end
506 end
507 end
508 if pl and pl ~ = 0 then
509 local p = pl * lfactor
510 chr . left_protruding = p
511 if trace_protrusion then
512 report_protrusions ( " left -> %0.3F %C " , p , i )
513 end
514 end
515 if pr and pr ~ = 0 then
516 local p = pr * rfactor
517 chr . right_protruding = p
518 if trace_protrusion then
519 report_protrusions ( " right -> %0.3F %C " , p , i )
520 end
521 end
522 end
523 elseif trace_protrusion then
524 report_protrusions ( " unknown vector %a in class %a " , class . vector , value )
525 end
526 elseif trace_protrusion then
527 report_protrusions ( " unknown class %a " , value )
528 end
529 end
530 end
531end
532
533local specification = {
534 name = " protrusion " ,
535 description = " l/r margin character protrusion " ,
536 initializers = {
537 base = initialize ,
538 node = initialize ,
539 }
540}
541
542registerotffeature ( specification )
543registerafmfeature ( specification )
544
545fonts . goodies . register ( " protrusions " , function ( ... ) return fonts . goodies . report ( " protrusions " , trace_protrusion , ... ) end )
546
547implement {
548 name = " setupfontprotrusion " ,
549 arguments = " 2 strings " ,
550 actions = function ( class , settings ) getparameters ( classes , class , ' preset ' , settings ) end
551}
552
553local function initialize ( tfmdata , value )
554 local properties = tfmdata . properties
555 local parameters = tfmdata . parameters
556 if properties then
557 value = tonumber ( value )
558 if value then
559 if value < 0 then
560 value = 0
561 elseif value > 10 then
562 report_expansions ( " threshold for %a @ %p limited to 10 pct " , properties . fontname , parameters . size )
563 value = 10
564 end
565 if value > 5 then
566 report_expansions ( " threshold for %a @ %p exceeds 5 pct " , properties . fontname , parameters . size )
567 end
568 end
569 properties . threshold = value or nil
570 end
571end
572
573local specification = {
574 name = " threshold " ,
575 description = " threshold for quality features " ,
576 initializers = {
577 base = initialize ,
578 node = initialize ,
579 }
580}
581
582registerotffeature ( specification )
583registerafmfeature ( specification )
584 |