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 texgetbox = tex.getbox
254
255local nodecodes = nodes.nodecodes
256local rulecodes = nodes.rulecodes
257
258local rule_code = nodecodes.rule
259
260local normalrule_code = rulecodes.normal
261local outlinerule_code = rulecodes.outline
262local userrule_code = rulecodes.user
263local emptyrule_code = rulecodes.empty
264
265local nuts = nodes.nuts
266local getwhd = nuts.getwhd
267local getexpansion = nuts.getexpansion
268local isglyph = nuts.isglyph
269
270local characters = fonts.hashes.characters
271local parameters = fonts.hashes.parameters
272local shapes = fonts.hashes.shapes
273local topaths = metapost.paths
274
275local f_text = formatters["mfun_do_outline_text_flush(%q,%i,%N,%N,%q)(%,t);"]
276local f_rule = formatters["mfun_do_outline_rule_flush(%q,%N,%N,%N,%N);"]
277local f_bounds = formatters["checkbounds(%N,%N,%N,%N);"]
278local s_nothing = "(origin scaled 10)"
279
280local sc = 10
281local fc = number.dimenfactors.bp
282
283local function glyph(kind,font,char,advance,shift,ex)
284 local character = characters[font][char]
285 if character then
286 local index = character.index
287 if index then
288 local shapedata = shapes[font]
289 local glyphs = shapedata.glyphs
290 if glyphs then
291 local glyf = glyphs[index]
292 if glyf then
293 local units = 1000
294 local yfactor = (sc/units) * parameters[font].factor / 655.36
295 local xfactor = yfactor
296 local shift = shift or 0
297 local advance = advance or 0
298 local exfactor = ex or 0
299 local wfactor = 1
300 local detail = kind == "p" and tostring(char) or ""
301 if exfactor ~= 0 then
302 wfactor = (1+(ex/units)/1000)
303 xfactor = xfactor * wfactor
304 end
305 local paths = topaths(glyf,xfactor,yfactor)
306 if paths then
307 return f_text(kind,#paths,advance,shift,detail,paths)
308 end
309 end
310 end
311 end
312 end
313end
314
315metapost.glyph = glyph
316
317local kind = ""
318local buffer = { }
319local b = 0
320
321local function reset()
322 buffer = { }
323 b = 0
324end
325
326local function flushcharacter(current, pos_h, pos_v, pod_r, font, char)
327 local char, font = isglyph(current)
328 local code = glyph(kind,font,char,pos_h*fc,pos_v*fc,getexpansion(current))
329 if code then
330 b = b + 1
331 buffer[b] = code
332 end
333end
334
335local function flushrule(current, pos_h, pos_v, pos_r, size_h, size_v, subtype)
336 if subtype == normalrule_code then
337 b = b + 1
338 buffer[b] = f_rule(kind,pos_h*fc,pos_v*fc,size_h*fc,size_v*fc)
339 elseif subtype == outlinerule_code then
340 b = b + 1
341 buffer[b] = f_rule("d",pos_h*fc,pos_v*fc,size_h*fc,size_v*fc)
342 elseif subtype == userrule_code then
343
344
345
346 elseif subtype == emptyrule_code then
347
348 else
349
350
351 end
352end
353
354local function flushsimplerule(pos_h, pos_v, pos_r, size_h, size_v)
355 flushrule(false,pos_h,pos_v,pos_r,size_h,size_v,normalrule_code)
356end
357
358local function flushspecialrule(pos_h, pos_v, pos_r, w, h, d, l, outline)
359 flushrule(false,pos_h,pos_v-d,pos_r,w,h+d,outline and outlinerule_code or normalrule_code)
360end
361
362
363
364drivers.install {
365 name = "mpo",
366 actions = {
367 initialize = function()
368 reset()
369 end,
370 finalize = function(driver,details)
371 local bb = details.boundingbox
372 local llx = bb[1] * fc
373 local lly = bb[2] * fc
374 local urx = bb[3] * fc
375 local ury = bb[4] * fc
376 b = b + 1
377 buffer[b] = f_bounds(llx,lly,urx,ury)
378
379 end,
380 },
381 flushers = {
382 updatefontstate = updatefontstate,
383 character = flushcharacter,
384 rule = flushrule,
385 simplerule = flushsimplerule,
386 specialrule = flushspecialrule,
387 }
388}
389
390function metapost.boxtomp(n,k)
391 kind = k
392 nodes.handlers.finalizebox(n)
393 drivers.converters.lmtx(drivers.instances.mpo,texgetbox(n),"box",1)
394 local result = concat(buffer,";")
395 reset()
396 return result
397end
398
399 |