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