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 = formatters["%.6N %.6N %.6N %.6N %.6N %.6N cm"]
115local f_cm_b = formatters["q %.6N %.6N %.6N %.6N %.6N %.6N cm"]
116
117local f_scn = formatters["%.3N"]
118
119local f_shade = formatters["MpSh%s"]
120local f_spot = formatters["/%s cs /%s CS %s SCN %s scn"]
121
122local s_cm_e <const> = "Q"
123
124local function checked_color_pair(color,...)
125 if not color then
126 return innercolor, outercolor
127 end
128 if outercolormode == 3 then
129 innercolor = color(...)
130 return innercolor, innercolor
131 else
132 return color(...), outercolor
133 end
134end
135
136function metapost.colorinitializer()
137 innercolor = outercolor
138 innertransparency = outertransparency
139 return outercolor, outertransparency
140end
141
142
143
144local specificationsplitter = tsplitat(" ")
145local colorsplitter = tsplitter(":",tonumber)
146local domainsplitter = tsplitter(" ",tonumber)
147local centersplitter = domainsplitter
148local coordinatesplitter = domainsplitter
149
150
151
152
153
154
155local nofshades = 0
156
157local function normalize(ca,cb)
158 if #cb == 1 then
159 if #ca == 4 then
160 cb[1], cb[2], cb[3], cb[4] = 0, 0, 0, 1-cb[1]
161 else
162 cb[1], cb[2], cb[3] = cb[1], cb[1], cb[1]
163 end
164 elseif #cb == 3 then
165 if #ca == 4 then
166 cb[1], cb[2], cb[3], cb[4] = rgbtocmyk(cb[1],cb[2],cb[3])
167 else
168 cb[1], cb[2], cb[3] = cmyktorgb(cb[1],cb[2],cb[3],cb[4])
169 end
170 end
171end
172
173
174local commasplitter = tsplitat(",")
175
176local function checkandconvertspot(n_a,f_a,c_a,v_a,n_b,f_b,c_b,v_b)
177
178 local name = f_shade(nofshades)
179 local ca = lpegmatch(commasplitter,v_a)
180 local cb = lpegmatch(commasplitter,v_b)
181 if #ca == 0 or #cb == 0 then
182 return { 0 }, { 1 }, "DeviceGray", name
183 else
184 for i=1,#ca do ca[i] = tonumber(ca[i]) or 0 end
185 for i=1,#cb do cb[i] = tonumber(cb[i]) or 1 end
186
187 return ca, cb, n_a or n_b, name
188 end
189end
190
191local function checkandconvert(ca,cb,model)
192 local name = f_shade(nofshades)
193 if not ca or not cb or type(ca) == "string" then
194 return { 0 }, { 1 }, "DeviceGray", name
195 else
196 if #ca > #cb then
197 normalize(ca,cb)
198 elseif #ca < #cb then
199 normalize(cb,ca)
200 end
201 if not model then
202 model = colors.currentnamedmodel()
203 end
204 if model == "all" then
205 model= (#ca == 4 and "cmyk") or (#ca == 3 and "rgb") or "gray"
206 end
207 if model == "rgb" then
208 if #ca == 4 then
209 ca = { cmyktorgb(ca[1],ca[2],ca[3],ca[4]) }
210 cb = { cmyktorgb(cb[1],cb[2],cb[3],cb[4]) }
211 elseif #ca == 1 then
212 local a = 1 - ca[1]
213 local b = 1 - cb[1]
214 ca = { a, a, a }
215 cb = { b, b, b }
216 end
217 return ca, cb, "DeviceRGB", name, model
218 elseif model == "cmyk" then
219 if #ca == 3 then
220 ca = { rgbtocmyk(ca[1],ca[2],ca[3]) }
221 cb = { rgbtocmyk(cb[1],cb[2],cb[3]) }
222 elseif #ca == 1 then
223 ca = { 0, 0, 0, ca[1] }
224 cb = { 0, 0, 0, ca[1] }
225 end
226 return ca, cb, "DeviceCMYK", name, model
227 else
228 if #ca == 4 then
229 ca = { cmyktogray(ca[1],ca[2],ca[3],ca[4]) }
230 cb = { cmyktogray(cb[1],cb[2],cb[3],cb[4]) }
231 elseif #ca == 3 then
232 ca = { rgbtogray(ca[1],ca[2],ca[3]) }
233 cb = { rgbtogray(cb[1],cb[2],cb[3]) }
234 end
235
236 return ca, cb, "DeviceGray", name, model
237 end
238 end
239end
240
241
242
243
244
245
246local stack = { }
247local top = nil
248local nofruns = 0
249
250local function preset(t,k)
251
252 local v = {
253 textrial = 0,
254 texfinal = 0,
255 texslots = { },
256 texorder = { },
257 texhash = { },
258 }
259 t[k] = v
260 return v
261end
262
263
264
265local function startjob(plugmode,kind,mpx)
266 insert(stack,top)
267 top = {
268 textexts = { },
269 texstrings = { },
270 texregimes = { },
271 mapstrings = { },
272 mapindices = { },
273 mapmoves = { },
274 texlast = 0,
275 texdata = setmetatableindex({},preset),
276 plugmode = plugmode,
277 extradata = mpx and metapost.getextradata(mpx),
278 }
279 if trace_runs then
280 report_metapost("starting %s run at level %i in %s mode",
281 kind,#stack+1,plugmode and "plug" or "normal")
282 end
283 return top
284end
285
286local function stopjob()
287 if top then
288 for slot, content in next, top.textexts do
289 if content then
290 flushlist(content)
291 if trace_textexts then
292 report_textexts("freeing text %s",slot)
293 end
294 end
295 end
296 if trace_runs then
297 report_metapost("stopping run at level %i",#stack+1)
298 end
299 top = remove(stack)
300 return top
301 end
302end
303
304function metapost.getjobdata()
305 return top
306end
307
308
309
310local settext = function(box,slot,str)
311 if top then
312
313
314
315 top.textexts[slot] = textakebox(box)
316 end
317end
318
319local gettext = function(box,slot)
320 if top then
321 texsetbox(box,top.textexts[slot])
322 top.textexts[slot] = false
323
324
325
326 end
327end
328
329metapost.settext = settext
330metapost.gettext = gettext
331
332implement { name = "mpsettext", actions = settext, arguments = { "integer", "integer" } }
333implement { name = "mpgettext", actions = gettext, arguments = { "integer", "integer" } }
334
335
336
337
338
339metapost.reducetogray = true
340
341local models = { }
342
343function models.all(cr)
344 local n = #cr
345 if n == 0 then
346 return checked_color_pair()
347 elseif metapost.reducetogray then
348 if n == 1 then
349 local s = cr[1]
350 return checked_color_pair(f_gray,s,s)
351 elseif n == 3 then
352 local r = cr[1]
353 local g = cr[2]
354 local b = cr[3]
355 if r == g and g == b then
356 return checked_color_pair(f_gray,r,r)
357 else
358 return checked_color_pair(f_rgb,r,g,b,r,g,b)
359 end
360 else
361 local c = cr[1]
362 local m = cr[2]
363 local y = cr[3]
364 local k = cr[4]
365 if c == m and m == y and y == 0 then
366 k = 1 - k
367 return checked_color_pair(f_gray,k,k)
368 else
369 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
370 end
371 end
372 elseif n == 1 then
373 local s = cr[1]
374 return checked_color_pair(f_gray,s,s)
375 elseif n == 3 then
376 local r = cr[1]
377 local g = cr[2]
378 local b = cr[3]
379 return checked_color_pair(f_rgb,r,g,b,r,g,b)
380 else
381 local c = cr[1]
382 local m = cr[2]
383 local y = cr[3]
384 local k = cr[4]
385 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
386 end
387end
388
389function models.rgb(cr)
390 local n = #cr
391 if n == 0 then
392 return checked_color_pair()
393 elseif metapost.reducetogray then
394 if n == 1 then
395 local s = cr[1]
396 return checked_color_pair(f_gray,s,s)
397 elseif n == 3 then
398 local r = cr[1]
399 local g = cr[2]
400 local b = cr[3]
401 if r == g and g == b then
402 return checked_color_pair(f_gray,r,r)
403 else
404 return checked_color_pair(f_rgb,r,g,b,r,g,b)
405 end
406 else
407 local c = cr[1]
408 local m = cr[2]
409 local y = cr[3]
410 local k = cr[4]
411 if c == m and m == y and y == 0 then
412 k = 1 - k
413 return checked_color_pair(f_gray,k,k)
414 else
415 local r, g, b = cmyktorgb(c,m,y,k)
416 return checked_color_pair(f_rgb,r,g,b,r,g,b)
417 end
418 end
419 elseif n == 1 then
420 local s = cr[1]
421 return checked_color_pair(f_gray,s,s)
422 else
423 local r = cr[1]
424 local g = cr[2]
425 local b = cr[3]
426 local r, g, b
427 if n == 3 then
428 r, g, b = cmyktorgb(r,g,b,cr[4])
429 end
430 return checked_color_pair(f_rgb,r,g,b,r,g,b)
431 end
432end
433
434function models.cmyk(cr)
435 local n = #cr
436 if n == 0 then
437 return checked_color_pair()
438 elseif metapost.reducetogray then
439 if n == 1 then
440 local s = cr[1]
441 return checked_color_pair(f_gray,s,s)
442 elseif n == 3 then
443 local r = cr[1]
444 local g = cr[2]
445 local b = cr[3]
446 if r == g and g == b then
447 return checked_color_pair(f_gray,r,r)
448 else
449 local c, m, y, k = rgbtocmyk(r,g,b)
450 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
451 end
452 else
453 local c = cr[1]
454 local m = cr[2]
455 local y = cr[3]
456 local k = cr[4]
457 if c == m and m == y and y == 0 then
458 k = 1 - k
459 return checked_color_pair(f_gray,k,k)
460 else
461 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
462 end
463 end
464 elseif n == 1 then
465 local s = cr[1]
466 return checked_color_pair(f_gray,s,s)
467 else
468 local c = cr[1]
469 local m = cr[2]
470 local y = cr[3]
471 local k = cr[4]
472 if n == 3 then
473 if c == m and m == y then
474 k, c, m, y = 1 - c, 0, 0, 0
475 else
476 c, m, y, k = rgbtocmyk(c,m,y)
477 end
478 end
479 return checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
480 end
481end
482
483function models.gray(cr)
484 local n = #cr
485 local s = 0
486 if n == 0 then
487 return checked_color_pair()
488 elseif n == 4 then
489 s = cmyktogray(cr[1],cr[2],cr[3],cr[4])
490 elseif n == 3 then
491 s = rgbtogray(cr[1],cr[2],cr[3])
492 else
493 s = cr[1]
494 end
495 return checked_color_pair(f_gray,s,s)
496end
497
498models[1] = models.all
499models[2] = models.gray
500models[3] = models.rgb
501models[4] = models.cmyk
502
503setmetatableindex(models, function(t,k)
504 local v = models.gray
505 t[k] = v
506 return v
507end)
508
509local function colorconverter(cs)
510 return models[outercolormodel](cs)
511end
512
513local factor = 65536*(7227/7200)
514
515implement {
516 name = "mpsetsxsy",
517 arguments = { "dimension", "dimension", "dimension" },
518 actions = function(wd,ht,dp)
519 local hd = ht + dp
520 setmacro("mlib_sx",wd ~= 0 and factor/wd or 0)
521 setmacro("mlib_sy",hd ~= 0 and factor/hd or 0)
522 end
523}
524
525local function sxsy(wd,ht,dp)
526 local hd = ht + dp
527 return (wd ~= 0 and factor/wd) or 0, (hd ~= 0 and factor/hd) or 0
528end
529
530metapost.sxsy = sxsy
531
532
533
534local do_begin_fig <const> = "; beginfig(1) ; "
535local do_end_fig <const> = "; endfig ;"
536local do_safeguard <const> = ";"
537
538function metapost.preparetextextsdata()
539 local textexts = top.textexts
540 local collected = { }
541 for k, data in sortedhash(top.texdata) do
542 local texorder = data.texorder
543 for n=1,#texorder do
544 local box = textexts[texorder[n]]
545 if box then
546 collected[n] = box
547 else
548 break
549 end
550 end
551 end
552 mp.mf_tt_initialize(collected)
553end
554
555local runmetapost = metapost.run
556
557local function checkaskedfig(askedfig)
558 if not askedfig then
559 return "direct", true
560 elseif askedfig == "all" then
561 return "all", false
562 elseif askedfig == "direct" then
563 return "all", true
564 else
565 askedfig = tonumber(askedfig)
566 if askedfig then
567 return askedfig, false
568 else
569 return "direct", true
570 end
571 end
572end
573
574
575
576
577
578
579
580function metapost.graphic_base_pass(specification)
581 local mpx = specification.mpx
582 local top = startjob(true,"base",mpx)
583 local data = specification.data or ""
584 local inclusions = specification.inclusions or ""
585 local filtering = specification.filtering
586 local initializations = specification.initializations or ""
587 local askedfig,
588 wrappit = checkaskedfig(specification.figure)
589 nofruns = nofruns + 1
590 top.askedfig = askedfig
591 top.wrappit = wrappit
592 top.nofruns = nofruns
593 metapost.namespace = specification.namespace or ""
594 top.mpx = mpx
595 top.data = data
596 top.initializations = initializations
597 if filtering then
598 if #filtering > 0 then
599 local t = typesetters.stacking.getselection(filtering)
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 local fasttrack = false
864
865 directives.register("metapost.text.fasttrack", function(v) fasttrack = v end)
866
867
868
869 local function mf_some_text(index,str,regime)
870 mp_target = index
871 mp_index = index
872 mp_c = nil
873 mp_a = nil
874 mp_t = nil
875 top.texstrings[mp_index] = str
876 top.texregimes[mp_index] = regime or -1
877 if trace_textexts then
878 report_textexts("running mptextoks, case 1: %s",top.texstrings[mp_index])
879 end
880 texrunlocal("mptexttoks")
881 local box = textakebox("mptextbox")
882 top.textexts[mp_target] = box
883 injecttriplet(bp*box.width,bp*box.height,bp*box.depth)
884 madetext = nil
885 end
886
887 local function mf_made_text(index)
888 mf_some_text(index,madetext,catcodes.numbers.ctxcatcodes)
889 end
890
891 registerdirect("sometextext", function() mf_some_text(mpscannumeric(),mpscanstring(),mpscannumeric()) end)
892 registerdirect("madetextext", function() mf_made_text(mpscannumeric()) end)
893
894
895
896
897 function metapost.processing()
898 return top and true or false
899 end
900
901 function metapost.remaptext(replacement)
902 if top then
903 local mapstrings = top.mapstrings
904 local mapindices = top.mapindices
905 local label = replacement.label
906 local index = 0
907 if label then
908 local found = mapstrings[label]
909 if found then
910 setmetatableindex(found,replacement)
911 index = found.index
912 else
913 index = #mapindices + 1
914 replacement.index = index
915 mapindices[index] = replacement
916 mapstrings[label] = replacement
917 end
918 end
919 return index
920 else
921 return 0
922 end
923 end
924
925 function metapost.remappedtext(what)
926 return top and (top.mapstrings[what] or top.mapindices[tonumber(what)])
927 end
928
929 function mp.mf_map_move(index)
930 mp.triplet(top.mapmoves[index])
931 end
932
933 function mp.mf_map_text(index,str,regime)
934 local map = top.mapindices[tonumber(str)]
935 if type(map) == "table" then
936 local text = map.text
937 local overload = map.overload
938 local offset = 0
939 local width = 0
940 local where = nil
941
942 mp_index = index
943
944 if overload then
945 top.texstrings[mp_index] = map.template or map.label or "error"
946 top.texregimes[mp_index] = regime or -1
947 if trace_textexts then
948 report_textexts("running mptextoks, case 2",top.texstrings[mp_index])
949 end
950 texrunlocal("mptexttoks")
951 local box = textakebox("mptextbox") or new_hlist()
952 width = bp * box.width
953 where = overload.where
954 end
955
956 top.texstrings[mp_index] = overload and overload.text or text or "error"
957 top.texregimes[mp_index] = regime or -1
958 if trace_textexts then
959 report_textexts("running mptextoks, case 3",top.texstrings[mp_index])
960 end
961 texrunlocal("mptexttoks")
962 local box = textakebox("mptextbox") or new_hlist()
963 local twd = bp * box.width
964 local tht = bp * box.height
965 local tdp = bp * box.depth
966
967 if where then
968 local scale = 1
969 if where == "l" or where == "left" then
970 offset = scale * (twd - width)
971 elseif where == "m" or where == "middle" then
972 offset = scale * (twd - width) / 2
973 end
974 end
975
976 top.textexts[mp_index] = box
977 top.mapmoves[mp_index] = { offset, map.dx or 0, map.dy or 0 }
978
979 mp.triplet(twd,tht,tdp)
980 madetext = nil
981 return
982 else
983 map = type(map) == "string" and map or str
984 return mf_some_text(index,context.escape(map) or map)
985 end
986 end
987
988
989
990
991
992
993
994
995 local reported = false
996 local alwayswrap = false
997
998 function metapost.maketext(s,mode)
999 if not reported then
1000 reported = true
1001 report_metapost("use 'textext(.....)' instead of 'btex ..... etex'")
1002 end
1003 if mode and mode == 1 then
1004 if trace_btexetex then
1005 report_metapost("ignoring verbatimtex: [[%s]]",s)
1006 end
1007 elseif alwayswrap then
1008 if trace_btexetex then
1009 report_metapost("rewrapping btex ... etex [[%s]]",s)
1010 end
1011 return 'rawtextext("' .. gsub(s,'"','"&ditto&"') .. '")'
1012 elseif metapost.currentmpxstatus() ~= 0 then
1013 if trace_btexetex then
1014 report_metapost("rewrapping btex ... etex at the outer level [[%s]]",s)
1015 end
1016 return 'rawtextext("' .. gsub(s,'"','"&ditto&"') .. '")'
1017 else
1018 if trace_btexetex then
1019 report_metapost("handling btex ... etex: [[%s]]",s)
1020 end
1021
1022 madetext = s
1023 return "rawmadetext"
1024 end
1025 end
1026
1027 function mp.mf_formatted_text(index,fmt,...)
1028 local t = { }
1029 for i=1,select("#",...) do
1030 local ti = select(i,...)
1031 if type(ti) ~= "table" then
1032 t[#t+1] = ti
1033 end
1034 end
1035 local f = lpegmatch(cleaner,fmt)
1036 local s = formatters[f](unpack(t)) or ""
1037 mf_some_text(index,s)
1038 end
1039
1040 interfaces.implement {
1041 name = "mptexttoks",
1042 actions = processtext,
1043 }
1044
1045 tx_reset = function()
1046 if top then
1047 top.texhash = { }
1048 top.texlast = 0
1049 end
1050 end
1051
1052 tx_process = function(object,prescript,before,after)
1053 local data = top.texdata[metapost.properties.number]
1054 local index = tonumber(prescript.tx_index)
1055 if index then
1056 if trace_textexts then
1057 report_textexts("using index %a",index)
1058 end
1059
1060 mp_c = object.color
1061 if #mp_c == 0 then
1062 local txc = prescript.tx_color
1063 if txc then
1064 mp_c = lpegmatch(pat,txc)
1065 end
1066 end
1067 mp_a = tonumber(prescript.tr_alternative)
1068 mp_t = tonumber(prescript.tr_transparency)
1069
1070 mp_index = index
1071 mp_target = top.texlast - 1
1072 top.texlast = mp_target
1073
1074 local mp_text = top.texstrings[mp_index]
1075 local mp_hash = prescript.tx_cache
1076 local box
1077 local donebox = fasttrack and top.textexts[mp_index]
1078 if mp_hash == "no" then
1079 if donebox then
1080 box = copylist(donebox)
1081 else
1082 if trace_textexts then
1083 report_textexts("running mptextoks, case 4",top.texstrings[mp_index])
1084 end
1085 texrunlocal("mptexttoks")
1086 box = textakebox("mptextbox")
1087 end
1088 else
1089 local cache = data.texhash
1090 if mp_hash then
1091 mp_hash = tonumber(mp_hash)
1092 end
1093 if mp_hash then
1094 local extradata = top.extradata
1095 if extradata then
1096 cache = extradata.globalcache
1097 if not cache then
1098 cache = { }
1099 extradata.globalcache = cache
1100 end
1101 if trace_runs then
1102 if cache[mp_hash] then
1103 report_textexts("reusing global entry %i",mp_hash)
1104 else
1105 report_textexts("storing global entry %i",mp_hash)
1106 end
1107 end
1108 else
1109 mp_hash = nil
1110 end
1111 end
1112 if not mp_hash then
1113 mp_hash = fmt(mp_text,mp_a or "-",mp_t or "-",mp_c or "-")
1114 end
1115 box = cache[mp_hash]
1116 if box then
1117 box = copylist(box)
1118 else
1119 if donebox then
1120 box = copylist(donebox)
1121 else
1122 if trace_textexts then
1123 report_textexts("running mptextoks, case 5",top.texstrings[mp_index])
1124 end
1125 texrunlocal("mptexttoks")
1126 box = textakebox("mptextbox")
1127 end
1128 cache[mp_hash] = box
1129 end
1130 end
1131 top.textexts[mp_target] = box
1132
1133 if box then
1134
1135 local sx, rx, ry, sy, tx, ty = cm(object)
1136 local target = mp_target
1137 before[#before+1] = function()
1138 context.MPLIBgettextscaledcm(target,
1139 f_f(sx),
1140 f_f(rx),
1141 f_f(ry),
1142 f_f(sy),
1143 f_f(tx),
1144 f_f(ty),
1145 sxsy(box.width,box.height,box.depth))
1146 end
1147 else
1148 before[#before+1] = function()
1149 report_textexts("unknown %s",index)
1150 end
1151 end
1152 if not trace_textexts then
1153 object.path = false
1154 end
1155 object.color = false
1156 object.grouped = true
1157 object.istext = true
1158 end
1159 end
1160
1161end
1162
1163
1164
1165
1166local function bx_process(object,prescript,before,after)
1167 local bx_category = prescript.bx_category
1168 local bx_name = prescript.bx_name
1169 if bx_category and bx_name then
1170 if trace_textexts then
1171 report_textexts("category %a, name %a",bx_category,bx_name)
1172 end
1173 local sx, rx, ry, sy, tx, ty = cm(object)
1174 local wd, ht, dp = nodes.boxes.dimensions(bx_category,bx_name)
1175 before[#before+1] = function()
1176 context.MPLIBgetboxscaledcm(bx_category,bx_name,
1177 f_f(sx),
1178 f_f(rx),
1179 f_f(ry),
1180 f_f(sy),
1181 f_f(tx),
1182 f_f(ty),
1183 sxsy(wd,ht,dp))
1184 end
1185 if not trace_textexts then
1186 object.path = false
1187 end
1188 object.color = false
1189 object.grouped = true
1190 object.istext = true
1191 end
1192end
1193
1194
1195
1196
1197local gt_reset, gt_process do
1198
1199 local graphics = { }
1200
1201 local mp_index = 0
1202 local mp_str = ""
1203
1204 function mp.mf_graphic_text(index,str)
1205 if not graphics[index] then
1206 mp_index = index
1207 mp_str = str
1208 texrunlocal("mpgraphictexttoks")
1209 end
1210 end
1211
1212 interfaces.implement {
1213 name = "mpgraphictexttoks",
1214 actions = function()
1215 context.MPLIBgraphictext(mp_index,mp_str)
1216 end,
1217 }
1218
1219end
1220
1221
1222
1223
1224local function sh_process(object,prescript,before,after)
1225 local sh_type = prescript.sh_type
1226 if sh_type then
1227 nofshades = nofshades + 1
1228 local domain = lpegmatch(domainsplitter,prescript.sh_domain or "0 1")
1229 local centera = lpegmatch(centersplitter,prescript.sh_center_a or "0 0")
1230 local centerb = lpegmatch(centersplitter,prescript.sh_center_b or "0 0")
1231 local transform = toboolean(prescript.sh_transform or "yes",true)
1232 local transformation = prescript.sh_transformation
1233 if transformation then
1234 transformation = lpegmatch(coordinatesplitter,transformation)
1235 end
1236
1237 local sx = 1
1238 local sy = 1
1239 local sr = 1
1240 local dx = 0
1241 local dy = 0
1242 if transform then
1243 local first = lpegmatch(coordinatesplitter,prescript.sh_first or "0 0")
1244 local setx = lpegmatch(coordinatesplitter,prescript.sh_set_x or "0 0")
1245 local sety = lpegmatch(coordinatesplitter,prescript.sh_set_y or "0 0")
1246
1247 local x = setx[1]
1248 local y = sety[1]
1249
1250 if x == 0 or y == 0 then
1251
1252 else
1253 local path = object.path
1254 local path1x = path[1].x_coord
1255 local path1y = path[1].y_coord
1256 local path2x = path[x].x_coord
1257 local path2y = path[y].y_coord
1258
1259 local dxa = path2x - path1x
1260 local dya = path2y - path1y
1261 local dxb = setx[2] - first[1]
1262 local dyb = sety[2] - first[2]
1263
1264 if dxa == 0 or dya == 0 or dxb == 0 or dyb == 0 then
1265
1266 else
1267 sx = dxa / dxb ; if sx < 0 then sx = - sx end
1268 sy = dya / dyb ; if sy < 0 then sy = - sy end
1269
1270 sr = sqrt(sx^2 + sy^2)
1271
1272 dx = path1x - sx*first[1]
1273 dy = path1y - sy*first[2]
1274 end
1275 end
1276 end
1277
1278
1279
1280
1281 local steps = tonumber(prescript.sh_step) or 1
1282 local sh_color_a = prescript.sh_color_a_1 or prescript.sh_color_a or "1"
1283 local sh_color_b = prescript.sh_color_b_1 or prescript.sh_color_b or "1"
1284 local ca, cb, colorspace, name, model, separation, fractions, opacities
1285 if prescript.sh_color == "into" and prescript.sp_name then
1286
1287 local value_a, components_a, fractions_a, name_a
1288 local value_b, components_b, fractions_b, name_b
1289 for i=1,#prescript do
1290
1291
1292
1293
1294
1295
1296
1297 local tag = prescript[i][1]
1298 if not name_a and tag == "sh_color_a" then
1299 value_a = prescript[i-5][2]
1300 components_a = prescript[i-4][2]
1301 fractions_a = prescript[i-3][2]
1302 name_a = prescript[i-2][2]
1303 elseif not name_b and tag == "sh_color_b" then
1304 value_b = prescript[i-5][2]
1305 components_b = prescript[i-4][2]
1306 fractions_b = prescript[i-3][2]
1307 name_b = prescript[i-2][2]
1308 end
1309 if name_a and name_b then
1310 break
1311 end
1312 end
1313 ca, cb, separation, name = checkandconvertspot(
1314 name_a,fractions_a,components_a,value_a,
1315 name_b,fractions_b,components_b,value_b
1316 )
1317 else
1318 local colora = lpegmatch(colorsplitter,sh_color_a)
1319 local colorb = lpegmatch(colorsplitter,sh_color_b)
1320 ca, cb, colorspace, name, model = checkandconvert(colora,colorb)
1321
1322 if steps > 1 then
1323 ca = { ca }
1324 cb = { cb }
1325
1326 fractions = { tonumber(prescript[formatters["sh_fraction_%i"](1)]) or 0 }
1327 opacities = { tonumber(prescript[formatters["sh_opacity_%i"](1)]) or false }
1328 for i=2,steps do
1329 local colora = lpegmatch(colorsplitter,prescript[formatters["sh_color_a_%i"](i)])
1330 local colorb = lpegmatch(colorsplitter,prescript[formatters["sh_color_b_%i"](i)])
1331 ca[i], cb[i] = checkandconvert(colora,colorb,model)
1332 fractions[i] = tonumber(prescript[formatters["sh_fraction_%i"](i)]) or (i/steps)
1333 opacities[i] = tonumber(prescript[formatters["sh_opacity_%i"](i)]) or false
1334 end
1335 end
1336 end
1337 if not ca or not cb then
1338 ca, cb, colorspace, name = checkandconvert()
1339 steps = 1
1340 end
1341 if sh_type == "linear" then
1342 local coordinates = { dx + sx*centera[1], dy + sy*centera[2], dx + sx*centerb[1], dy + sy*centerb[2] }
1343 lpdf.linearshade(name,domain,ca,cb,1,colorspace,coordinates,separation,steps>1 and steps,fractions,opacities)
1344 elseif sh_type == "circular" then
1345 local factor = tonumber(prescript.sh_factor) or 1
1346 local radiusa = factor * tonumber(prescript.sh_radius_a)
1347 local radiusb = factor * tonumber(prescript.sh_radius_b)
1348 local coordinates = { dx + sx*centera[1], dy + sy*centera[2], sr*radiusa, dx + sx*centerb[1], dy + sy*centerb[2], sr*radiusb }
1349 lpdf.circularshade(name,domain,ca,cb,1,colorspace,coordinates,separation,steps>1 and steps,fractions,opacities)
1350 else
1351
1352 end
1353
1354 before[#before+1] = "q /Pattern cs"
1355 if transformation then
1356 before[#before+1] = f_cm(unpack(transformation))
1357 end
1358 after[#after+1] = formatters["W n /%s sh Q"](name)
1359
1360 object.color = false
1361 object.type = false
1362 object.grouped = true
1363 end
1364end
1365
1366
1367
1368local function bm_process(object,prescript,before,after)
1369 local bm_xresolution = prescript.bm_xresolution
1370 local bm_yresolution = prescript.bm_yresolution
1371 if bm_xresolution then
1372
1373 local sx, rx, ry, sy, tx, ty = cm(object)
1374 local postscript = object.postscript
1375 before[#before+1] = function()
1376 context.MPLIBscaledcm(
1377 function()
1378 figures.bitmapimage {
1379 xresolution = tonumber(bm_xresolution),
1380 yresolution = tonumber(bm_yresolution),
1381 width = 1/basepoints,
1382 height = 1/basepoints,
1383 data = postscript,
1384 format = "png",
1385 }
1386 end,
1387 sx, rx, ry, sy, tx, ty
1388 )
1389 end
1390
1391 object.path = false
1392 object.color = false
1393 object.grouped = true
1394 end
1395end
1396
1397
1398
1399local function ps_process(object,prescript,before,after)
1400 local ps_label = prescript.ps_label
1401 if ps_label then
1402 local op = object.path
1403 local first = op[1]
1404 local third = op[3]
1405 local x, y, w, h
1406 if first and third then
1407 local properties = metapost.properties
1408 x = first.x_coord
1409 y = first.y_coord
1410 w = third.x_coord - x
1411 h = third.y_coord - y
1412 x = x - properties.llx
1413 y = properties.ury - y
1414 else
1415 x = 0
1416 y = 0
1417 w = 0
1418 h = 0
1419 end
1420 before[#before+1] = function()
1421 context.MPLIBpositionwhd(ps_label,x,y,w,h)
1422 end
1423 object.path = false
1424 end
1425end
1426
1427
1428
1429
1430
1431
1432function mp.mf_external_figure(filename)
1433 local f = figures.getinfo(filename)
1434 local w = 0
1435 local h = 0
1436 if f then
1437 local u = f.used
1438 if u and u.fullname then
1439 w = u.width or 0
1440 h = u.height or 0
1441 end
1442 else
1443 report_metapost("external figure %a not found",filename)
1444 end
1445 mp.triplet(w/65536,h/65536,0)
1446end
1447
1448local function fg_process(object,prescript,before,after)
1449 local fg_name = prescript.fg_name
1450 if fg_name then
1451 before[#before+1] = f_cm_b(cm(object))
1452 before[#before+1] = function()
1453 context.MPLIBfigure(fg_name,prescript.fg_mask or "")
1454 end
1455 before[#before+1] = s_cm_e
1456 object.path = false
1457 object.grouped = true
1458 end
1459end
1460
1461
1462
1463local value = Cs ( (
1464 (Carg(1) * C((1-P(","))^1)) / function(a,b) return f_f3(a * tonumber(b)) end
1465 + P(","))^1
1466)
1467
1468
1469
1470local t_list = attributes.list[attributes.private('transparency')]
1471local c_list = attributes.list[attributes.private('color')]
1472
1473local remappers = {
1474 [1] = formatters["s=%s"],
1475 [3] = formatters["r=%s,g=%s,b=%s"],
1476 [4] = formatters["c=%s,m=%s,y=%s,k=%s"],
1477}
1478
1479local processlast = 0
1480local processhash = setmetatableindex(function(t,k)
1481 processlast = processlast + 1
1482 local v = formatters["mp_%s"](processlast)
1483 defineprocesscolor(v,k,true,true)
1484 t[k] = v
1485 return v
1486end)
1487
1488local function checked_transparency(alternative,transparency,before,after)
1489 alternative = tonumber(alternative) or 1
1490 transparency = tonumber(transparency) or 0
1491 before[#before+1] = formatters["/Tr%s gs"](registertransparency(nil,alternative,transparency,true))
1492 after [#after +1] = "/Tr0 gs"
1493end
1494
1495local function tr_process(object,prescript,before,after)
1496
1497 local tr_alternative = prescript.tr_alternative
1498 if tr_alternative then
1499 checked_transparency(tr_alternative,prescript.tr_transparency,before,after)
1500 end
1501 local cs = object.color
1502 if cs and #cs > 0 then
1503 local c_b, c_a
1504 local sp_type = prescript.sp_type
1505
1506
1507 if not sp_type then
1508 c_b, c_a = colorconverter(cs)
1509 else
1510 local sp_name = prescript.sp_name or "black"
1511 if sp_type == "spot" then
1512 local sp_value = prescript.sp_value or "1"
1513 local components = split(sp_value,":")
1514 local specification = remappers[#components]
1515 if specification then
1516 specification = specification(unpack(components))
1517 else
1518 specification = "s=0"
1519 end
1520 local sp_spec = processhash[specification]
1521 definespotcolor(sp_name,sp_spec,"p=1",true)
1522 sp_type = "named"
1523 elseif sp_type == "multitone" then
1524 local sp_value = prescript.sp_value or "1"
1525 local sp_specs = { }
1526 local sp_list = split(sp_value," ")
1527 for i=1,#sp_list do
1528 local sp_value = sp_list[i]
1529 local components = split(sp_value,":")
1530 local specification = remappers[#components]
1531 if specification then
1532 specification = specification(unpack(components))
1533 else
1534 specification = "s=0"
1535 end
1536 local sp_spec = processhash[specification]
1537 sp_specs[i] = formatters["%s=1"](sp_spec)
1538 end
1539 sp_specs = concat(sp_specs,",")
1540 definemultitonecolor(sp_name,sp_specs,"","")
1541 sp_type = "named"
1542 elseif sp_type == "named" then
1543
1544 end
1545 if sp_type == "named" then
1546
1547
1548
1549 if not tr_alternative then
1550
1551 local t = t_list[sp_name]
1552 local v = t and transparencyvalue(t)
1553 if v then
1554 checked_transparency(v[1],v[2],before,after)
1555 end
1556 end
1557 local c = c_list[sp_name]
1558 local v = c and colorvalue(c)
1559 if v then
1560
1561 local colorspace = v[1]
1562 local factor = cs[1]
1563 if colorspace == 2 then
1564 local s = factor * v[2]
1565 c_b, c_a = checked_color_pair(f_gray,s,s)
1566 elseif colorspace == 3 then
1567 local r = factor * v[3]
1568 local g = factor * v[4]
1569 local b = factor * v[5]
1570 c_b, c_a = checked_color_pair(f_rgb,r,g,b,r,g,b)
1571 elseif colorspace == 4 or colorspace == 1 then
1572 local c = factor * v[6]
1573 local m = factor * v[7]
1574 local y = factor * v[8]
1575 local k = factor * v[9]
1576 c_b, c_a = checked_color_pair(f_cmyk,c,m,y,k,c,m,y,k)
1577 elseif colorspace == 5 then
1578
1579 local name = v[10]
1580 local value = split(v[13],",")
1581 if factor ~= 1 then
1582 for i=1,#value do
1583 value[i] = f_scn(factor * (tonumber(value[i]) or 1))
1584 end
1585 end
1586 value = concat(value," ")
1587 c_b, c_a = checked_color_pair(f_spot,name,name,value,value)
1588 else
1589 local s = factor *v[2]
1590 c_b, c_a = checked_color_pair(f_gray,s,s)
1591 end
1592 end
1593 end
1594 end
1595 if c_a and c_b then
1596 before[#before+1] = c_b
1597 after [#after +1] = c_a
1598 end
1599 end
1600end
1601
1602
1603
1604local function la_process(object,prescript,before,after)
1605 local la_name = prescript.la_name
1606 if la_name then
1607 local codeinjections = backends.codeinjections
1608 before[#before+1] = codeinjections.startlayer(la_name)
1609 insert( after, 1, codeinjections.stoplayer())
1610 end
1611end
1612
1613
1614
1615local function getcorners(path)
1616
1617
1618
1619 local p1 = path[1]
1620 local p2 = path[2]
1621 local p3 = path[3]
1622 local p4 = path[4]
1623 return
1624 min(p1.x_coord,p2.x_coord,p3.x_coord,p4.x_coord),
1625 min(p1.y_coord,p2.y_coord,p3.y_coord,p4.y_coord),
1626 max(p1.x_coord,p2.x_coord,p3.x_coord,p4.x_coord),
1627 max(p1.y_coord,p2.y_coord,p3.y_coord,p4.y_coord)
1628
1629end
1630
1631
1632
1633local function gr_process(object,prescript,before,after)
1634 local gr_state = prescript.gr_state
1635 if not gr_state then
1636 return
1637 elseif gr_state == "start" then
1638 local gr_type = utilities.parsers.settings_to_set(prescript.gr_type)
1639 local llx, lly, urx, ury = getcorners(object.path)
1640 before[#before+1] = function()
1641 context.MPLIBstartgroup(
1642 gr_type.isolated and 1 or 0,
1643 gr_type.knockout and 1 or 0,
1644 llx, lly, urx, ury
1645 )
1646 end
1647 elseif gr_state == "stop" then
1648 after[#after+1] = function()
1649 context.MPLIBstopgroup()
1650 end
1651 end
1652 object.path = false
1653 object.color = false
1654 object.grouped = true
1655end
1656
1657
1658
1659local function gs_process(object,prescript,before,after)
1660 local gs_type = prescript.gs_type
1661 if gs_type then
1662 object.detail = {
1663 type = gs_type,
1664 action = prescript.gs_action,
1665 name = prescript.gs_name,
1666 }
1667
1668 before[#before+1] = function() end
1669 after [#after +1] = function() end
1670 end
1671
1672
1673
1674end
1675
1676
1677
1678local pattern_index = 0
1679
1680local function pt_process(object,prescript,before,after)
1681 local pt_state = prescript.pt_state
1682 if not pt_state then
1683 return
1684 else
1685 local pt_action = prescript.pt_action
1686 if pt_state == "start" then
1687 local float = toboolean(prescript.pt_float) and 1 or 0
1688 local llx, lly, urx, ury = getcorners(object.path)
1689 if abs(llx) < 0.0001 then llx = 0 end
1690 if abs(lly) < 0.0001 then lly = 0 end
1691 if abs(urx) < 0.0001 then urx = 0 end
1692 if abs(ury) < 0.0001 then ury = 0 end
1693 before[#before+1] = function()
1694 if pt_action == "set" then
1695 pattern_index = pattern_index + 1
1696 context.MPLIBstartsetpattern(pattern_index, llx, lly, urx, ury, float)
1697 else
1698 context.MPLIBstartgetpattern(pattern_index, llx, lly, urx, ury, float)
1699 end
1700 end
1701 elseif pt_state == "stop" then
1702 after[#after+1] = function()
1703 if pt_action == "set" then
1704 context.MPLIBstopsetpattern()
1705 else
1706 context.MPLIBstopgetpattern()
1707 end
1708 end
1709 end
1710 end
1711 object.path = false
1712 object.color = false
1713 object.grouped = true
1714end
1715
1716
1717
1718local ot_reset, ot_process do
1719
1720 local outlinetexts = { }
1721
1722 ot_reset = function ()
1723 outlinetexts = { }
1724 end
1725
1726 local mp_index = 0
1727 local mp_kind = ""
1728 local mp_str = ""
1729
1730 function mp.mf_outline_text(index,str,kind)
1731 if not outlinetexts[index] then
1732 mp_index = index
1733 mp_kind = kind
1734 mp_str = str
1735 texrunlocal("mpoutlinetoks")
1736 end
1737 end
1738
1739 interfaces.implement {
1740 name = "mpoutlinetoks",
1741 actions = function()
1742 context.MPLIBoutlinetext(mp_index,mp_kind,mp_str)
1743 end,
1744 }
1745
1746 implement {
1747 name = "MPLIBconvertoutlinetext",
1748 arguments = { "integer", "string", "integer" },
1749 actions = function(index,kind,box)
1750 local boxtomp = fonts.metapost.boxtomp
1751 if boxtomp then
1752 outlinetexts[index] = boxtomp(box,kind)
1753 else
1754 outlinetexts[index] = ""
1755 end
1756 end
1757 }
1758
1759 function mp.mf_get_outline_text(index)
1760 mp.print(outlinetexts[index] or "draw origin;")
1761 end
1762
1763end
1764
1765
1766
1767local an_process do
1768
1769 local alternative = "actual"
1770
1771 directives.register("metapost.annotations", function(v)
1772 alternative = v
1773 end)
1774
1775 an_process = function(object,prescript,before,after)
1776 local text = prescript.an_text
1777 if text then
1778 local codeinjections = backends.codeinjections
1779 if alternative == true or alternative == "actual" then
1780 before[#before+1] = codeinjections.startactualtext(text)
1781 after [#after +1] = codeinjections.stopactualtext()
1782 elseif alternative == "alternative" then
1783 before[#before+1] = codeinjections.startalternativetext(text)
1784 after [#after +1] = codeinjections.stopalternativetext()
1785 end
1786 end
1787 end
1788
1789end
1790
1791
1792
1793do
1794
1795 local p1 = P("mf_object=")
1796 local p2 = lpeg.patterns.eol * p1
1797 local pattern = (1-p2)^0 * p2 + p1
1798
1799 function metapost.isobject(str)
1800 return pattern and str ~= "" and lpegmatch(p,str) and true or false
1801 end
1802
1803end
1804
1805local function installplugin(specification)
1806 local reset = specification.reset
1807 local process = specification.process
1808 local object = specification.object
1809 if reset then
1810 appendaction(resetteractions,"system",reset)
1811 end
1812 if process then
1813 appendaction(processoractions,"system",process)
1814 end
1815end
1816
1817metapost.installplugin = installplugin
1818
1819
1820
1821installplugin { name = "outline", process = ot_process, reset = ot_reset }
1822installplugin { name = "color", reset = cl_reset }
1823installplugin { name = "text", process = tx_process, reset = tx_reset }
1824installplugin { name = "group", process = gr_process }
1825installplugin { name = "pattern", process = pt_process }
1826installplugin { name = "graphictext", process = gt_process, reset = gt_reset }
1827installplugin { name = "shade", process = sh_process }
1828installplugin { name = "bitmap", process = bm_process }
1829installplugin { name = "box", process = bx_process }
1830installplugin { name = "position", process = ps_process }
1831installplugin { name = "figure", process = fg_process }
1832installplugin { name = "layer", process = la_process }
1833installplugin { name = "transparency", process = tr_process }
1834installplugin { name = "graphicstates", process = gs_process }
1835installplugin { name = "annotation", process = an_process }
1836 |