summaryrefslogtreecommitdiff
path: root/doc/context/sources/general/manuals/mk/mk-mplib.tex
blob: 78e7b8f97947e276be224e298f146ff732a35dbb (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
% language=uk

\useMPlibrary[dum]

\startcomponent mk-mplib

\environment mk-environment

\definetextbackground
    [sideline]
    [mp=mpos:par:sideline,
     framecolor=mkcolor,
     frameoffset=5mm]

\startuseMPgraphic{mpos:par:sideline}{linecolor,lineoffset}
    for i=1 upto nofmultipars :
        fill leftboundary multipars[i]
            shifted (-\MPvar{lineoffset},0)
            rightenlarged 1mm withcolor \MPvar{linecolor} ;
    endfor ;
\stopuseMPgraphic

\chapter{The MetaPost Library}

% \subject{Hans Hagen \& Taco Hoekwater} \blank[3*big]

This chapter is written by Taco and Hans around the time
that \MPLIB\ was integrated into \LUATEX.
It is part of our torture test.

\subject{introduction}

If \METAPOST\ support had not been as tightly integrated into
\CONTEXT\ as it is, at least half of the projects \PRAGMA\ has
been doing in the last decade could not have been done at all.
\starttextbackground[sideline]Take for instance
backgrounds behind text or graphic markers alongside text. These are
probably the most complex mechanisms in \CONTEXT: positions are
stored, and positional information is passed on to
\METAPOST, where intersections between the text areas and the running
text are converted into graphics that are then positioned in the
background of the text.\stoptextbackground{} Underlining of text
(sometimes used in the educational documents that we typeset) and
change bars (in the margins) are implemented using the same
mechanism because those are basically a background with only one of the
frame sides drawn.

You can probably imagine that a 300 page document with several such
graphics per page takes a while to process. A nice example of such
integrated graphics is the \LUATEX\ reference manual, that has an
unique graphic at each page: a stylized image of a revolving moon.

\startuseMPgraphic{lualogo-x}{angle}
color   luaplanetcolor ; luaplanetcolor := .5blue  ;
color   luaholecolor   ; luaholecolor   :=   white ;
numeric luaextraangle  ; luaextraangle  := \MPvar{angle} ;

vardef lualogo = image (
    % Graphic design by A. Nakonechnyj. Copyright (c) 1998, All rights reserved.
    save luaorbitcolor, d, r, p ; color luaorbitcolor ; numeric d, r, p ;
    luaorbitcolor := .5luaholecolor ; d := sqrt(2)/4 ; r := 1/4 ; p := r/8 ;
    fill fullcircle scaled 1 withcolor luaplanetcolor ;
    draw fullcircle rotated 40.5 scaled (1+r) dashed evenly scaled p withpen pencircle scaled (p/2) withcolor luaorbitcolor ;
    fill fullcircle scaled r shifted (d+1/8,d+1/8) rotated luaextraangle withcolor luaplanetcolor ;
    fill fullcircle scaled r shifted (d-1/8,d-1/8) withcolor luaholecolor   ;
    setbounds currentpicture to fullsquare scaled 1.3;
)  enddef ;

draw lualogo scaled 1cm ;
\stopuseMPgraphic

\startlinecorrection[blank]
\hbox to \hsize
  {\hss\dostepwiserecurse{0}{360}{60}{\useMPgraphic{lualogo-x}{angle=\recurselevel}\hss}}
\stoplinecorrection

Most of the running time integrating such graphics seemed to be
caused by the mechanics of the process: starting the separate
\METAPOST\ interpreter and having to deal with a number of
temporary files. Therefore our expectations were high with regards
to integrating \METAPOST\ more tightly into \LUATEX. Besides the
speed gain, it also true that the simpler the process of using
such use of graphics becomes, the more modern a \TEX\ runs looks
and the less problems new users will have with understanding how
all the processes cooperate.

This article will not discuss the application interface of the
\MPLIB\ library in detail, for that there is the \LUATEX\ manual. In short,
using the embedded \METAPOST\ interpreter in \LUATEX\ boils
down to the following:

\startitemize[packed]
\item Open an instance using \type {mplib.new}, either to process
      images with a format to be loaded, or to create such a format.
      This function returns a library object.
\item Execute sequences of \METAPOST\ commands, using the object's
      \type{execute} method. This returns a result.
\item Check if the result is valid and (if it is okay) request the list
      of objects. Do whatever you want with them, most probably
      convert them to some output format. You can also request a
      string representation of a graphic in \POSTSCRIPT\ format.
\stopitemize

There is no need to close the library object. As long as you didn't make
any fatal errors, the library recovers well and can stay alive during
the entire \LUATEX\ run.

Support for \MPLIB\ depends on a few components: integration,
conversion and extensions. This article shows some of the code
involved in supporting the library. Let's start with the conversion.

\subject{conversion}

The result of a \METAPOST\ run traditionally is a \POSTSCRIPT\
language description of the generated graphic(s). When
\PDF\ is needed, that \POSTSCRIPT\ code has to be converted to the target
format. This includes embedded text as well as penshapes used for
drawing. To demonstrate, here is a simple example graphic:

\startluacode
document.sample_mp_graphic = [[
    draw fullcircle
        scaled 2cm
        withpen pencircle xscaled 1mm yscaled .5mm rotated 30
        withcolor .75red ;
]]
\stopluacode

\startbuffer[mpexample]
draw fullcircle
  scaled 2cm
  withpen pencircle xscaled 1mm yscaled .5mm rotated 30
  withcolor .75red ;
\stopbuffer

\placefigure
  [left]
  {}
  {\startMPcode \ctxlua{tex.sprint(document.sample_mp_graphic)}\stopMPcode}

\typebuffer[mpexample]

Notice how the pen is not a circle but a rotated ellipse. Later on it
will become clear what the consequences of that are for the conversion.

How does this output look in \POSTSCRIPT ? If the preamble is left out
it looks like this:

\startbuffer
\startluacode
do
  local mpx = metapost.format("metafun")
  local result = mpx:execute(string.format("beginfig(0);%s;endfig;",document.sample_mp_graphic))
  local str = result.fig[1]:postscript()
  str = str:gsub("%%BeginProlog.-%%EndProlog","%% <<stripped preamble was here>>")
  tex.sprint(tex.ctxcatcodes,"\\starttyping\n")
  tex.sprint((str:gsub("[\n\r]$","")))
  tex.sprint("\\stoptyping")
end
\stopluacode
\stopbuffer

\getbuffer

The most prominent code here concerns the path. The numbers in brackets define
the transformation matrix for the pen we used. The \PDF\ variant looks as follows:

\startbuffer
\startluacode
do
  local mpx = metapost.format("metafun")
  local result = mpx:execute(string.format("beginfig(0);%s;endfig;",document.sample_mp_graphic))
  local list = metapost.pdfliterals(result)
  tex.sprint(tex.ctxcatcodes,"\\starttyping")
  tex.sprint(table.concat(list,"\n"))
  tex.sprint("\\stoptyping")
end
\stopluacode
\stopbuffer

\getbuffer

The operators don't look much different from the \POSTSCRIPT, which is
mostly due to the fact that in the \POSTSCRIPT\ code, the preamble
defines shortcuts like \type {c} for \type {curveto}.  Again, most code
involves the path. However, this time the numbers are different and
the transformation comes before the path.

In the case of \PDF\ output, we could use \TEX\ itself to do the
conversion: a generic converter is implemented in \type
{supp-pdf.tex}, while a converter optimized for \CONTEXT\ \MKII\ is
defined in the files whose names start with \type {meta-pdf}.  But in
\CONTEXT\ \MKIV\ we use \LUA\ code for the conversion instead. Thanks to
\LUA's powerful \LPEG\ parsing library, this gives cleaner code and is
also faster. This converter currently lives in \type {mlib-pdf.lua}.

Now, with the embedded \METAPOST\ library, conversion goes different
still because now it is possible to request the drawn result and
associated information in the form of \LUA\ tables.

\startbuffer
\startluacode
do
  local mpx = metapost.format("metafun")
  local result = mpx:execute(string.format("beginfig(0);%s;endfig;",document.sample_mp_graphic))
  local str = table.serialize(metapost.totable(result), "figure")
  tex.sprint(tex.ctxcatcodes,"\\starttyping")
  tex.sprint((str:gsub("[\n\r]$","")))
  tex.sprint("\\stoptyping")
end
\stopluacode
\stopbuffer % $<-emacs font-lock

% \startsimplecolumns[n=3,width=18.5cm]
% \getbuffer
% \stopsimplecolumns

\getbuffer

This means that instead of parsing \POSTSCRIPT\ output, we now can operate on
a proper datastructure and get code like the following:

\starttyping
function convertgraphic(result)
  if result then
    local figures = result.fig
    if figures then
      for fig in ipairs(figures) do
        local llx, lly, urx, ury = unpack(fig:boundingbox())
        if urx > llx then
          startgraphic(llx, lly, urx, ury)
          for object in ipairs(fig:objects()) do
            if object.type == "..." then
              ...
              flushgraphic(...)
              ...
            else
              ...
            end
          end
          finishgraphic()
        end
      end
    end
  end
end
\stoptyping

Here \type {result} is what the library returns when one or more
graphics are processed. As you can deduce from this snippet, a
result can contain multiple figures. Each figure corresponds with a
\type {beginfig} \type {...} \type {endfig}. The graphic operators that
the converter generates (so called \PDF\ literals) have to be
encapsulated in a proper box so this is why we have:

\startitemize[packed]
\item \type {startgraphic}: start packaging the graphic
\item \type {flushgraphic}: pipe literals to \TEX
\item \type {finishgraphic}: finish packaging the graphic
\stopitemize

It does not matter what number you passed to \type {beginfig}, the
graphics come out in the natural order.

Little over half a dozen different object types are possible. The example
\METAPOST\ \type{draw} command from above results in an \type {outline} object.
This object contains not only path information but also carries
rendering data, like the color and the pen. So, in the end we will
flush code like \type {1 M} which sets the \type {miterlimit} to one
or \type {.5 g} which sets the color to 50\% gray, in addition to a
path.

Because objects are returned in a way that closely resembles a
\METAPOST's internals, some extra work needs to be done in order to
calculate paths with elliptical pens. An example of a helper function
in somewhat simplified form is shown next:

\starttyping
function pen_characteristics(object)
  local p = object.pen[1]
  local wx, wy, width
  if p.right_x == p.x_coord and p.left_y == p.y_coord then
    wx = abs(p.left_x  - p.x_coord)
    wy = abs(p.right_y - p.y_coord)
  else -- pyth: sqrt(a^2 +b^2)
    wx = pyth(p.left_x - p.x_coord, p.right_x - p.x_coord)
    wy = pyth(p.left_y - p.y_coord, p.right_y - p.y_coord)
  end
  if wy/coord_range_x(object.path, wx) >=
                    wx/coord_range_y(object.path, wy) then
    width = wy
  else
    width = wx
  end
  local sx, sy = p.left_x, p.right_y
  local rx, ry = p.left_y, p.right_x
  local tx, ty = p.x_coord, p.y_coord
  if width ~= 1 then
    if width == 0 then
      sx, sy = 1, 1
    else
      rx, ry, sx, sy = rx/width, ry/width, sx/width, sy/width
    end
  end
  if abs(sx) < eps then sx = eps end
  if abs(sy) < eps then sy = eps end
  return sx, rx, ry, sy, tx, ty, width
end
\stoptyping

If \type {sx} and \type {sy} are 1, there is no need to transform
the path, otherwise a suitable transformation matrix is calculated
and returned. The function itself uses a few helpers that make the
calculations even more obscure. This kind of code does not fall in
the category trivial and as already mentioned, these basic
algorithms were derived from the \METAPOST\ sources. Even so,
these snippets demonstrate that interfacing using \LUA\ does not
look that bad.

In the actual \MKIV\ code things look a bit different because it does
a bit more and uses optimized code. There you will also find the code
dealing with the actual transformation, of which these helpers are
just a portion.

If you compare the \POSTSCRIPT\ and the \PDF\ code you will notice
that the paths looks different. This is because the use and
application of a transformation matrix in \PDF\ is different from how
it is handled in \POSTSCRIPT. In \PDF\ more work is assumed to be
done by the \PDF\ generating application. This is why in both the
\TEX\ and the \LUA\ based converters you will find transformation code
and the library follows the same pattern. In that respect \PDF\
differs fundamentally from \POSTSCRIPT.

Within the \TEX\ based converter there was the problem of keeping the
needed calculations within \TEX's accuracy, which fortunately permits
larger values that \METAPOST\ can produce. This plus the parsing code
resulted in a not-that-easy to follow bunch of \TEX\ code.  The \LUA\
based parser is more readable, but since it also operates on
\POSTSCRIPT\ code it is kind of unnatural too, but at least there are
less problems with keeping the calculations sane. The \MPLIB\ based
converter is definitely the cleanest and least sensitive to future
changes in the \POSTSCRIPT\ output. Does this mean that there is no
ugly code left? Alas, as we will see in the next section, dealing with
extensions is still somewhat messy. In practice users will not be
bothered with such issues, because writing a converter is a one time
job by macro package writers.

\subject{extensions}

In \METAFUN, which is the \METAPOST\ format used with \CONTEXT,
a few extensions are provided, like:

\startitemize[packed]
\item cmyk, spot and multitone colors
\item including external graphics
\item lineair and circulair shades
\item texts converted to outlines
\item inserting arbitrary texts
\stopitemize

Until now, most of these extensions have been implemented by using
specially coded colors and by injecting so called specials (think of
them as comments) into the output. On one of our trips to a \TEX\
conference, we discussed ways to pass information along with
paths and eventually we arrived at associating text strings with paths
as a simple and efficient solution.  As a result, recently \METAPOST\
was extended by \type {withprescript} and \type {withpostscript}
directives. For those who are unfamiliar with these new scripts,
they are used as follows:

\starttyping
draw fullcircle withprescript "hello" withpostscript "world" ;
\stoptyping

In the \POSTSCRIPT\ output these scripts end up before and after the
path, but in the \PDF\ converter they can be overloaded to implement
extensions, and that works reasonably well.  However, at the moment
there cannot be multiple pre- and postscripts associated with a single
path inside the \METAPOST\ internals. This means that for the moment,
the scripts mechanism is only used for a few of the extensions.
Future versions of \MPLIB\ may provide more sophisticated methods
for carrying information around.

The \MKIV\ conversion mechanism uses scripts for graphic inclusion,
shading and text processing but unfortunately cannot use them for
more advanced color support.

A nasty complication is that the color spaces in \METAPOST\ don't
cast, which means that one cannot assign any color to a color
variables: each colorspace has it's own type of variable.

\starttyping
color     one ; one := (1,1,0)   ; % correct
cmykcolor two ; two := (1,0,0,1) ; % correct
one := two ; % error
fill fullcircle scaled 1cm withcolor .5[one,two] ; % error
\stoptyping

In \CONTEXT\ we use constructs like this:

\starttyping
\startreusableMPgraphic{test}
  fill fullcircle scaled 1cm withcolor \MPcolor{mycolor} ;
\stopreusableMPgraphic

\reuseMPgraphic{test}
\stoptyping

Because \type {withcolor} is clever enough to understand what color
type it receives, this is ok, but how about:

\starttyping
\startreusableMPgraphic{test}
  color c ; c := \MPcolor{mycolor} ;
  fill fullcircle scaled 1cm withcolor c ;
\stopreusableMPgraphic
\stoptyping

Here the color variable only accepts an \RGB\ color and because in
\CONTEXT\ there is mixed color space support combined with
automatic colorspace conversions, it doesn't know in advance what type
it is going to get. By implementing color spaces other than \RGB\
using special colors (as before) such type mismatches can be avoided.

The two techniques (coding specials in colors and pre|/|postscripts)
cannot be combined because a script is associated with a path and
cannot be bound to a variable like \type{c}. So this again is an argument
for using special colors that remap onto \CMYK\, spot or
multi|-|tone colors.

Another area of extensions is text. In previous versions of
\CONTEXT\ the text processing was already isolated: text ended
up in a separate file and was processed in an separate run. More
recent versions of \CONTEXT\ use a more abstract model of boxes that
are preprocessed before a run, which avoids the external run(s). In
the new approach everything can be kept internal. The conversion
even permits constructs like:

\starttyping
for i=1 upto 100 :
  draw btex oeps etex rotated i ;
endfor ;
\stoptyping

but since this construct is kind of obsolete (at least in the library
version of \METAPOST) it is better to use:

\starttyping
for i=1 upto 100 :
  draw textext("cycle " & decimal i) rotated i ;
endfor ;
\stoptyping

Internally a trial pass is done so that indeed 100 different texts will
be drawn. The throughput of texts is so high that in practice one will
not even notice that this happens.

Dealing with text is yet another example of using \LPEG. The following
snippet of code sheds some light on how text in graphics is dealt with.
Actually this is a variation on a previous implementation. That one
was slightly faster but looked more complex. It was also not robust for
complex texts defined in macros in a format.

\starttyping
local P, S, V, Cs = lpeg.P, lpeg.S, lpeg.V, lpeg.Cs

local btex    = P("btex")
local etex    = P(" etex")
local vtex    = P("verbatimtex")
local ttex    = P("textext")
local gtex    = P("graphictext")
local spacing = S(" \n\r\t\v")^0
local dquote  = P('"')

local found = false

local function convert(str)
  found = true
  return "textext(\"" .. str .. "\")"
end
local function ditto(str)
  return "\" & ditto & \""
end
local function register()
  found = true
end

local parser = P {
    [1] = Cs((V(2)/register + V(3)/convert + 1)^0),
    [2] = ttex + gtex,
    [3] = (btex + vtex) * spacing *
                Cs((dquote/ditto + (1-etex))^0) * etex,
}

function metapost.check_texts(str)
  found = false
  return parser:match(str), found
end
\stoptyping

If you are unfamiliar with \LPEG\ it may take a while to see what
happens here: we replace the text between \type {btex} and \type {etex}
by a call to \type {textext}, a macro. Special care is given to
embedded double quotes.

When text is found, the graphic is processed two times. The definition
of \type {textext} is different for each run. The first run we have:

\starttyping
vardef textext(expr str) =
    image (
        draw unitsquare
            withprescript "tf"
            withpostscript str ;
    )
enddef ;
\stoptyping

After the first run the result is not really converted, but just
the outlines with the \type {tf} prescript are filtered. In the
loop over the object there is code like:

\starttyping
local prescript = object.prescript
if prescript then
  local special = metapost.specials[prescript]
  if special then
    special(object.postscript,object)
  end
end
\stoptyping

Here, \type {metapost} is just the namespace used by the
converter. The prescript tag \type {tf} triggers a function:

\starttyping
function metapost.specials.tf(specification,object)
  tex.sprint(tex.ctxcatcodes,format("\\MPLIBsettext{%s}{%s}",
    metapost.textext_current,specification))
  if metapost.textext_current < metapost.textext_last then
    metapost.textext_current = metapost.textext_current + 1
  end
  ...
end
\stoptyping

Again, you can forget about the details of this function. Important is
that there is a call out to \TEX\ that will process the text. Each snippet
gets the number of the box that holds the content. The macro that is
called just puts stuff in a box:

\starttyping
\def\MPLIBsettext#1#2%
  {\global\setbox#1\hbox{#2}}
\stoptyping

In the next processing cycle of the \METAPOST\ code, the \type {textext}
macro does something different :

\starttyping
vardef textext(expr str) =
    image (
        _tt_n_ := _tt_n_ + 1 ;
        draw unitsquare
            xscaled _tt_w_[_tt_n_]
            yscaled (_tt_h_[_tt_n_] + _tt_d_[_tt_n_])
            withprescript "ts"
            withpostscript decimal _tt_n_ ;
    )
enddef ;
\stoptyping

This time the by then known dimensions of the box that is used to
store the snippet are used. These are stored in the \type {_tt_w_},
\type {_tt_h_} and \type {_tt_d_} arrays. The arrays are defined by
\LUA\ using information about the boxes, and passed to the library
before the second run. The result from the second \METAPOST\ run
is converted, and again the prescript is used as trigger:

\starttyping
function metapost.specials.ts(specification,object,result)
    local op = object.path
    local first, second, fourth  = op[1], op[2], op[4]
    local tx, ty = first.x_coord      , first.y_coord
    local sx, sy = second.x_coord - tx, fourth.y_coord - ty
    local rx, ry = second.y_coord - ty, fourth.x_coord - tx
    if sx == 0 then sx = 0.00001 end
    if sy == 0 then sy = 0.00001 end
    metapost.flushfigure(result)
    tex.sprint(tex.ctxcatcodes,format(
        "\\MPLIBgettext{%f}{%f}{%f}{%f}{%f}{%f}{%s}",
        sx,rx,ry,sy,tx,ty,metapost.textext_current))
    ...
end
\stoptyping

At this point the converter is actually converting the graphic and
passing \PDF\ literals to \TEX. As soon as it encounters a text,
it flushes the \PDF\ code collected so far and injects some \TEX\
code. The \TEX\ macro looks like:

\starttyping
\def\MPLIBgettext#1#2#3#4#5#6#7%
  {\ctxlua{metapost.sxsy(\number\wd#7,\number\ht#7,\number\dp#7)}%
   \pdfliteral{q #1 #2 #3 #4 #5 #6 cm}%
   \vbox to \zeropoint{\vss\hbox to \zeropoint
     {\scale[sx=\sx,sy=\sy]{\raise\dp#7\box#7}\hss}}%
   \pdfliteral{Q}}
\stoptyping

Because text can be transformed, it needs to be scale back to the right
dimensions, using both the original box dimensions and the transformation
of the unitquare associated with the text.

\starttyping
local factor = 65536*(7200/7227)

function metapost.sxsy(wd,ht,dp) -- helper for text
  commands.edef("sx",(wd ~= 0 and 1/( wd    /(factor))) or 0)
  commands.edef("sy",(wd ~= 0 and 1/((ht+dp)/(factor))) or 0)
end
\stoptyping

So, in fact there are the following two processing alternatives:

\startitemize[packed]
\item tex: calls a \LUA\ function that processed the graphic
\item lua: parse the \METAPOST\ code for texts and decide if two
      runs are needed
\stopitemize

Now, if there was no text to be found, the continuation is:

\startitemize[packed]
\item lua: process the code using the library
\item lua: convert the resulting graphic (if needed) and check
      if texts are used
\stopitemize

Otherwise, the next steps are:

\startitemize[packed]
\item lua: process the code using the library
\item lua: parse the resulting graphic for texts (in the postscripts)
      and signal \TEX\ to process these texts afterwards
\item tex: process the collected text and put the result in boxes
\item lua: process the code again using the library but this time let
      the unitsquare be transformed using the text dimensions
\item lua: convert the resulting graphic and replace the transformed
      unitsquare by the boxes with text
\stopitemize

The processor itself is used in the \MKIV\ graphic function that takes
care of the multiple passes mentioned before. To give you an idea of
how it works, here is how the main graphic processing function roughly
looks.

\starttyping
local current_format, current_graphic

function metapost.graphic_base_pass(mpsformat,str,preamble)
    local prepared, done = metapost.check_texts(str)
    metapost.textext_current = metapost.first_box
    if done then
        current_format, current_graphic = mpsformat, prepared
        metapost.process(mpsformat, {
            preamble or "",
            "beginfig(1); ",
            "_trial_run_ := true ;",
            prepared,
            "endfig ;"
        }, true ) -- true means: trialrun
        tex.sprint(tex.ctxcatcodes,
            "\\ctxlua{metapost.graphic_extra_pass()}")
    else
        metapost.process(mpsformat, {
            preamble or "",
            "beginfig(1); ",
            "_trial_run_ := false ;",
            str,
            "endfig ;"
        } )
    end
end

function metapost.graphic_extra_pass()
    metapost.textext_current = metapost.first_box
    metapost.process(current_format, {
        "beginfig(0); ",
        "_trial_run_ := false ;",
        table.concat(metapost.texttextsdata()," ;\n"),
        current_graphic,
        "endfig ;"
    })
end
\stoptyping

The box information is generated as follows:

\starttyping
function metapost.texttextsdata()
    local t, n = { }, 0
    for i = metapost.first_box, metapost.last_box do
        n = n + 1
        local box_i = tex.box[i]
        if box_i then
            t[#t+1] = format(
                "_tt_w_[%i]:=%f;_tt_h_[%i]:=%f;_tt_d_[%i]:=%f;",
                n, box_i.width /factor,
                n, box_i.height/factor,
                n, box_i.depth /factor
            )
        else
            break
        end
    end
    return t
end
\stoptyping

This is a typical example of accessing information available inside
\TEX\ from \LUA, in this case information about boxes.

The \type {trial_run} flag is used at the \METAPOST\ end, in fact the
\type {textext} macro looks as follows:

\starttyping
vardef textext(expr str) =
    if _trial_run_ :
        % see first variant above
    else :
        % see second variant above
    fi
enddef ;
\stoptyping

This trickery is not new. We used it already in \CONTEXT\ for some
time, but until now the multiple runs took way more time and from
the perspective of the user this all looked much more complex.

It may not be that obvious, but: in the case of a trial run (for
instance when texts are found), after the first processing stage,
and during the parsing of the result, the commands that typeset the
content will be printed to \TEX. After processing, the command to do
an extra pass is printed to \TEX\ also. So, once control is passed
back to \TEX, at some point \TEX\ itself will pass control back to
\LUA\ and do the extra pass.

The base function is called in:

\starttyping
function metapost.graphic(mpsformat,str,preamble)
    local mpx = metapost.format(mpsformat or "metafun")
    metapost.graphic_base_pass(mpx,str,preamble)
end
\stoptyping

The \type {metapost.format} function is part of \type {mlib-run}.
It loads the \type{metafun} format, possibly after (re|)|generating it.

Now, admittedly all this looks a bit messy, but in pure \TEX\ macros
it would be even more so. Sometime in the future, the postponed calls to
\tex{ctxlua} and the explicit \tex{pdfliteral}s can and will be
replaced by using direct node generation, but that requires a rewrite
of the internal \LUATEX\ support for \PDF\ literals.

The snippets are part of the \type {mlib-*} files of \MKIV. These files are
tagged as experimental and will stay that way for a while yet. This is
proved by the fact that by now we use a slightly different approach.

Summarizing the impact of \MPLIB\ on extensions, we can conclude that
some are done better and some more or less the same. There are some
conceptual problems that prohibit using pre- and postscripts for
everything (at least currently).

\subject{integrating}

The largest impact of \MPLIB\ is processing graphics at runtime.
In \MKII\ there are two methods: real runtime processing (each
graphic triggered a call to \METAPOST) and collective processing
(between \TEX\ runs). The first method slows down the \TEX\ run,
the second method generates a whole lot of intermediate \POSTSCRIPT\
files. In both cases there is a lot of file \IO\ involved.

In \MKIV, the integrated library is capable of processing
thousands of graphics per second, including conversion. The
preliminary tests (which involved no extensions) involved graphics
with 10 random circles drawn with penshapes in random colors, and
the thoughput was around 2000 such graphics per second on a
2.3 MHz Core Duo:

\startlinecorrection[blank]
\hbox to \textwidth{\strut\dorecurse{5}{\startMPcode
numeric w ; w := \the\textwidth/6 ;
for k:=1 upto 10 :
    draw fullcircle
        scaled uniformdeviate(w)
        withpen pencircle xscaled (w/20) yscaled (w/40) rotated 30
        withcolor (red/(k/4)) ;
endfor ;
setbounds currentpicture to fullsquare scaled w ;
\stopMPcode\hss}\unskip}
\stoplinecorrection

In practice there will be some more overhead involved than in the
tests. For instance, in \CONTEXT\ information about the current state
of \TEX\ has to be passed on also: page dimensions, font information,
typesetting related parameters, preamble code, etc.

The whole \TEX\ interface is written around one process function:

\starttyping
metapost.graphic(metapost.format("metafun"),"mp code")
\stoptyping

optionally a preamble can be passed as the third argument.
This one function is used in several other macros, like:

\starttyping
\startMPcode                  ... \stopMPcode
\startMPpage                  ... \stopMPpage
\startuseMPgraphic     {name} ... \stopuseMPgraphic
\startreusableMPgraphic{name} ... \stopreusableMPgraphic
\startuniqueMPgraphic  {name} ... \stopuniqueMPgraphic

\useMPgraphic{name}
\reuseMPgraphic{name}
\uniqueMPgraphic{name}
\stoptyping

The user interface is downward compatible: in \MKIV\ the same
top-level commands are provided as in \MKII. However, the
(previously required) configuration macros and flags are obsolete.

This time, the conclusion is that the impact on \CONTEXT\ is immense:
The code for embedding graphics is very clean, and the running time
for graphics inclusion is now negligible. Support for text in graphics is
more natural now, and takes no runtime either (in \MKII\ some
parsing in \TEX\ takes place, and if needed long lines are split;
all this takes time).

In the styles that \PRAGMA\ uses internally, there is support for the
generation of placeholders for missing graphics. These placeholders
are \METAPOST\ graphics that have some 60 randomly scaled circles with randomized
colors. The time involved in generating 50 such graphics is (on Hans'
machine) some 14 seconds, while in \LUATEX\ only half a second is needed.

\startlinecorrection[blank]
\hbox to \textwidth \bgroup
\hss\dorecurse{4}{\externalfigure[dummy][width=.2\textwidth]\hss}%
\egroup
\stoplinecorrection

Because \LUATEX\ needs more startup time and deals with larger fonts
resources, \PDFTEX\ is generally faster, but now that we have \MPLIB,
\LUATEX\ suddenly is the winner.

% We end this article by showing a few graphics. \CONTEXT\ ships with a module
% that permits tracking of resource usage. Users can add the following line
% to their document:

% \starttyping
% \usemodule[timing]
% \stoptyping

% After that one can use commands like

% \starttyping
% \ShowNamedUsage{\jobname-luatex-progress}{luastate_bytes}{elapsed_time}
% \ShowNamedUsage{\jobname-luatex-progress}{dyn_used}{elapsed_time}
% \ShowNamedUsage{\jobname-luatex-progress}{str_ptr}{elapsed_time}
% \ShowNamedUsage{\jobname-luatex-progress}{pdf_literal}{elapsed_time}
% \ShowNamedUsage{\jobname-luatex-progress}{glyph}{elapsed_time}
% \stoptyping

% In this document, \LUA\ memory usage is as follows. The blue lines
% represent runtime, on Hans' machine some 3.5 seconds, including
% startuptime, which clearly shows in the graphic. Keep in mind that
% garbage collection only happens at certain moment, so \LUA\ memory
% usage is normally a sawtooth graphic. The horizontal axis reflects the
% number of pages.

% \startlinecorrection[blank]
% \ShowNamedUsage{\jobname-luatex-progress}{luastate_bytes}{elapsed_time}
% \stoplinecorrection

% Dynamic memory usage of \TEX\ grows a bit because at the \TEX\ end we need
% to store data as well.

% \startlinecorrection[blank]
% \ShowNamedUsage{\jobname-luatex-progress}{dyn_used}{elapsed_time}
% \stoplinecorrection

% Currently we use \type {\pdfliteral}, which means that all
% literals go through \TEX's tokenizer and string pool. With large
% graphics this can be a real memory hog.

% Unfortunately not all this memory is freed, so eventually Hartmut
% Henkel (the third member of the \LUATEX\ team) will reimplement
% this part of the backend.

% \startlinecorrection[blank]
% \ShowNamedUsage{\jobname-luatex-progress}{str_ptr}{elapsed_time}
% \stoplinecorrection

% Just to complete this picture, we show the usage of literals next. Although
% the converter collects as much data as possible before flushing, we see
% some peaks.

% \startlinecorrection[blank]
% \ShowNamedUsage{\jobname-luatex-progress}{pdf_literal}{elapsed_time}
% \stoplinecorrection

% Compare this to the glyph usage. Indeed: the more graphics we use, the
% less glyphs we encounter.

% \startlinecorrection[blank]
% \ShowNamedUsage{\jobname-luatex-progress}{glyph}{elapsed_time}
% \stoplinecorrection

% Of course these graphics were integrated, generated and converted
% using \MPLIB.

\stopcomponent