summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans Hagen <pragma@wxs.nl>2021-03-02 20:22:41 +0100
committerContext Git Mirror Bot <phg@phi-gamma.net>2021-03-02 20:22:41 +0100
commit0d300509bdd7497fd376844b2326f5917636590e (patch)
tree7b3236d0be4e2e6f0dac1171fde560ed9b9c89e6
parentd07afd7261f4bb5486cc016d8c90d532ba7fc0e4 (diff)
downloadcontext-0d300509bdd7497fd376844b2326f5917636590e.tar.gz
2021-03-02 19:20:00
-rw-r--r--doc/context/documents/general/manuals/lowlevel-paragraphs.pdfbin192854 -> 208745 bytes
-rw-r--r--doc/context/sources/general/manuals/lowlevel/lowlevel-paragraphs.tex153
-rw-r--r--doc/context/sources/general/manuals/metafun/metafun-effects.tex94
-rw-r--r--doc/context/sources/general/manuals/metafun/metafun-gadgets.tex2
-rw-r--r--doc/context/sources/general/manuals/metafun/metafun-sneaky.tex149
-rw-r--r--doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex1520
-rw-r--r--doc/context/sources/general/manuals/metafun/metafun-text.tex29
-rw-r--r--doc/context/sources/general/manuals/metafun/metafun.tex4
-rw-r--r--metapost/context/base/mpxl/mp-luas.mpxl10
-rw-r--r--scripts/context/lua/mtx-context.lua3
-rw-r--r--tex/context/base/mkii/cont-new.mkii2
-rw-r--r--tex/context/base/mkii/context.mkii2
-rw-r--r--tex/context/base/mkii/mult-cs.mkii1
-rw-r--r--tex/context/base/mkiv/back-exp.lua29
-rw-r--r--tex/context/base/mkiv/cont-new.mkiv2
-rw-r--r--tex/context/base/mkiv/context.mkiv2
-rw-r--r--tex/context/base/mkiv/meta-lua.lua2
-rw-r--r--tex/context/base/mkiv/status-files.pdfbin25363 -> 25371 bytes
-rw-r--r--tex/context/base/mkiv/status-lua.pdfbin256166 -> 256137 bytes
-rw-r--r--tex/context/base/mkxl/back-exp.mkxl2
-rw-r--r--tex/context/base/mkxl/cont-new.mkxl2
-rw-r--r--tex/context/base/mkxl/context.mkxl2
-rw-r--r--tex/context/base/mkxl/font-fea.mklx44
-rw-r--r--tex/context/base/mkxl/meta-imp-txt.mkxl24
-rw-r--r--tex/context/base/mkxl/mlib-fio.lmt12
-rw-r--r--tex/context/base/mkxl/mlib-mpf.lmt24
-rw-r--r--tex/context/base/mkxl/typo-par.lmt103
-rw-r--r--tex/context/base/mkxl/typo-shp.lmt150
-rw-r--r--tex/context/base/mkxl/typo-shp.mkxl1
-rw-r--r--tex/context/interface/mkii/keys-cs.xml1
-rw-r--r--tex/generic/context/luatex/luatex-fonts-merged.lua2
31 files changed, 2136 insertions, 235 deletions
diff --git a/doc/context/documents/general/manuals/lowlevel-paragraphs.pdf b/doc/context/documents/general/manuals/lowlevel-paragraphs.pdf
index b36f25dd0..bde7fda14 100644
--- a/doc/context/documents/general/manuals/lowlevel-paragraphs.pdf
+++ b/doc/context/documents/general/manuals/lowlevel-paragraphs.pdf
Binary files differ
diff --git a/doc/context/sources/general/manuals/lowlevel/lowlevel-paragraphs.tex b/doc/context/sources/general/manuals/lowlevel/lowlevel-paragraphs.tex
index dad9b2e4e..3098333f0 100644
--- a/doc/context/sources/general/manuals/lowlevel/lowlevel-paragraphs.tex
+++ b/doc/context/sources/general/manuals/lowlevel/lowlevel-paragraphs.tex
@@ -353,14 +353,14 @@ mechanism uses a combination of \type {\hangafter} and \type {\hangindent}, and
the second one depends on \type {\parshape}. In this section we discuss the
rectangular one.
-\startbuffer[hang]
+\startbuffer[demo-5]
\hangafter 4 \hangindent 4cm \samplefile{tufte} \page
\hangafter -4 \hangindent 4cm \samplefile{tufte} \page
\hangafter 4 \hangindent -4cm \samplefile{tufte} \page
\hangafter -4 \hangindent -4cm \samplefile{tufte} \page
\stopbuffer
-\typebuffer[hang][option=TEX]
+\typebuffer[demo-5][option=TEX]
As you can see in \in {figure} [fig:hang], the four cases are driven by the sign
of the values. If you want to hang into the margin you need to use different
@@ -370,10 +370,10 @@ uses at the same time).
\startplacefigure[title=Hanging indentation,reference=fig:hang]
\startcombination[nx=2,ny=2]
- {\typesetbuffer[hang][page=1,width=.4\textwidth,frame=on]} {\type{\hangafter +4 \hangindent +4cm}}
- {\typesetbuffer[hang][page=2,width=.4\textwidth,frame=on]} {\type{\hangafter -4 \hangindent +4cm}}
- {\typesetbuffer[hang][page=3,width=.4\textwidth,frame=on]} {\type{\hangafter +4 \hangindent -4cm}}
- {\typesetbuffer[hang][page=4,width=.4\textwidth,frame=on]} {\type{\hangafter -4 \hangindent -4cm}}
+ {\typesetbuffer[demo-5][page=1,width=.4\textwidth,frame=on]} {\type{\hangafter +4 \hangindent +4cm}}
+ {\typesetbuffer[demo-5][page=2,width=.4\textwidth,frame=on]} {\type{\hangafter -4 \hangindent +4cm}}
+ {\typesetbuffer[demo-5][page=3,width=.4\textwidth,frame=on]} {\type{\hangafter +4 \hangindent -4cm}}
+ {\typesetbuffer[demo-5][page=4,width=.4\textwidth,frame=on]} {\type{\hangafter -4 \hangindent -4cm}}
\stopcombination
\stopplacefigure
@@ -470,14 +470,14 @@ Also watch the \type {hsize} keyword: we don't calculate the hsize from the \typ
When a \type {right} keywords comes first the \type {left} is assumed to be zero.
In the examples that follow we will use a couple of definitions:
-\startbuffer[setup]
+\startbuffer[setup-0]
\startparagraphshape[test]
both 1mm both 2mm both 3mm both 4mm both 5mm both 6mm
both 7mm both 6mm both 5mm both 4mm both 3mm both 2mm
\stopparagraphshape
\stopbuffer
-\startbuffer[setup-repeat]
+\startbuffer[setup-0-repeat]
\startparagraphshape[test-repeat]
both 1mm both 2mm both 3mm both 4mm both 5mm both 6mm
both 7mm both 6mm both 5mm both 4mm both 3mm both 2mm
@@ -485,7 +485,7 @@ In the examples that follow we will use a couple of definitions:
\stopparagraphshape
\stopbuffer
-\typebuffer[setup,setup-repeat][option=TEX]
+\typebuffer[setup-0,setup-0-repeat][option=TEX]
The last one could also be defines as:
@@ -505,13 +505,13 @@ but just keep in mind that \type {repeat} is part of the \type {\parshape} and
act within a paragraph while \type {shift} and \type {cycle} are applied when a
new paragraph is started.
-\startbuffer[demo]
+\startbuffer[demo-1]
\startshapedparagraph[list=test]
\dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
\stopshapedparagraph
\stopbuffer
-\startbuffer[demo-repeat]
+\startbuffer[demo-1-repeat]
\startshapedparagraph[list=test-repeat]
\dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
\stopshapedparagraph
@@ -519,64 +519,64 @@ new paragraph is started.
In \in {figure} [fig:shape:discard] you see the following applied:
-\typebuffer[demo,demo-repeat][option=TEX]
+\typebuffer[demo-1,demo-1-repeat][option=TEX]
\startplacefigure[title=Discarded shaping,reference=fig:shape:discard]
\startcombination[nx=2,ny=2]
- {\typesetbuffer[setup,demo][page=1,width=.4\textwidth,frame=on]} {discard, finite shape, page 1}
- {\typesetbuffer[setup,demo][page=2,width=.4\textwidth,frame=on]} {discard, finite shape, page 2}
- {\typesetbuffer[setup-repeat,demo-repeat][page=1,width=.4\textwidth,frame=on]} {discard, repeat in shape, page 1}
- {\typesetbuffer[setup-repeat,demo-repeat][page=2,width=.4\textwidth,frame=on]} {discard, repeat in shape, page 2}
+ {\typesetbuffer[setup-0,demo-1] [page=1,width=.4\textwidth,frame=on]} {discard, finite shape, page 1}
+ {\typesetbuffer[setup-0,demo-1] [page=2,width=.4\textwidth,frame=on]} {discard, finite shape, page 2}
+ {\typesetbuffer[setup-0,demo-1-repeat][page=1,width=.4\textwidth,frame=on]} {discard, repeat in shape, page 1}
+ {\typesetbuffer[setup-0,demo-1-repeat][page=2,width=.4\textwidth,frame=on]} {discard, repeat in shape, page 2}
\stopcombination
\stopplacefigure
In \in {figure} [fig:shape:shift] we use this instead:
-\startbuffer[demo]
+\startbuffer[demo-2]
\startshapedparagraph[list=test,method=shift]
\dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
\stopshapedparagraph
\stopbuffer
-\startbuffer[demo-shift]
+\startbuffer[demo-2-shift]
\startshapedparagraph[list=test-repeat,method=shift]
\dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
\stopshapedparagraph
\stopbuffer
-\typebuffer[demo,demo-repeat][option=TEX]
+\typebuffer[demo-2,demo-2-repeat][option=TEX]
\startplacefigure[title=Shifted shaping,reference=fig:shape:shift]
\startcombination[nx=2,ny=2]
- {\typesetbuffer[setup,demo][page=1,width=.4\textwidth,frame=on]} {shift, finite shape, page 1}
- {\typesetbuffer[setup,demo][page=2,width=.4\textwidth,frame=on]} {shift, finite shape, page 2}
- {\typesetbuffer[setup-repeat,demo-shift][page=1,width=.4\textwidth,frame=on]} {shift, repeat in shape, page 1}
- {\typesetbuffer[setup-repeat,demo-shift][page=2,width=.4\textwidth,frame=on]} {shift, repeat in shape, page 2}
+ {\typesetbuffer[setup-0,demo-2][page=1,width=.4\textwidth,frame=on]} {shift, finite shape, page 1}
+ {\typesetbuffer[setup-0,demo-2][page=2,width=.4\textwidth,frame=on]} {shift, finite shape, page 2}
+ {\typesetbuffer[setup-0-repeat,demo-2-shift][page=1,width=.4\textwidth,frame=on]} {shift, repeat in shape, page 1}
+ {\typesetbuffer[setup-0-repeat,demo-2-shift][page=2,width=.4\textwidth,frame=on]} {shift, repeat in shape, page 2}
\stopcombination
\stopplacefigure
Finally, in \in {figure} [fig:shape:cycle] we use:
-\startbuffer[demo]
+\startbuffer[demo-3]
\startshapedparagraph[list=test,method=cycle]
\dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
\stopshapedparagraph
\stopbuffer
-\startbuffer[demo-cycle]
+\startbuffer[demo-3-cycle]
\startshapedparagraph[list=test-repeat,method=cycle]
\dorecurse{8}{\showparagraphshape\samplefile{tufte} \par}
\stopshapedparagraph
\stopbuffer
-\typebuffer[demo,demo-repeat][option=TEX]
+\typebuffer[demo-3,demo-3-repeat][option=TEX]
\startplacefigure[title=Cycled shaping,reference=fig:shape:cycle]
\startcombination[nx=2,ny=2]
- {\typesetbuffer[setup,demo][page=1,width=.4\textwidth,frame=on]} {cycle, finite shape, page 1}
- {\typesetbuffer[setup,demo][page=2,width=.4\textwidth,frame=on]} {cycle, finite shape, page 2}
- {\typesetbuffer[setup-repeat,demo-cycle][page=1,width=.4\textwidth,frame=on]} {cycle, repeat in shape, page 1}
- {\typesetbuffer[setup-repeat,demo-cycle][page=2,width=.4\textwidth,frame=on]} {cycle, repeat in shape, page 2}
+ {\typesetbuffer[setup-0,demo-3][page=1,width=.4\textwidth,frame=on]} {cycle, finite shape, page 1}
+ {\typesetbuffer[setup-0,demo-3][page=2,width=.4\textwidth,frame=on]} {cycle, finite shape, page 2}
+ {\typesetbuffer[setup-0-repeat,demo-3-cycle][page=1,width=.4\textwidth,frame=on]} {cycle, repeat in shape, page 1}
+ {\typesetbuffer[setup-0-repeat,demo-3-cycle][page=2,width=.4\textwidth,frame=on]} {cycle, repeat in shape, page 2}
\stopcombination
\stopplacefigure
@@ -626,7 +626,7 @@ some \METAPOST. The following code creates a shape for a circle. We use a
We plug this into the already described macros:
\startbuffer
-\startshapedparagraph[list=circle,mp=circle]%
+\startshapedparagraph[mp=circle]%
\setupalign[verytolerant,stretch,last]%
\samplefile{tufte}
\samplefile{tufte}
@@ -710,15 +710,12 @@ the original code is mid 2000, but the principles didn't change. The examples in
\startuseMPgraphic{test 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
@@ -726,14 +723,11 @@ the original code is mid 2000, but the principles didn't change. The examples in
\startuseMPgraphic{test 4}
begingroup ;
save d, p, q ; 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,
@@ -741,7 +735,6 @@ the original code is mid 2000, but the principles didn't change. The examples in
dy = d,
trace = true,
] ;
-
draw q withpen pencircle scaled 1pt ;
endgroup ;
\stopuseMPgraphic
@@ -795,7 +788,7 @@ Here is a bit more extreme example. Again we use a circle:
But we output a longer text:
\startbuffer
-\startshapedparagraph[list=circle,mp=circle,repeat=yes,method=cycle]%
+\startshapedparagraph[mp=circle,repeat=yes,method=cycle]%
\setupalign[verytolerant,stretch,last]\dontcomplain
{\darkred \samplefile{tufte}}\par
{\darkgreen \samplefile{tufte}}\par
@@ -814,7 +807,7 @@ We get a multi|-|page shape:
Compare this with:
\startbuffer
-\startshapedparagraph[list=circle,mp=circle,repeat=yes,method=cycle]%
+\startshapedparagraph[mp=circle,repeat=yes,method=cycle]%
\setupalign[verytolerant,stretch,last]\dontcomplain
{\darkred \samplefile{tufte}}
{\darkgreen \samplefile{tufte}}
@@ -834,6 +827,86 @@ Here the \type {bottomskip} takes care of subtle rounding issues as well as
discarding the last line in the shape so that we get nicer continuation. There is
no full automated solution for all you can come up with.
+Mixing a \METAPOST\ specification into a regular one is also possible. The next
+example demonstrates this as well as the option to remove some lines from a
+specification:
+
+\starttyping[option=TEX]
+\startparagraphshape[test]
+ left 0em right 0em
+ left 1em right 0em
+ metapost {circle}
+ delete 3
+ metapost {circle,circle,circle}
+ delete 7
+ metapost {circle}
+ repeat
+\stopparagraphshape
+\stoptyping
+
+You can combine a shape with narrowing a paragraph. Watch the \type {absolute}
+keyword in the next code. The result is shown in \in {figure} [fig:shape:skips].
+
+\startbuffer[demo-4]
+\startuseMPgraphic{circle}
+ lmt_parshape [
+ path = fullcircle scaled TextWidth,
+ bottomskip = - 1.5LineHeight,
+ ] ;
+\stopuseMPgraphic
+
+\startparagraphshape[test-1]
+ metapost {circle} repeat
+\stopparagraphshape
+
+\startparagraphshape[test-2]
+ absolute left metapost {circle} repeat
+\stopparagraphshape
+
+\startparagraphshape[test-3]
+ absolute right metapost {circle} repeat
+\stopparagraphshape
+
+\startparagraphshape[test-4]
+ absolute both metapost {circle} repeat
+\stopparagraphshape
+
+\showframe
+
+\startnarrower[4*left,2*right]
+ \startshapedparagraph[list=test-1,repeat=yes,method=repeat]%
+ \setupalign[verytolerant,stretch,last]\dontcomplain
+ \dorecurse{3}{\samplefile{thuan}}
+ \stopshapedparagraph
+ \page
+ \startshapedparagraph[list=test-2,repeat=yes,method=repeat]%
+ \setupalign[verytolerant,stretch,last]\dontcomplain
+ \dorecurse{3}{\samplefile{thuan}}
+ \stopshapedparagraph
+ \page
+ \startshapedparagraph[list=test-3,repeat=yes,method=repeat]%
+ \setupalign[verytolerant,stretch,last]\dontcomplain
+ \dorecurse{3}{\samplefile{thuan}}
+ \stopshapedparagraph
+ \page
+ \startshapedparagraph[list=test-4,repeat=yes,method=repeat]%
+ \setupalign[verytolerant,stretch,last]\dontcomplain
+ \dorecurse{3}{\samplefile{thuan}}
+ \stopshapedparagraph
+\stopnarrower
+\stopbuffer
+
+\typebuffer[demo-4][option=TEX]
+
+\startplacefigure[title=Skip compensation,reference=fig:shape:skips]
+\startcombination[nx=2,ny=2]
+ {\typesetbuffer[demo-4][page=1,width=.4\textwidth,frame=on]} {test 1}
+ {\typesetbuffer[demo-4][page=2,width=.4\textwidth,frame=on]} {test 2, left}
+ {\typesetbuffer[demo-4][page=3,width=.4\textwidth,frame=on]} {test 3, right}
+ {\typesetbuffer[demo-4][page=4,width=.4\textwidth,frame=on]} {test 4, both}
+\stopcombination
+\stopplacefigure
+
\stopsection
% \startsection[title=Linebreaks]
diff --git a/doc/context/sources/general/manuals/metafun/metafun-effects.tex b/doc/context/sources/general/manuals/metafun/metafun-effects.tex
index 3c2a3f4cc..6c020acda 100644
--- a/doc/context/sources/general/manuals/metafun/metafun-effects.tex
+++ b/doc/context/sources/general/manuals/metafun/metafun-effects.tex
@@ -2406,6 +2406,100 @@ play with that.
}
\stopplacefigure
+On the mailing list occasionally questions pop op with respect to outlines and
+user Garulfo came up with a neat solution for shaded text. First some examples:
+
+\startbuffer
+\startMPcode
+ picture p ; p := lmt_outline [
+ text = "\strut foo f o o",
+ drawcolor = "white",
+ rulethickness = .2
+ ] ysized 3cm ;
+ fill boundingbox p
+ withshademethod "linear"
+ withshadedirection(0,1)
+ withshadecolors ("darkblue", "darkyellow") ;
+ draw p;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+Here the background shines through the text:
+
+\startlinecorrection \getbuffer \stoplinecorrection
+
+You can actually use the effects features which for a larger text is more
+efficient because it just renders the font differently. The result is
+shown in \in {figure} [fig:effects:text].
+
+\startbuffer[effects-text]
+\startuseMPgraphic{MyShade}
+ fill OverlayBox
+ withshademethod "linear"
+ withshadedirection(0,1)
+ withshadecolors (red, blue) ;
+\stopuseMPgraphic
+
+\defineoverlay[MyShade][\useMPgraphic{MyShade}]
+
+\setupbackgrounds[page][background=MyShade]
+
+\startmakeup
+ \definedfont[SerifBold*default @ 50pt] \setupinterlinespace
+
+ \defineeffect[MyOutline][alternative=outer,rulethickness=1pt]
+
+ \startcolor[white]
+ \starteffect[MyOutline]
+ \input jojomayer
+ \stopeffect
+ \stopcolor
+\stopmakeup
+\stopbuffer
+
+\typebuffer[effects-text]
+
+\startplacefigure[title=Regular text effects,reference=fig:effects:text]
+ \typesetbuffer[effects-text][height=.3\textheight]
+\stopplacefigure
+
+We now come to the neat example:
+
+\startbuffer
+\startMPcode
+ picture tt ; tt := lmt_outline [
+ kind = "fillup",
+ text = "\definedfont[name:texgyrepagellabold*default]foo f o o",
+ ] xsized 12cm ;
+
+ path bb ; bb := boundingbox tt ;
+
+ path pp ; pp := bb enlarged 2cm ;
+
+ fill pp
+ withshademethod "linear"
+ withshadedirection down
+ withshadecolors ("darkred", "darkblue") ;
+
+ for i within tt :
+ nofill pathpart i;
+ endfor ;
+
+ eofill bb withcolor "darkgray" ;
+ clip currentpicture to bb ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer
+
+It uses a clever combination of refilling the shape and background:
+
+\startlinecorrection
+ \getbuffer
+\stoplinecorrection
+
\stopsection
\startsection[title=Transparency groups]
diff --git a/doc/context/sources/general/manuals/metafun/metafun-gadgets.tex b/doc/context/sources/general/manuals/metafun/metafun-gadgets.tex
index 9010fc403..014bd66e8 100644
--- a/doc/context/sources/general/manuals/metafun/metafun-gadgets.tex
+++ b/doc/context/sources/general/manuals/metafun/metafun-gadgets.tex
@@ -361,6 +361,8 @@ second argument in the next line:
\starttyping
\startuniqueMPgraphic{smile}{type,height,color}
+ % the image
+\stopuniqueMPgraphic
\stoptyping
Because unique graphics often are used in backgrounds, its uniqueness is
diff --git a/doc/context/sources/general/manuals/metafun/metafun-sneaky.tex b/doc/context/sources/general/manuals/metafun/metafun-sneaky.tex
index 02c502cf0..56bf5d4d6 100644
--- a/doc/context/sources/general/manuals/metafun/metafun-sneaky.tex
+++ b/doc/context/sources/general/manuals/metafun/metafun-sneaky.tex
@@ -22,12 +22,12 @@ undefined or special variables. Consider the following:
\starttyping
vardef foo@#(text t) =
- save s ; string s ; s := str @# ;
- if length(s) > 0 :
- textext(s)
- else :
- nullpicture
- fi
+ save s ; string s ; s := str @# ;
+ if length(s) > 0 :
+ textext(s)
+ else :
+ nullpicture
+ fi
enddef ;
\stoptyping
@@ -41,7 +41,7 @@ But if afterwards we say:
\starttyping
vardef bar(expr x) =
- 123
+ 123
enddef ;
\stoptyping
@@ -55,6 +55,141 @@ to store their meanings and allocate new ones after that inside the group.
\stopsection
+\startsection[title=Templates]
+
+This section is a bit off|-|topic and thereby also qualifies as sneaky. At the
+\TEX\ end we have a couple of alternative input methods, like \XML\ and templates.
+Just because we want to be consistent, the \METAPOST\ end also offers this.
+
+The first example resembled the \type{btex ... etex} approach:
+
+\startbuffer
+\startbuffer[test-a]
+ blua for i=0,100,20 do elua
+ draw fullcircle scaled (blua p(i) elua * cm)
+ withcolor "darkgreen" withpen pencircle scaled 1cm ;
+ blua end elua
+
+ blua for i=10,100,20 do elua
+ draw fullcircle scaled (blua p(i) elua * cm)
+ withcolor "darkred" withpen pencircle scaled 1cm ;
+ blua end elua
+\stopbuffer
+
+\startMPcode
+ draw image (
+ loadfile ("mpstemplate://buffer?name=test-a") ;
+ ) ysized 3cm ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer[test-1][option=TEX]
+
+The filename is specified as a \URI\ and the \type {mpstemplate} does the magic
+here.
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+The second example is like the \type {lmx} files that you can find in the distibution:
+
+\startbuffer
+\startbuffer[test-b]
+ <?lua for i=0,100,20 do ?>
+ draw fullcircle scaled (<?lua p(i) ?> * cm)
+ withcolor "darkblue" withpen pencircle scaled 1cm ;
+ <?lua end ?>
+
+ <?lua for i=10,100,20 do ?>
+ draw fullcircle scaled (<?lua p(i) ?> * cm)
+ withcolor "darkyellow" withpen pencircle scaled 1cm ;
+ <?lua end ?>
+\stopbuffer
+
+\startMPcode
+ draw image (
+ loadfile ("mpstemplate://buffer?name=test-b") ;
+ ) ysized 3cm ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer[test-b][option=TEX]
+
+The filename is again specified as a \URI:
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+\startbuffer
+\startMPcode
+ picture p[] ; % we can't input nested
+ loadfile("mpstemplate://buffer?name=test-a&method=metapost") ;
+ p[1] := currentpicture ; currentpicture := nullpicture ;
+ loadfile("mpstemplate://buffer?name=test-b&method=xml") ;
+ p[2] := currentpicture ; currentpicture := nullpicture ;
+ draw p[1] ysized 3cm ;
+ draw p[2] ysized 4cm shifted (4cm,0) ;
+\stopMPcode
+\stopbuffer
+
+\typebuffer[option=TEX]
+
+The combination comes out as:
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+Another approach is to load as image, which saves some typing:
+
+\startbuffer
+\startMPpage[offset=10pt]
+ draw image (loadfile("mpstemplate://buffer?name=test-a&method=metapost"))
+ xsized 2cm shifted ( 3cm,0) ;
+ draw image (loadfile("mpstemplate://buffer?name=test-b&method=xml"))
+ xsized 2cm shifted ( 6cm,0) ;
+ draw loadimage ("mpstemplate://buffer?name=test-a&method=metapost")
+ xsized 2cm shifted ( 9cm,0) ;
+ draw loadimage ("mpstemplate://buffer?name=test-b&method=xml")
+ xsized 2cm shifted (12cm,0) ;
+\stopMPpage
+\stopbuffer
+
+\typebuffer[option=TEX]
+
+The result is predictable:
+
+\startlinecorrection[blank] \getbuffer \stoplinecorrection
+
+Of course there is also a \type {cld} approach possible:
+
+\startbuffer
+\startluacode
+ context.startMPcode() -- context.startMPpage { offset = "10pt" }
+ for i=0,100,20 do
+ context ( [[draw fullcircle scaled (%s * cm)
+ withcolor "darkmagenta" withpen pencircle scaled 1cm ;]], i)
+ end
+ for i=10,100,20 do
+ context ( [[draw fullcircle scaled (%s * cm)
+ withcolor "darkcyan" withpen pencircle scaled 1cm ;]], i)
+ end
+ context.stopMPcode() -- context.stoppage()
+\stopluacode
+\stopbuffer
+
+\typebuffer[option=TEX]
+
+The commented commands will create a page. This is a convenient way to make
+graphics that can be used in other documents (programs). For practical reasons the
+example is scaled down:
+
+\startlinecorrection[blank] \scale[height=3cm]{\getbuffer} \stoplinecorrection
+
+All these methods are rather efficient because all happens in memory and without
+intermediate runs. It is this kind of features that the tight integration of \TEX,
+\METAPOST\ and \LUA\ make possible.
+
+\stoptext
+
+\stopsection
+
\stopchapter
\stopcomponent
diff --git a/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex b/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex
new file mode 100644
index 000000000..bd84f08ec
--- /dev/null
+++ b/doc/context/sources/general/manuals/metafun/metafun-text-lmtx.tex
@@ -0,0 +1,1520 @@
+% 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{test 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{test 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{test 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{test 4}
+ begingroup ;
+ save d, p, q ; 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[test 1][\useMPgraphic{test 1}]
+\defineoverlay[test 2][\useMPgraphic{test 2}]
+\defineoverlay[test 3][\useMPgraphic{test 3}]
+\defineoverlay[test 4][\useMPgraphic{test 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[test 1,test 2,test 3,test 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 macros \type {\parwidth} and \type {\parheight} are automatically
+set to the current shape dimensions. The normal result is shown in \in {figure}
+[fig:shapes].
+
+\startbuffer[shapes]
+\startbuffer
+\startcombination[2*2]
+ {\framed[offset=overlay,frame=off,background=test 1]{\getshapetext}} {test 1}
+ {\framed[offset=overlay,frame=off,background=test 2]{\getshapetext}} {test 2}
+ {\framed[offset=overlay,frame=off,background=test 3]{\getshapetext}} {test 3}
+ {\framed[offset=overlay,frame=off,background=test 4]{\getshapetext}} {test 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
diff --git a/doc/context/sources/general/manuals/metafun/metafun-text.tex b/doc/context/sources/general/manuals/metafun/metafun-text.tex
index 4442894cb..8229e35db 100644
--- a/doc/context/sources/general/manuals/metafun/metafun-text.tex
+++ b/doc/context/sources/general/manuals/metafun/metafun-text.tex
@@ -1,4 +1,4 @@
-% language=uk
+% engine=luatex language=uk
%
% copyright=pragma-ade readme=readme.pdf licence=cc-by-nc-sa
@@ -48,7 +48,7 @@ the right auxiliary programs are executed.
In \CONTEXT\ \MKIV\ you won't notice this at all because everything is tightly
integrated with \LUATEX's \MPLIB. This 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 loadint a
+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.
@@ -680,7 +680,7 @@ in \MKIV\ we use a different approach. There we use a mix of \TEX, \METAPOST, an
\LUA\ to define that macro. The principles remain the same but the code is more
robust.
-\input meta-imp-txt.mkiv % we need to force a reload \useMPlibrary[txt]
+\useMPlibrary[txt]
So, how does this compare to earlier results? The original, full text as typeset
by \TEX, looks like:
@@ -1342,9 +1342,6 @@ macro gets the value of the graphic at hand.
\typefile{mfun-mp-data.txt}
-% \blank{\em todo: mp data file}\blank
-% \writestatus{!!!!}{todo: mp data file}
-
So, reading in this file at the start of a paragraph will setup \TEX\ to follow
this shape.
@@ -1383,16 +1380,15 @@ able to handle multiple shapes at once, like the next example demonstrates.
\index{graphics+libraries}
-The macro discussed in the previous section is included in one of the \METAPOST\
-libraries, so we first have to say:
+In \MKIV\ and \LMTX\ the \METAFUN\ driven text around a curve is a core
+functionality. In \LMTX\ the specific paragraph shape are available in the core
+too. Otherwise you need to load a module:
\startbuffer
\useMPlibrary[txt]
\stopbuffer
-\typebuffer
-
-\getbuffer
+\typebuffer \getbuffer
We define four shapes. They are not really beautiful, but they demonstrate what
happens in border cases. For instance, too small first lines are ignored. First
@@ -1508,14 +1504,11 @@ set to the current shape dimensions. The normal result is shown in \in {figure}
\startbuffer[shapes]
\startbuffer
-\setupframed
- [offset=overlay,align=normal,frame=off,
- width=\parwidth,height=\parheight]
\startcombination[2*2]
- {\framed[background=test 1]{\getshapetext}} {test 1}
- {\framed[background=test 2]{\getshapetext}} {test 2}
- {\framed[background=test 3]{\getshapetext}} {test 3}
- {\framed[background=test 4]{\getshapetext}} {test 4}
+ {\framed[offset=overlay,frame=off,background=test 1]{\getshapetext}} {test 1}
+ {\framed[offset=overlay,frame=off,background=test 2]{\getshapetext}} {test 2}
+ {\framed[offset=overlay,frame=off,background=test 3]{\getshapetext}} {test 3}
+ {\framed[offset=overlay,frame=off,background=test 4]{\getshapetext}} {test 4}
\stopcombination
\stopbuffer
\stopbuffer
diff --git a/doc/context/sources/general/manuals/metafun/metafun.tex b/doc/context/sources/general/manuals/metafun/metafun.tex
index b7bc30a80..6739b1ed5 100644
--- a/doc/context/sources/general/manuals/metafun/metafun.tex
+++ b/doc/context/sources/general/manuals/metafun/metafun.tex
@@ -77,7 +77,11 @@
\component metafun-gadgets
\component metafun-effects
\component metafun-functions
+\ifcase\contextlmtxmode
\component metafun-text
+\else
+ \component metafun-text-lmtx
+\fi
\component metafun-debugging
\component metafun-styles
\component metafun-examples
diff --git a/metapost/context/base/mpxl/mp-luas.mpxl b/metapost/context/base/mpxl/mp-luas.mpxl
index 9d013a790..b98305bba 100644
--- a/metapost/context/base/mpxl/mp-luas.mpxl
+++ b/metapost/context/base/mpxl/mp-luas.mpxl
@@ -307,3 +307,13 @@ def showproperty = runscript mfid_showproperty enddef ;
def showhashentry = runscript mfid_showhashentry enddef ;
permanent showproperty, showhashentry ;
+
+newscriptindex mfid_textextanchor ; mfid_textextanchor := scriptindex("textextanchor") ;
+
+def textextanchor = runscript mfid_textextanchor enddef ;
+
+vardef textextanchor(expr p) =
+ runscript mfid_textextanchor (prescriptpart p)
+enddef ;
+
+permanent textextanchor ;
diff --git a/scripts/context/lua/mtx-context.lua b/scripts/context/lua/mtx-context.lua
index 6c16f655c..38cb363bf 100644
--- a/scripts/context/lua/mtx-context.lua
+++ b/scripts/context/lua/mtx-context.lua
@@ -1694,6 +1694,9 @@ elseif getargument("purge") then
elseif getargument("purgeall") then
-- only when no filename given, supports --pattern
scripts.context.purge(true,nil,true)
+elseif getargument("pattern") then
+ environment.filenames = dir.glob(getargument("pattern"))
+ scripts.context.timed(scripts.context.autoctx)
else
application.help("basic")
end
diff --git a/tex/context/base/mkii/cont-new.mkii b/tex/context/base/mkii/cont-new.mkii
index 623678b40..cbbe223a9 100644
--- a/tex/context/base/mkii/cont-new.mkii
+++ b/tex/context/base/mkii/cont-new.mkii
@@ -11,7 +11,7 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
-\newcontextversion{2021.03.01 15:33}
+\newcontextversion{2021.03.02 19:17}
%D This file is loaded at runtime, thereby providing an
%D excellent place for hacks, patches, extensions and new
diff --git a/tex/context/base/mkii/context.mkii b/tex/context/base/mkii/context.mkii
index 9ac6432f5..88620fc90 100644
--- a/tex/context/base/mkii/context.mkii
+++ b/tex/context/base/mkii/context.mkii
@@ -20,7 +20,7 @@
%D your styles an modules.
\edef\contextformat {\jobname}
-\edef\contextversion{2021.03.01 15:33}
+\edef\contextversion{2021.03.02 19:17}
%D For those who want to use this:
diff --git a/tex/context/base/mkii/mult-cs.mkii b/tex/context/base/mkii/mult-cs.mkii
index 798779b96..0f2336d65 100644
--- a/tex/context/base/mkii/mult-cs.mkii
+++ b/tex/context/base/mkii/mult-cs.mkii
@@ -1120,6 +1120,7 @@
\setinterfaceconstant{print}{print}
\setinterfaceconstant{printable}{tisknutelne}
\setinterfaceconstant{process}{process}
+\setinterfaceconstant{processors}{processors}
\setinterfaceconstant{profile}{profile}
\setinterfaceconstant{properties}{properties}
\setinterfaceconstant{pubsep}{pubsep}
diff --git a/tex/context/base/mkiv/back-exp.lua b/tex/context/base/mkiv/back-exp.lua
index 983c6059f..700c1f040 100644
--- a/tex/context/base/mkiv/back-exp.lua
+++ b/tex/context/base/mkiv/back-exp.lua
@@ -44,6 +44,8 @@ local formatters = string.formatters
local todimen = number.todimen
local replacetemplate = utilities.templates.replace
+local addsuffix, joinfile, nameonly, basename, filesuffix = file.addsuffix, file.join, file.nameonly, file.basename, file.suffix
+
local trace_export = false trackers.register ("export.trace", function(v) trace_export = v end)
local trace_spacing = false trackers.register ("export.trace.spacing", function(v) trace_spacing = v end)
local trace_details = false trackers.register ("export.trace.details", function(v) trace_details = v end)
@@ -328,10 +330,10 @@ local styletemplate = [[
[3] = "left", ["3"] = "left", [variables.flushleft ] = "left",
}
- function wrapups.allusedstyles(basename)
+ function wrapups.allusedstyles(filename)
local result = { replacetemplate(namespacetemplate, {
what = "styles",
- filename = basename,
+ filename = filename,
namespace = contextns,
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or cssnamespacenop,
cssnamespaceurl = cssnamespaceurl,
@@ -415,27 +417,27 @@ local imagetemplate = [[
local collected = { }
local function usedname(name,page)
- if file.suffix(name) == "pdf" then
+ if filesuffix(name) == "pdf" then
-- temp hack .. we will have a remapper
if page and page > 1 then
- name = f_svgpage(file.nameonly(name),page)
+ name = f_svgpage(nameonly(name),page)
else
- name = f_svgname(file.nameonly(name))
+ name = f_svgname(nameonly(name))
end
end
local scheme = url.hasscheme(name)
if not scheme or scheme == "file" then
-- or can we just use the name ?
- return file.join("../images",file.basename(url.filename(name)))
+ return joinfile("../images",basename(url.filename(name)))
else
return name
end
end
- function wrapups.allusedimages(basename)
+ function wrapups.allusedimages(filename)
local result = { replacetemplate(namespacetemplate, {
what = "images",
- filename = basename,
+ filename = filename,
namespace = contextns,
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or "",
cssnamespaceurl = cssnamespaceurl,
@@ -3498,7 +3500,7 @@ local cssheadlink = [[
elseif cssfile == "export-example.css" then
-- ignore
elseif not done[cssfile] then
- cssfile = file.join(path,cssfile)
+ cssfile = joinfile(path,basename(cssfile))
report_export("adding css reference '%s'",cssfile)
files[#files+1] = cssfile
result[#result+1] = replacetemplate(csspreamble, { filename = cssfile })
@@ -3559,10 +3561,10 @@ local htmltemplate = [[
mixed = "inline",
}
- local function allusedelements(basename)
+ local function allusedelements(filename)
local result = { replacetemplate(namespacetemplate, {
what = "template",
- filename = basename,
+ filename = filename,
namespace = contextns,
-- cssnamespaceurl = usecssnamespace and cssnamespaceurl or "",
cssnamespaceurl = cssnamespaceurl,
@@ -3878,11 +3880,6 @@ local htmltemplate = [[
-- local cssfile = nil directives.register("backend.export.css", function(v) cssfile = v end)
- local addsuffix = file.addsuffix
- local joinfile = file.join
- local nameonly = file.nameonly
- local basename = file.basename
-
local embedfile = false directives.register("export.embed",function(v) embedfile = v end)
function structurestags.finishexport()
diff --git a/tex/context/base/mkiv/cont-new.mkiv b/tex/context/base/mkiv/cont-new.mkiv
index 229feff8a..cea147adc 100644
--- a/tex/context/base/mkiv/cont-new.mkiv
+++ b/tex/context/base/mkiv/cont-new.mkiv
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2021.03.01 15:33}
+\newcontextversion{2021.03.02 19:17}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkiv/context.mkiv b/tex/context/base/mkiv/context.mkiv
index 796f686fc..abbe41be2 100644
--- a/tex/context/base/mkiv/context.mkiv
+++ b/tex/context/base/mkiv/context.mkiv
@@ -45,7 +45,7 @@
%D {YYYY.MM.DD HH:MM} format.
\edef\contextformat {\jobname}
-\edef\contextversion{2021.03.01 15:33}
+\edef\contextversion{2021.03.02 19:17}
%D Kind of special:
diff --git a/tex/context/base/mkiv/meta-lua.lua b/tex/context/base/mkiv/meta-lua.lua
index 42d036630..cdcd5c0a8 100644
--- a/tex/context/base/mkiv/meta-lua.lua
+++ b/tex/context/base/mkiv/meta-lua.lua
@@ -89,7 +89,7 @@ mplib.finders.mpstemplate = function(specification,name,mode,ftype)
data = errorformatter(nameonly)
end
local name = luatex.registertempfile(nameonly,true)
- local data = metapost.checktexts(data)
+-- local data = metapost.checktexts(data)
io.savedata(name,data)
return name
end
diff --git a/tex/context/base/mkiv/status-files.pdf b/tex/context/base/mkiv/status-files.pdf
index 58cd21876..4747b2d13 100644
--- a/tex/context/base/mkiv/status-files.pdf
+++ b/tex/context/base/mkiv/status-files.pdf
Binary files differ
diff --git a/tex/context/base/mkiv/status-lua.pdf b/tex/context/base/mkiv/status-lua.pdf
index 4241ea0a2..021bcf069 100644
--- a/tex/context/base/mkiv/status-lua.pdf
+++ b/tex/context/base/mkiv/status-lua.pdf
Binary files differ
diff --git a/tex/context/base/mkxl/back-exp.mkxl b/tex/context/base/mkxl/back-exp.mkxl
index 121f4bf9f..f41a8d7ba 100644
--- a/tex/context/base/mkxl/back-exp.mkxl
+++ b/tex/context/base/mkxl/back-exp.mkxl
@@ -11,6 +11,8 @@
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.
+% see t:/export/todo-fonts.tex for (future) experiment
+
\writestatus{loading}{ConTeXt Backend Macros / XML export}
\registerctxluafile{back-exp}{}
diff --git a/tex/context/base/mkxl/cont-new.mkxl b/tex/context/base/mkxl/cont-new.mkxl
index 088eb9591..dd4afb289 100644
--- a/tex/context/base/mkxl/cont-new.mkxl
+++ b/tex/context/base/mkxl/cont-new.mkxl
@@ -13,7 +13,7 @@
% \normalend % uncomment this to get the real base runtime
-\newcontextversion{2021.03.01 15:33}
+\newcontextversion{2021.03.02 19:17}
%D This file is loaded at runtime, thereby providing an excellent place for hacks,
%D patches, extensions and new features. There can be local overloads in cont-loc
diff --git a/tex/context/base/mkxl/context.mkxl b/tex/context/base/mkxl/context.mkxl
index d84bbb73c..5c1ff9888 100644
--- a/tex/context/base/mkxl/context.mkxl
+++ b/tex/context/base/mkxl/context.mkxl
@@ -29,7 +29,7 @@
%D {YYYY.MM.DD HH:MM} format.
\immutable\edef\contextformat {\jobname}
-\immutable\edef\contextversion{2021.03.01 15:33}
+\immutable\edef\contextversion{2021.03.02 19:17}
%overloadmode 1 % check frozen / warning
%overloadmode 2 % check frozen / error
diff --git a/tex/context/base/mkxl/font-fea.mklx b/tex/context/base/mkxl/font-fea.mklx
index 5d5cea23f..9f4d2119e 100644
--- a/tex/context/base/mkxl/font-fea.mklx
+++ b/tex/context/base/mkxl/font-fea.mklx
@@ -143,6 +143,8 @@
\newconstant\c_font_feature_state
+\newevery\everyfontfeatureswitch
+
% hashing at this end is slower
\permanent\tolerant\protected\def\addfeature [#1]#;#2{\edef\m_font_feature_asked{#1#2}\font_feature_add}
@@ -171,7 +173,8 @@
{\clf_addfeature{\m_font_feature_list}{\m_font_feature_asked}%
\edef\m_font_feature_list{\m_font_feature_list+\m_font_feature_asked}% also + at the lua end
\c_font_feature_state\plusone
- \let\currentfeature\m_font_feature_asked}
+ \let\currentfeature\m_font_feature_asked
+ \the\everyfontfeatureswitch}
\protected\def\font_feature_subtract
{\ifnum\c_font_feature_state=\minusone
@@ -186,7 +189,8 @@
{\clf_subtractfeature{\m_font_feature_list}{\m_font_feature_asked}%
\edef\m_font_feature_list{\m_font_feature_list-\m_font_feature_asked}% also - at the lua end
\c_font_feature_state\minusone
- \let\currentfeature\m_font_feature_asked}
+ \let\currentfeature\m_font_feature_asked
+ \the\everyfontfeatureswitch}
\protected\def\font_feature_replace
{\ifnum\c_font_feature_state=\zerocount
@@ -201,7 +205,8 @@
{\clf_replacefeature{\m_font_feature_list}{\m_font_feature_asked}%
\edef\m_font_feature_list{\m_font_feature_list=\m_font_feature_asked}% also = at the lua end
\c_font_feature_state\zerocount
- \let\currentfeature\m_font_feature_asked}
+ \let\currentfeature\m_font_feature_asked
+ \the\everyfontfeatureswitch}
\permanent\protected\def\resetfeature
{\ifx\currentfeature\s!current \else
@@ -235,25 +240,26 @@
{\clf_addfeature{\s!current}{\m_font_feature_asked}%
\edef\m_font_feature_list{\s!current+\m_font_feature_asked}% also + at the lua end
\c_font_feature_state\plusone
- \let\currentfeature\m_font_feature_asked}
+ \let\currentfeature\m_font_feature_asked
+ \the\everyfontfeatureswitch}
\installcorenamespace{featureshortcut}
-\letvalue{\??featureshortcut +}\addfeature
-\letvalue{\??featureshortcut -}\subtractfeature
-\letvalue{\??featureshortcut =}\replacefeature
-\letvalue{\??featureshortcut !}\resetandaddfeature
-\letvalue{\??featureshortcut >}\revivefeature
-\letvalue{\??featureshortcut <}\resetfeature
-
-\letvalue{\??featureshortcut\v!more }\addfeature % add set to previous set and combine with font set
-\letvalue{\??featureshortcut\v!less }\subtractfeature % subtract set from previous set and combine with font set
-\letvalue{\??featureshortcut\v!new }\replacefeature % replace font set
-\letvalue{\??featureshortcut\v!reset }\resetfeature % forget sets and revert to font set
-\letvalue{\??featureshortcut\v!default}\revivefeature % make sure the current set is used on top of the font set
-\letvalue{\??featureshortcut\v!old }\revivefeature
-\letvalue{\??featureshortcut\v!local }\resetandaddfeature
-\letvalue{\??featureshortcut\s!unknown}\empty
+\letcsname\??featureshortcut +\endcsname\addfeature
+\letcsname\??featureshortcut -\endcsname\subtractfeature
+\letcsname\??featureshortcut =\endcsname\replacefeature
+\letcsname\??featureshortcut !\endcsname\resetandaddfeature
+\letcsname\??featureshortcut >\endcsname\revivefeature
+\letcsname\??featureshortcut <\endcsname\resetfeature
+
+\letcsname\??featureshortcut\v!more \endcsname\addfeature % add set to previous set and combine with font set
+\letcsname\??featureshortcut\v!less \endcsname\subtractfeature % subtract set from previous set and combine with font set
+\letcsname\??featureshortcut\v!new \endcsname\replacefeature % replace font set
+\letcsname\??featureshortcut\v!reset \endcsname\resetfeature % forget sets and revert to font set
+\letcsname\??featureshortcut\v!default\endcsname\revivefeature % make sure the current set is used on top of the font set
+\letcsname\??featureshortcut\v!old \endcsname\revivefeature
+\letcsname\??featureshortcut\v!local \endcsname\resetandaddfeature
+\letcsname\??featureshortcut\s!unknown\endcsname\empty
% experimental bonus:
diff --git a/tex/context/base/mkxl/meta-imp-txt.mkxl b/tex/context/base/mkxl/meta-imp-txt.mkxl
index 0c3516a7b..c7586264e 100644
--- a/tex/context/base/mkxl/meta-imp-txt.mkxl
+++ b/tex/context/base/mkxl/meta-imp-txt.mkxl
@@ -214,18 +214,18 @@
\defineoverlay[test 4][\useMPgraphic{test 4}]
\startbuffer
- \startshapetext[test 1,test 2,test 3,test 4]
- \setupalign[verytolerant,stretch,normal]%
- \samplefile{douglas} % Douglas R. Hofstadter
- \stopshapetext
- \startTEXpage[offset=10pt]
- \startcombination[2*2]
- {\framed[offset=overlay,frame=off,background=test 1]{\getshapetext}} {test 1}
- {\framed[offset=overlay,frame=off,background=test 2]{\getshapetext}} {test 2}
- {\framed[offset=overlay,frame=off,background=test 3]{\getshapetext}} {test 3}
- {\framed[offset=overlay,frame=off,background=test 4]{\getshapetext}} {test 4}
- \stopcombination
- \stopTEXpage
+\startshapetext[test 1,test 2,test 3,test 4]
+ \setupalign[verytolerant,stretch,normal]%
+ \samplefile{douglas} % Douglas R. Hofstadter
+\stopshapetext
+\startTEXpage[offset=10pt]
+ \startcombination[2*2]
+ {\framed[offset=overlay,frame=off,background=test 1]{\getshapetext}} {test 1}
+ {\framed[offset=overlay,frame=off,background=test 2]{\getshapetext}} {test 2}
+ {\framed[offset=overlay,frame=off,background=test 3]{\getshapetext}} {test 3}
+ {\framed[offset=overlay,frame=off,background=test 4]{\getshapetext}} {test 4}
+ \stopcombination
+\stopTEXpage
\stopbuffer
\getbuffer
diff --git a/tex/context/base/mkxl/mlib-fio.lmt b/tex/context/base/mkxl/mlib-fio.lmt
index 2e31d56d1..cdffbfcf1 100644
--- a/tex/context/base/mkxl/mlib-fio.lmt
+++ b/tex/context/base/mkxl/mlib-fio.lmt
@@ -53,7 +53,6 @@ end
local finders = { }
mplib.finders = finders -- also used in meta-lua.lua
-
local function validftype(ftype)
if ftype == "mp" then
return "mp"
@@ -82,7 +81,7 @@ local function findmpfile(name,ftype)
return nil
end
-local function finder(name,mode,kind)
+finders.file = function(specification,name,mode,kind)
if mode == "r" then
return findmpfile(name,kind)
elseif file.is_writable(name) then
@@ -92,12 +91,13 @@ local function finder(name,mode,kind)
end
end
-finders.file = function(specification,name,mode,ftype)
- -- finder(name,mode,kind)
- return finder(name,mode,ftype)
+local function finder(name,mode,kind) -- fake message for mpost.map and metafun.mpvi
+ local specification = url.hashed(name)
+ local finder = finders[specification.scheme] or finders.file
+ local found = finder(specification,name,mode,validftype(ftype))
+ return found
end
-
local findtexfile = resolvers.findtexfile
local opentexfile = resolvers.opentexfile
local splitlines = string.splitlines
diff --git a/tex/context/base/mkxl/mlib-mpf.lmt b/tex/context/base/mkxl/mlib-mpf.lmt
index 87b6c2d4e..f24d7fde0 100644
--- a/tex/context/base/mkxl/mlib-mpf.lmt
+++ b/tex/context/base/mkxl/mlib-mpf.lmt
@@ -1065,16 +1065,28 @@ end
do
- local mppair = mp.pair
-
- function mp.textextanchor(s)
- local x, y = match(s,"tx_anchor=(%S+) (%S+)") -- todo: make an lpeg
+ -- local mppair = mp.pair
+ --
+ -- function mp.textextanchor(s)
+ -- local x, y = match(s,"tx_anchor=(%S+) (%S+)") -- todo: make an lpeg
+ -- if x and y then
+ -- x = tonumber(x)
+ -- y = tonumber(y)
+ -- end
+ -- mppair(x or 0,y or 0)
+ -- end
+
+ local injectpair = inject.pair
+ local scanstring = scan.string
+
+ metapost.registerscript("textextanchor", function()
+ local x, y = match(scanstring(),"tx_anchor=(%S+) (%S+)") -- todo: make an lpeg
if x and y then
x = tonumber(x)
y = tonumber(y)
end
- mppair(x or 0,y or 0)
- end
+ injectpair(x or 0,y or 0)
+ end)
end
diff --git a/tex/context/base/mkxl/typo-par.lmt b/tex/context/base/mkxl/typo-par.lmt
index b5751e497..005d1b32e 100644
--- a/tex/context/base/mkxl/typo-par.lmt
+++ b/tex/context/base/mkxl/typo-par.lmt
@@ -94,106 +94,3 @@ function builders.checkparcontext(where)
end
appendaction("paragraphcontext","system","builders.checkparcontext")
-
--- Another experiment: continuing parshapes with alternative definitions:
---
--- left d | right d | left d right d | both d | left d hsize d |
--- copy n | reset | repeat | done
-
-do
-
- local scanners = tokens.scanners
- local scanword = scanners.word
- local scandimen = scanners.dimen
- local scancardinal = scanners.cardinal
-
- implement {
- name = "setparagraphshape",
- protected = true,
- actions = function()
- local t = { }
- local n = 0
- local h = texget("hsize")
- while true do
- local key = scanword()
- ::AGAIN::
- if key == "left" then
- local l = scandimen()
- key = scanword()
- if key == "right" then
- n = n + 1 ; t[n] = { l, h - l - scandimen() }
- elseif key == "hsize" then
- n = n + 1 ; t[n] = { l, scandimen() }
- else
- n = n + 1 ; t[n] = { l, h }
- goto AGAIN
- end
- elseif key == "right" then
- n = n + 1 ; t[n] = { 0, h - scandimen() }
- elseif key == "both" then
- local b = scandimen()
- n = n + 1 ; t[n] = { b, h - b - b }
- elseif key == "copy" then
- local c = scancardinal()
- for i=1,c do
- local m = n + 1
- t[m] = t[n]
- n = m
- end
- elseif key == "done" then
- -- in case the user ended with "done"
- scanword()
- break
- elseif key == "repeat" then
- t["repeat"] = true
- elseif key == "reset" then
- n = n + 1 ; t[n] = { 0, h }
- break
- else
- logs.report("system","bad key %a in paragraphshape",key)
- break
- end
- end
- texset("parshape",t)
- end,
- }
-
- local NC = context.NC
- local NR = context.NR
- local VL = context.VL
-
- implement {
- name = "showparagraphshape",
- protected = true,
- public = true,
- actions = function()
- local p = texget("parshape")
- if p then
- -- only english interface (for now)
- context.inleftmargin(
- {
- align = "flushright",
- strut = "no",
- width = "0pt",
- -- voffset = "-\\lineheight"
- }, function()
- context.starttabulate {
- before = "",
- after = "",
- unit = "2pt",
- rulethickness = ".1pt",
- format = "|rb{\\smallinfofont}|lb{\\smallinfofont}|"
- }
- for i=1,#p do
- NC() context("%P",p[i][1])
- VL() context("%P",p[i][2])
- NC() NR()
- end
- context.stoptabulate()
- end
- )
- end
- end
- }
-
-end
diff --git a/tex/context/base/mkxl/typo-shp.lmt b/tex/context/base/mkxl/typo-shp.lmt
index 27cafe1bd..ffd9e556d 100644
--- a/tex/context/base/mkxl/typo-shp.lmt
+++ b/tex/context/base/mkxl/typo-shp.lmt
@@ -9,8 +9,10 @@ if not modules then modules = { } end modules ['meta-imp-txt'] = {
local setmetatableindex = table.setmetatableindex
local settings_to_array = utilities.parsers.settings_to_array
+local texget = tex.get
local texset = tex.set
local texgetcount = tex.getcount
+local texgetglue = tex.getglue
local expandmacro = token.expand_macro
@@ -115,3 +117,151 @@ implement {
context(value)
end
}
+
+-- Another experiment: continuing parshapes with alternative definitions:
+--
+-- left d | right d | left d right d | both d | left d hsize d |
+-- copy n | reset | repeat | done
+
+do
+
+ local scanners = tokens.scanners
+ local scanword = scanners.word
+ local scandimen = scanners.dimen
+ local scanstring = scanners.string
+ local scancardinal = scanners.cardinal
+
+ implement {
+ name = "setparagraphshape",
+ protected = true,
+ actions = function()
+ local t = { }
+ local n = 0
+ local h = texget("hsize")
+ local a = 0
+ while true do
+ local key = scanword()
+ ::AGAIN::
+ if key == "left" then
+ local l = scandimen()
+ key = scanword()
+ if key == "right" then
+ n = n + 1 ; t[n] = { l, a + h - l - scandimen() }
+ elseif key == "hsize" then
+ n = n + 1 ; t[n] = { l, a + scandimen() }
+ else
+ n = n + 1 ; t[n] = { l, a + h }
+ goto AGAIN
+ end
+ elseif key == "right" then
+ n = n + 1 ; t[n] = { 0, a + h - scandimen() }
+ elseif key == "both" then
+ local b = scandimen()
+ n = n + 1 ; t[n] = { b, a + h - b - b }
+ elseif key == "copy" then
+ local c = scancardinal()
+ for i=1,c do
+ local m = n + 1
+ t[m] = t[n]
+ n = m
+ end
+ elseif key == "done" then
+ -- in case the user ended with "done"
+ scanword()
+ break
+ elseif key == "metapost" then
+ local list = settings_to_array(scanstring()) -- array
+ properties = { }
+ parshapes = { }
+ for i=1,#list do
+ properties = { }
+ parshapes[i] = properties
+ expandmacro("spac_shapes_calculate","{"..list[i].."}")
+ end
+ for i=1,#parshapes do
+ local p = parshapes[i]
+ local s = p.shape
+ if s then
+ for i=1,(p.lines or #s) do
+ local si = s[i]
+ n = n + 1 ; t[n] = { si[1], a + si[2] }
+ end
+ end
+ end
+ elseif key == "repeat" then
+ t["repeat"] = true
+ elseif key == "delete" then
+ local c = scancardinal()
+ for i=1,c do
+ if n > 0 then
+ t[n] = nil
+ n = n - 1
+ else
+ break
+ end
+ end
+ elseif key == "reset" then
+ n = n + 1 ; t[n] = { 0, a + h }
+ break
+ elseif key == "absolute" then
+ local s = scanword()
+ local l = texgetglue("leftskip")
+ local r = texgetglue("rightskip")
+ if s == "left" then
+ a = l
+ elseif s == "right" then
+ a = r
+ elseif s == "both" then
+ a = l + r
+ else
+ a = l + r
+ goto AGAIN
+ end
+ else
+ logs.report("system","bad key %a in paragraphshape",key)
+ break
+ end
+ end
+ texset("parshape",t)
+ end,
+ }
+
+ local NC = context.NC
+ local NR = context.NR
+ local VL = context.VL
+
+ implement {
+ name = "showparagraphshape",
+ protected = true,
+ public = true,
+ actions = function()
+ local p = texget("parshape")
+ if p then
+ -- only english interface (for now)
+ context.inleftmargin(
+ {
+ align = "flushright",
+ strut = "no",
+ width = "0pt",
+ -- voffset = "-\\lineheight"
+ }, function()
+ context.starttabulate {
+ before = "",
+ after = "",
+ unit = "2pt",
+ rulethickness = ".1pt",
+ format = "|rb{\\smallinfofont}|lb{\\smallinfofont}|"
+ }
+ for i=1,#p do
+ NC() context("%P",p[i][1])
+ VL() context("%P",p[i][2])
+ NC() NR()
+ end
+ context.stoptabulate()
+ end
+ )
+ end
+ end
+ }
+
+end
diff --git a/tex/context/base/mkxl/typo-shp.mkxl b/tex/context/base/mkxl/typo-shp.mkxl
index 295fe3e1b..21df41bd4 100644
--- a/tex/context/base/mkxl/typo-shp.mkxl
+++ b/tex/context/base/mkxl/typo-shp.mkxl
@@ -67,6 +67,7 @@
\getdummyparameters[\c!method=,\c!list=,\c!mp=,\c!repeat=,#1]%
\edef\p_mp {\dummyparameter\c!mp}%
\edef\p_repeat{\dummyparameter\c!repeat}%
+ \setlocalhsize
\normalexpanded
{\endgroup
\ifempty\p_mp
diff --git a/tex/context/interface/mkii/keys-cs.xml b/tex/context/interface/mkii/keys-cs.xml
index 3a7c187c6..3006aa9b0 100644
--- a/tex/context/interface/mkii/keys-cs.xml
+++ b/tex/context/interface/mkii/keys-cs.xml
@@ -1126,6 +1126,7 @@
<cd:constant name='print' value='print'/>
<cd:constant name='printable' value='tisknutelne'/>
<cd:constant name='process' value='process'/>
+ <cd:constant name='processors' value='processors'/>
<cd:constant name='profile' value='profile'/>
<cd:constant name='properties' value='properties'/>
<cd:constant name='pubsep' value='pubsep'/>
diff --git a/tex/generic/context/luatex/luatex-fonts-merged.lua b/tex/generic/context/luatex/luatex-fonts-merged.lua
index c56b84c59..89650fcbc 100644
--- a/tex/generic/context/luatex/luatex-fonts-merged.lua
+++ b/tex/generic/context/luatex/luatex-fonts-merged.lua
@@ -1,6 +1,6 @@
-- merged file : c:/data/develop/context/sources/luatex-fonts-merged.lua
-- parent file : c:/data/develop/context/sources/luatex-fonts.lua
--- merge date : 2021-03-01 15:33
+-- merge date : 2021-03-02 19:17
do -- begin closure to overcome local limits and interference