diff options
author | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-01-12 17:15:07 +0100 |
---|---|---|
committer | Context Git Mirror Bot <phg42.2a@gmail.com> | 2016-01-12 17:15:07 +0100 |
commit | 8d8d528d2ad52599f11250cfc567fea4f37f2a8b (patch) | |
tree | 94286bc131ef7d994f9432febaf03fe23d10eef8 /tex/context/base/mkii/supp-pdf.mkii | |
parent | f5aed2e51223c36c84c5f25a6cad238b2af59087 (diff) | |
download | context-8d8d528d2ad52599f11250cfc567fea4f37f2a8b.tar.gz |
2016-01-12 16:26:00
Diffstat (limited to 'tex/context/base/mkii/supp-pdf.mkii')
-rw-r--r-- | tex/context/base/mkii/supp-pdf.mkii | 2187 |
1 files changed, 2187 insertions, 0 deletions
diff --git a/tex/context/base/mkii/supp-pdf.mkii b/tex/context/base/mkii/supp-pdf.mkii new file mode 100644 index 000000000..4dd2db776 --- /dev/null +++ b/tex/context/base/mkii/supp-pdf.mkii @@ -0,0 +1,2187 @@ +%D \module +%D [ file=supp-pdf, +%D version=2006.09.02, % 2004.12.16, +%D title=\CONTEXT\ Support Macros, +%D subtitle=\METAPOST\ to \PDF\ conversion, +%D author=Hans Hagen \& others (see text), +%D date=\currentdate, +%D copyright={PRAGMA ADE \& \CONTEXT\ Development Team}] +%C +%C This module is part of the \CONTEXT\ macro||package and is +%C therefore copyrighted by \PRAGMA. See mreadme.pdf for +%C details. + +\ifx\writestatus\undefined + \immediate\write16{[Loading MPS to PDF converter (version 2006.09.02).]} +\else + \writestatus{loading}{ConTeXt Support Macros / PDF} +\fi + +%D This module is not optimized because it is used outside +%D \CONTEXT\ and we cannot forsee what interference will take +%D place. We no longer load supp-mis. I got too tired of +%D keeping track of interferences with non \CONTEXT\ usage so +%D I moved the necessary code in here and use a derived version +%D in \CONTEXT. When I have the time I will clean up some of the +%D code that is of no use for non||\CONTEXT\ users. + +\ifx\contextversion\undefined + + \chardef\mptopdfstoredatcode\catcode`\@ + + \catcode\string`@=11 + + \def\unprotect + {\let\@@mpstopdf@@unprotect \unprotect + \let\@@mpstopdf@@protect \protect + \edef\protect + {\noexpand \let \noexpand \protect \noexpand \@@mpstopdf@@protect + \noexpand \let \noexpand \unprotect \noexpand \@@mpstopdf@@unprotect + % context specific + \catcode\string`\noexpand @=\the\catcode\string`@ + \catcode\string`\noexpand !=\the\catcode\string`! + \catcode\string`\noexpand ?=\the\catcode\string`? + % latex specific + \catcode\string`\noexpand /=\the\catcode\string`/ + \catcode\string`\noexpand -=\the\catcode\string`- + \catcode\string`\noexpand :=\the\catcode\string`: + \catcode\string`\noexpand ;=\the\catcode\string`; + \catcode\string`\noexpand "=\the\catcode\string`" + \catcode\string`\noexpand <=\the\catcode\string`< + \catcode\string`\noexpand >=\the\catcode\string`> + \catcode\string`\noexpand `=\the\catcode\string``} + \catcode\string`@=11 \catcode\string`!=11 \catcode\string`?=11 + \catcode\string`/=12 \catcode\string`-=12 + \catcode\string`:=12 \catcode\string`;=12 + \catcode\string`>=12 \catcode\string`<=12 + \catcode\string`"=12 \catcode\string``=12 } + + \def\defineMPtoPDFfallbacks + {% shortcuts + \chardef\@@escape 0 + \chardef\@@begingroup 1 + \chardef\@@endgroup 2 + \chardef\@@endofline 5 + \chardef\@@ignore 9 + \chardef\@@space 10 + \chardef\@@letter 11 + \chardef\@@other 12 + \chardef\@@active 13 + \chardef\@@comment 14 + % placeholders + \ifx\withoutpt \undefined \let\withoutpt \@@mptopdf@@withoutpt \fi + \ifx\twodigitrounding \undefined \let\twodigitrounding \@@mptopdf@@twodigitrounding \fi + \ifx\forgetall \undefined \let\forgetall \@@mptopdf@@forgetall \fi + \ifx\uncatcodespecials \undefined \let\uncatcodespecials \@@mptopdf@@uncatcodespecials \fi + \ifx\setnaturalcatcodes\undefined \let\setnaturalcatcodes\@@mptopdf@@setnaturalcatcodes \fi + \ifx\dospecials \undefined \let\dospecials \@@mptopdf@@dospecials \fi} + + \def\@@mptopdf@@forgetall + {\parskip0pt\leftskip0pt\parindent0pt\everypar{}} + + \def\@@mptopdf@@twodigitrounding#1% + {#1}% + + \def\@@mptopdf@@uncatcodespecials + {\def\do##1{\catcode`##1=\@@other}\dospecials + \catcode`\ =\@@space + \catcode`\^^L=\@@ignore + \catcode`\^^M=\@@endofline + \catcode`\^^?=\@@ignore} + + \def\@@mptopdf@@setnaturalcatcodes + {\catcode`\!=\@@other \catcode`\?=\@@other \catcode`\@=\@@other + \catcode`\#=\@@other \catcode`\&=\@@other \catcode`\|=\@@other + \catcode`\$=\@@other \catcode`\^=\@@other \catcode`\_=\@@other + \catcode`\*=\@@other \catcode`\/=\@@other + \catcode`\-=\@@other \catcode`+=\@@other + \catcode`\==\@@other \catcode`\<=\@@other \catcode`\>=\@@other + \catcode`\"=\@@other \catcode`\'=\@@other \catcode`\`=\@@other + \catcode`\:=\@@other \catcode`\;=\@@other + \catcode`\,=\@@other \catcode`\.=\@@other \catcode`\~=\@@other + \catcode`\(=\@@other \catcode`\)=\@@other + \catcode`\{=\@@other \catcode`\}=\@@other + \catcode`\\=\@@other \catcode`\%=\@@other} + + \def\@@mptopdf@@dospecials + {\do\ \do\\\do\{\do\}\do\$% + \do\#\do\^\do\_\do\&\do\%% + \do\~\do\^^A\do\^^K} + + { + \catcode`\.=12 + \catcode`\p=12 + \catcode`\t=12 + \gdef\@@MPTOPDF@@WITHOUTPT#1pt{#1} + } + + \def\@@mptopdf@@withoutpt#1% + {\expandafter\@@MPTOPDF@@WITHOUTPT#1} + +% \def\@@mptopdf@@newabove#1#2% \dimen \name +% {#1#2% +% \ifnum\expandafter\gobblesixarguments\meaning#2>20\else +% \expandafter\@@mptopdf@@newabove\expandafter#1\expandafter#2% +% \fi} + + \def\@@mptopdf@@stripnewabove#1% + {\ifnum10<9#1 #1\else\expandafter\@@mptopdf@@stripnewabove\fi}% + + \def\@@mptopdf@@newabove\csname#1\endcsname#2% \dimen \name + {\csname#1\endcsname#2% + \ifnum\expandafter\@@mptopdf@@stripnewabove\meaning#2>20\else + \@@mptopdf@@newabove\csname#1\endcsname#2% + \fi} + + \@@mptopdf@@newabove \csname newcount\endcsname \scratchcounter + \@@mptopdf@@newabove \csname newdimen\endcsname \scratchdimen + \csname newbox\endcsname \scratchbox + + \expandafter \newif \csname ifdone\endcsname + + \catcode`\@=\mptopdfstoredatcode + +\else + + \let\defineMPtoPDFfallbacks\relax + +\fi + +%D These macros are written as generic as possible. Some +%D general support macro's are loaded from a small module +%D especially made for non \CONTEXT\ use. In this module I +%D use a matrix transformation macro written by Tanmoy +%D Bhattacharya. Thanks to extensive testing by Sebastian +%D Ratz I was able to complete this module within reasonable +%D time. This module has support for \METAPOST\ extensions +%D built in. +%D +%D Daniel H. Luecking came up with a better (more precise) +%D transformation method. You can recognize his comment by +%D his initials. (We keep the old code around because it's a +%D nice illustration on how a module like this evolves.) + +%D Beware, we cannot use \type{\zeropoint} here since it may be +%D defined in the range \type{\dimen0} - 20 which we happen to use +%D as scratch registers; inside context we may consider +%D using dedicated registers. + +%D This module handles some \PDF\ conversion and insertions +%D topics. By default, the macros use the \PDFTEX\ primitive +%D \type{\pdfliteral} when available. Since \PDFTEX\ is now the +%D default engine for \TEX\ distributions, we need a more complex +%D test. + +\unprotect + +\ifx\PDFcode\undefined + \ifx\pdfliteral\undefined + \def\PDFcode#1{\special{PDF: #1}} + \else\ifx\pdfoutput\undefined + \def\PDFcode#1{\special{PDF: #1}} + \else\ifcase\pdfoutput + \def\PDFcode#1{\special{PDF: #1}} + \else % pdftex as well as in pdf mode + \let\PDFcode\pdfliteral + \fi\fi\fi +\else + % we probably use context +\fi + +%D First we define a handy constant: + +\bgroup \defineMPtoPDFfallbacks \catcode`\%=\@@other \xdef\letterpercent{\string%} \egroup + +%D \macros +%D {pdfimage,pdfimages,pdfclippedimage} +%D +%D Starting with pdftex version 14, images are included more +%D natural to the form embedding. This enables alternative +%D images to be embedded. +%D +%D \starttyping +%D \pdfimage <optional dimensions> {file} +%D \pdfimages <optional dimensions> {high res file} {low res file} +%D \stoptyping +%D +%D The first one replaces the pre||version||14 original, +%D while the latter provides alternative images. +%D +%D The next macro is dedicated to Maarten Gelderman, who +%D needed to paste prepared \PDF\ pages into conference +%D proceedings. +%D +%D \starttyping +%D \pdfclippedimage <optional dimensions> {file} {l} {r} {t} {b} +%D \stoptyping + +\ifx\pdftexversion\undefined \else \ifnum\pdftexversion>13 + + \def\pdfimage#1#% + {\dopdfimage{#1}} + + \def\dopdfimage#1#2% + {\immediate\pdfximage#1{#2}% + \pdfrefximage\pdflastximage} + + \def\pdfimages#1#% + {\dopdfimages{#1}} + + \def\dopdfimages#1#2#3% + {\immediate\pdfximage#1{#2}% + \immediate\pdfobj{[ << /Image \the\pdflastximage\space0 R /DefaultForPrinting true >> ]}% + \immediate\pdfximage#1 attr {/Alternates \the\pdflastobj\space0 R}{#3}% + \pdfrefximage\pdflastximage} + + \def\pdfclippedimage#1#% specs {file}{left}{right}{top}{bottom} + {\dopdfclippedimage{#1}} + + \def\dopdfclippedimage#1#2#3#4#5#6% + {\bgroup + \pdfximage#1{#2}% + \setbox\scratchbox\hbox + {\pdfrefximage\pdflastximage}% + \hsize\wd\scratchbox + \advance\hsize -#3 + \advance\hsize -#4 + \vsize\ht\scratchbox + \advance\vsize -#5 + \advance\vsize -#6 + \setbox\scratchbox\vbox to \vsize + {\vskip-#5\hbox to \hsize{\hskip-#3\box\scratchbox\hss}}% + \pdfxform\scratchbox + \pdfrefxform\pdflastxform + \egroup} + +\fi \fi + +%D If you want to save a few hash entries, you may prefer the +%D less readable alternatives, like: +%D +%D \starttyping +%D \def\pdfimage#1#% This one is less readable but needs no additional +%D {\bgroup % hash entry for the second stage macro. +%D \def\pdfimage##1% +%D {\immediate\pdfximage##1{#2}% +%D \pdfrefximage\pdflastximage\egroup}} +%D \stoptyping + +%D For old times sake we provide a few aliases. These will be +%D removed some day. + +\ifx\pdftexversion\undefined \else \ifnum\pdftexversion>13 + + \let\pdfform =\pdfxform + \let\pdflastform=\pdflastxform + \let\pdfrefform =\pdfrefxform + +\fi \fi + +%D The main conversion macro wraps the \PDF\ codes in a box +%D that is output as an object. The graphics are embedded +%D in~\type{q} and~\type{Q} and are scaled and positioned using +%D one transform call (\type{cm}). This saves some additional +%D scaling. + +%D \macros +%D {convertMPtoPDF} +%D +%D The next set of macros implements \METAPOST\ to \PDF\ +%D conversion. Because we want to test as fast as possible, we +%D first define the \POSTSCRIPT\ operators that \METAPOST\ +%D uses. We don't define irrelevant ones, because these are +%D skipped anyway. + +%D The converter can be made a bit faster by replacing the +%D two test macros (the ones with the many \type {\if's}) by +%D a call to named branch macros (something \typ {\getvalue +%D {xPSmoveto}}. For everyday documents with relatively +%D small graphics the gain in speed can be neglected. + +\def \PScurveto {curveto} +\def \PSlineto {lineto} +\def \PSmoveto {moveto} +\def \PSshowpage {showpage} +\def \PSnewpath {newpath} +\def \PSfshow {fshow} +\def \PSclosepath {closepath} +\def \PSfill {fill} +\def \PSstroke {stroke} +\def \PSclip {clip} +\def \PSrlineto {rlineto} +\def \PSsetlinejoin {setlinejoin} +\def \PSsetlinecap {setlinecap} +\def \PSsetmiterlimit {setmiterlimit} +\def \PSsetgray {setgray} +\def \PSsetrgbcolor {setrgbcolor} +\def \PSsetcmykcolor {setcmykcolor} +\def \PSsetdash {setdash} +\def \PSgsave {gsave} +\def \PSgrestore {grestore} +\def \PStranslate {translate} +\def \PSscale {scale} +\def \PSconcat {concat} +\def \PSdtransform {dtransform} +\def \PSsetlinewidth {setlinewidth} +\def \PSpop {pop} + +\def \PSnfont {nfont} % was needed for TUG98 proceedings +\def \PSspecial {special} % extensions to MetaPost + +%D A previous version set \type {%} to ignore, which +%D simplified the following definitions. At the start of +%D conversion the percent character was made active again. +%D Because the whole graphic is one paragraph (there are no +%D empty lines) this does not give the desired effect. This +%D went unnoticed untill Scott Pakin sent me a test file +%D percent characters in a string. So, from now on we have +%D to prefix the following strings with percentages. + +%D Some day I'll figure out a better solution (line by line reading +%D using \ETEX). + +\edef \PSBoundingBox {\letterpercent\letterpercent BoundingBox:} +\edef \PSHiResBoundingBox {\letterpercent\letterpercent HiResBoundingBox:} +\edef \PSExactBoundingBox {\letterpercent\letterpercent ExactBoundingBox:} +\edef \PSMetaPostSpecial {\letterpercent\letterpercent MetaPostSpecial:} +\edef \PSMetaPostSpecials {\letterpercent\letterpercent MetaPostSpecials:} +\edef \PSPage {\letterpercent\letterpercent Page:} +\edef \PSBeginProlog {\letterpercent\letterpercent BeginProlog} +\edef \PSEndProlog {\letterpercent\letterpercent EndProlog} +\edef \PSEof {\letterpercent\letterpercent EOF} + +%D By the way, the \type {setcmykcolor} operator is not +%D output by \METAPOST\ but can result from converting the +%D \cap{RGB} color specifications, as implemented in +%D \type{supp-mps}. + +%D In \POSTSCRIPT\ arguments precede the operators. Due to the +%D fact that in some translations we need access to those +%D arguments, and also because sometimes we have to skip them, +%D we stack them up. The stack is one||dimensional for non path +%D operators and two||dimensional for operators inside a path. +%D This is because we have to save the whole path for +%D (optional) postprocessing. Values are pushed onto the stack +%D by: +%D +%D \starttyping +%D \setMPargument {value} +%D \stoptyping +%D +%D They can be retrieved by the short named macros: +%D +%D \starttyping +%D \gMPa {number} +%D \gMPs {number} +%D \stoptyping +%D +%D When scanning a path specification, we also save the +%D operator, using +%D +%D \starttyping +%D \setMPkeyword {n} +%D \stoptyping +%D +%D The path drawing operators are coded for speed: \type{clip}, +%D \type{stroke}, \type{fill} and \type{fillstroke} become +%D 1, 2, 3 and~4. +%D +%D When processing the path this code can be retrieved +%D using +%D +%D \starttyping +%D \getMPkeyword % {n} +%D \stoptyping +%D +%D When setting an argument, the exact position on the stack +%D depends on the current value of the \COUNTERS\ +%D \type{\nofMPsegments} and \type{\nofMParguments}. + +\newcount\nofMPsegments +\newcount\nofMParguments + +%D These variables hold the coordinates. The argument part of +%D the stack is reset by: +%D +%D \starttyping +%D \resetMPstack +%D \stoptyping +%D +%D We use the prefix \type{@@MP} to keep the stack from +%D conflicting with existing macros. To speed up things a bit +%D more, we use the constant \type{\@@MP}. + +\def\@@MP{@@MP} + +\def\setMPargument% #1% + {\advance\nofMParguments 1 + \expandafter\def + \csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname} % {#1} + +\def\letMPargument + {\advance\nofMParguments 1 + \expandafter\let + \csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname} + +\def\setMPsequence#1 % + {\advance\nofMParguments 1 + \expandafter\def + \csname\@@MP\the\nofMPsegments\the\nofMParguments\endcsname{#1}% + \handleMPsequence} + +\def\gMPa#1% + {\csname\@@MP0\number#1\endcsname} + +\def\gMPs#1% + {\csname\@@MP\the\nofMPsegments\number#1\endcsname} + +\def\dogMPa#1% + {\expandafter\expandafter\expandafter\do\csname\@@MP0\number#1\endcsname} + +\def\setMPkeyword#1 % + {\expandafter\def\csname\@@MP\the\nofMPsegments0\endcsname{#1}% + \advance\nofMPsegments 1 + \nofMParguments0} + +\def\getMPkeyword% #1% + {\csname\@@MP\the\nofMPsegments0\endcsname} % {\csname\@@MP#10\endcsname} + +\def\docleanupMPargument#1% we need this because args can have [ or ] pre/appended + {\expandafter\edef\csname\@@MP\the\nofMPsegments\number#1\endcsname + {\csname\@@MP\the\nofMPsegments\number#1\endcsname}} + +%D When we reset the stack, we can assume that all further +%D comment is to be ignored and handled in strings. +%D By redefining the reset macro after the first call, we +%D save some run time. Only use this macro after all +%D comments are processed and use the simple alternative +%D when dealing with comments. + +\def\doresetMPstack + {\nofMParguments0\relax} + +\def\resetMPstack + {\let\handleMPgraphic\handleMPendgraphic + \let\resetMPstack\doresetMPstack + \resetMPstack} + +%D The arguments are saved with the preceding command +%D \type{\do}. By default this command expands to nothing, but +%D when we deal with strings it's used to strip off the +%D \type{(} and \type{)}. +%D +%D Strings are kind of tricky, because characters can be +%D passed verbatim \type{(hello)}, by octal number +%D \type{(\005)} or as command \type{(\()}. We therefore +%D cannot simply ignore \type{(} and \type{)}, the way we do +%D with \type{[} and \type{]}. Another complication is that +%D strings may contain characters that normally have a +%D special meaning in \TEX, like \type{$} and \type{{}}. +%D +%D A previous solution made \type{\} an active character and +%D let it look ahead for a number or characters. We had to +%D abandon this scheme because of the need for verbatim +%D support. The next solution involved some \CATCODE\ +%D trickery but works well. + +\def\octalMPcharacter#1#2#3% + {\char'#1#2#3\relax} + +%D curly braces and squarly brackets are stored in the argument stack +%D as part of strings, for instance in: +%D +%D \starttyping +%D /fshow {exch findfont exch scalefont setfont show}bind def +%D [3 3 ] 0 setdash +%D \stoptyping +%D +%D but we need to keep them in situation like +%D +%D \starttyping +%D ([bla bla] bla bla) ec-lmr10 9.96265 fshow +%D ({bla bla} bla bla) ec-lmr10 9.96265 fshow +%D \stoptyping +%D +%D So, when we store the snippets, we keep the special tokens, and +%D when needed we either ignore or obey them + +\bgroup +\defineMPtoPDFfallbacks +\catcode`\|=\@@comment +\catcode`\%=\@@active +\catcode`\[=\@@active +\catcode`\]=\@@active +\catcode`\{=\@@active +\catcode`\}=\@@active +\catcode`B=\@@begingroup +\catcode`E=\@@endgroup +\gdef\keepMPspecials| + B\let%\letterpercent| + \def[B\noexpand[E| + \def]B\noexpand]E| + \def{B\noexpand{E| + \def}B\noexpand}EE +\gdef\ignoreMPspecials| + B\let%\letterpercent| + \def[BE| + \def]BE| + \def{BE| + \def}BEE +\gdef\obeyMPspecials| + B\def%B\char 37\relax E| + \def[B\char 91\relax E| + \def]B\char 93\relax E| + \def{B\char123\relax E| + \def}B\char125\relax EE +\gdef\setMPspecials| + B\setnaturalcatcodes + \catcode`\\=\@@escape + \catcode`\%=\@@active + \catcode`\[=\@@active + \catcode`\]=\@@active + \catcode`\{=\@@active + \catcode`\}=\@@active + \lccode`\-=0 | latex sets this to `\- + \lccode`\%=`\% | otherwise it's seen as a number + \def\(B\char40\relax E| + \def\)B\char41\relax E| + \def\\B\char92\relax E| + \def\0B\octalMPcharacter0E| + \def\1B\octalMPcharacter1E| + \def\2B\octalMPcharacter2E| + \def\3B\octalMPcharacter3E| + \def\4B\octalMPcharacter4E| + \def\5B\octalMPcharacter5E| + \def\6B\octalMPcharacter6E| + \def\7B\octalMPcharacter7E| + \def\8B\octalMPcharacter8E| + \def\9B\octalMPcharacter9EE +\egroup + +%D We use the comment symbol as a sort of trigger. Beware! +%D The whole graphic is seen as on eparagraph, which means +%D that we cannot change the catcodes in between. + +\bgroup +\defineMPtoPDFfallbacks +\catcode`\%=\@@active +\gdef\startMPscanning{\let%=\startMPconversion} +\egroup + +%D In earlier versions we used the sequence +%D +%D \starttyping +%D \expandafter\handleMPsequence\input filename\relax +%D \stoptyping +%D +%D Persistent problems in \LATEX\ however forced us to use a +%D different scheme. Every \POSTSCRIPT\ file starts with a +%D \type{%}, so we temporary make this an active character +%D that starts the scanning and redefines itself. (The problem +%D originates in the redefinition by \LATEX\ of the +%D \type{\input} primitive.) + +\def\startMPconversion + {\keepMPspecials + \handleMPsequence} + +%D Here comes the main loop. Most arguments are numbers. This +%D means that they can be recognized by their \type{\lccode}. +%D This method saves a lot of processing time. We could +%D speed up the conversion by handling the \type{path} +%D seperately. + +\def\dohandleMPsequence#1% + {\ifdone + \ifcase\lccode`#1\relax + \expandafter\expandafter\expandafter\dohandleMPsequenceA + \else + \expandafter\expandafter\expandafter\dohandleMPsequenceB + \fi + \else + \expandafter\dohandleMPsequenceC + \fi#1} + +\let\dohandleMPsequenceA\setMPsequence + +\def\installMPSkeywordN#1#2% + {\expandafter\def\csname\@@MP:N:#1\endcsname{#2}} + +\def\installMPSshortcutN#1#2% todo: \let + {\expandafter\let\csname\@@MP:N:#1\expandafter\endcsname\csname\@@MP:N:#2\endcsname} + +\def\dohandleMPsequenceB#1 % + {\edef\somestring{#1}% + \ifcsname\@@MP:N:\somestring\endcsname + \csname\@@MP:N:\somestring\expandafter\endcsname + \else + \expandafter\handleMPgraphic + \fi + \handleMPsequence} + +\ifx\eTeXversion\undefined + \def\dohandleMPsequenceB#1 % + {\edef\somestring{#1}% + \expandafter\ifx\csname\@@MP:N:\somestring\endcsname\relax + \expandafter\handleMPgraphic + \else + \csname\@@MP:N:\somestring\expandafter\endcsname + \fi + \handleMPsequence} +\fi + +\installMPSkeywordN \PSmoveto + {\edef\lastMPmoveX{\gMPa1}% + \edef\lastMPmoveY{\gMPa2}% + \resetMPstack} +\installMPSkeywordN \PSnewpath + {\let\handleMPsequence\handleMPpath} +\installMPSkeywordN \PSgsave + {\PDFcode{q}% + \resetMPstack} +\installMPSkeywordN \PSgrestore + {\PDFcode{Q}% + \resetMPstack} +\installMPSkeywordN \PSdtransform % == setlinewidth + {\let\handleMPsequence\handleMPdtransform} + % after that we will encounter more tokens until setlinewidth+pop + % or pop+setlinewidth which we catch next; we explicitly need to + % reset the stack since [] n setdash may follow; a more clever + % approach would be to read on till the condition is met, but it's + % the only pop / setlinewidth we will encounter so ... +\installMPSkeywordN \PSsetlinewidth + {% already handled in dtransform + \resetMPstack} +\installMPSkeywordN \PSpop + {% already handled in dtransform + \resetMPstack} +\installMPSkeywordN \PSconcat + {\cleanupMPconcat + \PDFcode{\gMPa1 \gMPa2 \gMPa3 \gMPa4 \gMPa5 \gMPa6 cm}% + \resetMPstack} +\installMPSkeywordN \PSsetrgbcolor + {\handleMPrgbcolor + \resetMPstack} +\installMPSkeywordN \PSsetcmykcolor + {\handleMPcmykcolor + \resetMPstack} +\installMPSkeywordN \PSsetgray + {\handleMPgraycolor + \resetMPstack} +\installMPSkeywordN \PStranslate + {\PDFcode{1 0 0 1 \gMPa1 \gMPa2 cm}% + \resetMPstack} +\installMPSkeywordN \PSsetdash + {\handleMPsetdash + \resetMPstack} +\installMPSkeywordN \PSsetlinejoin + {\PDFcode{\gMPa1 j}% + \resetMPstack} +\installMPSkeywordN \PSsetmiterlimit + {\PDFcode{\gMPa1 M}% + \resetMPstack} +\installMPSkeywordN \PSfshow + {%\PDFcode{n}% removed ! + \handleMPfshow + \resetMPstack} +\installMPSkeywordN \PSsetlinecap + {\PDFcode{\gMPa1 J}% + \resetMPstack} +\installMPSkeywordN \PSrlineto + {\flushMPmoveto + \PDFcode{\!MP\lastMPmoveX\space\!MP\lastMPmoveY\space l S}% + \resetMPmoveto + \resetMPstack} +\installMPSkeywordN \PSscale + {\PDFcode{\gMPa1 0 0 \gMPa2 0 0 cm}% + \resetMPstack} +\installMPSkeywordN \PSspecial + {\handleMPspecialcommand + \resetMPstack} + +\installMPSshortcutN {n} \PSnewpath +\installMPSshortcutN {p} \PSclosepath +\installMPSshortcutN {l} \PSlineto +\installMPSshortcutN {r} \PSrlineto +\installMPSshortcutN {m} \PSmoveto +\installMPSshortcutN {c} \PScurveto +\installMPSshortcutN {C} \PSsetcmykcolor +\installMPSshortcutN {G} \PSsetgray +\installMPSshortcutN {R} \PSsetrgbcolor +\installMPSshortcutN {lj} \PSsetlinejoin +\installMPSshortcutN {ml} \PSsetmiterlimit +\installMPSshortcutN {lc} \PSsetlinecap +\installMPSshortcutN {sd} \PSsetdash +\installMPSshortcutN {S} \PSstroke +\installMPSshortcutN {F} \PSfill +\installMPSshortcutN {W} \PSclip + +\installMPSshortcutN {q} \PSgsave +\installMPSshortcutN {Q} \PSgrestore + +\installMPSshortcutN {s} \PSscale +\installMPSshortcutN {t} \PSconcat +\installMPSshortcutN {P} \PSshowpage + +\installMPSkeywordN {hlw} {\PDFcode{\gMPa1 w}\resetMPstack} +\installMPSkeywordN {vlw} {\PDFcode{\gMPa1 w}\resetMPstack} +\installMPSkeywordN {rd} {\PDFcode{[] 0 d}\resetMPstack} + +\def\dohandleMPsequenceC#1 % + {\edef\somestring{#1}% + \handleMPgraphic % {#1}% + \handleMPsequence} + +%D Since colors are not sensitive to transformations, they +%D are sometimes used for signaling. Therefore, we handle them +%D separately. The next macro can be redefined if needed. + +\def\handleMPrgbcolor + {\PDFcode{\!MPgMPa1 \!MPgMPa2 \!MPgMPa3 rg + \!MPgMPa1 \!MPgMPa2 \!MPgMPa3 RG}} + +\def\handleMPcmykcolor + {\PDFcode{\!MPgMPa1 \!MPgMPa2 \!MPgMPa3 \!MPgMPa4 k + \!MPgMPa1 \!MPgMPa2 \!MPgMPa3 \!MPgMPa4 K}} + +\def\handleMPgraycolor + {\PDFcode{\!MPgMPa1 g + \!MPgMPa1 G}} + +\def\handleMPspotcolor + {\PDFcode{0 g + 0 G}} + +%D Beginning and ending the graphics is taken care of by the +%D macro \type{\handleMPgraphic}, which is redefined when +%D the first graphics operator is met. + +\def\handleMPendgraphic % #1% + {\ifx\somestring\PSshowpage + \let\handleMPsequence\finishMPgraphic + \else\ifx\somestring\PSEof + \let\handleMPsequence\finishMPgraphic + \else + \letMPargument\somestring % {#1}% + \fi\fi} + +\def\handleMPbegingraphic % #1% + {\ifx\somestring\PSBoundingBox + \def\handleMPsequence{\handleMPboundingbox1}% + \else\ifx\somestring\PSHiResBoundingBox + \def\handleMPsequence{\handleMPboundingbox2}% + \else\ifx\somestring\PSExactBoundingBox + \def\handleMPsequence{\handleMPboundingbox3}% + \else\ifx\somestring\PSshowpage + \let\handleMPsequence\finishMPgraphic + \else\ifx\somestring\PSEof + \let\handleMPsequence\finishMPgraphic + \else\ifx\somestring\PSPage + \let\handleMPsequence\handleMPpage + \else\ifx\somestring\PSMetaPostSpecials + \let\handleMPsequence\handleMPspecialscomment + \else\ifx\somestring\PSMetaPostSpecial + \let\handleMPsequence\handleMPspecialcomment + \else\ifx\somestring\PSBeginProlog + \let\handleMPsequence\handleMPprolog + \else + \letMPargument\somestring % {#1}% + \fi\fi\fi\fi\fi\fi\fi\fi\fi} + +\let\handleMPgraphic=\handleMPbegingraphic + +%D New: we can best filter the prolog because nowdays it can contain +%D quite some code. + +% hm, catcode mess, so we need to tweak %'s catcode here +% \long\expandafter\def\expandafter\handleMPprolog\expandafter#\expandafter1\PSEndProlog% +% but today i'm not in the mood for ugly stuff + +\long\def\handleMPprolog#1EndProlog % + {\doresetMPstack + \let\handleMPsequence\dohandleMPsequence + \handleMPsequence} + +%D We check for three kind of bounding boxes: the normal one +%D and two high precision ones: +%D +%D \starttyping +%D BoundingBox: llx lly ucx ucy +%D HiResBoundingBox: llx lly ucx ucy +%D ExactBoundingBox: llx lly ucx ucy +%D \stoptyping +%D +%D The original as well as the recalculated dimensions are +%D saved for later use. + +\newif\ifskipemptyMPgraphic \skipemptyMPgraphicfalse + +\chardef\currentMPboundingbox=0 + +\def\handleMPboundingbox#1#2 #3 #4 #5 + {\ifnum#1>\currentMPboundingbox + \xdef\MPllx{#2}\xdef\MPlly{#3}% + \xdef\MPurx{#4}\xdef\MPury{#5}% + \dimen0=#2pt + \dimen0=-\MPxscale\dimen0 + \dimen2=#3pt + \dimen2=-\MPyscale\dimen2 + \xdef\MPxoffset{\withoutpt\the\dimen0}% + \xdef\MPyoffset{\withoutpt\the\dimen2}% + \dimen0=#2bp + \dimen0=-\dimen0 + \dimen2=#3bp + \dimen2=-\dimen2 + \advance\dimen0 #4bp + \dimen0=\MPxscale\dimen0 + \xdef\MPwidth{\the\dimen0}% + \advance\dimen2 #5bp + \xdef\MPyshift{\the\dimen2}% unscaled + \dimen2=\MPyscale\dimen2 + \xdef\MPheight{\the\dimen2}% + \chardef\currentMPboundingbox#1\relax + \fi + \doresetMPstack + \let\handleMPsequence\dohandleMPsequence + \let\next\handleMPsequence + \ifskipemptyMPgraphic + \ifdim\MPheight=0pt\relax\ifdim\MPwidth=0pt\relax + \def\next{\endinput\finishMPgraphic}% + \fi\fi + \fi + \next} + +%D Unless defined otherwise, we simply ignore specialcomments. + +\def\handleMPspecialcomment + {\doresetMPstack + \let\handleMPsequence\dohandleMPsequence + \handleMPsequence} + +\let\handleMPspecialscomment\handleMPspecialcomment + +%D We use the \type{page} comment as a signal that +%D stackbuilding can be started. + +\def\handleMPpage #1 #2 + {\doresetMPstack + \donetrue + \let\handleMPsequence\dohandleMPsequence + \handleMPsequence} + +%D The same applies to the special extensions. + +\def\handleMPspecialcommand + {\doresetMPstack + \let\handleMPsequence\dohandleMPsequence + \handleMPsequence} + +%D \METAPOST\ draws its dots by moving to a location and +%D invoking \type{0 0 rlineto}. This operator is not +%D available in \PDF. Our solution is straightforward: we draw +%D a line from $(current\_x, current\_y)$ to itself. This +%D means that the arguments of the preceding \type{moveto} have +%D to be saved. + +\def\lastMPmoveX{0} +\def\lastMPmoveY{0} + +%D These saved coordinates are also used when we handle the +%D texts. Text handling proved to be a bit of a nuisance, but +%D finally I saw the light. It proved that we also had to +%D take care of \type{(split arguments)}. + +% \def\setMPfshowfont#1#2% +% {\font\temp=#1\space at #2\relax\temp} + +% \startMPcode +% draw btex Ga toch effe f\kern0ptietsen?{}` etex ; +% \stopMPcode + +\newtoks \everyMPshowfont + +\def\setMPfshowfont#1#2% + {\font\temp=#1\space at #2\relax\temp + \the\everyMPshowfont} + +\let\MPfshowcommand\empty + +%D The next hackery handles characters one by one. We only support this +%D for the latest greatest \METAPOST\ binaries, the ones that escape +%D problematic chars. + +\def\doflushMPtext#1% + {\edef\!!stringa{#1}% + \expandafter\dodoflushMPtext\!!stringa\relax} + +\def\dodoflushMPtext + {\afterassignment\dododoflushMPtext\let\nexttoken=} + +\def\dododoflushMPtext + {\ifx\nexttoken\relax + % done + \else\ifx\nexttoken\char + \expandafter\expandafter\expandafter\dodododoflushMPtext + \else + {\nexttoken}% + \expandafter\expandafter\expandafter\dodoflushMPtext + \fi\fi} + +\def\dodododoflushMPtext + {\afterassignment\dododododoflushMPtext\scratchcounter} + +\def\dododododoflushMPtext + {{\char\scratchcounter}\let\next\dodoflushMPtext} + +\def\dohandleMPfshow + {\bgroup + \setbox\scratchbox\hbox + {\obeyMPspecials + \let\ \relax % mp breaks long lines and appends a \ + \edef\size{\gMPa\nofMParguments}% + \ifx\size\PSnfont % round font size (to pt) + \advance\nofMParguments -1 + \expandafter\scratchdimen\gMPa\nofMParguments pt\relax + \ifdim\scratchdimen<1pt + \def\size{1pt}% + \else + \advance\scratchdimen .5pt + \def\size##1.##2\relax{\def\size{##1pt}}% + \expandafter\size\the\scratchdimen\relax + \fi + \else + \edef\size{\size bp}% + \fi + \advance\nofMParguments -1 + %\font\temp=\gMPa\nofMParguments\space at \size + \let\temp\relax % to be sure + \setMPfshowfont{\gMPa\nofMParguments}\size + \advance\nofMParguments -1 + \temp + \MPfshowcommand + {\ifnum\nofMParguments=1 + \def\do(##1){##1}% + \doflushMPtext{\dogMPa1}% only latest mp gets this treatment + \else + % we need to catch ( a ) (a a a) (\123 \123 \123) etc + \scratchcounter1 + \def\dodo##1% Andreas Fieger's bug: (\304...) + {\edef\!!stringa{##1\empty\empty}% and another one: ( 11) -> \ifx 11 + \ifx\!!stringa\MPspacechar\MPspacechar\else\expandafter##1\fi}% + \def\do(##1{\dodo{##1}}% + \dogMPa\scratchcounter\MPspacechar + \let\do\relax + \loop + \advance\scratchcounter 1 + \ifnum\scratchcounter<\nofMParguments\relax + \gMPa\scratchcounter\MPspacechar + \repeat + \def\do##1){\dodo{##1}}% + \dogMPa\scratchcounter + \fi + \unskip}}% + \setbox\scratchbox\hbox + {\hskip\lastMPmoveX bp\raise\lastMPmoveY bp\box\scratchbox}% + \ht\scratchbox0pt% + \dp\scratchbox0pt% + \wd\scratchbox0pt% + \box\scratchbox + \egroup} + +\let\handleMPfshow\dohandleMPfshow % so we can overload this one later + +%D You could consider the following definition to be the most +%D natural one. + +% \def\MPspacechar{\space} % normal case + +\def\MPspacechar{\char32\relax} % old solution does not work with math + +%D However, the following implementation is more robust, since +%D some fonts have funny visible spaces in the space slot. This +%D gives a mismatch between the space that \METAPOST\ took into +%D account and the \quote {natural} space. This only happens in +%D labels, since \type {btex}||\type {etex} thingies don't have +%D spaces. This phenomena showed up when preparing the +%D \METAFUN\ manual, where Palatino fonts are used. We can +%D safely assume that \METAPOST\ considers \type {\char32} to +%D be the space. + +\def\MPspacechar{\setbox\scratchbox\hbox{\char32}\kern\wd\scratchbox} + +%D Well, this does not work with math fonts, so: + +\def\MPspacechar{\char32\relax} + +%D Most operators are just converted and keep their +%D arguments. Dashes however need a bit different treatment, +%D otherwise \PDF\ viewers complain loudly. Another +%D complication is that one argument comes after the \type{]}. +%D When reading the data, we simply ignore the array boundary +%D characters. We save ourselves some redundant newlines and +%D at the same time keep the output readable by packing the +%D literals. + +\def\handleMPsetdash + {\bgroup + \ignoreMPspecials + \def\somestring{[}% + \scratchcounter1 + \loop + \ifnum\scratchcounter<\nofMParguments + \edef\somestring{\somestring\space\gMPa\scratchcounter}% + \advance\scratchcounter 1 + \repeat + \edef\somestring{\somestring]\gMPa\scratchcounter\space d}% + \PDFcode{\somestring}% + \egroup} + +%D The \type{setlinewidth} commands looks a bit complicated. There are +%D two alternatives, that result in a similar look in both +%D $x$- and $y$-dorection. As John Hobby says: +%D +%D \startnarrower \switchtobodyfont[ss] +%D \starttyping +%D x 0 dtransform exch truncate exch idtransform pop setlinewidth +%D 0 y dtransform truncate idtransform setlinewidth pop +%D \stoptyping +%D +%D These are just fancy versions of \type{x setlinewidth} and +%D \type{y setlinewidth}. The \type{x 0 ...} form is used if +%D the path is {\em primarily vertical}. It rounds the width +%D so that vertical lines come out an integer number of pixels +%D wide in device space. The \type{0 y ...} form does the same +%D for paths that are {\em primarily horizontal}. The reason +%D why I did this is Knuth insists on getting exactly the +%D widths \TEX\ intends for the horizontal and vertical rules +%D in \type{btex...etex} output. (Note that PostScript scan +%D conversion rules cause a horizontal or vertical line of +%D integer width $n$ in device space to come out $n+1$ pixels +%D wide, regardless of the phase relative to the pixel grid.) +%D \stopnarrower +%D +%D The common operator in these sequences is \type{dtransform}, +%D so we can use this one to trigger setting the linewidth. + +\def\handleMPdtransform + {\ifdim\gMPa1 pt>0pt + \PDFcode{\gMPa1 w}% + \def\next##1 ##2 ##3 ##4 ##5 ##6 {\handleMPsequence}% + \else + \PDFcode{\gMPa2 w}% + \def\next##1 ##2 ##3 ##4 {\handleMPsequence}% + \fi + \let\handleMPsequence\dohandleMPsequence + \resetMPstack + \next} + +%D The most complicated command is \type{concat}. \METAPOST\ +%D applies this operator to \type{stroke}. At that moment the +%D points set by \type{curveto} and \type{moveto}, are already +%D fixed. In \PDF\ however the \type{cm} operator affects the +%D points as well as the pen (stroke). Like more \PDF\ +%D operators, \type{cm} is defined in a bit ambiguous way. +%D The only save route for non||circular penshapes, is saving +%D the path, recalculating the points and applying the +%D transformation matrix in such a way that we can be sure +%D that its behavior is well defined. This comes down to +%D inverting the path and applying \type{cm} to that path as +%D well as the pen. This all means that we have to save the +%D path. + +%D In \METAPOST\ there are three ways to handle a path $p$: +%D +%D \starttyping +%D draw p; fill p; filldraw p; +%D \stoptyping +%D +%D The last case outputs a \type{gsave fill grestore} before +%D \type{stroke}. Handling the path outside the main loops +%D saves about 40\% run time.\footnote{We can save some more by +%D following the \METAPOST\ output routine, but for the moment +%D we keep things simple.} Switching between the main loop and +%D the path loop is done by means of the recursely called +%D macro \type{\handleMPsequence}. + +\def\handleMPpath + {\chardef\finiMPpath0 + \let\closeMPpath\relax + \let\flushMPpath\flushnormalMPpath + \resetMPstack + \nofMPsegments1 + \let\handleMPsequence\dohandleMPpath + \dohandleMPpath} + +%D Most paths are drawn with simple round pens. Therefore we've +%D split up the routine in two. + +\def\flushnormalMPsegment + {\ifcase\getMPkeyword\relax + \PDFcode{\!MPgMPs1 \!MPgMPs2 l}% + \or + \PDFcode{\!MPgMPs1 \!MPgMPs2 \!MPgMPs3 \!MPgMPs4 \!MPgMPs5 \!MPgMPs6 c}% + \or + \PDFcode{\!MP\lastMPmoveX\space\!MP\lastMPmoveY\space l}% + \or + \edef\lastMPmoveX{\gMPs1}% evt \!MP here + \edef\lastMPmoveY{\gMPs2}% + \PDFcode{\!MP\lastMPmoveX\space \!MP\lastMPmoveY\space m}% + \fi} + +\def\flushconcatMPsegment + {\ifcase\getMPkeyword\relax + \doMPconcat{\gMPs1}\a{\gMPs2}\b% + \PDFcode{\!MP\a\space\!MP\b\space l}% + \or + \doMPconcat{\gMPs1}\a{\gMPs2}\b% + \doMPconcat{\gMPs3}\c{\gMPs4}\d% + \doMPconcat{\gMPs5}\e{\gMPs6}\f% + \PDFcode{\!MP\a\space\!MP\b\space + \!MP\c\space\!MP\d\space + \!MP\e\space\!MP\f\space c}% + \or + \bgroup + \noMPtranslate + \doMPconcat\lastMPmoveX\a\lastMPmoveY\b% + \PDFcode{\!MP\a\space\!MP\b\space l S}% + \egroup + \or + \edef\lastMPmoveX{\gMPs1}% + \edef\lastMPmoveY{\gMPs2}% + \doMPconcat\lastMPmoveX\a\lastMPmoveY\b% + \PDFcode{\!MP\a\space\!MP\b\space m}% + \fi} + +% \def\flushnormalMPpath +% {\scratchcounter\nofMPsegments +% \nofMPsegments 1 +% \loop +% \flushnormalMPsegment +% \advance\nofMPsegments 1 +% \ifnum\nofMPsegments<\scratchcounter +% \repeat} +% +% \def\flushconcatMPpath +% {\scratchcounter\nofMPsegments +% \nofMPsegments 1 +% \loop +% \flushconcatMPsegment +% \advance\nofMPsegments 1 +% \ifnum\nofMPsegments<\scratchcounter +% \repeat} +% +% an alternative is presented below: (no \def assignment) + +\def\doflushsomeMPpath + {\dodoflushsomeMPpath + \advance\nofMPsegments 1 + \ifnum\nofMPsegments<\scratchcounter + \expandafter\doflushsomeMPpath + \fi} + +\def\flushsomeMPpath + {\scratchcounter\nofMPsegments + \nofMPsegments 1 + \doflushsomeMPpath} + +\def\flushnormalMPpath{\let\dodoflushsomeMPpath\flushnormalMPsegment\flushsomeMPpath} + +%OLD \def\flushconcatMPpath{\let\dodoflushsomeMPpath\flushconcatMPsegment\flushsomeMPpath} + +%NEW pre-calculate 1/D so it needn't be repeated for each control point. + +\def\flushconcatMPpath + {\MPreciprocaldeterminant + \let\dodoflushsomeMPpath\flushconcatMPsegment\flushsomeMPpath} + +%D The transformation of the coordinates is handled by one of +%D the macros Tanmoy posted to the \PDFTEX\ mailing list. +%D I rewrote and optimized the original macro to suit the other +%D macros in this module. +%D +%D \starttyping +%D \doMPconcat {x position} \xresult {y position} \yresult +%D \stoptyping +%D +%D By setting the auxiliary \DIMENSIONS\ \type{\dimen0} upto +%D \type{\dimen10} only once per path, we save over 20\% run +%D time. Some more speed was gained by removing some parameter +%D passing. These macros can be optimized a bit more by using +%D more constants. There is however not much need for further +%D optimization because penshapes usually are round and +%D therefore need no transformation. Nevertheless we move the +%D factor to the outer level and use a bit different \type{pt} +%D removal macro. Although the values represent base points, +%D we converted them to pure points, simply because those can +%D be converted back. + +%OLD \mathchardef\MPconcatfactor=256 % beware don't remove spaces before it + +%OLD \def\doMPreducedimen#1 +%OLD {\count0\MPconcatfactor +%OLD \advance\dimen#1 \ifdim\dimen#1>0pt .5\else -.5\fi\count0 +%OLD \divide\dimen#1 \count0\relax} + +%OLD % too inaccurate (see old pragma logo) +%OLD +%OLD \def\doMPreducedimen#1 +%OLD {\count0=\MPconcatfactor +%OLD \divide\dimen#1 \count0\relax} + +%OLD \def\doMPreducedimen#1 +%OLD {\advance\dimen#1 \ifdim\dimen#1>0pt .5\else -.5\fi\MPconcatfactor +%OLD \divide\dimen#1 \MPconcatfactor} + +%D The transformation code is rewritten by Daniel H. Luecking who +%D describes his patch as follows: +%D +%D We would like to divide 1 by $X$, but all divisions are integer so +%D for accuracy we want to convert to large integers and make sure the +%D integer quotient has as many significant digits as possible. Thus we +%D need to replace $1/X$ with $M/N$ where $N$ is as large as possible +%D and $M/N$ is as large as possible. Also for simplicity $M$ should be +%D a power of 2. So we make $M = 2^{30}$ \footnote{$2^{31} - 1$ is the +%D largest legal integer. Using it (and simply ignoring the inaccuracy +%D caused by $-1$) turns out to be at least as accurate in all cases, +%D and more accurate in some.} (largest legal power of 2) and adjust +%D $X$ downward (if necessary) to the the range $1-2^{16}$. This gives +%D at least 15 significant binary digits, (almost as accurate as +%D \METAPOST\ for numbers near 1) or almost 5 significant figures +%D (decimal). + +\newcount\MPscratchCnt +\newdimen\MPscratchDim % will be assigned global + +\def\MPadjustdimen % sets \MPscratchDim and \MPscratchCnt + {\MPscratchCnt0 + \doMPadjustdimen} + +\def\doMPadjustdimen + {\ifdim\MPscratchDim>1pt + \divide\MPscratchDim 2 + \advance\MPscratchCnt 1 + \expandafter\doMPadjustdimen + \fi} + +%OLD \def\doMPexpanddimen#1 +%OLD {\multiply\dimen#1 \MPconcatfactor\relax} + +%D DHL: When viewed as an integer, $1 \hbox{pt}=2^{16}$ so $2^{32}/X$ +%D is the right way to do $(1 \hbox{pt})/(X \hbox{pt})$ and get the +%D answer in points. But we are limited to $2^{30}/X$. However, we +%D actually do $[ 2^{30} / (X/2^K) ]*2^{2-K}$ where $K$ is the number +%D of halvings it takes to bring $X$ below $1 \hbox{pt}$. If $K$ is 0 +%D or 1 we readjust by multiplying by 4 or 2, otherwise by halving +%D $(K-2)$ times \type {\MPscratchCnt} holds the value of $K$ from +%D \type {\MPadjustdimen}. + +\def\MPreadjustdimen % acts on \MPscratchDim and MPscratchCnt + {\ifcase\MPscratchCnt + \multiply\scratchdimen 4 + \or + \multiply\scratchdimen 2 + \else + \expandafter\doMPreadjustdimen + \fi} + +\def\doMPreadjustdimen + {\ifnum\MPscratchCnt>2 + \divide\scratchdimen 2 + \advance\MPscratchCnt -1 + \expandafter\doMPreadjustdimen + \fi} + +\def\MPreciprocaldeterminant + {\scratchdimen\withoutpt\the\dimen0 \dimen6 % s_x*s_y + \advance\scratchdimen - \withoutpt\the\dimen2 \dimen4 % s_x*s_y - r_x*r_y + \ifdim\scratchdimen<0pt % we need a positive dimension + \scratchdimen-\scratchdimen % for \MPadjustdimen (?) + \doMPreciprocal + \scratchdimen-\scratchdimen + \else + \doMPreciprocal + \fi + \edef\MPreciprocal{\withoutpt\the\scratchdimen}} + +\newcount\MPnumerator \MPnumerator = 1073741824 % 2^{30} + +% todo: dimexpr + +\def\doMPreciprocal % replace \scratchdimen with its reciprocal + {\ifdim\scratchdimen=1pt \else + \MPadjustdimen + \scratchcounter\MPnumerator + \divide\scratchcounter\scratchdimen + \scratchdimen1\scratchcounter % 1 needed ! + \MPreadjustdimen + \fi} + +%OLD \def\presetMPconcat +%OLD {\dimen 0=\gMPs1pt \doMPreducedimen 0 % r_x +%OLD \dimen 2=\gMPs2pt \doMPreducedimen 2 % s_x +%OLD \dimen 4=\gMPs3pt \doMPreducedimen 4 % s_y +%OLD \dimen 6=\gMPs4pt \doMPreducedimen 6 % r_y +%OLD \dimen 8=\gMPs5pt \doMPreducedimen 8 % t_x +%OLD \dimen10=\gMPs6pt \doMPreducedimen10 } % t_y +%OLD +%OLD \def\presetMPscale +%OLD {\dimen 0=\gMPs1pt \doMPreducedimen 0 +%OLD \dimen 2=0pt +%OLD \dimen 4=0pt +%OLD \dimen 6=\gMPs2pt \doMPreducedimen 6 +%OLD \dimen 8=0pt +%OLD \dimen10=0pt} + +\def\cleanupMPconcat + {\ignoreMPspecials + \docleanupMPargument1% + \docleanupMPargument6% + \keepMPspecials} + +\def\presetMPconcat + {\dimen 0=\gMPs1pt % s_x + \dimen 2=\gMPs2pt % r_x + \dimen 4=\gMPs3pt % r_y + \dimen 6=\gMPs4pt % s_y + \dimen 8=\gMPs5pt % t_x + \dimen10=\gMPs6pt} % t_y + +\def\presetMPscale + {\dimen 0=\gMPs1pt + \dimen 2=0pt + \dimen 4=0pt + \dimen 6=\gMPs2pt + \dimen 8=0pt + \dimen10=0pt} + +\def\noMPtranslate % use this one grouped + {\dimen 8=0pt % t_x + \dimen10=0pt} % t_y + +%D \starttyping +%D \def\doMPconcat#1#2#3#4% +%D {\dimen12=#1 pt \doMPreducedimen12 % p_x +%D \dimen14=#3 pt \doMPreducedimen14 % p_y +%D % +%D \dimen16 \dimen 0 +%D \multiply \dimen16 \dimen 6 +%D \dimen20 \dimen 2 +%D \multiply \dimen20 \dimen 4 +%D \advance \dimen16 -\dimen20 +%D % +%D \dimen18 \dimen12 +%D \multiply \dimen18 \dimen 6 +%D \dimen20 \dimen14 +%D \multiply \dimen20 \dimen 4 +%D \advance \dimen18 -\dimen20 +%D \dimen20 \dimen 4 +%D \multiply \dimen20 \dimen10 +%D \advance \dimen18 \dimen20 +%D \dimen20 \dimen 6 +%D \multiply \dimen20 \dimen 8 +%D \advance \dimen18 -\dimen20 +%D % +%D \multiply \dimen12 -\dimen 2 +%D \multiply \dimen14 \dimen 0 +%D \advance \dimen12 \dimen14 +%D \dimen20 \dimen 2 +%D \multiply \dimen20 \dimen 8 +%D \advance \dimen12 \dimen20 +%D \dimen20 \dimen 0 +%D \multiply \dimen20 \dimen10 +%D \advance \dimen12 -\dimen20 +%D % +%D \doMPreducedimen16 +%D \divide \dimen18 \dimen16 \doMPexpanddimen18 +%D \divide \dimen12 \dimen16 \doMPexpanddimen12 +%D % +%D \edef#2{\withoutpt\the\dimen18}% % p_x^\prime +%D \edef#4{\withoutpt\the\dimen12}} % p_y^\prime +%D \stoptyping + +%D The following optimization resulted from some tests by +%D and email exchanges with Sanjoy Mahajan. +%D +%D \starttyping +%D \def\doMPconcat#1#2#3#4% +%D {\dimen12=#1 pt \doMPreducedimen12 % p_x +%D \dimen14=#3 pt \doMPreducedimen14 % p_y +%D % +%D \dimen16 \dimen 0 +%D \multiply \dimen16 \dimen 6 +%D \dimen20 \dimen 2 +%D \multiply \dimen20 \dimen 4 +%D \advance \dimen16 -\dimen20 +%D % +%D \dimen18 \dimen12 +%D \multiply \dimen18 \dimen 6 +%D \dimen20 \dimen14 +%D \multiply \dimen20 \dimen 4 +%D \advance \dimen18 -\dimen20 +%D \dimen20 \dimen 4 +%D \multiply \dimen20 \dimen10 +%D \advance \dimen18 \dimen20 +%D \dimen20 \dimen 6 +%D \multiply \dimen20 \dimen 8 +%D \advance \dimen18 -\dimen20 +%D % +%D \multiply \dimen12 -\dimen 2 +%D \multiply \dimen14 \dimen 0 +%D \advance \dimen12 \dimen14 +%D \dimen20 \dimen 2 +%D \multiply \dimen20 \dimen 8 +%D \advance \dimen12 \dimen20 +%D \dimen20 \dimen 0 +%D \multiply \dimen20 \dimen10 +%D \advance \dimen12 -\dimen20 +%D % +%D %\ifdim\dimen16>1pt % oeps, can be < 1pt too +%D \ifdim\dimen16=1pt \else +%D \ifdim\dimen16>\MPconcatfactor pt +%D \doMPreducedimen16 +%D \divide \dimen18 \dimen16 \doMPexpanddimen18 +%D \divide \dimen12 \dimen16 \doMPexpanddimen12 +%D \else +%D \divide \dimen18 \dimen16 \doMPexpanddimen18 \doMPexpanddimen18 +%D \divide \dimen12 \dimen16 \doMPexpanddimen12 \doMPexpanddimen12 +%D \fi +%D \fi +%D % +%D \edef#2{\withoutpt\the\dimen18}% % p_x^\prime +%D \edef#4{\withoutpt\the\dimen12}} % p_y^\prime +%D \stoptyping +%D +%D But, this one is still too inaccurate, so we now have: + +% \def\doMPconcat#1#2#3#4% +% {\dimen12=#1pt % p_x +% \dimen14=#3pt % p_y +% % +% % we should test for >-1024 too, but for the moment take the gamble +% \chardef\MPfactor1\ifdim\dimen12<1024pt \ifdim\dimen14<1024pt 6\fi\fi +% % +% \multiply\dimen12 \MPfactor +% \multiply\dimen14 \MPfactor +% % +% \doMPreducedimen12 +% \doMPreducedimen14 +% % +% \dimen16 \dimen 0 +% \multiply \dimen16 \dimen 6 +% \dimen20 \dimen 2 +% \multiply \dimen20 \dimen 4 +% \advance \dimen16 -\dimen20 +% % +% \dimen18 \dimen12 +% \multiply \dimen18 \dimen 6 +% \dimen20 \dimen14 +% \multiply \dimen20 \dimen 4 +% \advance \dimen18 -\dimen20 +% \dimen20 \dimen 4 +% \multiply \dimen20 \dimen10 +% \advance \dimen18 \dimen20 +% \dimen20 \dimen 6 +% \multiply \dimen20 \dimen 8 +% \advance \dimen18 -\dimen20 +% % +% \multiply \dimen12 -\dimen 2 +% \multiply \dimen14 \dimen 0 +% \advance \dimen12 \dimen14 +% \dimen20 \dimen 2 +% \multiply \dimen20 \dimen 8 +% \advance \dimen12 \dimen20 +% \dimen20 \dimen 0 +% \multiply \dimen20 \dimen10 +% \advance \dimen12 -\dimen20 +% % +% \ifdim\dimen16=1pt \else +% \ifdim\dimen16>\MPconcatfactor pt +% \doMPreducedimen16 +% \divide \dimen18 \dimen16 \doMPexpanddimen18 +% \divide \dimen12 \dimen16 \doMPexpanddimen12 +% \else +% \divide \dimen18 \dimen16 \doMPexpanddimen18 \doMPexpanddimen18 +% \divide \dimen12 \dimen16 \doMPexpanddimen12 \doMPexpanddimen12 +% \fi +% \fi +% % +% \divide\dimen18 \MPfactor +% \divide\dimen12 \MPfactor +% % +% \edef#2{\withoutpt\the\dimen18}% % p_x^\prime +% \edef#4{\withoutpt\the\dimen12}} % p_y^\prime + +%D DHL: Ideally, $r_x$, $r_y$, $s_x$, $s_y$ should be in macros, not +%D dimensions (they are scalar quantities after all, not lengths). I +%D suppose the authors decided to do calculations with integer +%D arithmetic instead of using real factors because it's faster. +%D However, the actual macros test slower, possibly because I've +%D omitted three nested loops. In my test files, my approach is more +%D accurate. It is also far simpler and overflow does not seem to be a +%D significant concern. The scale factors written by Metapost are (?) +%D always $<=1$ (it scales coordinates internally) and coordinates are +%D always likely to be less than \type {\maxdimen}. +%D +%D If this should ever cause problems, the scale factors can be reduced. + +% \def\doMPconcat#1#2#3#4% +% {\dimen12=#1pt % p_x % #1pt +% \dimen14=#3pt % p_y % #3pt +% \advance\dimen12 -\dimen8 % p_x - t_x +% \advance\dimen14 -\dimen10 % p_y - t_y +% \dimen18=\withoutpt\the\dimen6 \dimen12 % s_y(p_x - t_x) +% \advance\dimen18 -\withoutpt\the\dimen4 \dimen14 % - r_y(p_y-t_y) +% \dimen14=\withoutpt\the\dimen0 \dimen14 % s_x(p_y-t_y) +% \advance\dimen14 -\withoutpt\the\dimen2 \dimen12 % - r_x(p_x-t_x) +% % \MPscratchDim contains precomputed 1/D: +% \dimen18=\withoutpt\the\MPscratchDim \dimen18 +% \dimen14=\withoutpt\the\MPscratchDim \dimen14 +% \edef#2{\withoutpt\the\dimen18}% % p_x^\prime +% \edef#4{\withoutpt\the\dimen14}} % p_y^\prime + +\def\doMPconcat#1#2#3#4% + {\dimen12=#1pt % p_x % #1pt + \dimen14=#3pt % p_y % #3pt + \advance\dimen12 -\dimen8 % p_x - t_x + \advance\dimen14 -\dimen10 % p_y - t_y + \dimen18=\withoutpt\the\dimen6 \dimen12 % s_y(p_x - t_x) + \advance\dimen18 -\withoutpt\the\dimen4 \dimen14 % - r_y(p_y-t_y) + \dimen14=\withoutpt\the\dimen0 \dimen14 % s_x(p_y-t_y) + \advance\dimen14 -\withoutpt\the\dimen2 \dimen12 % - r_x(p_x-t_x) + % \MPreciprocal contains precomputed 1/D: + \dimen18=\MPreciprocal\dimen18 + \dimen14=\MPreciprocal\dimen14 + \edef#2{\withoutpt\the\dimen18}% % p_x^\prime + \edef#4{\withoutpt\the\dimen14}} % p_y^\prime + +% faster but not that often used +% +% \def\doMPconcat#1#2#3#4% +% {\dimen12\dimexpr#1\points-\dimen 8\relax % p_x-t_x +% \dimen14\dimexpr#3\points-\dimen10\relax % p_y-t_y +% \dimen18\dimexpr\withoutpt\the\dimen6\dimen12-\withoutpt\the\dimen4\dimen14\relax % s_y(p_x-t_x)-r_y(p_y-t_y) +% \dimen14\dimexpr\withoutpt\the\dimen0\dimen14-\withoutpt\the\dimen2\dimen12\relax % s_x(p_y-t_y)-r_x(p_x-t_x) +% \edef#2{\withoutpt\the\dimexpr\MPreciprocal\dimen18\relax}% % p_x^\prime +% \edef#4{\withoutpt\the\dimexpr\MPreciprocal\dimen14\relax}} % p_y^\prime + +%D One reason for Daniel to write this patch was that at small sizes +%D the accuracy was less than optimal. Here is a test that demonstrates +%D that his alternative is pretty good: +%D +%D \startlinecorrection +%D \startMPcode +%D for i = 5cm,1cm,5mm,1mm,.5mm,.1mm,.01mm : +%D draw fullcircle scaled i withpen pencircle xscaled (i/10) yscaled (i/20) rotated 45 ; +%D endfor ; +%D \stopMPcode +%D \stoplinecorrection + +%D The following explanation of the conversion process was +%D posted to the \PDFTEX\ mailing list by Tanmoy. The original +%D macro was part of a set of macro's that included sinus and +%D cosinus calculations as well as scaling and translating. The +%D \METAPOST\ to \PDF\ conversion however only needs +%D transformation. + +%M \start \switchtobodyfont [ss] + +%D Given a point $(U_x, U_y)$ in user coordinates, the business +%D of \POSTSCRIPT\ is to convert it to device space. Let us say +%D that the device space coordinates are $(D_x, D_y)$. Then, in +%D \POSTSCRIPT\ $(D_x, D_y)$ can be written in terms of +%D $(U_x, U_y)$ in matrix notation, either as +%D +%D \placeformula +%D \startformula +%D \pmatrix{D_x&D_y&1\cr} = \pmatrix{U_x&U_y&1\cr} +%D \pmatrix{s_x&r_x&0\cr +%D r_y&s_y&0\cr +%D t_x&t_y&1\cr} +%D \stopformula +%D +%D or +%D +%D \placeformula +%D \startformula +%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x&r_y&t_x\cr +%D r_x&s_y&t_y\cr +%D 0 &0 &1 \cr} +%D \pmatrix{U_x\cr +%D U_y\cr +%D 1 \cr} +%D \stopformula +%D +%D both of which is a shorthand for the same set of equations: +%D +%D \placeformula +%D \startformula +%D D_x = s_x U_x + r_y U_y + t_x +%D \stopformula +%D +%D \placeformula +%D \startformula +%D D_y = r_x U_x + s_y U_y + t_y +%D \stopformula +%D +%D which define what is called an `affine transformation'. +%D +%D \POSTSCRIPT\ represents the `transformation matrix' as a +%D six element matrix instead of a $3\times 3$ array because +%D three of the elements are always~0, 0 and~1. Thus the above +%D transformation is written in postscript as $[s_x\, r_x\, +%D r_y\, s_y\, t_x\, t_y]$. However, when doing any +%D calculations, it is useful to go back to the original +%D matrix notation (whichever: I will use the second) and +%D continue from there. +%D +%D As an example, if the current transformation matrix is +%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$ and you say \typ{[a b +%D c d e f] concat}, this means: +%D +%D \startnarrower +%D Take the user space coordinates and transform them to an +%D intermediate set of coordinates using array $[a\, b\, c\, d\, +%D e\, f]$ as the transformation matrix. +%D +%D Take the intermediate set of coordinates and change them to +%D device coordinates using array $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$ +%D as the transformation matrix. +%D \stopnarrower +%D +%D Well, what is the net effect? In matrix notation, it is +%D +%D \placeformula +%D \startformula +%D \pmatrix{I_x\cr I_y\cr 1\cr} = \pmatrix{a&c&e\cr +%D b&d&f\cr +%D 0&0&1\cr} +%D \pmatrix{U_x\cr +%D U_y\cr +%D 1 \cr} +%D \stopformula +%D +%D \placeformula +%D \startformula +%D \pmatrix{D_y\cr D_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr +%D r_x&s_y&t_y\cr +%D 0 &0 &1 \cr} +%D \pmatrix{I_x\cr +%D I_y\cr +%D 1 \cr} +%D \stopformula +%D +%D where $(I_x, I_y)$ is the intermediate coordinate. +%D +%D Now, the beauty of the matrix notation is that when there is +%D a chain of such matrix equations, one can always compose +%D them into one matrix equation using the standard matrix +%D composition law. The composite matrix from two matrices can +%D be derived very easily: the element in the $i$\high{th} +%D horizontal row and $j$\high{th} vertical column is +%D calculated by`multiplying' the $i$\high{th} row of the first +%D matrix and the $j$\high{th} column of the second matrix (and +%D summing over the elements). Thus, in the above: +%D +%D \placeformula +%D \startformula +%D \pmatrix{D_x\cr D_y\cr 1} = \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr +%D r_x^\prime&s_y^\prime&t_y^\prime\cr +%D 0 &0 &0 \cr} +%D \pmatrix{U_x\cr +%D U_y\cr +%D 1 \cr} +%D \stopformula +%D +%D with +%D +%D \placeformula +%D \startformula +%D \eqalign +%D {s_x^\prime & = s_x a + r_y b \cr +%D r_x^\prime & = r_x a + s_y b \cr +%D r_y^\prime & = s_x c + r_y d \cr +%D s_y^\prime & = r_x c + s_y d \cr +%D t_x^\prime & = s_x e + r_y f + t_x \cr +%D t_y^\prime & = r_x e + s_y f + t_y \cr} +%D \stopformula + +%D In fact, the same rule is true not only when one is going +%D from user coordinates to device coordinates, but whenever +%D one is composing two `transformations' together +%D (transformations are `associative'). Note that the formula +%D is not symmetric: you have to keep track of which +%D transformation existed before (i.e.\ the equivalent of +%D $[s_x\, r_x\, r_y\, s_y\, t_x\, t_y]$) and which was +%D specified later (i.e.\ the equivalent of $[a\, b\, c\, d\, +%D e\, f]$). Note also that the language can be rather +%D confusing: the one specified later `acts earlier', +%D converting the user space coordinates to intermediate +%D coordinates, which are then acted upon by the pre||existing +%D transformation. The important point is that order of +%D transformation matrices cannot be flipped (transformations +%D are not `commutative'). +%D +%D Now what does it mean to move a transformation matrix +%D before a drawing? What it means is that given a point +%D $(P_x, P_y)$ we need a different set of coordinates +%D $(P_x^\prime, P_y^\prime)$ such that if the transformation +%D acts on $(P_x^\prime, P_y^\prime)$, they produce $(P_x, +%D P_y)$. That is we need to solve the set of equations: +%D +%D \placeformula +%D \startformula +%D \pmatrix{P_x\cr P_y\cr 1\cr} = \pmatrix{s_x&r_y&t_x\cr +%D r_x&s_y&t_y\cr +%D 0 &0 &1 \cr} +%D \pmatrix{P_x^\prime\cr +%D P_y^\prime\cr +%D 1 \cr} +%D \stopformula +%D +%D Again matrix notation comes in handy (i.e. someone has +%D already solved the problem for us): we need the inverse +%D transformation matrix. The inverse transformation matrix can +%D be calculated very easily: +%D +%D \placeformula +%D \startformula +%D \pmatrix{P_x^\prime\cr P_y^\prime\cr 1\cr} = +%D \pmatrix{s_x^\prime&r_y^\prime&t_x^\prime\cr +%D r_x^\prime&s_y^\prime&t_y^\prime\cr +%D 0 &0 &1 \cr} +%D \pmatrix{P_x\cr +%D P_y\cr +%D 1 \cr} +%D \stopformula +%D +%D where, the inverse transformation matrix is given by +%D +%D \placeformula +%D \startformula +%D \eqalign +%D {D & = s_x s_y - r_x r_y \cr +%D s_x^\prime & = s_y / D \cr +%D s_y^\prime & = s_x / D \cr +%D r_x^\prime & = - r_x / D \cr +%D r_y^\prime & = - r_y / D \cr +%D t_x^\prime & = ( - s_y t_x + r_y t_y ) / D \cr +%D t_y^\prime & = ( r_x t_x - s_x t_y ) / D \cr} +%D \stopformula +%D +%D And you can see that when expanded out, this does +%D give the formulas: +%D +%D \placeformula +%D \startformula +%D P_x^\prime = { { s_y(p_x-t_x) + r_y(t_y-p_y) } \over +%D { s_x s_y-r_x r_y } } +%D \stopformula +%D +%D \placeformula +%D \startformula +%D P_y^\prime = { { s_x(p_y-t_y) + r_x(t_x-p_x) } \over +%D { s_x*s_y-r_x*r_y } } +%D \stopformula +%D +%D The code works by representing a real number by converting +%D it to a dimension to be put into a \DIMENSION\ register: 2.3 would +%D be represented as 2.3pt for example. In this scheme, +%D multiplying two numbers involves multiplying the \DIMENSION\ +%D registers and dividing by 65536. Accuracy demands that the +%D division be done as late as possible, but overflow +%D considerations need early division. +%D +%D Division involves dividing the two \DIMENSION\ registers and +%D multiplying the result by 65536. Again, accuracy would +%D demand that the numerator be multiplied (and|/|or the +%D denominator divided) early: but that can lead to overflow +%D which needs to be avoided. +%D +%D If nothing is known about the numbers to start with (in +%D concat), I have chosen to divide the 65536 as a 256 in each +%D operand. However, in the series calculating the sine and +%D cosine, I know that the terms are small (because I never +%D have an angle greater than 45 degrees), so I chose to +%D apportion the factor in a different way. + +%M \stop + +%D The path is output using the values saved on the stack. If +%D needed, all coordinates are recalculated. + +\def\finishMPpath + {\PDFcode{\ifcase\finiMPpath W n\or S\or f\or B\fi}} + +\def\processMPpath + {\checkMPpath + \ifcase\nofMPsegments\else + \flushMPpath + \closeMPpath + \finishMPpath + \fi + \let\handleMPsequence\dohandleMPsequence + \resetMPstack + \nofMPsegments0 + \handleMPsequence} + +%D The following \METAPOST\ code is quite valid but, when +%D processed and converted to \PDF, will make a file +%D unprintable on a Hewlett Packard printer (from Acrobat +%D $v<=5$). Who is to blame, the driver of the OS layer in +%D between, is hard to determine, so we add an additional +%D check. +%D +%D \starttyping +%D clip currentpicture to origin -- cycle ; +%D setbounds currentpicture to fullsquare scaled 5cm ; +%D \stoptyping + +\def\checkMPpath + {\ifcase\finiMPpath + \ifnum\nofMPsegments<3 % n is one ahead + \message{omitting zero clip path}% + \nofMPsegments0 + \fi + \fi} + +%D In \PDF\ the \type{cm} operator must precede the path +%D specification. We therefore can output the \type{cm} at +%D the moment we encounter it. + +\def\handleMPpathconcat + {\presetMPconcat + \PDFcode{\gMPs1 \gMPs2 \gMPs3 \gMPs4 \gMPs5 \gMPs6 cm}% + \resetMPstack} + +\def\handleMPpathscale + {\presetMPscale + \PDFcode{\gMPs1 0 0 \gMPs2 0 0 cm}% + \resetMPstack} + +%D This macro interprets the path and saves it as compact as +%D possible. + +\def\dohandleMPpath#1% + {\ifcase\lccode`#1\relax + \expandafter\dohandleMPpathA + \else + \expandafter\dohandleMPpathB + \fi#1} + +%\def\dohandleMPpathA#1 % +% {\setMPargument{#1}% +% \handleMPsequence} + +\let\dohandleMPpathA\setMPsequence + +% \def\dohandleMPpathB#1 % +% {\def\somestring{#1}% +% \ifx\somestring\PSlineto +% \setMPkeyword0 +% \else\ifx\somestring\PScurveto +% \setMPkeyword1 +% \else\ifx\somestring\PSrlineto +% \setMPkeyword2 +% \else\ifx\somestring\PSmoveto +% \setMPkeyword3 +% \else\ifx\somestring\PSclip +% % \chardef\finiMPpath0 % already +% \let\handleMPsequence\processMPpath +% \else\ifx\somestring\PSgsave +% \chardef\finiMPpath3 +% \else\ifx\somestring\PSgrestore +% \else\ifx\somestring\PSfill +% \ifcase\finiMPpath +% \chardef\finiMPpath2 +% \let\handleMPsequence\processMPpath +% \fi +% \else\ifx\somestring\PSstroke +% \ifcase\finiMPpath +% \chardef\finiMPpath1 +% \fi +% \let\handleMPsequence\processMPpath +% \else\ifx\somestring\PSclosepath +% \def\closeMPpath{\PDFcode{h}}% +% \else\ifx\somestring\PSconcat +% \cleanupMPconcat +% \let\flushMPpath\flushconcatMPpath +% \handleMPpathconcat +% \else\ifx\somestring\PSscale +% \let\flushMPpath\flushconcatMPpath +% \handleMPpathscale +% \fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi\fi +% \handleMPsequence} + +\def\installMPSkeywordP#1#2% + {\expandafter\def\csname\@@MP:P:#1\endcsname{#2}} + +\def\installMPSshortcutP#1#2% todo: \let + {\expandafter\let\csname\@@MP:P:#1\expandafter\endcsname\csname\@@MP:P:#2\endcsname} + +\def\dohandleMPpathB#1 % + {\def\somestring{#1}% + \ifcsname\@@MP:P:\somestring\endcsname + \csname\@@MP:P:\somestring\expandafter\endcsname + \fi + \handleMPsequence} + +\ifx\eTeXversion\undefined + \def\dohandleMPpathB#1 % + {\def\somestring{#1}% + \csname\@@MP:P:\somestring\endcsname + \handleMPsequence} +\fi + +\installMPSkeywordP \PSlineto + {\setMPkeyword0 } +\installMPSkeywordP \PScurveto + {\setMPkeyword1 } +\installMPSkeywordP \PSrlineto + {\setMPkeyword2 } +\installMPSkeywordP \PSmoveto + {\edef\lastMPmoveX{\gMPs1}% + \edef\lastMPmoveY{\gMPs2}% + \resetMPstack + \setMPkeyword3 } +\installMPSkeywordP \PSclip + {% \chardef\finiMPpath\zerocount % already + \let\handleMPsequence\processMPpath} +\installMPSkeywordP \PSgsave + {\chardef\finiMPpath3 } +\installMPSkeywordP \PSgrestore + {} +\installMPSkeywordP \PSfill + {\ifcase\finiMPpath + \chardef\finiMPpath2 + \let\handleMPsequence\processMPpath + \fi} +\installMPSkeywordP \PSstroke + {\ifcase\finiMPpath + \chardef\finiMPpath1 + \fi + \let\handleMPsequence\processMPpath} +\installMPSkeywordP \PSclosepath + {\def\closeMPpath{\PDFcode{h}}} +\installMPSkeywordP \PSconcat + {\cleanupMPconcat + \let\flushMPpath\flushconcatMPpath + \handleMPpathconcat} +\installMPSkeywordP \PSscale + {\let\flushMPpath\flushconcatMPpath + \handleMPpathscale} + +\installMPSshortcutP {l} \PSlineto +\installMPSshortcutP {r} \PSrlineto +\installMPSshortcutP {m} \PSmoveto +\installMPSshortcutP {c} \PScurveto + +\installMPSshortcutP {q} \PSgsave +\installMPSshortcutP {Q} \PSgrestore +\installMPSshortcutP {S} \PSstroke +\installMPSshortcutP {F} \PSfill +\installMPSshortcutP {B} \PSgsave +\installMPSshortcutP {W} \PSclip +\installMPSshortcutP {p} \PSclosepath + +\installMPSshortcutP {s} \PSscale +\installMPSshortcutP {t} \PSconcat + +%D The main conversion command is: +%D +%D \starttyping +%D \convertMPtoPDF {filename} {x scale} {y scale} +%D \stoptyping +%D +%D The dimensions are derived from the bounding box. So we +%D only have to say: +%D +%D \starttyping +%D \convertMPtoPDF{mp-pra-1.eps}{1}{1} +%D \convertMPtoPDF{mp-pra-1.eps}{.5}{.5} +%D \stoptyping + +%D \macros +%D {makeMPintoPDFobject,lastPDFMPobject} +%D +%D For experts there are a few more options. When attributes +%D are to be added, the code must be embedded in an object +%D accompanied with the appropriate directives. One can +%D influence this process with \type {\makeMPintoPDFobject}. +%D +%D This option defaults to~0, because \CONTEXT\ takes care +%D of objects at another level, which saves some bytes. +%D +%D \starttabulate[|l|l|p|] +%D \NC 0 \NC never \NC don't use an object \NC\NR +%D \NC 1 \NC always \NC always use an object \NC\NR +%D \NC 2 \NC optional \NC use object when needed \NC\NR +%D \stoptabulate +%D +%D The last object number used is avaliable in the macro +%D \type {\lastPDFMPobject}. + +\ifx\makeMPintoPDFobject\undefined \newcount\makeMPintoPDFobject \fi + +\def\lastPDFMPobject{0} + +%D The additional code needed can be made available in the +%D (global) macro \type {\currentPDFresources}. + +\let\currentPDFresources\empty + +\newtoks\everyMPtoPDFconversion + +\def\convertMPtoPDF % #1#2#3% + {\bgroup + \defineMPtoPDFfallbacks + \ifx\pdfdecimaldigits\undefined\else \pdfdecimaldigits=5 \fi % new + \setbox\scratchbox\vbox\bgroup + \xdef\MPheight{0pt}% + \xdef\MPwidth {0pt}% + \forgetall + \offinterlineskip + \startMPresources + \doprocessMPtoPDFfile} % + +%D The next one is kind of private and probably will become obsolete): + +\def\processMPtoPDFfile % file xscale yscale + {\bgroup + \let\finishMPgraphic\egroup + \doprocessMPtoPDFfile} + +\let\setMPextensions\relax + +\def\doprocessMPtoPDFfile#1#2#3% file xscale yscale + {\setMPspecials + \setMPextensions + \the\everyMPtoPDFconversion + \catcode`\^^M=\@@endofline + \startMPscanning + \let\do\empty + \xdef\MPxscale{#2}% + \xdef\MPyscale{#3}% + \xdef\MPxoffset{0}% + \xdef\MPyoffset{0}% + \xdef\MPyshift{0pt}% + \donefalse + \let\handleMPsequence\dohandleMPsequence + \message{[MP to PDF]}% was: [MP to PDF #1] but there is a (#1) anyway + \input#1\relax} + +\def\PDFMPformoffset + {\ifx\objectoffset\undefined0pt\else\objectoffset\fi} + +\chardef\blackoutMPgraphic0 % in ConTeXt 1 + +\def\finishMPgraphic + {\stopMPresources + \egroup + \setbox\scratchbox\vbox + {\forgetall + \hbox + {\PDFcode{q \MPxscale\space 0 0 \MPyscale\space \MPxoffset\space \MPyoffset\space cm}% + \ifcase\blackoutMPgraphic\or\PDFcode{0 g 0 G}\fi + \lower\MPyshift\box\scratchbox % unscaled shift + \PDFcode{Q}}}% + \ht\scratchbox\MPheight + \wd\scratchbox\MPwidth + \dp\scratchbox0pt\relax + \dopackageMPgraphic\scratchbox + \egroup + \endinput} + +%D Alternative for \PDFTEX. We cannot come up with something more contexy +%D because this module is also used in \LATEX. + +\def\dopackageMPgraphic#1% #1 = boxregister + {%\ifx\pdfxform\undefined + % \makeMPintoPDFobject0 % no pdftex at all + %\else\ifx\pdftexversion\undefined + % \makeMPintoPDFobject0 % no pdftex at all + %\else\ifnum\pdftexversion<14 + % \makeMPintoPDFobject0 % no resource support + %\else + % % keep the default value + %\fi\fi\fi + \ifcase\makeMPintoPDFobject\or\or\ifx\currentPDFresources\empty\else + % an existing value of 2 signals object support (set elsewhere) + \makeMPintoPDFobject1 + \fi\fi + \ifcase\makeMPintoPDFobject + \box#1% + \or + \scratchdimen\PDFMPformoffset\relax + \ifdim\scratchdimen>0pt % compensate for error + \setbox#1\vbox spread 2\scratchdimen + {\forgetall\vss\hbox spread 2\scratchdimen{\hss\box#1\hss}\vss}% + \fi + \setMPPDFobject{\currentPDFresources}{#1}% + \ifdim\scratchdimen>0pt % compensate for error + \vbox to \MPheight + {\forgetall\vss\hbox to \MPwidth{\hss\getMPPDFobject\hss}\vss}% + \else + \getMPPDFobject + \fi + \global\let\currentPDFresources\empty + \else + \box#1% + \fi} + +\def\setMPPDFobject#1#2% resources boxnumber + {\ifx\pdfxform\undefined + \def\getMPPDFobject{\box#2}% + \else\ifx\pdftexversion\undefined + \def\getMPPDFobject{\box#2}% + \else\ifnum\pdftexversion<14 + \def\getMPPDFobject{\box#2}% + \else + \ifx\everyPDFxform\undefined\else\the\everyPDFxform\fi + \immediate\pdfxform resources{#1}#2% + \edef\getMPPDFobject{\noexpand\pdfrefxform\the\pdflastxform}% + \fi\fi\fi} + +\let\getMPPDFobject\relax + +%D \macros +%D {deleteMPgraphic, +%D startMPresources, +%D stopMPresources} +%D +%D Here are a few hooks for \CONTEXT\ specific things. + +\ifx\deleteMPgraphic\undefined + \def\deleteMPgraphic#1{} +\fi + +\ifx\startMPresources\undefined + \let\startMPresources\relax + \let\stopMPresources\relax +\fi + +%D \macros +%D {twodigitMPoutput} +%D +%D We can limit the precision to two digits after the comma +%D by saying: +%D +%D \starttyping +%D \twodigitMPoutput +%D \stoptyping +%D +%D This option only works in \CONTEXT\ combined with \ETEX. + +\def\twodigitMPoutput + {\let\!MP \twodigitrounding + \def\!MPgMPs##1{\twodigitrounding{\gMPs##1}}% + \def\!MPgMPa##1{\twodigitrounding{\gMPa##1}}} + +\let\!MP \empty +\let\!MPgMPa\gMPa +\let\!MPgMPs\gMPs + +%D This kind of conversion is possible because \METAPOST\ +%D does all the calculations. Converting other \POSTSCRIPT\ +%D files would drive both me and \TEX\ crazy. + +\protect \endinput |