summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex
diff options
context:
space:
mode:
Diffstat (limited to 'Master/texmf-dist/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex')
-rw-r--r--Master/texmf-dist/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex1519
1 files changed, 1519 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex b/Master/texmf-dist/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex
new file mode 100644
index 00000000000..abdca3c3ad0
--- /dev/null
+++ b/Master/texmf-dist/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex
@@ -0,0 +1,1519 @@
+% language=uk
+%
+% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa
+
+\startcomponent metafun-text
+
+\environment metafun-environment
+
+\startchapter[reference=sec:typesetting,title={Typesetting in \METAPOST}]
+
+\startintro
+
+It is said that a picture tells more than a thousand words. So you might expect
+that text in graphics becomes superfluous. Out of experience we can tell you that
+this is not the case. In this chapter we explore the ways to add text to
+\METAPOST\ graphics, and let you choose whether or not to have it typeset by
+\TEX.
+
+\stopintro
+
+\startsection[title={The process}]
+
+\index{text}
+
+The \METAPOST\ program is about graphics, not about text. Its ancestor was made
+for creating fonts and in order to do so, it actually had some limited
+capabilities to add text to a graphic, like coordinates to points. Now, when
+you really want to add typeset text, we need something more. The traditional way
+to add some text to a \METAPOST\ graphic was to use this:
+
+\starttyping
+btex Some text to be typeset by \TEX etex
+\stoptyping
+
+The machinery was set up in such a way that these snippets got delegated to \TEX,
+and the resulting \DVI\ converted back into a a \METAPOST\ picture with objects
+that refer to a font and character. Although the \METAPOST\ program could handle
+that by calling out to \TEX, we never used that method. In \MKII\ we had two
+flows: either direct processing, or collect all texts and process them between
+runs. Because the backend (conversion to \PDF) was under \CONTEXT\ control we
+could do more than usual. You can find some information in the older manuals.
+
+In \CONTEXT\ \MKIV\ we started using the library variant of \METAPOST. Its
+integration in \LUATEX\ made it possible to do all text rendering runtime at high
+speed. This change has an enormous speed gain: when this manual had about 425
+pages, on my laptop with mobile 3840QM processor, one run of this document takes
+18 seconds (14.5 with \LUAJITTEX) and that includes loading a bunch of (outline)
+fonts and processing some 2200 \METAPOST\ images. While writing the first version
+of this manual runtime was upto 50 times slower for half the number of pages so
+compared to \MKII\ we have gained a lot.
+
+In \MKIV\ we still have two internal runs per \METAPOST\ graphic that has text:
+the first time the texts snippets are collected and afterwards handed over to
+\LUA\ that tells the \TEX\ ending to process it. The dimensions are saved and
+used in a second processing of the graphic. Contrary to \MKII\ the user doesn't
+see these two runs: they appear as one. In \in {figure} [fig:text:mkiv] this is
+illustrated.
+
+\startFLOWchart[mkiv]
+ \startFLOWcell
+ \name {metapost 1}
+ \location {1,1}
+ \shape {action}
+ \text {\METAPOST\ \type{textext 1}}
+ \connection [rl] {lua 1}
+ \stopFLOWcell
+ \startFLOWcell
+ \name {lua 1}
+ \location {2,1}
+ \shape {action}
+ \text {\LUA}
+ \connection [rl] {context 1}
+ \connection [bb] {metapost 2}
+ \stopFLOWcell
+ \startFLOWcell
+ \name {context 1}
+ \location {3,1}
+ \shape {action}
+ \text {\CONTEXT}
+ \stopFLOWcell
+ \startFLOWcell
+ \name {metapost 2}
+ \location {4,1}
+ \shape {action}
+ \text {\METAPOST\ \type{textext 2}}
+ \connection [bb] {lua 1}
+ \connection [rl] {backend 1}
+ \stopFLOWcell
+ \startFLOWcell
+ \name {backend 1}
+ \location {5,1}
+ \shape {action}
+ \text {backend}
+ \stopFLOWcell
+\stopFLOWchart
+
+In the later versions of \MKIV\ it was possible to jump out to \TEX\ immediately
+and save the second run, although there were cases where this was not possible
+(reliable). In \LMTX\ we always have one run. This is summarized in \in {figure}
+[fig:text:mkiv]. All this has to do with the fact that \TEX, \METAPOST\ and \LUA\
+are integrated but still kind of independent. When you expand a macro (that
+triggers processing of a graphic) you end up in a call to the \METAPOST\ library
+but \TEX\ is still in that macro. In \LUATEX\ and more advanced in \LUAMETATEX\
+you can sort of spawn a subprocess in \TEX\ (called local control) and indeed
+process the text immediately and use the calculated dimension after that has been
+done. All that \METAPOST\ needs is dimensions as it the backend that eventually
+will include the text.
+
+\startplacefigure[title={How \TEX\ and \METAPOST\ work together (\MKIV).},reference=fig:text:mkiv]
+ \FLOWchart[mkiv]
+\stopplacefigure
+
+\startFLOWchart[lmtx]
+ \startFLOWcell
+ \name {context 1}
+ \location {1,1}
+ \shape {action}
+ \text {\CONTEXT}
+ \connection [rl] {lua 1}
+ \stopFLOWcell
+ \startFLOWcell
+ \name {lua 1}
+ \location {2,1}
+ \shape {action}
+ \text {\LUA}
+ \connection [lr] {context 1}
+ \connection [rl] {metapost 1}
+ \stopFLOWcell
+ \startFLOWcell
+ \name {metapost 1}
+ \location {3,1}
+ \shape {action}
+ \text {\METAPOST\ \type{textext}}
+ \connection [lr] {lua 1}
+ \connection [rl] {backend 1}
+ \stopFLOWcell
+ \startFLOWcell
+ \name {backend 1}
+ \location {5,1}
+ \shape {action}
+ \text {backend}
+ \stopFLOWcell
+\stopFLOWchart
+
+\startplacefigure[title={How \TEX\ and \METAPOST\ work together (\LMTX).},reference=fig:text:lmtx]
+ \FLOWchart[lmtx]
+\stopplacefigure
+
+\stopsection
+
+\startsection[title={Environments}]
+
+\index{environments}
+
+The \type {textext} command is the main text handling command and it is used in many places
+in this manual. It takes a string.
+
+In \MKII\ text was processed between runs or immediately but still by running an
+independent \TEX\ run. That has some consequences when the text was to share its
+properties with the main document. This means that in \MKII\ we pass
+characteristics of the layout, spacing, fonts, color and optionally an
+environment that a user has set up. This is mentioned in the older manual but no
+longer relevant in \MKIV\ and \LMTX. Because we handle the text runtime we
+automatically use the same style and document properties.
+
+This means that in code like the following, a Palatino font will be used because
+that is what we use in this document.
+
+\starttyping
+\startMPcode
+draw btex Meta is a female lion! etex xysized (TextWidth,TextHeight) ;
+\stopMPcode
+\stoptyping
+
+But even when we still support \type {btex} we strongly advise users to use this:
+
+\starttyping
+\startMPcode
+draw textext("Meta is a female lion!") xysized (TextWidth,TextHeight) ;
+\stopMPcode
+\stoptyping
+
+In this example as well in the next one you see that we access \type {TextWidth}
+directly. In older examples in the \CONTEXT\ distribution you will notice that we
+serialize \TEX\ registers like \type {\textwidth}. This is still valid but less
+preferable. Here \type {TextWidth} is actually a macro that calls out to \LUA\
+from where we fetch the value of \type {\textwidth} and pipe it back to
+\METAPOST\ in a way that makes it look like we have a variable.
+
+\startbuffer[lioncode]
+\startMPcode
+numeric w, h ; w := TextWidth ; h := w/2 ;
+
+picture p ; p := textext.urt("Meta is a female lion!") xysized (w,h) ;
+picture q ; q := textext.urt("Meta is a female lion!") xysized (w,h) ;
+
+path b ; b := boundingbox p ; draw p withcolor "darkyellow" ;
+
+draw textextanchor(p) withpen pencircle scaled 5mm withcolor "darkblue" ;
+
+for i = (.28w,.90h), (.85w,.90h), (w,.05h) :
+ picture r ; r := q ;
+ path s ; s := (fullsquare xscaled .05w yscaled .4h) shifted i ;
+ clip r to s ;
+ draw r withcolor "darkred";
+endfor ;
+
+setbounds currentpicture to b ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer[lioncode]
+
+\in {Figure} [lionclip] shows the previous sentence in a slightly different look.
+You may consider coloring the dots to be an exercise in clipping.
+
+\startplacefigure[title={An example of clipping.},reference=lionclip]
+ \getbuffer[lioncode]
+\stopplacefigure
+
+In this example we show that the origin of the text. By default it gets centered
+but the \type {urt} suffix moves it. Here is another example of showing the
+origin:
+
+\startbuffer
+\startMPcode
+picture p ; p := thetextext.top("foo",(10,1));
+picture q ; q := thetextext.lft("foo",(1,10));
+
+draw textextanchor(p) withpen pencircle scaled 2mm withcolor "darkred" ;
+draw textextanchor(q) withpen pencircle scaled 1mm withcolor "white" ;
+
+draw p;
+draw q;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+It gives the following:
+
+\startlinecorrection[blank]
+\getbuffer
+\stoplinecorrection
+
+\stopsection
+
+\startsection[title={Labels}]
+
+\index{labels}
+
+In \METAPOST\ you can use the \type {label} macro to position text at certain
+points.
+
+\starttyping
+label("x", origin) ;
+\stoptyping
+
+The font and scale are determined by two variables, \type {defaultfont} and \type
+{defaultscale}, the former expecting the name of a font in the form of a string,
+the latter expecting a numeric to be used in the scaling of the font. Should you
+choose not to set these yourself, they default to \type {"Mono"} and \type
+{1.0}, respectively. However, you can change the defaults as follows:
+
+\starttyping
+defaultfont := "texgyrepagella-regular*default" ;
+defaultscale := 1.2 ;
+\stoptyping
+
+These settings selects Pagella at about 12pt. You can also set these variables
+to \CONTEXT\ related values. For \CONTEXT\ graphics they are set to:
+
+\starttyping
+defaultfont := "\truefontname{Regular}*default" ;
+defaultscale := \the\bodyfontsize/10 ;
+\stoptyping
+
+This means that they will adapt themselves to the current body font (in this
+document we get \truefontname {Regular}) and the current size of the bodyfont
+(here \the\bodyfontsize/10).
+
+Normally you can stick to the default and forget about these details. More important
+is how you anchor labels. This is best shown with some examples:
+
+\startbuffer
+\startMPcode
+ path p ; p := fullcircle scaled 3cm ;
+
+ drawarrow p ;
+
+ dotlabel ("test",point 0 of p) withcolor red ;
+ dotlabel.rt ("rt", point 1 of p) ;
+ dotlabel.urt ("urt", point 2 of p) ;
+ dotlabel.top ("top", point 3 of p) ;
+ dotlabel.ulft("ulft",point 4 of p) ;
+ dotlabel.lft ("lft", point 5 of p) ;
+ dotlabel.llft("llft",point 6 of p) ;
+ dotlabel.bot ("bot", point 7 of p) ;
+ dotlabel.lrt ("lrt", point 8 of p) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer \startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\startbuffer
+\startMPcode
+ path p ; p := fullcircle scaled 3cm ;
+
+ drawarrow p ;
+
+ dotlabel ("test",p) ;
+ dotlabel.rt ("rt", p) ;
+ dotlabel.urt ("urt", p) ;
+ dotlabel.top ("top", p) ;
+ dotlabel.ulft("ulft",p) ;
+ dotlabel.lft ("lft", p) ;
+ dotlabel.llft("llft",p) ;
+ dotlabel.bot ("bot", p) ;
+ dotlabel.lrt ("lrt", p) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer \startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\startbuffer
+\startMPcode
+ p := (origin..right..up..left) scaled 3cm ;
+
+ drawarrow p ;
+
+ label ("test",p) ;
+ label.rt ("rt", p) ;
+ label.urt ("urt", p) ;
+ label.top ("top", p) ;
+ label.ulft("ulft",p) ;
+ label.lft ("lft", p) ;
+ label.llft("llft",p) ;
+ label.bot ("bot", p) ;
+ label.lrt ("lrt", p) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer \startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\startbuffer
+\startMPcode
+ picture p ; p := image(drawarrow (origin..right..up..left) scaled 3cm ;) ;
+
+ draw p ;
+ draw bbox p dashed evenly ;
+
+ label ("test",p) ;
+ label.rt ("rt", p) ;
+ label.urt ("urt", p) ;
+ label.top ("top", p) ;
+ label.ulft("ulft",p) ;
+ label.lft ("lft", p) ;
+ label.llft("llft",p) ;
+ label.bot ("bot", p) ;
+ label.lrt ("lrt", p) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer \startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\startbuffer
+\startMPcode
+ picture p ; p := image(drawarrow (origin..right..up..left) scaled 3cm ;) ;
+
+ draw p ;
+ draw bbox p dashed evenly ;
+
+ draw textext ("test") shifted theoffset (p) ;
+ draw textext.lft ("rt") shifted theoffset.rt (p) ;
+ draw textext.llft("urt") shifted theoffset.urt (p) ;
+ draw textext.bot ("top") shifted theoffset.top (p) ;
+ draw textext.lrt ("ulft") shifted theoffset.ulft(p) ;
+ draw textext.rt ("lft") shifted theoffset.lft (p) ;
+ draw textext.urt ("llft") shifted theoffset.llft(p) ;
+ draw textext.top ("bot") shifted theoffset.bot (p) ;
+ draw textext.ulft("lrt") shifted theoffset.lrt (p) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer \startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\stopsection
+
+\startsection[title={Text along a path}]
+
+\index{text}
+
+In the next example we will use a special mechanism for building graphics step by
+step. The advantage of this method is that we can do intermediate calculations in
+\TEX. Our objective is to write a macro that draws text along a circular path.
+While doing so we want to achieve the following:
+
+\startitemize[packed]
+ \startitem
+ the text should be properly kerned, i.e.\ the spacing between characters
+ should be optimal,
+ \stopitem
+ \startitem
+ the position on the circle should vary, and
+ \stopitem
+ \startitem
+ the radius of the circle should vary.
+ \stopitem
+\stopitemize
+
+This code below is a bit rusted but it illustrates the principles. In \MKIV\ and
+\LMTX\ we have typesetting along a curve built in so we no longer show the \TEX\
+code that integrates it. This implementation is not the most straightforward one,
+but by doing it step by step, at least we see what is involved.
+
+We let the bodyfont match the font used in this document, and define \type
+{RotFont} to be the regular typeface, the one you are reading right now, but
+bold.
+
+\startbuffer
+\definefont[RotFont][RegularBold*default]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Since \METAPOST\ is unaware of kerning, we have to use \TEX\ to keep track of the
+positions. We will split the text into tokens (often characters) and store the
+result in an array of pictures (\type {pic}). We will also store the accumulated
+width in an array (\type {len}). The number of characters is stored in~\type {n}.
+In a few paragraphs we will see why the other arrays are needed.
+
+While defining the graphic, we need \TEX\ to do some calculations. Therefore, we
+will use \type {\startMPdrawing} to stepwise construct the definition. The basic
+pattern we will follow is:
+
+\starttyping
+\resetMPdrawing
+\startMPdrawing
+ metapost code
+\stopMPdrawing
+tex code
+\startMPdrawing
+ metapost code
+\stopMPdrawing
+\MPdrawingdonetrue
+\getMPdrawing
+\stoptyping
+
+In the process, we will use a few variables. We will store the individual
+characters of the text in the variable \type {pic}, its width in \type {wid} and
+the length of the string so far in \type {len}. Later we will use the \type {pos}
+array to store the position where a character ends up. The variable \type {n}
+holds the number of tokens.
+
+\startbuffer[init]
+\resetMPdrawing
+\startMPdrawing
+ picture pic[] ;
+ numeric wid[], len[], pos[], n ;
+ wid[0] := len[0] := pos[0] := n := 0 ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[init]
+
+We also started fresh by resetting the drawing. From now on, each start command
+will add some more to this graphic. The next macro is responsible for collecting
+the data. Each element is passed on to \TEX, using the \type {btex} construct.
+So, \METAPOST\ itself will call \TEX !
+
+\startbuffer[toks]
+\def\whatever#1%
+ {\appendtoks#1\to\MPtoks
+ \setbox\MPbox=\hbox{\bfd\the\MPtoks}%
+ \startMPdrawing
+ n := n + 1 ; len[n] := \the\wd\MPbox ;
+ \stopMPdrawing
+ \startMPdrawing[-]
+ pic[n] := textext("\bfd\setstrut\strut#1") ;
+ pic[n] := pic[n] shifted - llcorner pic[n] ;
+ \stopMPdrawing}
+
+\handletokens MetaPost is Fun!\with\whatever
+\stopbuffer
+
+\typebuffer[toks]
+
+We use the low level \CONTEXT\ macro \type {\appendtoks} to extend the token list
+\type {\MPtoks}. The \type {\handletokens} macro passes each token (character) of
+\typ {MetaPost is Fun!} to the macro \type {\whatever}. The tokens are appended
+to the token register \type {\MPtoks} (already defined). Then we typeset the
+content of \type {\MPtoks} in \type {\MPbox} (also already defined). The width of
+the box is passed to \METAPOST\ and stored in \type {len}.
+
+By default the content of the drawing is expanded, which means that the macro is
+replaced by its current meaning, so the current width ends up in the \METAPOST\
+file. The next part of the drawing, starting with \type {btex}, puts the token in
+a picture. This time we don't expand the drawing, since we want to pass font
+information. Here, the \type {[-]} suppresses expansion of \typ {btex \bfd #1
+etex}. The process is iterated by \type {\handletokens} for each character of the
+text \typ {MetaPost is Fun!}.
+
+Before we typeset the text, now available in pieces in \type {pic}, in a circle,
+we will first demonstrate what they look like. You may like to take a look at the
+file \type {mpgraph.mp} to see what is passed to \METAPOST.
+
+\startbuffer[test]
+\startMPdrawing
+ pair len ; len := origin ;
+ for i=1 upto n :
+ draw pic[i] shifted len ;
+ draw boundingbox pic[i] shifted len
+ withpen pencircle scaled .25pt withcolor red ;
+ len := len+(xpart urcorner pic[i]-xpart llcorner pic[i],0) ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[test]
+
+\startbuffer[show]
+\MPdrawingdonetrue\getMPdrawing
+\stopbuffer
+
+We can call up this drawing with \type {\getMPdrawing}, but first we inform the
+compiler that our \METAPOST\ drawing is completed.
+
+\typebuffer[show]
+
+This results in:
+
+\startlinecorrection[blank]
+\getbuffer[init,toks,test,show]
+\stoplinecorrection
+
+Compare this text with the text as typeset by \TEX:
+
+\blank \start \bfd MetaPost is Fun!\par \stop \blank
+
+and you will see that the text produced by \METAPOST\ is not properly kerned.
+When putting characters after each other, \TEX\ uses the information available in
+the font, to optimize the spacing between characters, while \METAPOST\ looks at
+characters as separate entities. But, since we have stored the optimal spacing in
+\type {len}, we can let \METAPOST\ do a better job. Let's first calculate the
+correction needed.
+
+\startbuffer[kern]
+\startMPdrawing
+ for i=1 upto n :
+ wid[i] := abs(xpart urcorner pic[i] - xpart llcorner pic[i]) ;
+ pos[i] := len[i]-wid[i] ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[kern]
+
+This compares well to the text as typeset by \TEX:
+
+\blank \start \bfd MetaPost is Fun!\par \stop \blank
+
+We can now use the values in \type {pos} to position the pictures according to
+what \TEX\ considered to be the best (relative) position.
+
+\startbuffer[test]
+\startMPdrawing
+ for i=1 upto n :
+ draw pic[i] shifted (pos[i],0) ;
+ draw boundingbox pic[i] shifted (pos[i],0)
+ withpen pencircle scaled .25pt withcolor red ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[test]
+
+That this correction is adequate, is demonstrated in the next graphic. If you
+look closely, you will see that for instance the \quote {o} is moved to the left,
+under the capital \quote {P}.
+
+\startlinecorrection[blank]
+\getbuffer[init,toks,kern,test,show]
+\stoplinecorrection
+
+When we want to position the pictures along a circle, we need to apply some
+rotations, especially because we want to go clockwise. Since we don't want to use
+\quote {complicated} math or more advanced \METAPOST\ code yet, we will do it in
+steps.
+
+\startbuffer[swap]
+\startMPdrawing
+ for i=1 upto n:
+ pic[i] := pic[i] rotatedaround(origin,-270) ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[swap]
+
+\startlinecorrection[blank]
+\getbuffer[init,toks,kern,swap,test,show]
+\stoplinecorrection
+
+\startbuffer[cent]
+\startMPdrawing
+ for i=1 upto n :
+ pic[i] := pic[i]
+ shifted (0,ypart -.5[ulcorner pic[i],llcorner pic[i]]) ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+We will now center the pictures around the baseline. Centering comes down to
+shifting over half the height of the picture. This can be expressed by:
+
+\starttyping
+ypart -.5[ulcorner pic[i],llcorner pic[i]]
+\stoptyping
+
+but different ways of calculating the distance are possible
+too.
+
+\typebuffer[cent]
+
+So, now we have:
+
+\startlinecorrection[blank]
+\getbuffer[init,toks,kern,swap,cent,test,show]
+\stoplinecorrection
+
+When we typeset on a (half) circle, we should map the actual length onto a
+partial circle. We denote the radius with an~\type {r} and shift the pictures to
+the left.
+
+\startbuffer[shif]
+\startMPdrawing
+ numeric r ; r := len[n]/pi ;
+ for i=1 upto n :
+ pic[i] := pic[i] shifted (-r,0) ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[shif]
+
+You can now use the following code to test the current state of the pictures. Of
+course this code should not end up in the final definitions.
+
+\startbuffer[test]
+\startMPdrawing
+ draw origin
+ withpen pencircle scaled 5pt withcolor red ;
+ for i=1 upto n :
+ draw pic[i] ;
+ draw boundingbox pic[i]
+ withpen pencircle scaled .25pt withcolor red ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[test]
+
+\startlinecorrection[blank]
+\getbuffer[init,toks,kern,swap,cent,shif,test,show]
+\stoplinecorrection
+
+Later we will write a compact, efficient macro to take care of rotation. However,
+for the moment, so as not to overwhelm you with complicated code, we will rotate
+each individual picture with the following code fragment.
+
+\startbuffer[rots]
+\startMPdrawing
+ numeric delta, extra, radius, rot[] ;
+
+ delta := extra := radius := 0 ;
+
+ for i=1 upto n :
+ rot[i] := extra+delta-((pos[i]+.5wid[i])/len[n])*(180+2delta) ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[rots]
+
+Here we introduce a few variables that we can use later to tune the result a bit.
+With \type {delta}, the space between the characters can be increased, while
+\type {extra} rotates the whole string around the origin. The \type {radius}
+variable can be used to increase the distance to the origin. Without these
+variables, the assignment would have been:
+
+\starttyping
+rot[i] := ((pos[i]+.5wid[i])/len[n])*180 ;
+\stoptyping
+
+Placing the pictures is now rather easy:
+
+\startbuffer[done]
+\startMPdrawing
+ for i=1 upto n :
+ draw pic[i] shifted (-radius,0) rotatedaround(origin,rot[i]) ;
+ endfor ;
+\stopMPdrawing
+\stopbuffer
+
+\typebuffer[done]
+
+The pictures are now positioned on half a circle, properly kerned.
+
+\startlinecorrection[blank]
+\getbuffer[init,toks,kern,swap,cent,shif,rots,done,show]
+\stoplinecorrection
+
+A bit more insight is given in the next picture:
+
+\startbuffer[test]
+\startMPdrawing
+ def moved(expr i) =
+ shifted (-radius,0) rotatedaround(origin,rot[i])
+ enddef ;
+ pickup pencircle scaled .5pt ;
+ for i=1 upto n :
+ draw pic[i] moved(i) ;
+ draw boundingbox pic[i] moved(i) withcolor red ;
+ draw origin -- center pic[i] moved(i) withcolor green ;
+ endfor ;
+ draw tcircle scaled 2r withcolor blue ;
+\stopMPdrawing
+\stopbuffer
+
+\startlinecorrection[blank]
+\getbuffer[init,toks,kern,swap,cent,shif,rots,test,show]
+\stoplinecorrection
+
+This was defined as follows. The path variable \type {tcycle} is predefined to
+the top half of a fullcircle.
+
+\typebuffer[test]
+
+We will now package all of this into a nice, efficient macro, using, of course,
+the predefined scratch registers \type {\MPtoks} and \type {\MPbox}. First we
+define the token processor. Note again the expansion inhibition switch \type
+{[-]}. This code is presented as an example of how these mechanissm evolved in
+\CONTEXT.
+
+\startbuffer
+\def\processrotationtoken#1%
+ {\appendtoks#1\to\MPtoks
+ \setbox\MPbox=\hbox{\RotFont\the\MPtoks}%
+ \startMPdrawing
+ n := n + 1 ; len[n] := \the\wd\MPbox ;
+ \stopMPdrawing
+ \startMPdrawing[-]
+ pic[n] := textext("\RotFont\setstrut\strut#1") ;
+ pic[n] := pic[n] shifted - llcorner pic[n] ;
+ \stopMPdrawing}
+\stopbuffer
+
+\typebuffer
+
+\getbuffer
+
+The main macro is a bit more complicated but by using a few scratch numerics, we
+can keep it readable.
+
+\startbuffer
+\def\rotatetokens#1#2#3#4% delta extra radius tokens
+ {\vbox\bgroup
+ \MPtoks\emptytoks
+ \resetMPdrawing
+ \startMPdrawing
+ picture pic[] ;
+ numeric wid, len[], rot ;
+ numeric delta, extra, radius, n, r ;
+ len[0] := n := 0 ;
+ delta := #1 ; extra := #2 ; radius := #3 ;
+ \stopMPdrawing
+ \handletokens#4\with\processrotationtoken
+ \startMPdrawing
+ r := len[n]/pi ;
+ for i=1 upto n :
+ wid := abs(xpart lrcorner pic[i] -
+ xpart llcorner pic[i]) ;
+ rot := extra + delta -
+ ((len[i]-.5wid)/len[n]) * (180+2delta) ;
+ draw pic[i]
+ rotatedaround (origin,-270) shifted (-r-radius,
+ ypart -.5[ulcorner pic[i], llcorner pic[i]])
+ rotatedaround (origin,rot) ;
+ endfor ;
+ \stopMPdrawing
+ \MPdrawingdonetrue
+ \getMPdrawing
+ \resetMPdrawing
+ \egroup}
+\stopbuffer
+
+\typebuffer
+
+\getbuffer
+
+\startbuffer
+\startcombination[3*1]
+ {\rotatetokens {0} {0}{0}{Does it work ok?}} {A}
+ {\rotatetokens{20} {0}{0}{Does it work ok?}} {B}
+ {\rotatetokens{20}{30}{0}{Does it work ok?}} {C}
+\stopcombination
+\stopbuffer
+
+We can use this macro as follows:
+
+\typebuffer
+
+\startlinecorrection[blank]
+\getbuffer
+\stoplinecorrection
+
+The previous macro is not really an example of generalization, but we used it for
+demonstrating how to build graphics in a stepwise way. If you put the steps in
+buffers, you can even combine steps and replace them at will. This is how we made
+the previous step by step examples: We put each sub||graphic in a buffer and then
+called the ones we wanted.
+
+Next we show how it is done today in \LMTX. Instead of wrapping it in a macro we
+just do all in \METAPOST. Watch how we use the key|/|value interface:
+
+\startbuffer
+\startMPcode
+ draw lmt_followtext [
+ path = halfcircle rotated 45 scaled 4cm,
+ text = "Does it work ok?",
+ spread = true,
+ trace = true,
+ ] ;
+ draw lmt_followtext [
+ path = halfcircle rotated -30 scaled 3cm,
+ text = "Does it work ok?",
+ spread = false,
+ trace = true,
+ ] shifted (4cm,0) ;
+ draw lmt_followtext [
+ path = reverse halfcircle scaled 2cm,
+ text = "Does it work ok?",
+ spread = true,
+ trace = true,
+ ] shifted (8cm,0) ;
+\stopMPcode
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+\startlinecorrection[blank]
+\getbuffer
+\stoplinecorrection
+
+\stopsection
+
+\startsection[title={Using shapes}]
+
+Sometimes, others may say oftentimes, we are in need for some fancy typesetting.
+If we want to typeset a paragraph of text in a non standard shape, like a circle,
+we have to fall back on \type {\parshape}. Unfortunately, \TEX\ is not that
+strong in providing the specifications of more complicated shapes, unless you are
+willing to do some complicated arithmetic \TEX. Given that \METAPOST\ knows how
+to deal with shapes, the question is: \quotation {Can \METAPOST\ be of help?}
+
+In the process of finding out how to deal with this, we first define a simple
+path. Because we are going to replace pieces of code, we will compose the graphic
+from components. First, we create the path.
+
+\startbuffer
+\startuseMPgraphic{text path}
+ path p ; p := ((0,1)..(-1,0)..(1,0)--cycle) scaled 65pt ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+This shape is not that beautiful, but it has a few characteristics that will help
+us to identify bordercases.
+
+\startbuffer
+\startuseMPgraphic{text draw}
+ drawarrow p withpen pencircle scaled 1pt withcolor red ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Now we use \CONTEXT's \type {\includeMPgraphic} command to build our graphic from
+the previously defined components.
+
+\startbuffer
+\startuseMPgraphic{text}
+ \includeMPgraphic{text path}
+ \includeMPgraphic{text draw}
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+When called with \type {\useMPgraphic{text}}, we get:
+
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+For the moment we start the path at $(x=0,y>0)$, but later using more complicated
+macros, we will see that we can use arbitrary paths.
+
+We are going to split the path in two, and will use the points that make up the
+bounding box as calcutated by \METAPOST. The next graphic shows one of these
+points, the lower left corner, available as point \typ {llcorner p}.
+
+\startbuffer
+\startuseMPgraphic{text draw}
+ draw p withpen pencircle scaled 3pt withcolor red ;
+ draw boundingbox p withpen pencircle scaled 1pt ;
+ draw llcorner p withpen pencircle scaled 5pt ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+The five points that \METAPOST\ can report for each path or picture are:
+
+\starttabulate[|Tl|l|]
+\NC llcorner \NC lower left corner \NC \NR
+\NC lrcorner \NC lower right corner \NC \NR
+\NC urcorner \NC upper right corner \NC \NR
+\NC ulcorner \NC upper left corner \NC \NR
+\NC center \NC intersection of the diagonals \NC \NR
+\stoptabulate
+
+If we want to typeset text inside this circle, we need to know where a line
+starts and ends. Given that lines are horizontal and straight, we therefore need
+to calculate the intersection points of the lines and the path. As a first step,
+we calculate the top and bottom of the path and after that we split off the left
+and right path.
+
+\startbuffer
+\startuseMPgraphic{text split}
+ pair t, b ; path l, r ;
+
+ t := (ulcorner p -- urcorner p) intersectionpoint p ;
+ b := (llcorner p -- lrcorner p) intersectionpoint p ;
+
+ l := p cutbefore t ; l := l cutafter b ;
+ r := p cutbefore b ; r := r cutafter t ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The \type {intersectionpoint} macro returns the point where two paths cross. If
+the paths don't cross, an error is reported, when the paths cross more times,
+just one point is returned. The \type {cutafter} and \type {cutbefore} commands
+do as their names say and return a path.
+
+In the \type {text split} code fragment, \type {t} and \type {b} are the top
+points of the main path, while \type {l} and \type {r} become the left and right
+half of path \type {p}.
+
+We now draw the original path using a thick pen and both halves with a thinner
+pen on top of the original. The arrows show the direction.
+
+\startbuffer
+\startuseMPgraphic{text draw}
+ draw p withpen pencircle scaled 3pt withcolor red ;
+ drawarrow l withpen pencircle scaled 1pt withcolor green ;
+ drawarrow r withpen pencircle scaled 1pt withcolor blue ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+We use \type {\includeMPgraphic} to assemble the components:
+
+\startbuffer
+\startuseMPgraphic{text}
+ \includeMPgraphic{text path}
+ \includeMPgraphic{text split}
+ \includeMPgraphic{text draw}
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+This graphic is typeset with \type {\useMPgraphic{text}}:
+
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+Before we are going to use them, we define some variables that specify the text.
+We use a baseline distance of 8~points. The part of the line above the baseline
+is 7.2~points, while the (maximum) depth is 2.8~points. These ratios are the ones
+we use in \CONTEXT. Because we don't want the text to touch the circle so we
+define an offset too.
+
+\startbuffer
+\startuseMPgraphic{text vars}
+ MyOffset := LineHeight/2 ;
+ MyTopSkip := StrutHeight ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+We more or less achieve the offset by scaling the path. In doing so, we use the
+width and height, which we call \type {hsize} and \type {vsize}, thereby
+conforming to the \TEX\ naming scheme.
+
+First we calculate both dimensions from the bounding box of the path. Next we
+down scale the path to compensate for the offset. When done, we recalculate the
+dimensions.
+
+\startbuffer
+\startuseMPgraphic{text move}
+ pair t, b ; path q, l, r ;
+
+ hsize := xpart lrcorner p - xpart llcorner p ;
+ vsize := ypart urcorner p - ypart lrcorner p ;
+
+ q := p xscaled ((hsize-2MyOffset)/hsize)
+ yscaled ((vsize-2MyOffset)/vsize) ;
+
+ hsize := xpart lrcorner q - xpart llcorner q ;
+ vsize := ypart urcorner q - ypart lrcorner q ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startbuffer
+\startuseMPgraphic{text split}
+ t := (ulcorner q -- urcorner q) intersectionpoint q ;
+ b := (llcorner q -- lrcorner q) intersectionpoint q ;
+
+ l := q cutbefore t ; l := l cutafter b ;
+ r := q cutbefore b ; r := r cutafter t ;
+\stopuseMPgraphic
+\stopbuffer
+
+We adapt the \type {text split} code to use the reduced path
+instead of the original.
+
+\typebuffer \getbuffer
+
+\startbuffer
+\startuseMPgraphic{text draw}
+ drawarrow p withpen pencircle scaled 1pt withcolor red ;
+ draw t withpen pencircle scaled 2pt ;
+ draw b withpen pencircle scaled 2pt ;
+ drawarrow l withpen pencircle scaled 1pt withcolor green ;
+ drawarrow r withpen pencircle scaled 1pt withcolor blue ;
+\stopuseMPgraphic
+\stopbuffer
+
+In order to test what we have reached so far, we draw the original path, the left
+and right part of the reduced path, and both the top and bottom point.
+
+\typebuffer \getbuffer
+
+Again we use \type {\includeMPgraphic} to combine the
+components into a graphic.
+
+\startbuffer
+\startuseMPgraphic{text}
+ \includeMPgraphic{text path} \includeMPgraphic{text vars}
+ \includeMPgraphic{text move} \includeMPgraphic{text split}
+ \includeMPgraphic{text draw}
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Then we use \type {\useMPgraphic{text}} to call up the picture.
+
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+The offset is not optimal. Note the funny gap at the top. We could try to fix
+this, but there is a better way to optimize both paths.
+
+We lower the top edge of \type {q}'s bounding box by \type {MyTopSkip}, then cut
+any part of the left and right pieces of \type {q} that lie above it. Similarly,
+we raise the bottom edge and cut off the pieces that fall below this line.
+
+\startbuffer
+\startuseMPgraphic{text cutoff}
+ path tt, bb ;
+
+ tt := (ulcorner q -- urcorner q) shifted (0,-MyTopSkip) ;
+ bb := (llcorner q -- lrcorner q) shifted (0,StrutDepth) ;
+
+ l := l cutbefore (l intersectionpoint tt) ;
+ l := l cutafter (l intersectionpoint bb) ;
+ r := r cutbefore (r intersectionpoint bb) ;
+ r := r cutafter (r intersectionpoint tt) ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Because we use \type {\includeMPgraphic} to construct the graphic, we can
+redefine \type {text draw} to show the result of this effort.
+
+\startbuffer
+\startuseMPgraphic{text draw}
+ drawarrow p withpen pencircle scaled 1pt withcolor red ;
+ drawarrow l withpen pencircle scaled 1pt withcolor green ;
+ drawarrow r withpen pencircle scaled 1pt withcolor blue ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The \type {text} graphic now becomes:
+
+\startbuffer
+\startuseMPgraphic{text}
+ \includeMPgraphic{text path} \includeMPgraphic{text vars}
+ \includeMPgraphic{text move} \includeMPgraphic{text split}
+ \includeMPgraphic{text cutoff} \includeMPgraphic{text draw}
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Or, as graphic:
+
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+We are now ready for an attempt to calculate the shape of the text. For each
+line, we have to calculate the left and right intersection points, and since a
+line has a height and depth, we have to determine which part touches first.
+
+\startbuffer
+\startuseMPgraphic{text calc}
+ vardef found_point (expr lin, pat, sig) =
+ pair a, b ;
+ a := pat intersection_point (lin shifted (0,StrutHeight)) ;
+ if intersection_found :
+ a := a shifted (0,-StrutHeight) ;
+ else :
+ a := pat intersection_point lin ;
+ fi ;
+ b := pat intersection_point (lin shifted (0,-StrutDepth)) ;
+ if intersection_found :
+ if sig :
+ if xpart b > xpart a : a := b shifted (0,StrutDepth) fi ;
+ else :
+ if xpart b < xpart a : a := b shifted (0,StrutDepth) fi ;
+ fi ;
+ fi ;
+ a
+ enddef ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Instead of using \METAPOST's \type {intersectionpoint} macro, we use one that
+comes with \CONTEXT. That way we don't get an error message when no point is
+found, and can use a boolean flag to take further action. Since we use a \type
+{vardef}, all calculations are hidden and the~\type {a} at the end is returned,
+so that we can use this macro in an assignment. The \type {sig} variable is used
+to distinguish between the beginning and end of a line (the left and right
+subpath).
+
+\startbuffer
+\startuseMPgraphic{text step}
+ path line; pair lll, rrr ;
+
+ for i=MyTopSkip step LineHeight until vsize :
+
+ line := (ulcorner q -- urcorner q) shifted (0,-i) ;
+
+ lll := found_point(line,l,true ) ;
+ rrr := found_point(line,r,false) ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Here we divide the available space in lines. The first line starts at \type
+{StrutHeight} from the top.
+
+We can now finish our graphic by visualizing the lines. Both the height and depth
+of the lines are shown.
+
+\startbuffer
+\startuseMPgraphic{text line}
+ fill (lll--rrr--rrr shifted (0,StrutHeight)--lll
+ shifted (0,StrutHeight)--cycle) withcolor .5white ;
+ fill (lll--rrr--rrr shifted (0,-StrutDepth)--lll
+ shifted (0,-StrutDepth)--cycle) withcolor .7white ;
+ draw lll withpen pencircle scaled 2pt ;
+ draw rrr withpen pencircle scaled 2pt ;
+ draw (lll--rrr) withpen pencircle scaled .5pt ;
+\stopuseMPgraphic
+
+\startuseMPgraphic{text done}
+ endfor ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The result is still a bit disappointing.
+
+\startbuffer
+\startuseMPgraphic{text}
+ \includeMPgraphic{text path} \includeMPgraphic{text vars}
+ \includeMPgraphic{text move} \includeMPgraphic{text split}
+ \includeMPgraphic{text cutoff} \includeMPgraphic{text draw}
+ \includeMPgraphic{text calc} \includeMPgraphic{text step}
+ \includeMPgraphic{text line} \includeMPgraphic{text done}
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+In order to catch the overflow at the bottom, we need to change the \type
+{for}||loop a bit, so that the number of lines does not exceed the available
+space. The test that surrounds the assignment of \type {vvsize} makes sure that
+we get better results when we (on purpose) take a smaller height.
+
+\startbuffer
+\startuseMPgraphic{text step}
+ path line; pair lll, rrr ; numeric vvsize ;
+
+ if (StrutHeight+StrutDepth<LineHeight) :
+ vvsize := vsize ;
+ else :
+ vvsize := (vsize div LineHeight) * LineHeight ;
+ fi ;
+
+ for i=MyTopSkip step LineHeight until vvsize :
+
+ line := (ulcorner q -- urcorner q) shifted (0,-i) ;
+
+ lll := found_point(line,l,true ) ;
+ rrr := found_point(line,r,false) ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+We can manipulate the heigth and depth of the lines to give different (and maybe
+better) results.
+
+\startbuffer
+\startuseMPgraphic{text vars}
+MyOffset := .5LineHeight ;
+MyTopSkip := StrutHeight ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\startlinecorrection[blank]
+\useMPgraphic{text}
+\stoplinecorrection
+
+Now that we know a bit how this works we demonstrate the implementation in \LMTX.
+Where in \MKIV\ and \MKII\ we let \METAPOST\ pass the dimensions to \TEX\ via a
+temporary file in \LMTX\ we communicate more directly. You can take a look at the
+source code if you want to know how that works.
+
+We start by defining four shapes. They are not really beautiful, but they
+demonstrate what happens in border cases. For instance, too small first lines are
+ignored. First we define a circle. Watch how the dimensions are set in the
+graphic. The arguments passed to \type {lmt_parshape} are: path, an offset, an
+additional horizontal and vertical displacement, the baseline distance, the
+height and depth of the line, and the height of the first line (aka topskip). The
+height and depth of a line are often called strut height and depth, with a strut
+being an invisible character with maximum dimensions. Variables like \type
+{StrutHeight} refer to values at the \TEX\ end. We play safe and group so that we
+can save variables.
+
+\startbuffer
+\startuseMPgraphic{shapetest-1}
+ begingroup ;
+ save p ; path p ; p := fullcircle scaled 6cm ;
+ lmt_parshape [
+ path = p,
+ offset = BodyFontSize/2,
+ dx = 0, % default
+ dy = 0, % default
+ lineheight = LineHeight, % default
+ strutheight = StrutHeight, % default
+ strutdepth = StrutDepth, % default
+ topskip = StrutHeight, % default
+ ] ;
+ draw p withpen pencircle scaled 1pt ;
+ endgroup ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The second shape is a diamond. This is a rather useless shape, unless the text
+suits the small lines at the top and bottom.
+
+\startbuffer
+\startuseMPgraphic{shapetest-2}
+ begingroup ;
+ save p ; path p ; p := fullsquare rotated 45 scaled 5cm ;
+ lmt_parshape [
+ path = p,
+ offset = BodyFontSize/2,
+ trace = true,
+ ] ;
+ draw p withpen pencircle scaled 1pt ;
+ endgroup ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The third and fourth shape demonstrate that providing a suitable offset is not
+always trivial.
+
+\startbuffer
+\startuseMPgraphic{shapetest-3}
+ begingroup ;
+ save w, h, p ; path p ; w := h := 6cm ;
+ p := (.5w,h) -- ( 0, h) -- (0,0) -- (w,0) &
+ ( w,0) .. (.75w,.5h) .. (w,h) & (w,h) -- cycle ;
+ lmt_parshape [
+ path = p,
+ offset = BodyFontSize/2,
+ ] ;
+ draw p withpen pencircle scaled 1pt ;
+ endgroup ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Contrary to the first three shapes, here we use a different path for the
+calculations and the drawing. Watch carefully! If, instead of an offset, we pass
+a path, \METAPOST\ is able to calculate the right dimensions and offsets. This is
+needed, since we need these later on.
+
+\startbuffer
+\startuseMPgraphic{shapetest-4}
+ begingroup ;
+ save d, p, q, shape ; path p, q ; d := BodyFontSize/2;
+ vardef shape(expr w, h, o) =
+ (o,o) -- (w-o,o) & (w-o,o) .. (.75w-o,.5h) ..
+ (w-2o,h-o) & (w-2o,h-o) -- (o,h-o) -- cycle
+ enddef ;
+ p := shape(6cm, 6cm, d) ;
+ q := shape(6cm, 6cm, 0) ;
+ lmt_parshape [
+ path = p,
+ offsetpath = q,
+ dx = d,
+ dy = d,
+ trace = true,
+ ] ;
+ draw q withpen pencircle scaled 1pt ;
+ endgroup ;
+\stopuseMPgraphic
+\stopbuffer
+
+\typebuffer \getbuffer
+
+Since we also want these graphics as backgrounds, we define them as overlays. If
+you don't want to show the graphic, you may omit this step.
+
+\startbuffer
+\defineoverlay[shapetest-1][\useMPgraphic{shapetest-1}]
+\defineoverlay[shapetest-2][\useMPgraphic{shapetest-2}]
+\defineoverlay[shapetest-3][\useMPgraphic{shapetest-3}]
+\defineoverlay[shapetest-4][\useMPgraphic{shapetest-4}]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+As text, we use a quote from Douglas R.~Hofstadter's book \quotation {Metamagical
+Themas, Questing for the Essence of Mind and Pattern}. Watch how we pass a list
+of shapes.
+
+\startbuffer[text]
+\startshapetext[shapetest-1,shapetest-2,shapetest-3,shapetest-4]
+ \forgetall % as it says
+ \setupalign[verytolerant,stretch,normal]%
+ \samplefile{douglas}% Douglas R. Hofstadter
+\stopshapetext
+\stopbuffer
+
+\typebuffer[text]
+
+Finally we combine text and shapes. Since we also want a background, we use \type
+{\framed}. The normal result is shown in \in {figure} [fig:shapes].
+
+\startbuffer[shapes]
+\startbuffer
+\startcombination[2*2]
+ {\framed[offset=overlay,frame=off,background=shapetest-1]{\getshapetext}} {shapetest-1}
+ {\framed[offset=overlay,frame=off,background=shapetest-2]{\getshapetext}} {shapetest-2}
+ {\framed[offset=overlay,frame=off,background=shapetest-3]{\getshapetext}} {shapetest-3}
+ {\framed[offset=overlay,frame=off,background=shapetest-4]{\getshapetext}} {shapetest-4}
+\stopcombination
+\stopbuffer
+\stopbuffer
+
+\typebuffer[shapes]
+
+\getbuffer[shapes]
+
+By using a buffer we keep \type {\placefigure} readable. You might have noticed
+that for two shapes we turned on tracing.
+
+\startbuffer[a]
+\placefigure
+ [here][fig:shapes]
+ {A continuous text, typeset in a non||standard shape,
+ spread over four areas, and right aligned.}
+ {\getbuffer}
+\stopbuffer
+
+\startbuffer[b]
+\placefigure
+ [here][fig:shapes]
+ {A continuous text, typeset in a non||standard shape,
+ spread over four areas.}
+ {\scale[factor=max,height=.9\textheight]{\getbuffer}}
+\stopbuffer
+
+\typebuffer[a]
+
+\doifmodeelse{screen}{\getbuffer[text,b]}{\getbuffer[text,a]}
+
+\blank
+
+We can combine all those tricks, although the input is somewhat fuzzy. First we
+define a quote typeset in a circular paragraph shape where we use the defaults.
+
+\startbuffer[shape]
+\startuseMPgraphic{center}
+ lmt_parshape [
+ path = fullcircle scaled 8cm,
+ ]
+\stopuseMPgraphic
+
+\startshapetext[center]
+ \samplefile{douglas}%
+\stopshapetext
+
+\defineoverlay[center][\useMPgraphic{center}]
+\stopbuffer
+
+\typebuffer[shape]
+
+We will surround this text with a circular line, that we define as follows. By
+using a buffer we keep things organized.
+
+\startbuffer
+\startuseMPgraphic{circle}
+ save p ; path p ;
+ p := reverse fullcircle rotatedaround(origin,90)
+ xscaled OverlayWidth yscaled OverlayHeight ;
+
+ draw lmt_followtext [
+ path = p,
+ text = "This is just a dummy text, kerned by \TeX\ and typeset
+ in a circle using \MetaPost.\quad",
+ spread = true,
+ trace = true,
+ ] ;
+
+% draw p ;
+\stopuseMPgraphic
+
+\defineoverlay[edge][\useMPgraphic{circle}]
+\stopbuffer
+
+\typebuffer \getbuffer
+
+The text and graphics come together in a framed text:
+
+\startbuffer
+\startplacefigure[title={One more time Hofstadter's quotation (normal).}]
+ \getbuffer[shape,quote]%
+ \framed
+ [offset=24pt,
+ background=edge,
+ frame=off,
+ backgroundoffset=-18pt]
+ {\getshapetext}
+\stopplacefigure
+\stopbuffer
+
+\typebuffer \getbuffer
+
+\stopsection
+
+\stopchapter
+
+\stopcomponent