1if not modules then modules = { } end modules ['mlib-pps'] = {
2 version = 1.001,
3 comment = "companion to mlib-ctx.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 format, gmatch, match, split, gsub = string.format, string.gmatch, string.match, string.split, string.gsub
10local tonumber, type, unpack, next, select = tonumber, type, unpack, next, select
11local round, sqrt, min, max = math.round, math.sqrt, math.min, math.max
12local insert, remove, concat = table.insert, table.remove, table.concat
13local Cs, Cf, C, Cg, Ct, P, S, V, Carg = lpeg.Cs, lpeg.Cf, lpeg.C, lpeg.Cg, lpeg.Ct, lpeg.P, lpeg.S, lpeg.V, lpeg.Carg
14local lpegmatch, tsplitat, tsplitter = lpeg.match, lpeg.tsplitat, lpeg.tsplitter
15local formatters = string.formatters
16
17local mplib = mplib
18local metapost = metapost
19local lpdf = lpdf
20local context = context
21
22local implement = interfaces.implement
23local setmacro = interfaces.setmacro
24
25local texsetbox = tex.setbox
26local textakebox = tex.takebox
27local texrunlocal = tex.runlocal
28local copylist = nodes.copylist
29local flushlist = nodes.flushlist
30local setmetatableindex = table.setmetatableindex
31local sortedhash = table.sortedhash
32
33local new_hlist = nodes.pool.hlist
34
35local starttiming = statistics.starttiming
36local stoptiming = statistics.stoptiming
37
38local trace_runs = false trackers.register("metapost.runs", function(v) trace_runs = v end)
39local trace_textexts = false trackers.register("metapost.textexts", function(v) trace_textexts = v end)
40local trace_scripts = false trackers.register("metapost.scripts", function(v) trace_scripts = v end)
41local trace_btexetex = false trackers.register("metapost.btexetex", function(v) trace_btexetex = v end)
42
43local report_metapost = logs.reporter("metapost")
44local report_textexts = logs.reporter("metapost","textexts")
45local report_scripts = logs.reporter("metapost","scripts")
46
47local colors = attributes.colors
48local defineprocesscolor = colors.defineprocesscolor
49local definespotcolor = colors.definespotcolor
50local definemultitonecolor = colors.definemultitonecolor
51local colorvalue = colors.value
52
53local transparencies = attributes.transparencies
54local registertransparency = transparencies.register
55local transparencyvalue = transparencies.value
56
57local rgbtocmyk = colors.rgbtocmyk
58local cmyktorgb = colors.cmyktorgb
59local rgbtogray = colors.rgbtogray
60local cmyktogray = colors.cmyktogray
61
62local nooutercolor = "0 g 0 G"
63local nooutertransparency = "/Tr0 gs"
64local outercolormode = 0
65local outercolormodel = 1
66local outercolor = nooutercolor
67local outertransparency = nooutertransparency
68local innercolor = nooutercolor
69local innertransparency = nooutertransparency
70
71local pdfcolor = lpdf.color
72local pdftransparency = lpdf.transparency
73
74function metapost.setoutercolor(mode,colormodel,colorattribute,transparencyattribute)
75
76
77 outercolormode = mode
78 outercolormodel = colormodel
79 if mode == 1 or mode == 3 then
80
81 outercolor = pdfcolor(colormodel,colorattribute) or nooutercolor
82 outertransparency = pdftransparency(transparencyattribute) or nooutertransparency
83 elseif mode == 2 then
84
85 outercolor = ""
86 outertransparency = ""
87 else
88 outercolor = nooutercolor
89 outertransparency = nooutertransparency
90 end
91 innercolor = outercolor
92 innertransparency = outertransparency
93end
94
95
96
97local f_f = formatters["%.6N"]
98local f_f3 = formatters["%.3N"]
99local f_gray = formatters["%.3N g %.3N G"]
100local f_rgb = formatters["%.3N %.3N %.3N rg %.3N %.3N %.3N RG"]
101local f_cmyk = formatters["%.3N %.3N %.3N %.3N k %.3N %.3N %.3N %.3N K"]
102local f_cm_b = formatters["q %.6N %.6N %.6N %.6N %.6N %.6N cm"]
103local f_scn = formatters["%.3N"]
104
105local f_shade = formatters["MpSh%s"]
106local f_spot = formatters["/%s cs /%s CS %s SCN %s scn"]
107local s_cm_e = "Q"
108
109local function checked_color_pair(color,...)
110 if not color then
111 return innercolor, outercolor
112 end
113 if outercolormode == 3 then
114 innercolor = color(...)
115 return innercolor, innercolor
116 else
117 return color(...), outercolor
118 end
119end
120
121function metapost.colorinitializer()
122 innercolor = outercolor
123 innertransparency = outertransparency
124 return outercolor, outertransparency
125end
126
127
128
129local specificationsplitter = tsplitat(" ")
130local colorsplitter = tsplitter(":",tonumber)
131local domainsplitter = tsplitter(" ",tonumber)
132local centersplitter = domainsplitter
133local coordinatesplitter = domainsplitter
134
135
136
137
138
139
140local nofshades = 0
141
142local function normalize(ca,cb)
143 if #cb == 1 then
144 if #ca == 4 then
145 cb[1], cb[2], cb[3], cb[4] = 0, 0, 0, 1-cb[1]
146 else
147 cb[1], cb[2], cb[3] = cb[1], cb[1], cb[1]
148 end
149 elseif #cb == 3 then
150 if #ca == 4 then
151 cb[1], cb[2], cb[3], cb[4] = rgbtocmyk(cb[1],cb[2],cb[3])
152 else
153 cb[1], cb[2], cb[3] = cmyktorgb(cb[1],cb[2],cb[3],cb[4])
154 end
155 end
156end
157
158
159local commasplitter = tsplitat(",")
160
161local function checkandconvertspot(n_a,f_a,c_a,v_a,n_b,f_b,c_b,v_b)
162
163 local name = f_shade(nofshades)
164 local ca = lpegmatch(commasplitter,v_a)
165 local cb = lpegmatch(commasplitter,v_b)
166 if #ca == 0 or #cb == 0 then
167 return { 0 }, { 1 }, "DeviceGray", name
168 else
169 for i=1,#ca do ca[i] = tonumber(ca[i]) or 0 end
170 for i=1,#cb do cb[i] = tonumber(cb[i]) or 1 end
171
172 return ca, cb, n_a or n_b, name
173 end
174end
175
176local function checkandconvert(ca,cb,model)
177 local name = f_shade(nofshades)
178 if not ca or not cb or type(ca) == "string" then
179 return { 0 }, { 1 }, "DeviceGray", name
180 else
181 if #ca > #cb then
182 normalize(ca,cb)
183 elseif #ca < #cb then
184 normalize(cb,ca)
185 end
186 if not model then
187 model = colors.currentnamedmodel()
188 end
189 if model == "all" then
190 model= (#ca == 4 and "cmyk") or (#ca == 3 and "rgb") or "gray"
191 end
192 if model == "rgb" then
193 if #ca == 4 then
194 ca = { cmyktorgb(ca[1],ca[2],ca[3],ca[4]) }
195 cb = { cmyktorgb(cb[1],cb[2],cb[3],cb[4]) }
196 elseif #ca == 1 then
197 local a = 1 - ca[1]
198 local b = 1 - cb[1]
199 ca = { a, a, a }
200 cb = { b, b, b }
201 end
202 return ca, cb, "DeviceRGB", name, model
203 elseif model == "cmyk" then
204 if #ca == 3 then
205 ca = { rgbtocmyk(ca[1],ca[2],ca[3]) }
206 cb = { rgbtocmyk(cb[1],cb[2],cb[3]) }
207 elseif #ca == 1 then
208 ca = { 0, 0, 0, ca[1] }
209 cb = { 0, 0, 0, ca[1] }
210 end
211 return ca, cb, "DeviceCMYK", name, model
212 else
213 if #ca == 4 then
214 ca = { cmyktogray(ca[1],ca[2],ca[3],ca[4]) }
215 cb = { cmyktogray(cb[1],cb[2],cb[3],cb[4]) }
216 elseif #ca == 3 then
217 ca = { rgbtogray(ca[1],ca[2],ca[3]) }
218 cb = { rgbtogray(cb[1],cb[2],cb[3]) }
219 end
220
221 return ca, cb, "DeviceGray", name, model
222 end
223 end
224end
225
226
227
228
229
230
231local stack = { }
232local top = nil
233local nofruns = 0
234
235local function preset(t,k)
236
237 local v = {
238 textrial = 0,
239 texfinal = 0,
240 texslots = { },
241 texorder = { },
242 texhash = { },
243 }
244 t[k] = v
245 return v
246end
247
248local function startjob(plugmode,kind,mpx)
249 insert(stack,top)
250 top = {
251 textexts = { },
252 texstrings = { },
253 texregimes = { },
254 mapstrings = { },
255 mapindices = { },
256 mapmoves = { },
257 texlast = 0,
258 texdata = setmetatableindex({},preset),
259 plugmode = plugmode,
260 extradata = mpx and metapost.getextradata(mpx),
261 }
262 if trace_runs then
263 report_metapost("starting %s run at level %i in %s mode",
264 kind,#stack+1,plugmode and "plug" or "normal")
265 end
266 return top
267end
268
269local function stopjob()
270 if top then
271 for slot, content in next, top.textexts do
272 if content then
273 flushlist(content)
274 if trace_textexts then
275 report_textexts("freeing text %s",slot)
276 end
277 end
278 end
279 if trace_runs then
280 report_metapost("stopping run at level %i",#stack+1)
281 end
282 top = remove(stack)
283 return top
284 end
285end
286
287function metapost.getjobdata()
288 return top
289end
290
291
292
293local settext = function(box,slot,str)
294 if top then
295
296
297
298 top.textexts[slot] = textakebox(box)
299 end
300end
301
302local gettext = function(box,slot)
303 if top then
304 texsetbox(box,top.textexts[slot])
305 top.textexts[slot] = false
306
307
308
309 end
310end
311
312metapost.settext = settext
313metapost.gettext = gettext
314
315implement { name = "mpsettext", actions = settext, arguments = { "integer", "integer" } }
316implement { name = "mpgettext", actions = gettext, arguments = { "integer", "integer" } }
317
318
319
320
321
322metapost.reducetogray = true
323
324local models = { }
325
326function models.all(cr)
327 local n = #cr
328 if n == 0 then
329 return checked_color_pair()
330 elseif metapost.reducetogray then
331 if n == 1 then
332 local s = cr[1]
333 return checked_color_pair(f_gray,s,s)
334 elseif n == 3 then
335 local r = cr[1]
336 local g = cr[2]
337 local b = cr[3]
338 if r == g and g == b then
339 return checked_color_pair(f_gray,r,r)
340 else
341 return checked_color_pair(f_rgb,r,g,b,r,g,b)
342 end
343 else
344 local c = cr[1]
345 local m = cr[2]
346 local y = cr[3]
347 local k = cr[4]
348 if c == m and m == y and y == 0 then
349 k = 1 - k
350 return checked_color_pair(f_gray,k,k)
351 else
352 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
353 end
354 end
355 elseif n == 1 then
356 local s = cr[1]
357 return checked_color_pair(f_gray,s,s)
358 elseif n == 3 then
359 local r = cr[1]
360 local g = cr[2]
361 local b = cr[3]
362 return checked_color_pair(f_rgb,r,g,b,r,g,b)
363 else
364 local c = cr[1]
365 local m = cr[2]
366 local y = cr[3]
367 local k = cr[4]
368 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
369 end
370end
371
372function models.rgb(cr)
373 local n = #cr
374 if n == 0 then
375 return checked_color_pair()
376 elseif metapost.reducetogray then
377 if n == 1 then
378 local s = cr[1]
379 return checked_color_pair(f_gray,s,s)
380 elseif n == 3 then
381 local r = cr[1]
382 local g = cr[2]
383 local b = cr[3]
384 if r == g and g == b then
385 return checked_color_pair(f_gray,r,r)
386 else
387 return checked_color_pair(f_rgb,r,g,b,r,g,b)
388 end
389 else
390 local c = cr[1]
391 local m = cr[2]
392 local y = cr[3]
393 local k = cr[4]
394 if c == m and m == y and y == 0 then
395 k = 1 - k
396 return checked_color_pair(f_gray,k,k)
397 else
398 local r, g, b = cmyktorgb(c,m,y,k)
399 return checked_color_pair(f_rgb,r,g,b,r,g,b)
400 end
401 end
402 elseif n == 1 then
403 local s = cr[1]
404 return checked_color_pair(f_gray,s,s)
405 else
406 local r = cr[1]
407 local g = cr[2]
408 local b = cr[3]
409 local r, g, b
410 if n == 3 then
411 r, g, b = cmyktorgb(r,g,b,cr[4])
412 end
413 return checked_color_pair(f_rgb,r,g,b,r,g,b)
414 end
415end
416
417function models.cmyk(cr)
418 local n = #cr
419 if n == 0 then
420 return checked_color_pair()
421 elseif metapost.reducetogray then
422 if n == 1 then
423 local s = cr[1]
424 return checked_color_pair(f_gray,s,s)
425 elseif n == 3 then
426 local r = cr[1]
427 local g = cr[2]
428 local b = cr[3]
429 if r == g and g == b then
430 return checked_color_pair(f_gray,r,r)
431 else
432 local c, m, y, k = rgbtocmyk(r,g,b)
433 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
434 end
435 else
436 local c = cr[1]
437 local m = cr[2]
438 local y = cr[3]
439 local k = cr[4]
440 if c == m and m == y and y == 0 then
441 k = 1 - k
442 return checked_color_pair(f_gray,k,k)
443 else
444 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
445 end
446 end
447 elseif n == 1 then
448 local s = cr[1]
449 return checked_color_pair(f_gray,s,s)
450 else
451 local c = cr[1]
452 local m = cr[2]
453 local y = cr[3]
454 local k = cr[4]
455 if n == 3 then
456 if c == m and m == y then
457 k, c, m, y = 1 - c, 0, 0, 0
458 else
459 c, m, y, k = rgbtocmyk(c,m,y)
460 end
461 end
462 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
463 end
464end
465
466function models.gray(cr)
467 local n = #cr
468 local s = 0
469 if n == 0 then
470 return checked_color_pair()
471 elseif n == 4 then
472 s = cmyktogray(cr[1],cr[2],cr[3],cr[4])
473 elseif n == 3 then
474 s = rgbtogray(cr[1],cr[2],cr[3])
475 else
476 s = cr[1]
477 end
478 return checked_color_pair(f_gray,s,s)
479end
480
481models[1] = models.all
482models[2] = models.gray
483models[3] = models.rgb
484models[4] = models.cmyk
485
486setmetatableindex(models, function(t,k)
487 local v = models.gray
488 t[k] = v
489 return v
490end)
491
492local function colorconverter(cs)
493 return models[outercolormodel](cs)
494end
495
496local factor = 65536*(7227/7200)
497
498implement {
499 name = "mpsetsxsy",
500 arguments = { "dimen", "dimen", "dimen" },
501 actions = function(wd,ht,dp)
502 local hd = ht + dp
503 setmacro("mlib_sx",wd ~= 0 and factor/wd or 0)
504 setmacro("mlib_sy",hd ~= 0 and factor/hd or 0)
505 end
506}
507
508local function sxsy(wd,ht,dp)
509 local hd = ht + dp
510 return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0
511end
512
513metapost.sxsy = sxsy
514
515
516
517local do_begin_fig = "; beginfig(1) ; "
518local do_end_fig = "; endfig ;"
519local do_safeguard = ";"
520
521function metapost.preparetextextsdata()
522 local textexts = top.textexts
523 local collected = { }
524 for k, data in sortedhash(top.texdata) do
525 local texorder = data.texorder
526 for n=1,#texorder do
527 local box = textexts[texorder[n]]
528 if box then
529 collected[n] = box
530 else
531 break
532 end
533 end
534 end
535 mp.mf_tt_initialize(collected)
536end
537
538local runmetapost = metapost.run
539
540local function checkaskedfig(askedfig)
541 if not askedfig then
542 return "direct", true
543 elseif askedfig == "all" then
544 return "all", false
545 elseif askedfig == "direct" then
546 return "all", true
547 else
548 askedfig = tonumber(askedfig)
549 if askedfig then
550 return askedfig, false
551 else
552 return "direct", true
553 end
554 end
555end
556
557local function extrapass()
558 if trace_runs then
559 report_metapost("second run of job %s, asked figure %a",top.nofruns,top.askedfig)
560 end
561 metapost.preparetextextsdata()
562 runmetapost {
563 mpx = top.mpx,
564 askedfig = top.askedfig,
565 incontext = true,
566 data = {
567 top.wrappit and do_begin_fig or "",
568 no_trial_run,
569 top.initializations,
570 do_safeguard,
571 top.data,
572 top.wrappit and do_end_fig or "",
573 },
574 }
575end
576
577
578
579
580
581
582
583function metapost.graphic_base_pass(specification)
584 local mpx = specification.mpx
585 local top = startjob(true,"base",mpx)
586 local data = specification.data or ""
587 local inclusions = specification.inclusions or ""
588 local initializations = specification.initializations or ""
589 local askedfig,
590 wrappit = checkaskedfig(specification.figure)
591 nofruns = nofruns + 1
592 top.askedfig = askedfig
593 top.wrappit = wrappit
594 top.nofruns = nofruns
595 metapost.namespace = specification.namespace or ""
596 top.mpx = mpx
597 top.data = data
598 top.initializations = initializations
599 if trace_runs then
600 report_metapost("running job %s, asked figure %a",nofruns,askedfig)
601 end
602 runmetapost {
603 mpx = mpx,
604 askedfig = askedfig,
605 incontext = true,
606 data = {
607 inclusions,
608 wrappit and do_begin_fig or "",
609 initializations,
610 do_safeguard,
611 data,
612 wrappit and do_end_fig or "",
613 },
614 }
615 context(stopjob)
616end
617
618local function oldschool(mpx, data, trial_run, flusher, was_multi_pass, is_extra_pass, askedfig, incontext)
619 metapost.process {
620 mpx = mpx,
621 flusher = flusher,
622 askedfig = askedfig,
623 useplugins = incontext,
624 incontext = incontext,
625 data = data,
626 }
627end
628
629function metapost.process(specification,...)
630 if type(specification) ~= "table" then
631 oldschool(specification,...)
632 else
633 startjob(specification.incontext or specification.useplugins,"process",false)
634 runmetapost(specification)
635 stopjob()
636 end
637end
638
639
640
641local sequencers = utilities.sequencers
642local appendgroup = sequencers.appendgroup
643local appendaction = sequencers.appendaction
644
645local resetteractions = sequencers.new { arguments = "t" }
646local processoractions = sequencers.new { arguments = "object,prescript,before,after" }
647
648appendgroup(resetteractions, "system")
649appendgroup(processoractions,"system")
650
651
652
653local scriptsplitter = Ct ( Ct (
654 C((1-S("= "))^1) * S("= ")^1 * C((1-S("\n\r"))^0) * S("\n\r")^0
655)^0 )
656
657local function splitprescript(script)
658 local hash = lpegmatch(scriptsplitter,script)
659 for i=#hash,1,-1 do
660 local h = hash[i]
661 if h == "reset" then
662 for k, v in next, hash do
663 if type(k) ~= "number" then
664 hash[k] = nil
665 end
666 end
667 else
668 hash[h[1]] = h[2]
669 end
670 end
671 if trace_scripts then
672 report_scripts(table.serialize(hash,"prescript"))
673 end
674 return hash
675end
676
677metapost.splitprescript = splitprescript
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693function metapost.pluginactions(what,t,flushfigure)
694 if top and top.plugmode then
695 for i=1,#what do
696 local wi = what[i]
697 if type(wi) == "function" then
698
699 flushfigure(t)
700 t = { }
701 wi()
702 else
703 t[#t+1] = wi
704 end
705 end
706 return t
707 end
708end
709
710function metapost.resetplugins(t)
711 if top and top.plugmode then
712 outercolormodel = colors.currentmodel()
713 resetteractions.runner(t)
714 end
715end
716
717function metapost.processplugins(object)
718 if top and top.plugmode then
719 local prescript = object.prescript
720 if prescript and #prescript > 0 then
721 local before = { }
722 local after = { }
723 processoractions.runner(object,splitprescript(prescript) or { },before,after)
724 return #before > 0 and before, #after > 0 and after
725 else
726 local c = object.color
727 if c and #c > 0 then
728 local b, a = colorconverter(c)
729 return { b }, { a }
730 end
731 end
732 end
733end
734
735
736
737local basepoints = number.dimenfactors["bp"]
738
739local function cm(object)
740 local op = object.path
741 if op then
742 local first = op[1]
743 local second = op[2]
744 local fourth = op[4]
745 if fourth then
746 local tx = first.x_coord
747 local ty = first.y_coord
748 local sx = second.x_coord - tx
749 local sy = fourth.y_coord - ty
750 local rx = second.y_coord - ty
751 local ry = fourth.x_coord - tx
752 if sx == 0 then sx = 0.00001 end
753 if sy == 0 then sy = 0.00001 end
754 return sx, rx, ry, sy, tx, ty
755 end
756 end
757 return 1, 0, 0, 1, 0, 0
758end
759
760metapost.cm = cm
761
762
763
764local function cl_reset(t)
765 t[#t+1] = metapost.colorinitializer()
766end
767
768
769
770local tx_reset, tx_process do
771
772 local eol = S("\n\r")^1
773 local cleaner = Cs((P("@@")/"@" + P("@")/"%%" + P(1))^0)
774 local splitter = Ct(
775 ( (
776 P("s:") * C((1-eol)^1)
777 + P("n:") * ((1-eol)^1/tonumber)
778 + P("b:") * ((1-eol)^1/toboolean)
779 ) * eol^0 )^0)
780
781 local function applyformat(s)
782 local t = lpegmatch(splitter,s)
783 if #t == 1 then
784 return s
785 else
786 local f = lpegmatch(cleaner,t[1])
787 return formatters[f](unpack(t,2))
788 end
789 end
790
791 local fmt = formatters["%s %s %s % t"]
792
793 local pat = lpeg.tsplitter(":",tonumber)
794
795 local f_gray_yes = formatters["s=%.3N,a=%i,t=%.3N"]
796 local f_gray_nop = formatters["s=%.3N"]
797 local f_rgb_yes = formatters["r=%.3N,g=%.3N,b=%.3N,a=%.3N,t=%.3N"]
798 local f_rgb_nop = formatters["r=%.3N,g=%.3N,b=%.3N"]
799 local f_cmyk_yes = formatters["c=%.3N,m=%.3N,y=%.3N,k=%.3N,a=%.3N,t=%.3N"]
800 local f_cmyk_nop = formatters["c=%.3N,m=%.3N,y=%.3N,k=%.3N"]
801
802 local ctx_MPLIBsetNtext = context.MPLIBsetNtextX
803 local ctx_MPLIBsetCtext = context.MPLIBsetCtextX
804 local ctx_MPLIBsettext = context.MPLIBsettextX
805
806 local bp = number.dimenfactors.bp
807
808 local mp_index = 0
809 local mp_target = 0
810 local mp_c = nil
811 local mp_a = nil
812 local mp_t = nil
813
814 local function processtext()
815 local mp_text = top.texstrings[mp_index]
816 local mp_regime = top.texregimes[mp_index]
817 if mp_regime and tonumber(mp_regime) >= 0 then
818 mp_text = function()
819 context.sprint(mp_regime,top.texstrings[mp_index] or "")
820 end
821 end
822 if not mp_text then
823 report_textexts("missing text for index %a",mp_index)
824 elseif not mp_c then
825 ctx_MPLIBsetNtext(mp_target,mp_text)
826 elseif #mp_c == 1 then
827 if mp_a and mp_t then
828 ctx_MPLIBsetCtext(mp_target,f_gray_yes(mp_c[1],mp_a,mp_t),mp_text)
829 else
830 ctx_MPLIBsetCtext(mp_target,f_gray_nop(mp_c[1]),mp_text)
831 end
832 elseif #mp_c == 3 then
833 if mp_a and mp_t then
834 ctx_MPLIBsetCtext(mp_target,f_rgb_yes(mp_c[1],mp_c[2],mp_c[3],mp_a,mp_t),mp_text)
835 else
836 ctx_MPLIBsetCtext(mp_target,f_rgb_nop(mp_c[1],mp_c[2],mp_c[3]),mp_text)
837 end
838 elseif #mp_c == 4 then
839 if mp_a and mp_t then
840 ctx_MPLIBsetCtext(mp_target,f_cmyk_yes(mp_c[1],mp_c[2],mp_c[3],mp_c[4],mp_a,mp_t),mp_text)
841 else
842 ctx_MPLIBsetCtext(mp_target,f_cmyk_nop(mp_c[1],mp_c[2],mp_c[3],mp_c[4]),mp_text)
843 end
844 else
845
846 ctx_MPLIBsetNtext(mp_target,mp_text)
847 end
848 end
849
850 local madetext = nil
851
852 function mp.mf_some_text(index,str,regime)
853 mp_target = index
854 mp_index = index
855 mp_c = nil
856 mp_a = nil
857 mp_t = nil
858 top.texstrings[mp_index] = str
859 top.texregimes[mp_index] = regime or -1
860 texrunlocal("mptexttoks")
861 local box = textakebox("mptextbox")
862 top.textexts[mp_target] = box
863 mp.triplet(bp*box.width,bp*box.height,bp*box.depth)
864 madetext = nil
865 end
866
867 function mp.mf_made_text(index)
868 mp.mf_some_text(index,madetext,catcodes.numbers.ctxcatcodes)
869 end
870
871
872
873
874 function metapost.processing()
875 return top and true or false
876 end
877
878 function metapost.remaptext(replacement)
879 if top then
880 local mapstrings = top.mapstrings
881 local mapindices = top.mapindices
882 local label = replacement.label
883 local index = 0
884 if label then
885 local found = mapstrings[label]
886 if found then
887 setmetatableindex(found,replacement)
888 index = found.index
889 else
890 index = #mapindices + 1
891 replacement.index = index
892 mapindices[index] = replacement
893 mapstrings[label] = replacement
894 end
895 end
896 return index
897 else
898 return 0
899 end
900 end
901
902 function metapost.remappedtext(what)
903 return top and (top.mapstrings[what] or top.mapindices[tonumber(what)])
904 end
905
906 function mp.mf_map_move(index)
907 mp.triplet(top.mapmoves[index])
908 end
909
910 function mp.mf_map_text(index,str,regime)
911 local map = top.mapindices[tonumber(str)]
912 if type(map) == "table" then
913 local text = map.text
914 local overload = map.overload
915 local offset = 0
916 local width = 0
917 local where = nil
918
919 mp_index = index
920
921 if overload then
922 top.texstrings[mp_index] = map.template or map.label or "error"
923 top.texregimes[mp_index] = regime or -1
924 texrunlocal("mptexttoks")
925 local box = textakebox("mptextbox") or new_hlist()
926 width = bp * box.width
927 where = overload.where
928 end
929
930 top.texstrings[mp_index] = overload and overload.text or text or "error"
931 top.texregimes[mp_index] = regime or -1
932 texrunlocal("mptexttoks")
933 local box = textakebox("mptextbox") or new_hlist()
934 local twd = bp * box.width
935 local tht = bp * box.height
936 local tdp = bp * box.depth
937
938 if where then
939 local scale = 1
940 if where == "l" or where == "left" then
941 offset = scale * (twd - width)
942 elseif where == "m" or where == "middle" then
943 offset = scale * (twd - width) / 2
944 end
945 end
946
947 top.textexts[mp_index] = box
948 top.mapmoves[mp_index] = { offset, map.dx or 0, map.dy or 0 }
949
950 mp.triplet(twd,tht,tdp)
951 madetext = nil
952 return
953 else
954 map = type(map) == "string" and map or str
955 return mp.mf_some_text(index,context.escape(map) or map)
956 end
957 end
958
959
960
961
962
963
964
965
966 local reported = false
967 local alwayswrap = false
968
969 function metapost.maketext(s,mode)
970 if not reported then
971 reported = true
972 report_metapost("use 'textext(.....)' instead of 'btex ..... etex'")
973 end
974 if mode and mode == 1 then
975 if trace_btexetex then
976 report_metapost("ignoring verbatimtex: [[%s]]",s)
977 end
978 elseif alwayswrap then
979 if trace_btexetex then
980 report_metapost("rewrapping btex ... etex [[%s]]",s)
981 end
982 return 'rawtextext("' .. gsub(s,'"','"&ditto&"') .. '")'
983 elseif metapost.currentmpxstatus() ~= 0 then
984 if trace_btexetex then
985 report_metapost("rewrapping btex ... etex at the outer level [[%s]]",s)
986 end
987 return 'rawtextext("' .. gsub(s,'"','"&ditto&"') .. '")'
988 else
989 if trace_btexetex then
990 report_metapost("handling btex ... etex: [[%s]]",s)
991 end
992
993 madetext = s
994 return "rawmadetext"
995 end
996 end
997
998 function mp.mf_formatted_text(index,fmt,...)
999 local t = { }
1000 for i=1,select("#",...) do
1001 local ti = select(i,...)
1002 if type(ti) ~= "table" then
1003 t[#t+1] = ti
1004 end
1005 end
1006 local f = lpegmatch(cleaner,fmt)
1007 local s = formatters[f](unpack(t)) or ""
1008 mp.mf_some_text(index,s)
1009 end
1010
1011 interfaces.implement {
1012 name = "mptexttoks",
1013 actions = processtext,
1014 }
1015
1016 tx_reset = function()
1017 if top then
1018 top.texhash = { }
1019 top.texlast = 0
1020 end
1021 end
1022
1023 tx_process = function(object,prescript,before,after)
1024 local data = top.texdata[metapost.properties.number]
1025 local index = tonumber(prescript.tx_index)
1026 if index then
1027 if trace_textexts then
1028 report_textexts("using index %a",index)
1029 end
1030
1031 mp_c = object.color
1032 if #mp_c == 0 then
1033 local txc = prescript.tx_color
1034 if txc then
1035 mp_c = lpegmatch(pat,txc)
1036 end
1037 end
1038 mp_a = tonumber(prescript.tr_alternative)
1039 mp_t = tonumber(prescript.tr_transparency)
1040
1041 mp_index = index
1042 mp_target = top.texlast - 1
1043 top.texlast = mp_target
1044
1045 local mp_text = top.texstrings[mp_index]
1046 local mp_hash = prescript.tx_cache
1047 local box
1048 if mp_hash == "no" then
1049 texrunlocal("mptexttoks")
1050 box = textakebox("mptextbox")
1051 else
1052 local cache = data.texhash
1053 if mp_hash then
1054 mp_hash = tonumber(mp_hash)
1055 end
1056 if mp_hash then
1057 local extradata = top.extradata
1058 if extradata then
1059 cache = extradata.globalcache
1060 if not cache then
1061 cache = { }
1062 extradata.globalcache = cache
1063 end
1064 if trace_runs then
1065 if cache[mp_hash] then
1066 report_textexts("reusing global entry %i",mp_hash)
1067 else
1068 report_textexts("storing global entry %i",mp_hash)
1069 end
1070 end
1071 else
1072 mp_hash = nil
1073 end
1074 end
1075 if not mp_hash then
1076 mp_hash = fmt(mp_text,mp_a or "-",mp_t or "-",mp_c or "-")
1077 end
1078 box = cache[mp_hash]
1079 if box then
1080 box = copylist(box)
1081 else
1082 texrunlocal("mptexttoks")
1083 box = textakebox("mptextbox")
1084 cache[mp_hash] = box
1085 end
1086 end
1087 top.textexts[mp_target] = box
1088
1089 if box then
1090
1091 local sx, rx, ry, sy, tx, ty = cm(object)
1092 local target = mp_target
1093 before[#before+1] = function()
1094 context.MPLIBgettextscaledcm(target,
1095 f_f(sx),
1096 f_f(rx),
1097 f_f(ry),
1098 f_f(sy),
1099 f_f(tx),
1100 f_f(ty),
1101 sxsy(box.width,box.height,box.depth))
1102 end
1103 else
1104 before[#before+1] = function()
1105 report_textexts("unknown %s",index)
1106 end
1107 end
1108 if not trace_textexts then
1109 object.path = false
1110 end
1111 object.color = false
1112 object.grouped = true
1113 object.istext = true
1114 end
1115 end
1116
1117end
1118
1119
1120
1121
1122local function bx_process(object,prescript,before,after)
1123 local bx_category = prescript.bx_category
1124 local bx_name = prescript.bx_name
1125 if bx_category and bx_name then
1126 if trace_textexts then
1127 report_textexts("category %a, name %a",bx_category,bx_name)
1128 end
1129 local sx, rx, ry, sy, tx, ty = cm(object)
1130 local wd, ht, dp = nodes.boxes.dimensions(bx_category,bx_name)
1131 before[#before+1] = function()
1132 context.MPLIBgetboxscaledcm(bx_category,bx_name,
1133 f_f(sx),
1134 f_f(rx),
1135 f_f(ry),
1136 f_f(sy),
1137 f_f(tx),
1138 f_f(ty),
1139 sxsy(wd,ht,dp))
1140 end
1141 if not trace_textexts then
1142 object.path = false
1143 end
1144 object.color = false
1145 object.grouped = true
1146 object.istext = true
1147 end
1148end
1149
1150
1151
1152
1153local gt_reset, gt_process do
1154
1155 local graphics = { }
1156
1157
1158 local mp_index = 0
1159 local mp_str = ""
1160
1161 function mp.mf_graphic_text(index,str)
1162 if not graphics[index] then
1163 mp_index = index
1164 mp_str = str
1165 texrunlocal("mpgraphictexttoks")
1166 end
1167 end
1168
1169 interfaces.implement {
1170 name = "mpgraphictexttoks",
1171 actions = function()
1172 context.MPLIBgraphictext(mp_index,mp_str)
1173 end,
1174 }
1175
1176end
1177
1178
1179
1180local function sh_process(object,prescript,before,after)
1181 local sh_type = prescript.sh_type
1182 if sh_type then
1183 nofshades = nofshades + 1
1184 local domain = lpegmatch(domainsplitter,prescript.sh_domain or "0 1")
1185 local centera = lpegmatch(centersplitter,prescript.sh_center_a or "0 0")
1186 local centerb = lpegmatch(centersplitter,prescript.sh_center_b or "0 0")
1187 local transform = toboolean(prescript.sh_transform or "yes",true)
1188
1189 local sx = 1
1190 local sy = 1
1191 local sr = 1
1192 local dx = 0
1193 local dy = 0
1194 if transform then
1195 local first = lpegmatch(coordinatesplitter,prescript.sh_first or "0 0")
1196 local setx = lpegmatch(coordinatesplitter,prescript.sh_set_x or "0 0")
1197 local sety = lpegmatch(coordinatesplitter,prescript.sh_set_y or "0 0")
1198
1199 local x = setx[1]
1200 local y = sety[1]
1201
1202 if x == 0 or y == 0 then
1203
1204 else
1205 local path = object.path
1206 local path1x = path[1].x_coord
1207 local path1y = path[1].y_coord
1208 local path2x = path[x].x_coord
1209 local path2y = path[y].y_coord
1210
1211 local dxa = path2x - path1x
1212 local dya = path2y - path1y
1213 local dxb = setx[2] - first[1]
1214 local dyb = sety[2] - first[2]
1215
1216 if dxa == 0 or dya == 0 or dxb == 0 or dyb == 0 then
1217
1218 else
1219 sx = dxa / dxb ; if sx < 0 then sx = - sx end
1220 sy = dya / dyb ; if sy < 0 then sy = - sy end
1221
1222 sr = sqrt(sx^2 + sy^2)
1223
1224 dx = path1x - sx*first[1]
1225 dy = path1y - sy*first[2]
1226 end
1227 end
1228 end
1229
1230 local steps = tonumber(prescript.sh_step) or 1
1231 local sh_color_a = prescript.sh_color_a_1 or prescript.sh_color_a or "1"
1232 local sh_color_b = prescript.sh_color_b_1 or prescript.sh_color_b or "1"
1233 local ca, cb, colorspace, name, model, separation, fractions
1234 if prescript.sh_color == "into" and prescript.sp_name then
1235
1236 local value_a, components_a, fractions_a, name_a
1237 local value_b, components_b, fractions_b, name_b
1238 for i=1,#prescript do
1239
1240
1241
1242
1243
1244
1245
1246 local tag = prescript[i][1]
1247 if not name_a and tag == "sh_color_a" then
1248 value_a = prescript[i-5][2]
1249 components_a = prescript[i-4][2]
1250 fractions_a = prescript[i-3][2]
1251 name_a = prescript[i-2][2]
1252 elseif not name_b and tag == "sh_color_b" then
1253 value_b = prescript[i-5][2]
1254 components_b = prescript[i-4][2]
1255 fractions_b = prescript[i-3][2]
1256 name_b = prescript[i-2][2]
1257 end
1258 if name_a and name_b then
1259 break
1260 end
1261 end
1262 ca, cb, separation, name = checkandconvertspot(
1263 name_a,fractions_a,components_a,value_a,
1264 name_b,fractions_b,components_b,value_b
1265 )
1266 else
1267 local colora = lpegmatch(colorsplitter,sh_color_a)
1268 local colorb = lpegmatch(colorsplitter,sh_color_b)
1269 ca, cb, colorspace, name, model = checkandconvert(colora,colorb)
1270
1271 if steps > 1 then
1272 ca = { ca }
1273 cb = { cb }
1274 fractions = { tonumber(prescript[formatters["sh_fraction_%i"](1)]) or 0 }
1275 for i=2,steps do
1276 local colora = lpegmatch(colorsplitter,prescript[formatters["sh_color_a_%i"](i)])
1277 local colorb = lpegmatch(colorsplitter,prescript[formatters["sh_color_b_%i"](i)])
1278 ca[i], cb[i] = checkandconvert(colora,colorb,model)
1279 fractions[i] = tonumber(prescript[formatters["sh_fraction_%i"](i)]) or (i/steps)
1280 end
1281 end
1282 end
1283 if not ca or not cb then
1284 ca, cb, colorspace, name = checkandconvert()
1285 steps = 1
1286 end
1287 if sh_type == "linear" then
1288 local coordinates = { dx + sx*centera[1], dy + sy*centera[2], dx + sx*centerb[1], dy + sy*centerb[2] }
1289 lpdf.linearshade(name,domain,ca,cb,1,colorspace,coordinates,separation,steps>1 and steps,fractions)
1290 elseif sh_type == "circular" then
1291 local factor = tonumber(prescript.sh_factor) or 1
1292 local radiusa = factor * tonumber(prescript.sh_radius_a)
1293 local radiusb = factor * tonumber(prescript.sh_radius_b)
1294 local coordinates = { dx + sx*centera[1], dy + sy*centera[2], sr*radiusa, dx + sx*centerb[1], dy + sy*centerb[2], sr*radiusb }
1295 lpdf.circularshade(name,domain,ca,cb,1,colorspace,coordinates,separation,steps>1 and steps,fractions)
1296 else
1297
1298 end
1299 before[#before+1] = "q /Pattern cs"
1300 after [#after+1] = formatters["W n /%s sh Q"](name)
1301
1302 object.colored = false
1303 object.type = false
1304 object.grouped = true
1305 end
1306end
1307
1308
1309
1310local function bm_process(object,prescript,before,after)
1311 local bm_xresolution = prescript.bm_xresolution
1312 if bm_xresolution then
1313 before[#before+1] = f_cm_b(cm(object))
1314 before[#before+1] = function()
1315 figures.bitmapimage {
1316 xresolution = tonumber(bm_xresolution),
1317 yresolution = tonumber(prescript.bm_yresolution),
1318 width = 1/basepoints,
1319 height = 1/basepoints,
1320 data = object.postscript
1321 }
1322 end
1323 before[#before+1] = s_cm_e
1324 object.path = false
1325 object.color = false
1326 object.grouped = true
1327 end
1328end
1329
1330
1331
1332local function ps_process(object,prescript,before,after)
1333 local ps_label = prescript.ps_label
1334 if ps_label then
1335 local op = object.path
1336 local first = op[1]
1337 local third = op[3]
1338 local x = first.x_coord
1339 local y = first.y_coord
1340 local w = third.x_coord - x
1341 local h = third.y_coord - y
1342 local properties = metapost.properties
1343 x = x - properties.llx
1344 y = properties.ury - y
1345 before[#before+1] = function()
1346 context.MPLIBpositionwhd(ps_label,x,y,w,h)
1347 end
1348 object.path = false
1349 end
1350end
1351
1352
1353
1354
1355
1356
1357function mp.mf_external_figure(filename)
1358 local f = figures.getinfo(filename)
1359 local w = 0
1360 local h = 0
1361 if f then
1362 local u = f.used
1363 if u and u.fullname then
1364 w = u.width or 0
1365 h = u.height or 0
1366 end
1367 else
1368 report_metapost("external figure %a not found",filename)
1369 end
1370 mp.triplet(w/65536,h/65536,0)
1371end
1372
1373local function fg_process(object,prescript,before,after)
1374 local fg_name = prescript.fg_name
1375 if fg_name then
1376 before[#before+1] = f_cm_b(cm(object))
1377 before[#before+1] = function()
1378 context.MPLIBfigure(fg_name,prescript.fg_mask or "")
1379 end
1380 before[#before+1] = s_cm_e
1381 object.path = false
1382 object.grouped = true
1383 end
1384end
1385
1386
1387
1388local value = Cs ( (
1389 (Carg(1) * C((1-P(","))^1)) / function(a,b) return f_f3(a * tonumber(b)) end
1390 + P(","))^1
1391)
1392
1393
1394
1395local t_list = attributes.list[attributes.private('transparency')]
1396local c_list = attributes.list[attributes.private('color')]
1397
1398local remappers = {
1399 [1] = formatters["s=%s"],
1400 [3] = formatters["r=%s,g=%s,b=%s"],
1401 [4] = formatters["c=%s,m=%s,y=%s,k=%s"],
1402}
1403
1404local processlast = 0
1405local processhash = setmetatableindex(function(t,k)
1406 processlast = processlast + 1
1407 local v = formatters["mp_%s"](processlast)
1408 defineprocesscolor(v,k,true,true)
1409 t[k] = v
1410 return v
1411end)
1412
1413local function checked_transparency(alternative,transparency,before,after)
1414 alternative = tonumber(alternative) or 1
1415 transparency = tonumber(transparency) or 0
1416 before[#before+1] = formatters["/Tr%s gs"](registertransparency(nil,alternative,transparency,true))
1417 after [#after +1] = "/Tr0 gs"
1418end
1419
1420local function tr_process(object,prescript,before,after)
1421
1422 local tr_alternative = prescript.tr_alternative
1423 if tr_alternative then
1424 checked_transparency(tr_alternative,prescript.tr_transparency,before,after)
1425 end
1426 local cs = object.color
1427 if cs and #cs > 0 then
1428 local c_b, c_a
1429 local sp_type = prescript.sp_type
1430 if not sp_type then
1431 c_b, c_a = colorconverter(cs)
1432 else
1433 local sp_name = prescript.sp_name or "black"
1434 if sp_type == "spot" then
1435 local sp_value = prescript.sp_value or "1"
1436 local components = split(sp_value,":")
1437 local specification = remappers[#components]
1438 if specification then
1439 specification = specification(unpack(components))
1440 else
1441 specification = "s=0"
1442 end
1443 local sp_spec = processhash[specification]
1444 definespotcolor(sp_name,sp_spec,"p=1",true)
1445 sp_type = "named"
1446 elseif sp_type == "multitone" then
1447 local sp_value = prescript.sp_value or "1"
1448 local sp_specs = { }
1449 local sp_list = split(sp_value," ")
1450 for i=1,#sp_list do
1451 local sp_value = sp_list[i]
1452 local components = split(sp_value,":")
1453 local specification = remappers[#components]
1454 if specification then
1455 specification = specification(unpack(components))
1456 else
1457 specification = "s=0"
1458 end
1459 local sp_spec = processhash[specification]
1460 sp_specs[i] = formatters["%s=1"](sp_spec)
1461 end
1462 sp_specs = concat(sp_specs,",")
1463 definemultitonecolor(sp_name,sp_specs,"","")
1464 sp_type = "named"
1465 elseif sp_type == "named" then
1466 cs = { 1 }
1467 end
1468 if sp_type == "named" then
1469
1470
1471
1472 if not tr_alternative then
1473
1474 local t = t_list[sp_name]
1475 local v = t and transparencyvalue(t)
1476 if v then
1477 checked_transparency(v[1],v[2],before,after)
1478 end
1479 end
1480 local c = c_list[sp_name]
1481 local v = c and colorvalue(c)
1482 if v then
1483
1484 local colorspace = v[1]
1485 local factor = cs[1]
1486 if colorspace == 2 then
1487 local s = factor * v[2]
1488 c_b, c_a = checked_color_pair(f_gray,s,s)
1489 elseif colorspace == 3 then
1490 local r = factor * v[3]
1491 local g = factor * v[4]
1492 local b = factor * v[5]
1493 c_b, c_a = checked_color_pair(f_rgb,r,g,b,r,g,b)
1494 elseif colorspace == 4 or colorspace == 1 then
1495 local c = factor * v[6]
1496 local m = factor * v[7]
1497 local y = factor * v[8]
1498 local k = factor * v[9]
1499 c_b, c_a = checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
1500 elseif colorspace == 5 then
1501
1502 local name = v[10]
1503 local value = split(v[13],",")
1504 if factor ~= 1 then
1505 for i=1,#value do
1506 value[i] = f_scn(factor * (tonumber(value[i]) or 1))
1507 end
1508 end
1509 value = concat(value," ")
1510 c_b, c_a = checked_color_pair(f_spot,name,name,value,value)
1511 else
1512 local s = factor *v[2]
1513 c_b, c_a = checked_color_pair(f_gray,s,s)
1514 end
1515 end
1516 end
1517 end
1518 if c_a and c_b then
1519 before[#before+1] = c_b
1520 after [#after +1] = c_a
1521 end
1522 end
1523end
1524
1525
1526
1527local function la_process(object,prescript,before,after)
1528 local la_name = prescript.la_name
1529 if la_name then
1530 before[#before+1] = backends.codeinjections.startlayer(la_name)
1531 insert(after,1,backends.codeinjections.stoplayer())
1532 end
1533end
1534
1535
1536
1537local function gr_process(object,prescript,before,after)
1538 local gr_state = prescript.gr_state
1539 if not gr_state then
1540 return
1541 elseif gr_state == "start" then
1542 local gr_type = utilities.parsers.settings_to_set(prescript.gr_type)
1543 local path = object.path
1544 local p1 = path[1]
1545 local p2 = path[2]
1546 local p3 = path[3]
1547 local p4 = path[4]
1548 local llx = min(p1.x_coord,p2.x_coord,p3.x_coord,p4.x_coord)
1549 local lly = min(p1.y_coord,p2.y_coord,p3.y_coord,p4.y_coord)
1550 local urx = max(p1.x_coord,p2.x_coord,p3.x_coord,p4.x_coord)
1551 local ury = max(p1.y_coord,p2.y_coord,p3.y_coord,p4.y_coord)
1552 before[#before+1] = function()
1553 context.MPLIBstartgroup(
1554 gr_type.isolated and 1 or 0,
1555 gr_type.knockout and 1 or 0,
1556 llx, lly, urx, ury
1557 )
1558 end
1559 elseif gr_state == "stop" then
1560 after[#after+1] = function()
1561 context.MPLIBstopgroup()
1562 end
1563 end
1564 object.path = false
1565 object.color = false
1566 object.grouped = true
1567end
1568
1569
1570
1571local ot_reset, ot_process do
1572
1573 local outlinetexts = { }
1574
1575 ot_reset = function ()
1576 outlinetexts = { }
1577 end
1578
1579 local mp_index = 0
1580 local mp_kind = ""
1581 local mp_str = ""
1582
1583 function mp.mf_outline_text(index,str,kind)
1584 if not outlinetexts[index] then
1585 mp_index = index
1586 mp_kind = kind
1587 mp_str = str
1588 texrunlocal("mpoutlinetoks")
1589 end
1590 end
1591
1592 interfaces.implement {
1593 name = "mpoutlinetoks",
1594 actions = function()
1595 context.MPLIBoutlinetext(mp_index,mp_kind,mp_str)
1596 end,
1597 }
1598
1599 implement {
1600 name = "MPLIBconvertoutlinetext",
1601 arguments = { "integer", "string", "integer" },
1602 actions = function(index,kind,box)
1603 local boxtomp = fonts.metapost.boxtomp
1604 if boxtomp then
1605 outlinetexts[index] = boxtomp(box,kind)
1606 else
1607 outlinetexts[index] = ""
1608 end
1609 end
1610 }
1611
1612 function mp.mf_get_outline_text(index)
1613 mp.print(outlinetexts[index] or "draw origin;")
1614 end
1615
1616end
1617
1618
1619
1620local p1 = P("mf_object=")
1621local p2 = lpeg.patterns.eol * p1
1622local pattern = (1-p2)^0 * p2 + p1
1623
1624function metapost.isobject(str)
1625 return pattern and str ~= "" and lpegmatch(p,str) and true or false
1626end
1627
1628local function installplugin(specification)
1629 local reset = specification.reset
1630 local process = specification.process
1631 local object = specification.object
1632 if reset then
1633 appendaction(resetteractions,"system",reset)
1634 end
1635 if process then
1636 appendaction(processoractions,"system",process)
1637 end
1638end
1639
1640metapost.installplugin = installplugin
1641
1642
1643
1644installplugin { name = "outline", reset = ot_reset, process = ot_process }
1645installplugin { name = "color", reset = cl_reset, process = cl_process }
1646installplugin { name = "text", reset = tx_reset, process = tx_process }
1647installplugin { name = "group", reset = gr_reset, process = gr_process }
1648installplugin { name = "graphictext", reset = gt_reset, process = gt_process }
1649installplugin { name = "shade", reset = sh_reset, process = sh_process }
1650installplugin { name = "bitmap", reset = bm_reset, process = bm_process }
1651installplugin { name = "box", reset = bx_reset, process = bx_process }
1652installplugin { name = "position", reset = ps_reset, process = ps_process }
1653installplugin { name = "figure", reset = fg_reset, process = fg_process }
1654installplugin { name = "layer", reset = la_reset, process = la_process }
1655installplugin { name = "transparency", reset = tr_reset, process = tr_process }
1656 |