%D \module
%D   [       file=core-obj,
%D        version=1998.01.15,
%D          title=\CONTEXT\ Core Macros,
%D       subtitle=Object Handling, 
%D         author=Hans Hagen,
%D           date=\currentdate,
%D      copyright={PRAGMA / Hans Hagen \& Ton Otten}]
%C
%C This module is part of the \CONTEXT\ macro||package and is
%C therefore copyrighted by \PRAGMA. See mreadme.pdf for 
%C details. 

\writestatus{loading}{Context Core Macros / Object Handling}

\unprotect

\startmessages  dutch  library: references
     30: onbekend object --
     31: dubbel object --
\stopmessages

\startmessages  english  library: references
     30: unknown object --
     31: duplicate object --
\stopmessages

\startmessages  german  library: references
     30: unbekanntes Object --
     31: doppeltes Object --
\stopmessages

\startmessages  czech  library: references
     30: neznamy objekt --
     31: duplicitni object --
\stopmessages

\startmessages  italian  library: references
     30: oggetto sconosciuto --
     31: oggetto duplicato --
\stopmessages

\startmessages  norwegian  library: references
     30: ukjent objekt --
     31: duplikat objekt --
\stopmessages

\startmessages  romanian  library: references
     30: obiect necunoscut --
     31: obiect duplicat --
\stopmessages

%D \macros 
%D   {setobject,getobject,ifinobject}
%D
%D Boxes can be considered reuable objects. Unfortunaltely once
%D passed to the \DVI\ file, such objects cannot be reused. In
%D \PDF\ however, reusing is possible and sometimes even a
%D necessity. Therefore, \CONTEXT\ supports reusable objects. 
%D 
%D During the \TEX\ processing run, boxes can serve the purpose
%D of objects, and the \DVI\ driver module implements objects
%D using packed boxes. 
%D 
%D The \PDF\ and \PDFTEX\ driver modules implement objects
%D using \PDF\ forms. There is no (real) restriction on the
%D number of objects there. 
%D 
%D The first application of objects in \CONTEXT\ concerned
%D \METAPOST\ graphics and fill||in form fields. The first
%D application can save lots of bytes, while the latter use is
%D more a necessity than byte saving. 
%D 
%D \starttypen
%D \setobject{class}{name}\somebox{}
%D \getobject{class}{name}
%D \stoptypen
%D 
%D Here \type{\somebox} can be whatever box specification suits
%D \TEX. We save the dimensions of an object, although some
%D drivers will do so themselves. This means that when for
%D instance using \PDFTEX\ we could save a hash entry plus some
%D 20+ memory locations per object by delegating this
%D housekeeping to the driver. The current approach permits 
%D us to keep the box characteristic too. 

\newif\ifinobject

\def\presetobject#1#2%
  {\doifundefined{\r!object#1::#2}
     {\setxvalue{\r!object#1::#2}{NOT YET FLUSHED}}}

\def\dosetobject#1#2#3% evt \initializepaper naar \everyshipout
  {\initializepaper
   \ifundefined{\r!object#2::#3}%
     \expandafter\dodosetobject
   \else
     \expandafter\gobblefivearguments
   \fi
   {#1}{#2}{#3}}

%D Somehow there is a rounding error problem in either \PDFTEX\
%D or in viewers, or maybe it is conforming the specs. The next
%D variable compensate for it by removing the rather tight
%D clip. 

\def\objectoffset{1cm}

% \def\dodosetobject#1#2#3%   
%  {\bgroup
%   \inobjecttrue
%   \dowithnextbox       
%     {\bgroup
%      \dontshowcomposition % rather fuzzy in \setxvalue ... \hbox
%      \setxvalue{\r!object#2::#3}% 
%        {\noexpand\dohandleobject{#2}{#3} 
%           {\ifhbox\nextbox\hbox\else\vbox\fi}
%          %{\the\wd\nextbox}{\the\ht\nextbox}{\the\dp\nextbox}}%
%           {\number\wd\nextbox}{\number\ht\nextbox}{\number\dp\nextbox}}%
%      \expanded % fix the dimensions since \dostartobject may use \nextbox
%        {\dostartobject
%           {#2}{#3}
%           {\number\wd\nextbox}{\number\ht\nextbox}{\number\dp\nextbox}}%
%      \ifcase#1\relax\else\ifdim\objectoffset>\!!zeropoint\relax
%        \scratchdimen=\objectoffset
%        \edef\next%
%          {\wd\nextbox\the\wd\nextbox
%           \ht\nextbox\the\ht\nextbox
%           \dp\nextbox\the\dp\nextbox}%
%        \setbox\nextbox=\vbox spread 2\scratchdimen
%          {\forgetall
%           \vss
%           \hbox spread 2\scratchdimen{\hss\box\nextbox\hss}%
%           \vss}%
%        \setbox\nextbox=\hbox
%          {\hskip-\scratchdimen\lower\scratchdimen\box\nextbox}% 
%        \next
%      \fi\fi
%      \box\nextbox
%      \dostopobject
%      \egroup
%      \egroup}}

\def\dodosetobject#1#2#3%   
  {\bgroup
   \inobjecttrue
   \dowithnextbox       
     {\bgroup
      \dontshowcomposition % rather fuzzy in \setxvalue ... \hbox
      \setxvalue{\r!object#2::#3}% 
        {\noexpand\dohandleobject{#2}{#3} 
           {\ifhbox\nextbox\hbox\else\vbox\fi}
          %{\the\wd\nextbox}{\the\ht\nextbox}{\the\dp\nextbox}}%
           {\number\wd\nextbox}{\number\ht\nextbox}{\number\dp\nextbox}}%
      \expanded % fix the dimensions since \dostartobject may use \nextbox
        {\dostartobject
           {#2}{#3}
           {\number\wd\nextbox}{\number\ht\nextbox}{\number\dp\nextbox}}%
      \ifcase#1\relax
        \box\nextbox
      \else\ifdim\objectoffset>\!!zeropoint
        \scratchdimen=\objectoffset
        \edef\width {\the\wd\nextbox}%
        \edef\height{\the\ht\nextbox}%
        \edef\depth {\the\dp\nextbox}%
        \setbox\nextbox=
          \vbox spread 2\scratchdimen
            {\forgetall
             \vss
             \hbox spread 2\scratchdimen{\hss\box\nextbox\hss}%
             \vss}%
        \setbox\nextbox=\hbox
          {\hskip-\scratchdimen\lower\scratchdimen\box\nextbox}% 
        \wd\nextbox=\width
        \ht\nextbox=\height
        \dp\nextbox=\depth
        \box\nextbox
      \else
        \box\nextbox
      \fi\fi
      \dostopobject
      \egroup
      \egroup}}

\def\dogetobject#1#2#3#4#5#6%
  {\initializepaper
   \bgroup
   \forgetall 
   \dontshowcomposition
   \setbox0=\vbox
     {\doinsertobject{#1}{#2}}%
   \setbox0=#3%
     {\vbox to #5\s!sp  
        {\ifdim\ht0>#5\s!sp % or \ifdim\wd0>#4\s!sp
           \vss\hbox to #4\s!sp{\hss\box0\hss}\vss
         \else
           \vss\box0
         \fi}}%
   \wd0=#4\s!sp
   \ht0=#5\s!sp
   \dp0=#6\s!sp
   \box0
   \egroup}

\def\getobject#1#2%
  {\let\dohandleobject\dogetobject
   \getvalue{\r!object#1::#2}}

%D If needed one can ask for the dimensions of an object with:
%D
%D \starttypen
%D \getobjectdimensions{class}{name}
%D \stoptypen
%D
%D The results are reported in \type {\objectwidth}, \type 
%D {\objectheight} and \type {\objectdepth}. 

\def\dogetobjectdimensions#1#2#3#4#5#6% 
  {\def\objectwidth {#4\s!sp}%
   \def\objectheight{#5\s!sp}%
   \def\objectdepth {#6\s!sp}}

\def\getobjectdimensions#1#2%
  {\let\dohandleobject\dogetobjectdimensions
   \let\objectwidth \!!zeropoint
   \let\objectheight\!!zeropoint
   \let\objectdepth \!!zeropoint
   \getvalue{\r!object#1::#2}}

%D Apart from this kind of objects, that have typeset content, 
%D we can have low level driver specific objects. Both types 
%D can have references to internal representations, hidden for 
%D the user. We keep track of such references by means of a 
%D dedicated cross reference mechanism. Normally, objects are 
%D defined before they are used, but forward referencing 
%D sometimes occurs. 
%D 
%D \starttypen
%D \dosetobjectreference {class} {identifier} {reference value}
%D \dogetobjectreference {class} {identifier} \csname
%D \stoptypen
%D 
%D These commands are to be called by the \type{\startobject},
%D \type{\stopobject} and \type{\insertobject} specials.

\newif\ifobjectreferencing \objectreferencingtrue

\def\checkobjectreferences%
  {\bgroup
   \setbox0=\hbox
     {\doutilities{objectreferences}{\jobname}{}{}{}}%
   \global\let\checkobjectreferences=\relax
   \egroup}

\def\setobjectreferences%
  {\def\objectreference##1##2##3%
     {\doifundefinedelse{\r!driver##1::##2}
        {\setxvalue{\r!driver##1::##2}{##3}}
        {\showmessage{\m!references}{31}{[##1 ##2=>##3]}}}}

\def\resetobjectreferences%
  {\let\objectreference=\gobblethreearguments}

\resetobjectreferences

\def\dosetobjectreference#1#2#3%
  {\checkobjectreferences
   \ifobjectreferencing 
     \bgroup
     \edef\dowritereference%
       {\writeutilitycommand{\objectreference{#1}{#2}{#3}}}%
     \dowritereference
     \egroup
   \else
     \global\objectreferencingtrue
   \fi
   \setxvalue{\r!driver#1::#2}{#3}}

\def\defaultobjectreference#1#2{0}

\def\dogetobjectreference#1#2#3%
  {\checkobjectreferences
   \doifdefinedelse{\r!driver#1::#2}
     {\@EA\xdef\@EA#3\@EA{\csname\r!driver#1::#2\endcsname}}
     {\showmessage{\m!references}{30}{[#1 #2=>\defaultobjectreference{#1}{#2}]}%
      \xdef#3{\defaultobjectreference{#1}{#2}}}}

\def\setobject     {\global\objectreferencingfalse\dosetobject1}
\def\settightobject{\global\objectreferencingfalse\dosetobject0}

%D \macros
%D   {doifobjectfoundelse,doifobjectreferencefoundelse}
%D
%D To prevent redundant definition of objects, one can use 
%D the next tests:
%D
%D \starttypen
%D \doifobjectfoundelse{class}{object}{do then}{do else}
%D \doifobjectreferencefoundelse{class}{object}{do then}{do else}
%D \stoptypen

\def\doifobjectfoundelse#1#2#3#4%
  {\doifundefinedelse{\r!object#1::#2}{#4}{#3}}

\def\doifobjectreferencefoundelse#1#2#3#4%
  {\checkobjectreferences
   \doifundefinedelse{\r!driver#1::#2}{#4}{#3}}

%D \macros
%D   {doifobjectssupportedelse}
%D
%D Starting with reuse of graphics, we will implement object 
%D reuse when possible. To enable mechanisms to determine 
%D what method to use, we provide:
%D
%D \starttypen
%D \doifobjectssupportedelse{true action}{false action}
%D \stoptypen
%D
%D As we can see, currently objects depend on the special 
%D driver. 

\newif\ifobjectssupported \objectssupportedtrue

\def\doifobjectssupportedelse#1#2%
  {\ifobjectssupported
     \doifspecialavailableelse\doinsertobject{#1}{#2}%
   \else
     #2%
   \fi}

%D There is a conceptual problem here. Objects are not possible
%D in \DVI, unless faked like in \type {spec-dvi}. This means
%D that we must be careful in loading special drivers that do 
%D support objects while we still want to be able to use the 
%D \DVI\ output. 

\protect

\endinput 
