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 |