1if not modules then modules = { } end modules [ ' font-mps ' ] = {
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 tostring = tostring
10local concat = table . concat
11local formatters = string . formatters
12
13
14
15
16
17
18
19
20
21fonts = fonts or { }
22local metapost = fonts . metapost or { }
23fonts . metapost = metapost
24
25local f_moveto = formatters [ " (%N,%N) " ]
26local f_lineto = formatters [ " --(%N,%N) " ]
27local f_curveto = formatters [ " ..controls(%N,%N)and(%N,%N)..(%N,%N) " ]
28local s_cycle = " --cycle "
29
30local f_nofill = formatters [ " nofill %s; " ]
31local f_dofill = formatters [ " fill %s; " ]
32
33local f_draw_trace = formatters [ " drawpathonly %s; " ]
34local f_draw = formatters [ " draw %s; " ]
35
36local f_boundingbox = formatters [ " ((%N,%N)--(%N,%N)--(%N,%N)--(%N,%N)--cycle) " ]
37local f_vertical = formatters [ " ((%N,%N)--(%N,%N)) " ]
38
39function metapost . boundingbox ( d , factor )
40 local bounds = d . boundingbox
41 local factor = factor or 1
42 local llx = factor * bounds [ 1 ]
43 local lly = factor * bounds [ 2 ]
44 local urx = factor * bounds [ 3 ]
45 local ury = factor * bounds [ 4 ]
46 return f_boundingbox ( llx , lly , urx , lly , urx , ury , llx , ury )
47end
48
49function metapost . widthline ( d , factor )
50 local bounds = d . boundingbox
51 local factor = factor or 1
52 local lly = factor * bounds [ 2 ]
53 local ury = factor * bounds [ 4 ]
54 local width = factor * d . width
55 return f_vertical ( width , lly , width , ury )
56end
57
58function metapost . zeroline ( d , factor )
59 local bounds = d . boundingbox
60 local factor = factor or 1
61 local lly = factor * bounds [ 2 ]
62 local ury = factor * bounds [ 4 ]
63 return f_vertical ( 0 , lly , 0 , ury )
64end
65
66function metapost . paths ( d , xfactor , yfactor )
67 local sequence = d . sequence
68 local segments = d . segments
69 local list = { }
70 local path = { }
71 local size = 0
72 local xfactor = xfactor or 1
73 local yfactor = yfactor or xfactor
74 if sequence then
75 local i = 1
76 local n = # sequence
77 while i < n do
78 local operator = sequence [ i ]
79 if operator = = " m " then
80 if size > 0 then
81 size = size + 1
82 path [ size ] = s_cycle
83 list [ # list + 1 ] = concat ( path , " " , 1 , size )
84 size = 1
85 else
86 size = size + 1
87 end
88 path [ size ] = f_moveto ( xfactor * sequence [ i + 1 ] , yfactor * sequence [ i + 2 ] )
89 i = i + 3
90 elseif operator = = " l " then
91 size = size + 1
92 path [ size ] = f_lineto ( xfactor * sequence [ i + 1 ] , yfactor * sequence [ i + 2 ] )
93 i = i + 3
94 elseif operator = = " c " then
95 size = size + 1
96 path [ size ] = f_curveto ( xfactor * sequence [ i + 1 ] , yfactor * sequence [ i + 2 ] , xfactor * sequence [ i + 3 ] , yfactor * sequence [ i + 4 ] , xfactor * sequence [ i + 5 ] , yfactor * sequence [ i + 6 ] )
97 i = i + 7
98 elseif operator = = " q " then
99 size = size + 1
100
101 local l_x = xfactor * sequence [ i -2 ]
102 local l_y = yfactor * sequence [ i -1 ]
103 local m_x = xfactor * sequence [ i + 1 ]
104 local m_y = yfactor * sequence [ i + 2 ]
105 local r_x = xfactor * sequence [ i + 3 ]
106 local r_y = yfactor * sequence [ i + 4 ]
107 path [ size ] = f_curveto (
108 l_x + 2 / 3 * ( m_x - l_x ) ,
109 l_y + 2 / 3 * ( m_y - l_y ) ,
110 r_x + 2 / 3 * ( m_x - r_x ) ,
111 r_y + 2 / 3 * ( m_y - r_y ) ,
112 r_x , r_y
113 )
114 i = i + 5
115 else
116
117 i = i + 1
118 end
119 end
120 elseif segments then
121 for i = 1 , # segments do
122 local segment = segments [ i ]
123 local operator = segment [ # segment ]
124 if operator = = " m " then
125 if size > 0 then
126 size = size + 1
127 path [ size ] = s_cycle
128 list [ # list + 1 ] = concat ( path , " " , 1 , size )
129 size = 1
130 else
131 size = size + 1
132 end
133 path [ size ] = f_moveto ( xfactor * segment [ 1 ] , yfactor * segment [ 2 ] )
134 elseif operator = = " l " then
135 size = size + 1
136 path [ size ] = f_lineto ( xfactor * segment [ 1 ] , yfactor * segment [ 2 ] )
137 elseif operator = = " c " then
138 size = size + 1
139 path [ size ] = f_curveto ( xfactor * segment [ 1 ] , yfactor * segment [ 2 ] , xfactor * segment [ 3 ] , yfactor * segment [ 4 ] , xfactor * segment [ 5 ] , yfactor * segment [ 6 ] )
140 elseif operator = = " q " then
141 size = size + 1
142
143 local prev = segments [ i -1 ]
144 local l_x = xfactor * prev [ # prev -2 ]
145 local l_y = yfactor * prev [ # prev -1 ]
146 local m_x = xfactor * segment [ 1 ]
147 local m_y = yfactor * segment [ 2 ]
148 local r_x = xfactor * segment [ 3 ]
149 local r_y = yfactor * segment [ 4 ]
150 path [ size ] = f_curveto (
151 l_x + 2 / 3 * ( m_x - l_x ) ,
152 l_y + 2 / 3 * ( m_y - l_y ) ,
153 r_x + 2 / 3 * ( m_x - r_x ) ,
154 r_y + 2 / 3 * ( m_y - r_y ) ,
155 r_x , r_y
156 )
157 else
158
159 end
160 end
161 else
162 return
163 end
164 if size > 0 then
165 size = size + 1
166 path [ size ] = s_cycle
167 list [ # list + 1 ] = concat ( path , " " , 1 , size )
168 end
169 return list
170end
171
172function metapost . fill ( paths )
173 local r = { }
174 local n = # paths
175 for i = 1 , n do
176 if i < n then
177 r [ i ] = f_nofill ( paths [ i ] )
178 else
179 r [ i ] = f_dofill ( paths [ i ] )
180 end
181 end
182 return concat ( r )
183end
184
185function metapost . draw ( paths , trace )
186 local r = { }
187 local n = # paths
188 for i = 1 , n do
189 if trace then
190 r [ i ] = f_draw_trace ( paths [ i ] )
191 else
192 r [ i ] = f_draw ( paths [ i ] )
193 end
194 end
195 return concat ( r )
196end
197
198function metapost . maxbounds ( data , index , factor )
199 local maxbounds = data . maxbounds
200 local factor = factor or 1
201 local glyphs = data . glyphs
202 local glyph = glyphs [ index ]
203 local boundingbox = glyph . boundingbox
204 local xmin , ymin , xmax , ymax
205 if not maxbounds then
206 xmin = 0
207 ymin = 0
208 xmax = 0
209 ymax = 0
210 for i = 1 , # glyphs do
211 local d = glyphs [ i ]
212 if d then
213 local b = d . boundingbox
214 if b then
215 if b [ 1 ] < xmin then xmin = b [ 1 ] end
216 if b [ 2 ] < ymin then ymin = b [ 2 ] end
217 if b [ 3 ] > xmax then xmax = b [ 3 ] end
218 if b [ 4 ] > ymax then ymax = b [ 4 ] end
219 end
220 end
221 end
222 maxbounds = { xmin , ymin , xmax , ymax }
223 data . maxbounds = maxbounds
224 else
225 xmin = maxbounds [ 1 ]
226 ymin = maxbounds [ 2 ]
227 xmax = maxbounds [ 3 ]
228 ymax = maxbounds [ 4 ]
229 end
230 local llx = boundingbox [ 1 ]
231 local lly = boundingbox [ 2 ]
232 local urx = boundingbox [ 3 ]
233 local ury = boundingbox [ 4 ]
234 local width = glyph . width
235 if llx > 0 then
236 llx = 0
237 end
238 if width > urx then
239 urx = width
240 end
241 return f_boundingbox (
242 factor * llx , factor * ymin ,
243 factor * urx , factor * ymin ,
244 factor * urx , factor * ymax ,
245 factor * llx , factor * ymax
246 )
247end
248
249
250
251
252
253local nodecodes = nodes . nodecodes
254local rulecodes = nodes . rulecodes
255
256local glyph_code = nodecodes . glyph
257local disc_code = nodecodes . disc
258local kern_code = nodecodes . kern
259local glue_code = nodecodes . glue
260local hlist_code = nodecodes . hlist
261local vlist_code = nodecodes . vlist
262local rule_code = nodecodes . rule
263
264local normalrule_code = rulecodes . normal
265
266local nuts = nodes . nuts
267local getnext = nuts . getnext
268local getid = nuts . getid
269local getlist = nuts . getlist
270local getsubtype = nuts . getsubtype
271local getreplace = nuts . getreplace
272local getbox = nuts . getbox
273local getwhd = nuts . getwhd
274local getkern = nuts . getkern
275local getshift = nuts . getshift
276local getwidth = nuts . getwidth
277local getheight = nuts . getheight
278local getdepth = nuts . getdepth
279local getexpansion = nuts . getexpansion
280local isglyph = nuts . isglyph
281
282local effectiveglue = nuts . effectiveglue
283
284local characters = fonts . hashes . characters
285local parameters = fonts . hashes . parameters
286local shapes = fonts . hashes . shapes
287local topaths = metapost . paths
288
289local f_code = formatters [ " mfun_do_outline_text_flush(%q,%i,%N,%N,%q)(%,t); " ]
290local f_rule = formatters [ " mfun_do_outline_rule_flush(%q,%N,%N,%N,%N); " ]
291local f_bounds = formatters [ " checkbounds(%N,%N,%N,%N); " ]
292local s_nothing = " (origin scaled 10) "
293
294local sc = 10
295local fc = number . dimenfactors . bp * sc / sc
296
297
298
299function metapost . output ( kind , font , char , advance , shift , ex )
300 local character = characters [ font ] [ char ]
301 if character then
302 local index = character . index
303 if index then
304 local shapedata = shapes [ font ]
305 local glyphs = shapedata . glyphs
306 if glyphs then
307 local glyf = glyphs [ index ]
308 if glyf then
309 local units = 1000
310 local yfactor = ( sc / units ) * parameters [ font ] . factor / 655 . 36
311 local xfactor = yfactor
312 local shift = shift or 0
313 local advance = advance or 0
314 local exfactor = ex or 0
315 local wfactor = 1
316 local detail = kind = = " p " and tostring ( char ) or " "
317 if exfactor ~ = 0 then
318 wfactor = ( 1 + ( ex / units ) / 1000 )
319 xfactor = xfactor * wfactor
320 end
321 local paths = topaths ( glyf , xfactor , yfactor )
322 if paths then
323 local code = f_code ( kind , # paths , advance , shift , detail , paths )
324 return code , character . width * fc * wfactor
325 else
326 return " " , 0
327 end
328 end
329 end
330 end
331 end
332 return s_nothing , 10 * sc / 1000
333end
334
335
336
337local signal = -0x3FFFFFFF - 1
338
339function fonts . metapost . boxtomp ( n , kind )
340
341 local result = { }
342 local advance = 0
343 local distance = 0
344
345 local llx , lly , urx , ury = 0 , 0 , 0 , 0
346
347 local horizontal , vertical
348
349 horizontal = function ( parent , current , xoffset , yoffset )
350 local dx = 0
351 while current do
352 local char , id = isglyph ( current )
353 if char then
354 local code , width = metapost . output ( kind , id , char , xoffset + dx , yoffset , getexpansion ( current ) )
355 result [ # result + 1 ] = code
356 dx = dx + width
357 elseif id = = disc_code then
358 local replace = getreplace ( current )
359 if replace then
360 dx = dx + horizontal ( parent , replace , xoffset + dx , yoffset )
361 end
362 elseif id = = kern_code then
363 dx = dx + getkern ( current ) * fc
364 elseif id = = glue_code then
365 dx = dx + effectiveglue ( current , parent ) * fc
366 elseif id = = hlist_code then
367 local list = getlist ( current )
368 if list then
369 horizontal ( current , list , xoffset + dx , yoffset - getshift ( current ) * fc )
370 end
371 dx = dx + getwidth ( current ) * fc
372 elseif id = = vlist_code then
373 local list = getlist ( current )
374 if list then
375 vertical ( current , list , xoffset + dx , yoffset - getshift ( current ) * fc )
376 end
377 dx = dx + getwidth ( current ) * fc
378 elseif id = = rule_code then
379 local wd , ht , dp = getwhd ( current )
380 if wd ~ = 0 then
381 wd = wd * fc
382 if ht = = signal then
383 ht = getheight ( parent )
384 end
385 if dp = = signal then
386 dp = getdepth ( parent )
387 end
388 local hd = ( ht + dp ) * fc
389 if hd ~ = 0 and getsubtype ( current ) = = normalrule_code then
390 result [ # result + 1 ] = f_rule ( kind , xoffset + dx + wd / 2 , yoffset + hd / 2 , wd , hd )
391 end
392 dx = dx + wd
393 end
394 end
395 current = getnext ( current )
396 end
397 return dx
398 end
399
400 vertical = function ( parent , current , xoffset , yoffset )
401 local dy = getheight ( parent ) * fc
402 while current do
403 local id = getid ( current )
404 if id = = hlist_code then
405 local _ , ht , dp = getwhd ( current )
406 dy = dy - ht * fc
407 local list = getlist ( current )
408 if list then
409 horizontal ( current , list , xoffset + getshift ( current ) * fc , yoffset + dy )
410 end
411 dy = dy - dp * fc
412 elseif id = = vlist_code then
413 local wd , ht , dp = getwhd ( current )
414 dy = dy - ht * fc
415 local list = getlist ( current )
416 if list then
417 vertical ( current , list , xoffset + getshift ( current ) * fc , yoffset + dy )
418 end
419 dy = dy - dp * fc
420 elseif id = = kern_code then
421 dy = dy - getkern ( current ) * fc
422 elseif id = = glue_code then
423 dy = dy - effectiveglue ( current , parent ) * fc
424 elseif id = = rule_code then
425 local wd , ht , dp = getwhd ( current )
426 local hd = ( ht + dp ) * fc
427 if hd ~ = 0 then
428 if wd = = signal then
429 wd = getwidth ( parent ) * fc
430 else
431 wd = wd * fc
432 end
433 dy = dy - ht * fc
434 if wd ~ = 0 and getsubtype ( current ) = = 0 then
435 result [ # result + 1 ] = f_rule ( kind , xoffset + wd / 2 , yoffset + dy + hd / 2 , wd , hd )
436 end
437 dy = dy - dp * fc
438 end
439 end
440 current = getnext ( current )
441 end
442 return dy
443 end
444
445 local box = getbox ( n )
446 local list = box and getlist ( box )
447 if list then
448 ( getid ( box ) = = hlist_code and horizontal or vertical ) ( box , list , 0 , 0 )
449 end
450
451 local wd , ht , dp = getwhd ( box )
452
453 result [ # result + 1 ] = f_bounds ( 0 , - dp * fc , wd * fc , ht * fc )
454
455 return concat ( result )
456
457end
458 |