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