%D \module
%D   [       file=meta-pdf,
%D        version=2006.06.07,
%D          title=\CONTEXT\ Support Macros,
%D       subtitle=\METAPOST\ to \PDF\ conversion,
%D         author=Hans Hagen \& others (see text),
%D           date=\currentdate,
%D      copyright=\PRAGMA]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for
%C details.

%D Formerly known as supp-pdf.tex and supp-mpe.tex.

%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.)

% Beware, we cannot use 0pt here by defaukt since it may be
% defined in the range \dimen 0 - 20 which we happen to use
% as scratch registers; for this reason we start allocating
% scratch registers > 20

%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.

\writestatus{loading}{Context Support Macros / MPS to PDF}

\unprotect

\ifx\PDFcode   \undefined \let\PDFcode      \gobbleoneargument                \fi
\ifx\PDFcomment\undefined \def\PDFcomment#1{\PDFcode{\letterpercent\space#1}} \fi

%D First we define a handy constant:

\bgroup \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\dimexpr\wd\scratchbox-#3-#4\relax
     \vsize\dimexpr\ht\scratchbox-#5-#6\relax
     \setbox\scratchbox\vbox to \vsize
       {\vskip-#5\hbox to \hsize{\hskip-#3\box\scratchbox\hss}}%
     \pdfxform\scratchbox
     \pdfrefxform\pdflastxform
     \egroup}

\fi \fi

%D \macros
%D   {convertMPtoPDF}
%D
%D The next set of macros implements \METAPOST\ to \PDF\
%D conversion. The traditional method is in the MkII file.

%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 \chardef\makeMPintoPDFobject   \zerocount \fi
\ifx\blackoutMPgraphic     \undefined \chardef\blackoutMPgraphic     \plusone   \fi
\ifx\everyMPtoPDFconversion\undefined \newtoks\everyMPtoPDFconversion           \fi

\let\lastPDFMPobject    \!!zerocount
\let\currentPDFresources\empty
\let\setMPextensions    \relax

\def\PDFMPformoffset
  {\ifx\objectoffset\undefined\zeropoint\else\objectoffset\fi}

\def\resetMPvariables#1#2#3%
  {\global\let\MPwidth \!!zeropoint
   \global\let\MPheight\!!zeropoint
   \global\let\MPllx   \!!zerocount
   \global\let\MPlly   \!!zerocount
   \global\let\MPurx   \!!zerocount
   \global\let\MPury   \!!zerocount
   \xdef\MPxscale      {#2}\ifx\MPxscale\empty\let\MPxscale\!!plusone\fi
   \xdef\MPyscale      {#3}\ifx\MPyscale\empty\let\MPyscale\!!plusone\fi
   \xdef\MPfilename    {#1}}

%D The main macro:

\def\convertMPtoPDF#1#2#3%
  {\resetMPvariables{#1}{#2}{#3}%
   \mkconvertMPtoPDF}

\def\processMPtoPDFfile#1#2#3% obsolete
  {\resetMPvariables{#1}{#2}{#3}%
   \mkprocessMPtoPDFfile}

%D A common hook.

\let\MPfshowcommand\empty

%D Objects.

\def\dopackageMPgraphic#1% #1 = boxregister
  {\ifcase\makeMPintoPDFobject\or\or\ifx\currentPDFresources\empty\else
     % an existing value of 2 signals object support (set elsewhere)
     \chardef\makeMPintoPDFobject\plusone
   \fi\fi
   \ifcase\makeMPintoPDFobject
     \box#1%
   \or
     \scratchdimen\PDFMPformoffset\relax
     \ifdim\scratchdimen>\zeropoint % 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>\zeropoint % 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}

\ifx\deleteMPgraphic\undefined
  \def\deleteMPgraphic#1{}
\fi

\ifx\startMPresources\undefined
  \let\startMPresources\relax
  \let\stopMPresources\relax
\fi

%D We implement extensions by using the \METAPOST\ special
%D mechanism. Opposite to \TEX's specials, the \METAPOST\ ones
%D are flushed before or after the graphic data, but thereby
%D are no longer connected to a position.
%D
%D We implement specials by overloading the \type {fill}
%D operator. By counting the fills, we can let the converter
%D treat the appropriate fill in a special way. The
%D specification of the speciality can have two forms,
%D determined by the setting of a boolean variable:
%D
%D \starttyping
%D _inline_specials_ := false ; % comment like code (default)
%D _inline_specials_ := true  ; % command like code
%D \stoptyping
%D
%D When the specification is embedded as comment, it looks
%D like:
%D
%D \starttyping
%D %%MetaPostSpecial <size> <data> <number> <identifier>
%D \stoptyping
%D
%D The in||line alternative is more tuned for \POSTSCRIPT,
%D since it permits us to define a macro \type {special}.
%D
%D \starttyping
%D inline  : <data> <number> <identifier> <size> special
%D \stoptyping
%D
%D The \type {identifier} determines what to do, and the data
%D can be used to accomplish this. A type~2 shading function
%D has identifier~2. Alltogether, the number of parameters is
%D specified in \type {size}. The \type {number} is the number
%D of the fill that needs the special treatment. For a type~2
%D and~3 shaded fill, the datablock contains the following

%D data:
%D
%D \starttyping
%D from to n inner_r g b x y        outer_r g b x y
%D from to n inner_r g b x y radius outer_r g b x y radius
%D \stoptyping

\newconditional\manyMPspecials \settrue\manyMPspecials

%D In case of \PDF, we need to prepare resourcs.

\newtoks\MPstartresources
\newtoks\MPstopresources

\def\startMPresources
  {\the\MPstartresources}

\def\stopMPresources
  {\the\MPstopresources}

%D Some day we may consider collecting local resources.

\appendtoks
  \global\let\currentPDFresources\empty % kind of redundant
\to \MPstartresources

% \appendtoks
%    \collectPDFresources
%    \global\let\currentPDFresources\collectedPDFresources
% \to \MPstopresources

\appendtoksonce
   \the\everyPDFxform
\to \MPstopresources

%D Since colors are not subjected to transformations, we can
%D only use colors as signal. In our case, we use a dummy colored
%D path with a red color component of \type {0.n}, so \type
%D {0.001} is the first path and \type {0.010} the tenth. Since
%D \METAPOST strips trailing zeros, we have to padd the string.

\newif\ifMPcmykcolors
\newif\ifMPspotcolors

\def\dohandleMPrgb   #1#2#3{\revokeMPtransparencyspecial\execcolorR   #1:#2:#3:0:0\od}
\def\dohandleMPcmyk#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
\def\dohandleMPgray      #1{\revokeMPtransparencyspecial\execcolorS         #1:0:0\od}
\def\dohandleMPspot#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}

%D Specials:

\settrue \manyMPspecials \newcount\nofMParguments \let\extraMPpathcode\empty

\def\@@MP  {@@MP}
\def\@@MPSK{@MPSK@}

\def\MPspecial{\@@MPSK\@@MPSK\gMPs\nofMParguments}

\def\defineMPspecial#1#2%
  {\setvalue{\@@MPSK\@@MPSK#1}{#2}}

%D Special number~1 is dedicated to \CMYK\ support. If you
%D want to know why: look at this:
%D
%D \startbuffer[mp]
%D   fill fullcircle xyscaled (3cm,1cm) withcolor \MPcolor{test} ;
%D \stopbuffer
%D
%D \startbuffer[cmyk]
%D \startcombination[4*1]
%D   {\definecolor[test][c=1,y=.3,k=.3] \processMPbuffer[mp]} {c=1 y=.3 k=.3}
%D   {\definecolor[test][c=.9,y=.15]    \processMPbuffer[mp]} {c=.9 y=.15}
%D   {\definecolor[test][c=.25,y=.8]    \processMPbuffer[mp]} {c=.25 y=.8}
%D   {\definecolor[test][c=.45,y=.1]    \processMPbuffer[mp]} {c=.45 y=.1}
%D \stopcombination
%D \stopbuffer
%D
%D \placefigure
%D   {\CMYK\ support disabled,
%D    conversion to \RGB.}
%D   {\setupcolors[cmyk=nee,state=start]\getbuffer[cmyk]}
%D
%D \placefigure
%D   {\CMYK\ support enabled,
%D    no support in \METAPOST.}
%D   {\setupcolors[cmyk=ja,mpcmyk=nee,state=start]\getbuffer[cmyk]}
%D
%D \placefigure
%D   {\CMYK\ support enabled,
%D    no conversion to \RGB,
%D    support in \METAPOST}
%D   {\setupcolors[cmyk=ja,state=start]\getbuffer[cmyk]}

\defineMPspecial{1}
  {\ifMPcmykcolors
     \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPcmykcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
   \fi}

\defineMPspecial{2}
  {\ifMPspotcolors
     \setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPspotcolor{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}}%
%      \checkMPspot{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}%
   \fi}

% \def\checkMPspot#1#2#3#4%
%   {\expanded{\resolveMPspotcolor#1 #2 #3 #4}\end
%    \ifx\MPspotspace\MPresolvedspace
%      \edef\MPspotspacespec{/\MPspotspace\space}%
%      \doifinstringelse\MPspotspacespec\currentMPcolorspaces
%        \donothing\registerMPcolorspace
%    \fi}

\let\revokeMPtransparencyspecial\relax

\def\dohandleMPrgbcolor   #1#2#3{\revokeMPtransparencyspecial\execcolorR   #1:#2:#3:0:0\od}
\def\dohandleMPcmykcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorC#1:#2:#3:#4:0:0\od}
\def\dohandleMPgraycolor      #1{\revokeMPtransparencyspecial\execcolorS         #1:0:0\od}
\def\dohandleMPspotcolor#1#2#3#4{\revokeMPtransparencyspecial\execcolorP#1:#2:#3:#4:0:0\od}

%D Transparency support used specials 60 (rgb) and 61
%D (cmyk).
%D
%D \startbufferFshade

%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
%D
%D fill p rotated  90 withcolor transparent(1,.5,yellow) ;
%D fill p rotated 210 withcolor transparent(1,.5,green) ;
%D fill p rotated 330 withcolor transparent(1,.5,blue) ;
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlinecorrection \processMPbuffer \stoplinecorrection
%D
%D One can also communicate colors between \CONTEXT\ and
%D \METAPOST:
%D
%D \startbuffer
%D \definecolor[tcyan]   [c=1,k=.2,t=.5]
%D \definecolor[tmagenta][m=1,k=.2,t=.5]
%D \definecolor[tyellow] [y=1,k=.2,t=.5]
%D \stopbuffer
%D
%D \typebuffer \getbuffer
%D
%D \startbuffer
%D u := 2cm ; path p ; p := fullcircle scaled u shifted (u/4,0);
%D
%D fill p rotated  90 withcolor \MPcolor{tcyan} ;
%D fill p rotated 210 withcolor \MPcolor{tmagenta} ;
%D fill p rotated 330 withcolor \MPcolor{tyellow} ;
%D \stopbuffer
%D
%D \startlinecorrection \processMPbuffer \stoplinecorrection
%D
%D We save all the three components needed in one macro,
%D just to save hash space.

\def\dohandleMPrgbtransparency   #1#2#3#4#5{\execcolorR   #1:#2:#3:#4:#5\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
\def\dohandleMPcmyktransparency#1#2#3#4#5#6{\execcolorC#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
\def\dohandleMPgraytransparency      #1#2#3{\execcolorS         #1:#2:#3\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}
\def\dohandleMPspottransparency#1#2#3#4#5#6{\execcolorP#1:#2:#3:#4:#5:#6\od\let\revokeMPtransparencyspecial\dorevokeMPtransparencyspecial}

\def\dorevokeMPtransparencyspecial
  {\PDFcode{\PDFtransparencyresetidentifier\space gs}%
   \let\revokeMPtransparencyspecial\relax}

\defineMPspecial{3} % rgb
  {\setxvalue{\@@MPSK\gMPs6}{\noexpand\dohandleMPrgbtransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs1}{\gMPs2}}}

\defineMPspecial{4} % cmyk
  {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPcmyktransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}}

\defineMPspecial{5} % spot
  {\setxvalue{\@@MPSK\gMPs7}{\noexpand\dohandleMPspottransparency{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs1}{\gMPs2}}%
   }%\checkMPspot{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}

%D Shading is an example of a more advanced graphic feature,
%D but users will seldom encounter those complications. Here
%D we only show a few simple examples, but many other
%D alternatives are possible by setting up the functions built
%D in \PDF\ in the appropriate way.
%D
%D Shading has to do with interpolation between two or more
%D points or user supplied ranges. In \PDF, the specifications
%D of a shade has to be encapsulated in objects and passed on
%D as resources. This is a \PDF\ level 1.3. feature. One can
%D simulate three dimensional shades as well and define simple
%D functions using a limited set of \POSTSCRIPT\ primitives.
%D Given the power of \METAPOST\ and these \PDF\ features, we
%D can achieve superb graphic effects.
%D
%D Since everything is hidden in \TEX\ and \METAPOST\ graphics,
%D we can stick to high level \CONTEXT\ command, as shown in
%D the following exmples.
%D
%D \startbuffer
%D \startuniqueMPgraphic{CircularShade}
%D   path  p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
%D   circular_shade(p,0,.2red,.9red) ;
%D \stopuniqueMPgraphic
%D
%D \startuniqueMPgraphic{LinearShade}
%D   path  p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
%D   linear_shade(p,0,.2blue,.9blue) ;
%D \stopuniqueMPgraphic
%D
%D \startuniqueMPgraphic{DuotoneShade}
%D   path  p ; p := unitsquare xscaled \overlaywidth yscaled \overlayheight ;
%D   linear_shade(p,2,.5green,.5red) ;
%D \stopuniqueMPgraphic
%D \stopbuffer
%D
%D \typebuffer
%D
%D \getbuffer
%D
%D These graphics can be hooked into the overlay mechanism,
%D which is available in many commands.
%D
%D \startbuffer
%D \defineoverlay[demo 1][\uniqueMPgraphic{CircularShade}]
%D \defineoverlay[demo 2][\uniqueMPgraphic  {LinearShade}]
%D \defineoverlay[demo 3][\uniqueMPgraphic {DuotoneShade}]
%D \stopbuffer
%D
%D \typebuffer
%D
%D \getbuffer
%D
%D These backgrounds can for instance be applied to \type
%D {\framed}:
%D
%D \startbuffer
%D \setupframed[width=3cm,height=2cm,frame=off]
%D \startcombination[3*1]
%D   {\framed[backgroundachtergrond=demo 1]{\bfd \white Demo 1}} {}
%D   {\framed[backgroundachtergrond=demo 2]{\bfd \white Demo 2}} {}
%D   {\framed[backgroundachtergrond=demo 3]{\bfd \white Demo 3}} {}
%D \stopcombination
%D \stopbuffer
%D
%D \typebuffer
%D
%D \startlinecorrection
%D \getbuffer
%D \stoplinecorrection
%D
%D There are a few more alternatives, determined by the second
%D parameter passed to \type {circular_shade} and alike.
%D
%D \def\SomeShade#1#2#3#4#5%
%D   {\startuniqueMPgraphic{Shade-#1}
%D      width := \overlaywidth ;
%D      height := \overlayheight ;
%D      path p ; p := unitsquare xscaled width yscaled height ;
%D      #2_shade(p,#3,#4,#5) ;
%D    \stopuniqueMPgraphic
%D    \defineoverlay[Shade-#1][\uniqueMPgraphic{Shade-#1}]%
%D    \framed[backgroundachtergrond=Shade-#1,width=2cm,height=2cm,frame=off]{}}
%D
%D \startlinecorrection
%D \startcombination[5*1]
%D   {\SomeShade{10}{circular}{0}{.3blue}{.9blue}} {circular 0}
%D   {\SomeShade{11}{circular}{1}{.3blue}{.9blue}} {circular 1}
%D   {\SomeShade{12}{circular}{2}{.3blue}{.9blue}} {circular 2}
%D   {\SomeShade{13}{circular}{3}{.3blue}{.9blue}} {circular 3}
%D   {\SomeShade{14}{circular}{4}{.3blue}{.9blue}} {circular 4}
%D \stopcombination
%D \stoplinecorrection
%D
%D \blank
%D
%D \startlinecorrection
%D \startcombination[5*1]
%D   {\SomeShade{20}{circular}{0}{.9green}{.3green}} {circular 0}
%D   {\SomeShade{21}{circular}{1}{.9green}{.3green}} {circular 1}
%D   {\SomeShade{22}{circular}{2}{.9green}{.3green}} {circular 2}
%D   {\SomeShade{23}{circular}{3}{.9green}{.3green}} {circular 3}
%D   {\SomeShade{24}{circular}{4}{.9green}{.3green}} {circular 4}
%D \stopcombination
%D \stoplinecorrection
%D
%D \blank
%D
%D \startlinecorrection
%D \startcombination[4*1]
%D   {\SomeShade{30}{linear}{0}{.3red}{.9red}} {linear 0}
%D   {\SomeShade{31}{linear}{1}{.3red}{.9red}} {linear 1}
%D   {\SomeShade{32}{linear}{2}{.3red}{.9red}} {linear 2}
%D   {\SomeShade{33}{linear}{3}{.3red}{.9red}} {linear 3}
%D \stopcombination
%D \stoplinecorrection
%D
%D These macros closely cooperate with the \METAPOST\ module
%D \type {mp-spec.mp}, which is part of the \CONTEXT\
%D distribution.
%D
%D The low level (\PDF) implementation is based on the \TEX\
%D based \METAPOST\ to \PDF\ converter. Shading is supported
%D by overloading the \type {fill} operator as implemented
%D earlier. In \PDF\ type~2 and~3 shading functions are
%D specified in terms of:
%D
%D \starttabulate[|Tl|l|]
%D \NC /Domain \NC sort of meeting range \NC \NR
%D \NC /C0     \NC inner shade \NC \NR
%D \NC /C1     \NC outer shade \NC \NR
%D \NC /N      \NC smaller values, bigger inner circles \NC \NR
%D \stoptabulate

\newcount\currentPDFshade  % 0  % global (document wide) counter

\def\dosetMPlinearshade#1%
  {\immediate\pdfobj
     {<</FunctionType 2
        /Domain [\gMPs1 \gMPs2]
        /C0 [\MPshadeA]
        /C1 [\MPshadeB]
        /N \gMPs3>>}%
   \immediate\pdfobj
     {<</ShadingType 2
        /ColorSpace /\MPresolvedspace
        /Function \the\pdflastobj\space 0 R
        /Coords [\MPshadeC]
        /Extend [true true]>>}%
   \global\advance\currentPDFshade \plusone
   \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\the\pdflastobj\space0 R }%
   \setxvalue{\@@MPSK#1}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}

\defineMPspecial{30}
  {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
   \expanded{\resolveMPrgbcolor{\gMPs{9}}{\gMPs{10}}{\gMPs{11}}}\to\MPshadeB
   \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs{12} \gMPs{13}}%
   \dosetMPlinearshade{\gMPs{14}}}

\defineMPspecial{32}
  {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
   \expanded{\resolveMPcmykcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
   \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
   \dosetMPlinearshade{\gMPs{16}}}

\defineMPspecial{34}
  {\expanded{\resolveMPspotcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
   \expanded{\resolveMPspotcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}}\to\MPshadeB
   \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{14} \gMPs{15}}%
   \dosetMPlinearshade{\gMPs{16}}}

\def\dosetMPcircularshade#1%
  {\immediate\pdfobj
     {<</FunctionType 2
        /Domain [\gMPs1 \gMPs2]
        /C0 [\MPshadeA]
        /C1 [\MPshadeB]
        /N \gMPs3>>}%
   \immediate\pdfobj
     {<</ShadingType 3
        /ColorSpace /\MPresolvedspace
        /Function \the\pdflastobj\space 0 R
        /Coords [\MPshadeC]
        /Extend [true true]>>}%
   \global\advance\currentPDFshade \plusone
   \appendtoPDFdocumentshades{/Sh\the\currentPDFshade\space\the\pdflastobj\space0 R }%
   \setxvalue{\@@MPSK#1}{\noexpand\dohandleMPshade{\the\currentPDFshade}}}

\defineMPspecial{31}
  {\expanded{\resolveMPrgbcolor{\gMPs4}{\gMPs5}{\gMPs6}}\to\MPshadeA
   \expanded{\resolveMPrgbcolor{\gMPs{10}}{\gMPs{11}}{\gMPs{12}}}\to\MPshadeB
   \edef\MPshadeC{\gMPs7 \gMPs8 \gMPs9 \gMPs{13} \gMPs{14} \gMPs{15}}%
   \dosetMPcircularshade{\gMPs{16}}}

\defineMPspecial{33}
  {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
   \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
   \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
   \dosetMPcircularshade{\gMPs{18}}}

\defineMPspecial{35}
  {\expanded{\resolveMPcmykcolor{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}}\to\MPshadeA
   \expanded{\resolveMPcmykcolor{\gMPs{11}}{\gMPs{12}}{\gMPs{13}}{\gMPs{14}}}\to\MPshadeB
   \edef\MPshadeC{\gMPs8 \gMPs9 \gMPs{10} \gMPs{15} \gMPs{16} \gMPs{17}}%
   \dosetMPcircularshade{\gMPs{18}}}

\newconditional\ignoreMPpath

\def\dohandleMPshade#1%
  {\revokeMPtransparencyspecial
   \settrue\ignoreMPpath
   \def\extraMPpathcode{/Sh#1 sh Q}%
   \chardef\finiMPpath\zerocount
   \PDFcode{q /Pattern cs}}

%D Figure inclusion is kind of strange to \METAPOST, but when
%D Santiago Muelas started discussing this with me, I was able
%D to cook up a solution using specials.

\defineMPspecial{10}
  {\setxvalue{\@@MPSK\gMPs8}%
     {\noexpand\handleMPfigurespecial{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}{\gMPs7}{\gMPs8}}}

\def\handleMPfigurespecial#1#2#3#4#5#6#7#8% todo : combine with ext fig
  {\global\letvalue{\@@MPSK#8}\empty
   \vbox to \zeropoint
     {\vss
      \hbox to \zeropoint
        {\ifcase\pdfoutput\or % will be hooked into the special driver
           \doiffileelse{#7}
             {\doifundefinedelse{mps:x:#7}
                {\immediate\pdfximage\!!width\onebasepoint\!!height\onebasepoint{#7}%
                 \setxvalue{mps:x:#7}{\pdfrefximage\the\pdflastximage}}%
                {\message{[reusing figure #7]}}%
              \PDFcode{q #1 #2 #3 #4 #5 #6 cm}%
              \rlap{\getvalue{mps:x:#7}}%
              \PDFcode{Q}}
             {\message{[unknown figure #7]}}%
         \fi
         \hss}}}

%D An example of using both special features is the
%D following.
%D
%D \starttyping
%D \startMPpage
%D   externalfigure "hakker1b.png" scaled 22cm rotated  10 shifted (-2cm,0cm);
%D   externalfigure "hakker1b.png" scaled 10cm rotated -10 ;
%D   externalfigure "hakker1b.png" scaled  7cm rotated  45 shifted (8cm,12cm) ;
%D   path p ; p := unitcircle xscaled 15cm yscaled 20cm;
%D   path q ; q := p rotatedaround(center p,90) ;
%D   path r ; r := buildcycle(p,q) ; clip currentpicture to r ;
%D   path s ; s := boundingbox currentpicture enlarged 5mm ;
%D   picture c ; c := currentpicture ; currentpicture := nullpicture ;
%D   circular_shade(s,0,.2red,.9red) ;
%D   addto currentpicture also c ;
%D \stopMPpage
%D \stoptyping

%D This is some experimental hyperlink driver that I wrote
%D for Mark Wicks.

\defineMPspecial{20}
  {\setxvalue{\@@MPSK\gMPs6}%
     {\noexpand\handleMPhyperlink{\gMPs1}{\gMPs2}{\gMPs3}{\gMPs4}{\gMPs5}{\gMPs6}}}

\def\handleMPhyperlink#1#2#3#4#5#6%
  {\global\letvalue{\@@MPSK#6}\empty
   \setbox\scratchbox\hbox
     {\setbox\scratchbox\null
      \wd\scratchbox\dimexpr-#1\onebasepoint+#3\onebasepoint\relax
      \ht\scratchbox\dimexpr-#2\onebasepoint+#4\onebasepoint\relax
      \incolorfalse
      \gotobox{\box\scratchbox}[#5]}%
   \setbox\scratchbox\hbox
     {\hskip\dimexpr\MPxoffset\onebasepoint+#1\onebasepoint\relax
      \raise\dimexpr\MPyoffset\onebasepoint+#2\onebasepoint\relax
      \box\scratchbox}%
   \smashbox\scratchbox
   \box\scratchbox}

%D This special (number 50) passes positions to a tex file.
%D This method uses a two||pass approach an (mis|)|used the
%D context positioning macros. In \type {core-pos} we will
%D implement the low level submacro needed.
%D
%D \startbuffer
%D \definelayer[test]
%D
%D \setlayer
%D   [test]
%D   [x=\MPx{somepos-1},y=\MPy{somepos-1}]
%D   {Whatever we want here!}
%D
%D \setlayer
%D   [test]
%D   [x=\MPx{somepos-2},y=\MPy{somepos-2}]
%D   {Whatever we need there!}
%D
%D \startuseMPgraphic{oeps}
%D   draw fullcircle scaled 6cm withcolor red ;
%D   register ("somepos-1",1cm,2cm,center currentpicture) ;
%D   register ("somepos-2",4cm,3cm,(-1cm,-2cm)) ;
%D \stopuseMPgraphic
%D
%D \framed[background=test,offset=overlay]{\useMPgraphic{oeps}}
%D \stopbuffer
%D
%D \typebuffer
%D
%D Here the width and height are not realy used, but one can
%D imagine situations where tex has to work with values
%D calculated by \METAPOST.
%D
%D \startlinecorrection
%D \getbuffer
%D \stoplinecorrection
%D
%D Later we will implement a more convenient macro:
%D
%D \starttyping
%D \setMPlayer [test] [somepos-1] {Whatever we want here!}
%D \setMPlayer [test] [somepos-2] {Whatever we need there!}
%D \stoptyping

\defineMPspecial{50} % x y width height label
  {\dosavepositionwhd
     {\gMPs5}%
     {0}%
     {\the\dimexpr-\MPllx\onebasepoint+\gMPs1\onebasepoint\relax}
     {\the\dimexpr\gMPs2\onebasepoint-\scratchdimen+\MPury\onebasepoint\relax}%
     {\the\dimexpr\gMPs3\onebasepoint\relax}%
     {\the\dimexpr\gMPs4\onebasepoint\relax}%
     {0pt}}

%D A few auxiliary macros. This will move to colo-ini.

\def\MPgrayspace{DeviceGray}
\def\MPrgbspace {DeviceRGB}
\def\MPcmykspace{DeviceCMYK}
\let\MPspotspace\MPgrayspace

\def\MPcmykBlack{0 0 0 0}
\def\MPcmykWhite{0 0 0 1}

\def\startMPcolorresolve
  {\bgroup
   \def\dostartgraycolormode##1%
     {\global\let\MPresolvedspace\MPgrayspace
      \xdef\MPresolvedcolor{##1}}%
   \def\dostartrgbcolormode ##1##2##3%
     {\global\let\MPresolvedspace\MPrgbspace
      \xdef\MPresolvedcolor{##1 ##2 ##3}}%
   \def\dostartcmykcolormode##1##2##3##4%
     {\global\let\MPresolvedspace\MPcmykspace
      \xdef\MPresolvedcolor{##1 ##2 ##3 ##4}}%
   \def\dostartspotcolormode##1##2%
     {\global\let\MPspotspace\empty
      \xdef\MPresolvedspace{##1}%
      \xdef\MPresolvedcolor{##2}%
      \global\let\MPspotspace\MPresolvedspace}% signal
   \dostartgraycolormode\!!zerocount} % kind of hackery initialization

\let\stopMPcolorresolve\egroup

\def\resolveMPrgbcolor#1#2#3\to#4%
  {\startMPcolorresolve
   \execcolorR#1:#2:#3:0:0\od
   \stopMPcolorresolve
   \let#4\MPresolvedcolor}

\def\resolveMPcmykcolor#1#2#3#4\to#5%
  {\startMPcolorresolve
   \execcolorC#1:#2:#3:#4:0:0\od
   \stopMPcolorresolve
   \let#5\MPresolvedcolor}

\def\resolveMPgraycolor#1\end\to#2%
  {\startMPcolorresolve
   \execcolorS#1:0:0\od
   \stopMPcolorresolve
   \let#2\MPresolvedcolor}

\def\resolveMPspotcolor#1#2#3#4\end\to#5%
  {\startMPcolorresolve
   \ifnum#2>\plusone
     \checkmultitonecolor{#1}%
   \fi
   \execcolorP#1:#2:#3:#4:0:0\od
   \stopMPcolorresolve
   \let#5\MPresolvedcolor}

%D \macros
%D   {dogetPDFmediabox}
%D
%D The next macro can be used to find the mediabox of a \PDF\
%D illustration.
%D
%D \starttyping
%D \dogetPDFmediabox
%D   {filename}
%D   {new dimen}{new dimen}{new dimen}{new dimen}
%D \stoptyping
%D
%D Beware of dimen clashes: this macro uses the 5~default
%D scratch registers! When no file or mediabox is found, the
%D dimensions are zeroed.

\def\dogetPDFmediabox#1#2#3#4#5%
  {\bgroup
   \def\PDFxscale{1}%
   \def\PDFyscale{1}%
   \uncatcodespecials
   \endlinechar\minusone
   \def\checkPDFtypepage##1/Type /Page##2##3\done%
     {\ifx##2\relax
      \else\if##2s% accept /Page and /Pages
        \let\doprocessPDFline\findPDFmediabox
      \else
        \let\doprocessPDFline\findPDFmediabox
      \fi\fi}%
   \def\findPDFtypepage
     {\expandafter\checkPDFtypepage\fileline/Type /Page\relax\done}%
   \def\checkPDFmediabox##1/MediaBox##2##3\done%
     {\ifx##2\relax \else
        \setPDFmediabox##2##3\done
        \fileprocessedtrue
      \fi}%
   \def\findPDFmediabox
     {\expandafter\checkPDFmediabox\fileline/MediaBox\relax\done}%
   \let\doprocessPDFline\findPDFtypepage
   \doprocessfile\scratchread{#1}\doprocessPDFline
   \egroup
   \ifx\PDFxoffset\undefined
     #2=\zeropoint
     #3=\zeropoint
     #4=\zeropoint
     #5=\zeropoint
   \else
     #2=\PDFxoffset\onebasepoint
     #3=\PDFyoffset\onebasepoint
     #4=\PDFwidth
     #5=\PDFheight
   \fi}

\def\setPDFboundingbox#1#2#3#4#5#6%
  {\dimen0=#1\dimen0=#5\dimen0
   \ScaledPointsToBigPoints{\number\dimen0}\PDFxoffset
   \dimen0=#3\dimen0=#5\dimen0
   \xdef\PDFwidth{\the\dimen0}%
   \dimen0=#2\dimen0=#6\dimen0
   \ScaledPointsToBigPoints{\number\dimen0}\PDFyoffset
   \dimen0=#4\dimen0=#6\dimen0
   \xdef\PDFheight{\the\dimen0}%
   \global\let\PDFxoffset\PDFxoffset
   \global\let\PDFyoffset\PDFyoffset}

\def\setPDFmediabox#1[#2 #3 #4 #5]#6\done
  {\dimen2=#2\onebasepoint\dimen2=-\dimen2 % \dimen2=-#2\onebasepoint also works since tex handles --
   \dimen4=#3\onebasepoint\dimen4=-\dimen4 % \dimen4=-#3\onebasepoint also works since tex handles --
   \dimen6=#4\onebasepoint\advance\dimen6 \dimen2
   \dimen8=#5\onebasepoint\advance\dimen8 \dimen4
   \setPDFboundingbox{\dimen2}{\dimen4}{\dimen6}{\dimen8}\PDFxscale\PDFyscale}

%D End of soon obsolete code.

%D The plugins:

\startMPinitializations
  mp_shade_version := 2 ;
\stopMPinitializations

\loadmarkfile{meta-pdf}

%D Test code:

% \startMPcode
%     fill fullcircle scaled 3cm withcolor red ;
%     fill fullcircle scaled 2cm withcolor green ;
%     fill fullcircle scaled 1cm withcolor blue ;
%     currentpicture := currentpicture shifted (-4cm,0) ;
%     fill fullcircle scaled 3cm withcolor cmyk(0,0,1,0) ;
%     fill fullcircle scaled 2cm withcolor cmyk(0,1,0,0) ;
%     fill fullcircle scaled 1cm withcolor cmyk(0,0,1,0) ;
%     currentpicture := currentpicture shifted (-4cm,0) ;
%     draw fullcircle scaled 3cm dashed evenly ;
%     draw fullcircle scaled 2cm dashed withdots  ;
%     draw origin withpen pencircle scaled 3mm;
%     currentpicture := currentpicture shifted (-4cm,0) ;
%     fill fullcircle scaled 2cm shifted (-.5cm,+.5cm) withcolor transparent(1,.5,red);
%     fill fullcircle scaled 2cm shifted (-.5cm,-.5cm) withcolor transparent(1,.5,red);
%     fill fullcircle scaled 2cm shifted (+.5cm,+.5cm) withcolor transparent(1,.5,green);
%     fill fullcircle scaled 2cm shifted (+.5cm,-.5cm) withcolor transparent(1,.5,cmyk(1,0,1,.5));
%     currentpicture := currentpicture shifted (12cm,-4cm) ;
%     draw "o e p s" infont defaultfont scaled 2 shifted (-1cm,0) ;
%     currentpicture := currentpicture shifted (-4cm,0) ;
%     % bug: shift
%     draw fullcircle scaled 3cm withpen pencircle yscaled 3mm xscaled 2mm rotated 30  ;
%     draw fullcircle scaled 2cm withpen pencircle yscaled 3mm xscaled 2mm rotated 20 withcolor red ;
%     filldraw fullcircle scaled 1cm withpen pencircle yscaled 3mm xscaled 2mm rotated 10 withcolor green ;
%     currentpicture := currentpicture shifted (-4cm,0) ;
%     % shade cannot handle shift
%     circular_shade(fullcircle scaled 3cm,0,.2red,.9green) ;
%     circular_shade(fullcircle scaled 3cm shifted(+4cm,0),0,cmyk(1,0,0,0),cmyk(0,1,0,0)) ;
%     filldraw boundingbox currentpicture enlarged -3cm withpen pencircle scaled 1pt withcolor .5white ;
% \stopMPcode

\protect \endinput
