1if not modules then modules = { } end modules ['font-fbk'] = {
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
9local cos, tan, rad, format = math.cos, math.tan, math.rad, string.format
10local utfbyte, utfchar = utf.byte, utf.char
11local next = next
12
13local trace_visualize = false trackers.register("fonts.composing.visualize", function(v) trace_visualize = v end)
14local trace_define = false trackers.register("fonts.composing.define", function(v) trace_define = v end)
15
16local report = logs.reporter("fonts","composing")
17
18local allocate = utilities.storage.allocate
19
20local fonts = fonts
21local handlers = fonts.handlers
22local constructors = fonts.constructors
23local helpers = fonts.helpers
24
25local otf = handlers.otf
26local afm = handlers.afm
27local registerotffeature = otf.features.register
28local registerafmfeature = afm.features.register
29
30local addotffeature = otf.addfeature
31
32local unicodecharacters = characters.data
33local unicodefallbacks = characters.fallbacks
34
35local vfcommands = helpers.commands
36local charcommand = vfcommands.char
37local rightcommand = vfcommands.right
38local downcommand = vfcommands.down
39local upcommand = vfcommands.up
40local push = vfcommands.push
41local pop = vfcommands.pop
42
43local force_combining = false
44local fraction = 0.15
45
46
47
48
49
50
51
52
53
54
55local missing = {
56
57 [0x323] = { kind = "bottom", top = 0x2D9 },
58
59
60
61}
62
63local function fakecharacters(tfmdata,key,value)
64 if key and value then
65 local characters = tfmdata.characters
66 local descriptions = tfmdata.descriptions
67 for unicode, detail in next, missing do
68 local c = characters[k]
69 if not c then
70 local kind = detail.kind
71 if kind == "bottom" then
72 local u = detail.top
73 local d = characters[u]
74 if d then
75 local ex = tfmdata.parameters.xheight
76 characters[unicode] = {
77 width = d.width,
78 height = 0,
79 depth = ex/2,
80 commands = { { "offset", 0, -d.height - ex/5 , u } },
81 unicode = unicode,
82 }
83
84 local d = descriptions[u]
85 local x = descriptions[0x78]
86 if d and x then
87 local t = table.copy(d)
88 local x = -x.boundingbox[4]/2
89 local b = t.boundingbox
90 b[2] = x
91 b[4] = x
92 descriptions[unicode] = t
93 end
94 if trace then
95 report("deriving %C from %C",unicode,u)
96 end
97 end
98 end
99 end
100 end
101 end
102end
103
104local specification = {
105 name = "fakecombining",
106 description = "add missing combining accents",
107 manipulators = {
108
109 base = fakecharacters,
110 node = fakecharacters,
111 }
112}
113
114fonts.handlers.otf.features.register(specification)
115
116local function composecharacters(tfmdata)
117
118 local characters = tfmdata.characters
119 local descriptions = tfmdata.descriptions
120 local parameters = tfmdata.parameters
121 local properties = tfmdata.properties
122 local Xdesc = descriptions[utfbyte("X")]
123 local xdesc = descriptions[utfbyte("x")]
124 if Xdesc and xdesc then
125 local scale = parameters.factor or 1
126 local deltaxheight = scale * (Xdesc.boundingbox[4] - xdesc.boundingbox[4])
127 local extraxheight = fraction * deltaxheight
128 local italicfactor = parameters.italicfactor or 0
129 local red, green, blue, black
130 if trace_visualize then
131 red = { "startcolor", "red" }
132 green = { "startcolor", "green" }
133 blue = { "startcolor", "blue" }
134 black = { "stopcolor" }
135 end
136 local compose = fonts.goodies.getcompositions(tfmdata)
137 if compose and trace_visualize then
138 report("using compose information from goodies file")
139 end
140 local done = false
141 for i, c in next, unicodecharacters do
142 if force_combining or not characters[i] then
143 local s = c.specials
144 if s and s[1] == 'char' then
145 local chr = s[2]
146 local charschr = characters[chr]
147 if charschr then
148 local cc = c.category
149 if cc == 'll' or cc == 'lu' or cc == 'lt' then
150 local acc = s[3]
151 local t = { }
152 for k, v in next, charschr do
153 if k ~= "commands" then
154 t[k] = v
155 end
156 end
157 local charsacc = characters[acc]
158
159
160
161
162
163
164
165
166 if not charsacc then
167 acc = unicodefallbacks[acc]
168 charsacc = acc and characters[acc]
169 end
170 local chr_t = charcommand[chr]
171 if charsacc then
172 if trace_define then
173 report("composed %C, base %C, accent %C",i,chr,acc)
174 end
175 local acc_t = charcommand[acc]
176 local cb = descriptions[chr]
177 local ab = descriptions[acc]
178 local cb = cb and cb.boundingbox
179 local ab = ab and ab.boundingbox
180
181 if cb and ab then
182 local c_llx = scale*cb[1]
183 local c_lly = scale*cb[2]
184 local c_urx = scale*cb[3]
185 local c_ury = scale*cb[4]
186 local a_llx = scale*ab[1]
187 local a_lly = scale*ab[2]
188 local a_urx = scale*ab[3]
189 local a_ury = scale*ab[4]
190 local done = false
191 if compose then
192 local i_compose = compose[i]
193 local i_anchored = i_compose and i_compose.anchored
194 if i_anchored then
195 local c_compose = compose[chr]
196 local a_compose = compose[acc]
197 local c_anchors = c_compose and c_compose.anchors
198 local a_anchors = a_compose and a_compose.anchors
199 if c_anchors and a_anchors then
200 local c_anchor = c_anchors[i_anchored]
201 local a_anchor = a_anchors[i_anchored]
202 if c_anchor and a_anchor then
203 local cx = c_anchor.x or 0
204 local cy = c_anchor.y or 0
205 local ax = a_anchor.x or 0
206 local ay = a_anchor.y or 0
207 local dx = cx - ax
208 local dy = cy - ay
209 if trace_define then
210 report("building %C from %C and %C",i,chr,acc)
211 report(" boundingbox:")
212 report(" chr: %3i %3i %3i %3i",unpack(cb))
213 report(" acc: %3i %3i %3i %3i",unpack(ab))
214 report(" anchors:")
215 report(" chr: %3i %3i",cx,cy)
216 report(" acc: %3i %3i",ax,ay)
217 report(" delta:")
218 report(" %s: %3i %3i",i_anchored,dx,dy)
219 end
220 local right = rightcommand[scale*dx]
221 local down = upcommand[scale*dy]
222 if trace_visualize then
223 t.commands = {
224 push, right, down,
225 green, acc_t, black,
226 pop, chr_t,
227 }
228 else
229 t.commands = {
230 push, right, down,
231 acc_t, pop, chr_t,
232 }
233 end
234 done = true
235 end
236 end
237 end
238 end
239 if not done then
240
241 local dx = (c_urx - a_urx - a_llx + c_llx)/2
242 local dd = (c_urx - c_llx)*italicfactor
243 if a_ury < 0 then
244 local right = rightcommand[dx-dd]
245 if trace_visualize then
246 t.commands = {
247 push, right, red, acc_t,
248 black, pop, chr_t,
249 }
250 else
251 t.commands = {
252 push, right, acc_t, pop,
253 chr_t,
254 }
255 end
256 t.depth = a_ury
257 elseif c_ury > a_lly then
258 local dy
259 if compose then
260
261
262 dy = compose[i]
263 if dy then
264 dy = dy.dy
265 end
266 if not dy then
267 dy = compose[acc]
268 if dy then
269 dy = dy and dy.dy
270 end
271 end
272 if not dy then
273 dy = compose.dy
274 end
275 if not dy then
276 dy = - deltaxheight + extraxheight
277 elseif dy > -1.5 and dy < 1.5 then
278
279 dy = - dy * deltaxheight
280 else
281
282 dy = - dy * scale
283 end
284 else
285 dy = - deltaxheight + extraxheight
286 end
287 t.height = a_ury-dy
288 local right = rightcommand[dx+dd]
289 local down = downcommand[dy]
290 if trace_visualize then
291 t.commands = {
292 push, right, down, green,
293 acc_t, black, pop, chr_t,
294 }
295 else
296 t.commands = {
297 push, right, down, acc_t,
298 pop, chr_t,
299 }
300 end
301 else
302 local right = rightcommand[dx+dd]
303 if trace_visualize then
304 t.commands = {
305 push, right, blue, acc_t,
306 black, pop, chr_t,
307 }
308 else
309 t.commands = {
310 push, right, acc_t, pop,
311 chr_t,
312 }
313 end
314 t.height = a_ury
315 end
316 end
317 else
318 t.commands = {
319 chr_t,
320 }
321 end
322 else
323 if trace_define then
324 report("%C becomes simplified %C",i,chr)
325 end
326 t.commands = {
327 chr_t,
328 }
329 end
330 done = true
331 characters[i] = t
332 local d = { }
333 for k, v in next, descriptions[chr] do
334 d[k] = v
335 end
336 descriptions[i] = d
337 end
338 end
339 end
340 end
341 end
342 end
343end
344
345local specification = {
346 name = "compose",
347 description = "additional composed characters",
348 manipulators = {
349 base = composecharacters,
350 node = composecharacters,
351 }
352}
353
354registerotffeature(specification)
355registerafmfeature(specification)
356
357addotffeature {
358 name = "char-ligatures",
359 type = "ligature",
360 data = characters.splits.char,
361 order = { "char-ligatures" },
362 prepend = true,
363}
364
365addotffeature {
366 name = "compat-ligatures",
367 type = "ligature",
368 data = characters.splits.compat,
369 order = { "compat-ligatures" },
370 prepend = true,
371}
372
373registerotffeature {
374 name = 'char-ligatures',
375 description = 'unicode char specials to ligatures',
376}
377
378registerotffeature {
379 name = 'compat-ligatures',
380 description = 'unicode compat specials to ligatures',
381}
382
383
384
385fonts.helpers.composecharacters = composecharacters
386
387
388
389
390
391do
392
393 local vf = handlers.vf
394 local commands = vf.combiner.commands
395
396 vf.helpers.composecharacters = composecharacters
397
398 commands["compose.trace.enable"] = function() trace_visualize = true end
399 commands["compose.trace.disable"] = function() trace_visualize = false end
400 commands["compose.force.enable"] = function() force_combining = true end
401 commands["compose.force.disable"] = function() force_combining = false end
402
403 commands["compose.trace.set"] = function(g,v)
404 if v[2] == nil then
405 trace_visualize = true
406 else
407 trace_visualize = v[2]
408 end
409 end
410
411 commands["compose.apply"] = function(g,v)
412 composecharacters(g)
413 end
414
415end
416 |