1if not modules then modules = { } end modules ['font-imp-effects'] = {
2 version = 1.001,
3 comment = "companion to font-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
9
10
11
12local next, type, tonumber = next, type, tonumber
13
14local fonts = fonts
15local handlers = fonts.handlers
16local registerotffeature = handlers.otf.features.register
17local registerafmfeature = handlers.afm.features.register
18
19local settings_to_hash = utilities.parsers.settings_to_hash_colon_too
20
21local report_effect = logs.reporter("fonts","effect")
22
23local trace = false
24
25trackers.register("fonts.effect", function(v) trace = v end)
26
27
28
29local effects = {
30 [0] = 0, [1] = 1, [2] = 2, [3] = 3, [7]= 7,
31 inner = 0,
32 normal = 0,
33 outer = 1,
34 outline = 1,
35 both = 2,
36 hidden = 3,
37 clip = 7,
38}
39
40
41
42local rules = {
43 "RadicalRuleThickness",
44 "OverbarRuleThickness",
45 "FractionRuleThickness",
46 "UnderbarRuleThickness",
47}
48
49
50
51
52
53
54
55
56
57
58
59
60
61local function applyeffect(tfmdata)
62 local effect = tfmdata.properties.effect
63 if effect and not effect.done then
64 local characters = tfmdata.characters
65 local parameters = tfmdata.parameters
66 local mathparameters = tfmdata.mathparameters
67 local extend = effect.extend
68 local squeeze = effect.squeeze
69
70 local weight = effect.weight or 0
71 if weight ~= 0 then
72
73 weight = weight / 2
74
75 local fraction = (parameters.designsize or parameters.size) / parameters.size
76 if not texconditionals["c_font_compact"] then
77 local f = 65536 * fraction * weight
78 local fw = f * 2
79 local fh = f
80 local fd = f
81 local fi = f
82 for unicode, character in next, characters do
83 local v = character.width
84 if v and v > 0 then
85 if not character.advance then
86 character.advance = v
87 end
88 character.width = v + fw
89 end
90 v = character.height
91 if v and v > 0 then
92 character.height = v + fh
93 end
94 v = character.depth
95 if v and v > 0 then
96 character.depth = v + fd
97 end
98 v = character.italic
99 if v and v > 0 then
100 character.italic = v + fi
101 end
102 v = character.topanchor
103 if v and v > 0 then
104 character.topanchor = v + fh
105 end
106 v = character.bottomanchor
107 if v and v > 0 then
108 character.bottomanchor = v - fd
109 end
110
111
112
113
114
115
116
117
118
119 end
120
121 parameters.hshift = weight * fraction
122
123if mathparameters then
124
125 for i=1,#rules do
126 local name = rules[i]
127 local value = mathparameters[name]
128 if value then
129 mathparameters[name] = value + f + f
130 end
131 end
132end
133 end
134 effect.weight = weight
135 else
136 effect.weight = 0
137 end
138 effect.done = true
139 end
140end
141
142
143
144
145
146local function seteffect(tfmdata,key,value,min,max)
147 if value then
148 value = tonumber(value) or 0
149 if not value then
150 value = 0
151 elseif value > max then
152 value = max
153 elseif value < min then
154 value = min
155 end
156 local properties = tfmdata.properties
157 local parameters = tfmdata.parameters
158 local effect = properties.effect
159 if not effect then
160 effect = { }
161 properties.effect = effect
162 end
163 if trace then
164 report_effect("applying %s %0.3f",key,value)
165 end
166 effect[key] = value
167 effect.done = false
168 if key == "slant" then
169 properties.usedslant = value
170 parameters.usedslant = value
171 end
172 end
173end
174
175local function initializeslant(tfmdata,value)
176 seteffect(tfmdata,"slant",value,-1,1)
177end
178
179local specification = {
180 name = "slant",
181 description = "slant glyphs",
182 initializers = {
183 base = initializeslant,
184 node = initializeslant,
185 },
186 manipulators = {
187 base = applyeffect,
188 node = applyeffect,
189 },
190}
191
192registerotffeature(specification)
193registerafmfeature(specification)
194
195local function initializeextend(tfmdata,value)
196 seteffect(tfmdata,"extend",value,0,10)
197end
198
199local specification = {
200 name = "extend",
201 description = "scale glyphs horizontally",
202 initializers = {
203 base = initializeextend,
204 node = initializeextend,
205 },
206 manipulators = {
207 base = applyeffect,
208 node = applyeffect,
209 },
210}
211
212registerotffeature(specification)
213registerafmfeature(specification)
214
215local function initializesqueeze(tfmdata,value)
216 seteffect(tfmdata,"squeeze",value,0,10)
217end
218
219local specification = {
220 name = "squeeze",
221 description = "scale glyphs vertically",
222 initializers = {
223 base = initializesqueeze,
224 node = initializesqueeze,
225 },
226 manipulators = {
227 base = applyeffect,
228 node = applyeffect,
229 },
230}
231
232registerotffeature(specification)
233registerafmfeature(specification)
234
235local function initializeweight(tfmdata,value)
236 seteffect(tfmdata,"weight",value,0,1)
237end
238
239local specification = {
240 name = "weight",
241 description = "bolden glyphs",
242 initializers = {
243 base = initializeweight,
244 node = initializeweight,
245 },
246 manipulators = {
247 base = applyeffect,
248 node = applyeffect,
249 },
250}
251
252registerotffeature(specification)
253registerafmfeature(specification)
254
255local function initializeoutline(tfmdata,value)
256 value = tonumber(value)
257 if not value then
258 value = 0
259 else
260 value = tonumber(value) or 0
261 end
262 local parameters = tfmdata.parameters
263 local properties = tfmdata.properties
264 if trace then
265 report_effect("applying outline %0.3f",value)
266 end
267
268
269 properties.effect = {
270 mode = effects.outline,
271 weight = value,
272 }
273end
274
275local specification = {
276 name = "outline",
277 description = "outline glyphs",
278 initializers = {
279 base = initializeoutline,
280 node = initializeoutline,
281 },
282 manipulators = {
283 base = applyeffect,
284 node = applyeffect,
285 },
286}
287
288registerotffeature(specification)
289registerafmfeature(specification)
290
291
292
293local function initializeoption(tfmdata,key,value)
294 if value then
295 local parameters = tfmdata.parameters
296 local properties = tfmdata.properties
297 if trace then
298 report_effect("applying effect %a",value)
299 end
300 local effect = properties.effect
301 if not effect then
302 effect = { }
303 properties.effect = effect
304 end
305 effect[key] = value
306 end
307end
308
309local function initializeeffect(tfmdata,value)
310 if tfmdata.properties.effect then
311 report_effect("ignored effect %a",effect)
312 elseif type(value) == "string" then
313 local specification = settings_to_hash(value)
314 if specification.width and not specification.weight then
315 specification.weight = specification.width
316 specification.width = nil
317 end
318 initializeextend (tfmdata,specification.extend)
319 initializesqueeze(tfmdata,specification.squeeze)
320 initializeslant (tfmdata,specification.slant)
321 initializeweight (tfmdata,specification.weight)
322 initializeoption (tfmdata,"mode",effects[specification.effect or specification.mode or "both"])
323 initializeoption (tfmdata,"auto",specification.auto)
324
325 else
326 value = tonumber(value)
327 if value then
328 initializeextend(tfmdata,value)
329 end
330 end
331end
332
333local specification = {
334 name = "effect",
335 description = "apply effects to glyphs",
336 initializers = {
337 base = initializeeffect,
338 node = initializeeffect,
339 },
340 manipulators = {
341 base = applyeffect,
342 node = applyeffect,
343 },
344}
345
346registerotffeature(specification)
347registerafmfeature(specification)
348
349local function checkautoeffect(tfmdata)
350 local effect = tfmdata.properties.effect
351 if effect and effect.auto then
352 local weight = effect.weight
353 if weight and weight ~= 0 and not texconditionals["c_font_compact"] then
354 local parameters = tfmdata.parameters
355 local extend = effect.extend
356 local squeeze = effect.squeeze
357 local amount = 65.536 * weight
358 if not squeeze then
359 local xheight = parameters.xheight
360 effect.squeeze = xheight / (xheight + amount)
361 end
362 if not extend then
363 local emwidth = parameters.quad
364 effect.extend = emwidth / (emwidth + 2 * amount)
365
366 end
367 end
368 end
369end
370
371local specification = {
372 name = "checkautoeffect",
373 description = "check auto effect",
374 default = true,
375 initializers = {
376 base = checkautoeffect,
377 node = checkautoeffect,
378 },
379}
380
381registerotffeature(specification)
382registerafmfeature(specification)
383 |