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