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","combining")
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
49local function composecharacters(tfmdata)
50
51 local characters = tfmdata.characters
52 local descriptions = tfmdata.descriptions
53 local parameters = tfmdata.parameters
54 local properties = tfmdata.properties
55 local Xdesc = descriptions[utfbyte("X")]
56 local xdesc = descriptions[utfbyte("x")]
57 if Xdesc and xdesc then
58 local scale = parameters.factor or 1
59 local deltaxheight = scale * (Xdesc.boundingbox[4] - xdesc.boundingbox[4])
60 local extraxheight = fraction * deltaxheight
61 local italicfactor = parameters.italicfactor or 0
62 local vfspecials = backends.tables.vfspecials
63 local red, green, blue, black
64 if trace_visualize then
65 red = vfspecials.startcolor("red")
66 green = vfspecials.startcolor("green")
67 blue = vfspecials.startcolor("blue")
68 black = vfspecials.stopcolor
69 end
70 local compose = fonts.goodies.getcompositions(tfmdata)
71 if compose and trace_visualize then
72 report("using compose information from goodies file")
73 end
74 local done = false
75 for i, c in next, unicodecharacters do
76 if force_combining or not characters[i] then
77 local s = c.specials
78 if s and s[1] == 'char' then
79 local chr = s[2]
80 local charschr = characters[chr]
81 if charschr then
82 local cc = c.category
83 if cc == 'll' or cc == 'lu' or cc == 'lt' then
84 local acc = s[3]
85 local t = { }
86 for k, v in next, charschr do
87 if k ~= "commands" then
88 t[k] = v
89 end
90 end
91 local charsacc = characters[acc]
92
93
94
95
96
97
98
99
100 if not charsacc then
101 acc = unicodefallbacks[acc]
102 charsacc = acc and characters[acc]
103 end
104 local chr_t = charcommand[chr]
105 if charsacc then
106 if trace_define then
107 report("composed %C, base %C, accent %C",i,chr,acc)
108 end
109 local acc_t = charcommand[acc]
110 local cb = descriptions[chr].boundingbox
111 local ab = descriptions[acc].boundingbox
112
113 if cb and ab then
114 local c_llx = scale*cb[1]
115 local c_lly = scale*cb[2]
116 local c_urx = scale*cb[3]
117 local c_ury = scale*cb[4]
118 local a_llx = scale*ab[1]
119 local a_lly = scale*ab[2]
120 local a_urx = scale*ab[3]
121 local a_ury = scale*ab[4]
122 local done = false
123 if compose then
124 local i_compose = compose[i]
125 local i_anchored = i_compose and i_compose.anchored
126 if i_anchored then
127 local c_compose = compose[chr]
128 local a_compose = compose[acc]
129 local c_anchors = c_compose and c_compose.anchors
130 local a_anchors = a_compose and a_compose.anchors
131 if c_anchors and a_anchors then
132 local c_anchor = c_anchors[i_anchored]
133 local a_anchor = a_anchors[i_anchored]
134 if c_anchor and a_anchor then
135 local cx = c_anchor.x or 0
136 local cy = c_anchor.y or 0
137 local ax = a_anchor.x or 0
138 local ay = a_anchor.y or 0
139 local dx = cx - ax
140 local dy = cy - ay
141 if trace_define then
142 report("building %C from %C and %C",i,chr,acc)
143 report(" boundingbox:")
144 report(" chr: %3i %3i %3i %3i",unpack(cb))
145 report(" acc: %3i %3i %3i %3i",unpack(ab))
146 report(" anchors:")
147 report(" chr: %3i %3i",cx,cy)
148 report(" acc: %3i %3i",ax,ay)
149 report(" delta:")
150 report(" %s: %3i %3i",i_anchored,dx,dy)
151 end
152 local right = rightcommand[scale*dx]
153 local down = upcommand[scale*dy]
154 if trace_visualize then
155 t.commands = {
156 push, right, down,
157 green, acc_t, black,
158 pop, chr_t,
159 }
160 else
161 t.commands = {
162 push, right, down,
163 acc_t, pop, chr_t,
164 }
165 end
166 done = true
167 end
168 end
169 end
170 end
171 if not done then
172
173 local dx = (c_urx - a_urx - a_llx + c_llx)/2
174 local dd = (c_urx - c_llx)*italicfactor
175 if a_ury < 0 then
176 local right = rightcommand[dx-dd]
177 if trace_visualize then
178 t.commands = {
179 push, right, red, acc_t,
180 black, pop, chr_t,
181 }
182 else
183 t.commands = {
184 push, right, acc_t, pop,
185 chr_t,
186 }
187 end
188t.depth = a_ury
189 elseif c_ury > a_lly then
190 local dy
191 if compose then
192
193
194 dy = compose[i]
195 if dy then
196 dy = dy.dy
197 end
198 if not dy then
199 dy = compose[acc]
200 if dy then
201 dy = dy and dy.dy
202 end
203 end
204 if not dy then
205 dy = compose.dy
206 end
207 if not dy then
208 dy = - deltaxheight + extraxheight
209 elseif dy > -1.5 and dy < 1.5 then
210
211 dy = - dy * deltaxheight
212 else
213
214 dy = - dy * scale
215 end
216 else
217 dy = - deltaxheight + extraxheight
218 end
219t.height = a_ury-dy
220 local right = rightcommand[dx+dd]
221 local down = downcommand[dy]
222 if trace_visualize then
223 t.commands = {
224 push, right, down, green,
225 acc_t, black, pop, chr_t,
226 }
227 else
228 t.commands = {
229 push, right, down, acc_t,
230 pop, chr_t,
231 }
232 end
233 else
234 local right = rightcommand[dx+dd]
235 if trace_visualize then
236 t.commands = {
237 push, right, blue, acc_t,
238 black, pop, chr_t,
239 }
240 else
241 t.commands = {
242 push, right, acc_t, pop,
243 chr_t,
244 }
245 end
246t.height = a_ury
247 end
248 end
249 else
250 t.commands = {
251 chr_t,
252 }
253 end
254 else
255 if trace_define then
256 report("%C becomes simplified %C",i,chr)
257 end
258 t.commands = {
259 chr_t,
260 }
261 end
262 done = true
263 characters[i] = t
264 local d = { }
265 for k, v in next, descriptions[chr] do
266 d[k] = v
267 end
268 descriptions[i] = d
269 end
270 end
271 end
272 end
273 end
274 if done then
275 properties.virtualized = true
276 end
277 end
278end
279
280local specification = {
281 name = "compose",
282 description = "additional composed characters",
283 manipulators = {
284 base = composecharacters,
285 node = composecharacters,
286 }
287}
288
289registerotffeature(specification)
290registerafmfeature(specification)
291
292addotffeature {
293 name = "char-ligatures",
294 type = "ligature",
295 data = characters.splits.char,
296 order = { "char-ligatures" },
297 prepend = true,
298}
299
300addotffeature {
301 name = "compat-ligatures",
302 type = "ligature",
303 data = characters.splits.compat,
304 order = { "compat-ligatures" },
305 prepend = true,
306}
307
308registerotffeature {
309 name = 'char-ligatures',
310 description = 'unicode char specials to ligatures',
311}
312
313registerotffeature {
314 name = 'compat-ligatures',
315 description = 'unicode compat specials to ligatures',
316}
317
318do
319
320
321
322
323 local vf = handlers.vf
324 local commands = vf.combiner.commands
325
326 vf.helpers.composecharacters = composecharacters
327
328 commands["compose.trace.enable"] = function()
329 trace_visualize = true
330 end
331
332 commands["compose.trace.disable"] = function()
333 trace_visualize = false
334 end
335
336 commands["compose.force.enable"] = function()
337 force_combining = true
338 end
339
340 commands["compose.force.disable"] = function()
341 force_combining = false
342 end
343
344 commands["compose.trace.set"] = function(g,v)
345 if v[2] == nil then
346 trace_visualize = true
347 else
348 trace_visualize = v[2]
349 end
350 end
351
352 commands["compose.apply"] = function(g,v)
353 composecharacters(g)
354 end
355
356end
357 |