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