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