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