//====START_GENERATED_PROLOG======================================
//
//
//   COMPONENT_NAME: odpubutils
//
//   CLASSES: none
//
//   ORIGINS: 82,27,94
//
//
//   (C) COPYRIGHT International Business Machines Corp. 1995,1996
//   All Rights Reserved
//   Licensed Materials - Property of IBM
//   US Government Users Restricted Rights - Use, duplication or
//   disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
//   	
//   IBM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
//   ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
//   PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, INDIRECT OR
//   CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
//   USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
//   OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
//   OR PERFORMANCE OF THIS SOFTWARE.
//
//====END_GENERATED_PROLOG========================================
//
// @(#) 1.25 nt/src/pubutils/src/FocusLib.cpp, odpubutils, od96nt, odnt9714c 3/25/97 11:27:09 [ 4/2/97 17:55:23 ]
#ifdef _PLATFORM_WIN32_
// We have a Win32 specific implementation here!

/*
        File:           FocusLib.cpp

        Contains:       Library routines for focusing (setting up for drawing into a facet)

        Owned by:       Jens Alfke

        Copyright:      © 1993 - 1995 by Apple Computer, Inc., all rights reserved.

*/

#define _OD_DONT_IMPORT_CPP_
 
#ifndef SOM_ODFrame_xh
#include <Frame.xh>
#endif

#ifndef SOM_ODFacet_xh
#include <Facet.xh>
#endif

#ifndef SOM_ODShape_xh
#include <Shape.xh>
#endif

#ifndef SOM_Module_OpenDoc_Polygon_defined
#include <Polygon.xh>
#endif

#ifndef SOM_ODTransform_xh
#include <Trnsform.xh>
#endif

#ifndef SOM_ODCanvas_xh
#include <Canvas.xh>
#endif

#ifndef SOM_ODWindow_xh
#include <Window.xh>
#endif

#ifndef SOM_ODFacet_xh
#include <Facet.xh>
#endif

#ifndef _FOCUSLIB_
#include "FocusLib.h"
#endif

#ifndef _SOM_ODWin32WindowCanvas_xh
#include "WinWCanv.xh"
#endif

#ifndef _SOM_ODWin32StandardCanvas_xh
#include "WinSCanv.xh"
#endif

#ifndef _ODMATH_
#include <ODMath.h>
#endif



WIN32_DLLEXPORT CFocus::CFocus( ODFacet *facet, ODShape* invalShape, HDC *theHDC )
{
   (void) f.BeginFocus( facet, invalShape, kODFalse );
   *theHDC = f.fHDC;
}



WIN32_DLLEXPORT CFocus::~CFocus()
{
   f.EndFocus();
}



WIN32_DLLEXPORT CFocusWindow::CFocusWindow( ODFacet *facet, ODShape* invalShape, HDC *theHDC, HWND *theHWnd )
{
   (void) f.BeginFocus( facet, invalShape, kODTrue );
   *theHDC = f.fHDC;
   *theHWnd = f.fHWnd;
}



WIN32_DLLEXPORT void
FocusState::BeginFocus( ODFacet *facet, ODShape* invalShape, ODBoolean toWindow )
{
   // Remember toWindow
   fToWindow = toWindow;

   // Remember the facet
   fFacet          = facet;
   fclipShape      = kODNULL;
   fSaveDC         = kODNULL;
   Environment *ev = somGetGlobalEnvironment();
   ODBoolean isMetafileDC = kODFalse;
   OSVERSIONINFO osVersion;

   osVersion.dwOSVersionInfoSize = sizeof( OSVERSIONINFO );

   // Get the HDC
   if( toWindow ) {
      fHWnd = facet->GetWindow( ev )->GetPlatformWindow( ev );
      fHDC = GetDC( fHWnd );
   } else {
      ODWin32Canvas *platcanv = (ODWin32Canvas *) facet->GetCanvas( ev )->GetPlatformCanvas( ev, kODWin32 );
      fHDC = platcanv->GetDC( ev );
   }


   // Find out if we're a Metafile DC
   DWORD objType = GetObjectType( fHDC );
   if( objType == OBJ_METADC || objType == OBJ_ENHMETADC ) {
      isMetafileDC = kODTrue;
   }

   // Are we Printing?
   ODBoolean isPrinting = !(facet->GetCanvas( ev )->IsDynamic( ev ));

   // If the platform is Win95, a printer DC returns an object type
   // from GetObjectType for an enhanced metafile.  The next chunk of 
   // code checks to see whether the platform canvas has a metafile extent
   // associated with it.  If it doesn't, then this is really a printing
   // context and not an enhanced metafile context.

   GetVersionEx( &osVersion );
   if( (osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)  && isPrinting && isMetafileDC ) {
      ODPlatformCanvas *pc = facet->GetCanvas( ev )->GetPlatformCanvas( ev, kODWin32 );
      ODBoolean valChk = ( (ODWin32Canvas*)pc )->GetMetafileExtent( ev, &fOldWinExtent );
      if( !valChk ) {
         isMetafileDC = kODFalse;
      }
   }

   // Clip to it (don't clip if to a Window)
   if ( !toWindow && !isMetafileDC ) {

      fclipShape = facet->CreateShape( ev );

      if ( fclipShape ) {
         // Copy the facet's aggregate clip shape
         ODShape *aggshape = facet->AcquireAggregateClipShape( ev, kODNULL );
         fclipShape->CopyFrom( ev, aggshape );
         aggshape->Release( ev );

         if (isPrinting) {
            ODShape *usedshape = facet->GetFrame(ev)->AcquireUsedShape(ev, kODNULL);
            fclipShape->Intersect( ev, usedshape );
            usedshape->Release( ev );
         }

         // If an invalid shape was passed in
         if ( invalShape ) {
            // Intersect the facet's aggregate clip shape and the invalid 
            // shape.  They should both be in the facet's frame coordinates.
            fclipShape->Intersect( ev, invalShape );
         }

         ODTransform *frameTransform;
         if (!isPrinting) {
           // Transform the intersection using the facet's window frame
           // transform.  This should convert the intersection to window
           // coordinates for the docshell window.
           frameTransform = facet->AcquireWindowFrameTransform( ev, kODNULL );
           fclipShape->Transform( ev, frameTransform );
         }
         else
         {
           // For printing, transform using the facet's frame transform. The
           // facet's window frame transform wouldn't work in this case.
           frameTransform = facet->AcquireFrameTransform(ev, kODNULL);
           fclipShape->Transform(ev, frameTransform);
         }


         if (!isPrinting) {
           // Create a transform
           ODTransform *xform = frameTransform->NewTransform( ev );

           // If transform created
           if ( xform ) {
              // Get the offset from the window frame transform
              ODPoint offset;
              ODShape *frameShape = facet->GetFrame(ev)->AcquireFrameShape(ev, kODNULL);
              ODShape *frameShape2 = frameShape->Copy(ev);
              frameShape->Release(ev);
              frameShape2->Transform(ev, frameTransform);
              ODRect RectBounds;
              frameShape2->GetBoundingBox(ev, &RectBounds);
              frameShape2->Release(ev);
              offset.x = RectBounds.left;
              offset.y = RectBounds.top;

              // Set the new transform's offset
              xform->SetOffset( ev, &offset );

              // Inverse transform the intersection using this new transform.
              // This puts the intersected shape in the facet window's 
              // coordinates.
              fclipShape->InverseTransform( ev, xform );
           }

           xform->Release(ev); 
         }  // end if ( xform )

         frameTransform->Release(ev);

      }  // end if ( fclipShape )
   }  // end if ( !toWindow && !isMetafileDC ) 

   // Transform
   ODPoint         scale, offset;
   ODTransform*    localToGlobal;

   if ( toWindow ) {
      localToGlobal = facet->AcquireWindowContentTransform( ev, kODNULL );
   } 
   else {
      localToGlobal = facet->AcquireContentTransform( ev, kODNULL );
   }

   // note: Rotation logic is as follows for NT.  Note that rotation is
   //       not currently supported by Windows/95.  Rotation is also not
   //       supported for metafiles.  In order to maintain compatibility
   //       among Windows/NT and Windows/95, it is not enabled here.
   // fOldMapMode = SetMapMode( fHDC, MM_ANISOTROPIC );
   // fOldGraphicsMode = SetGraphicsMode(fHDC, GM_ADVANCED);
   // ODMatrix matrix;
   // localToGlobal->GetMatrix(ev, &matrix);
   // XFORM xform;
   // xform.eM11 = ODFixedToFloat(matrix.m[0][0]);
   // xform.eM12 = ODFixedToFloat(matrix.m[0][1]);
   // xform.eM21 = ODFixedToFloat(matrix.m[1][0]);
   // xform.eM22 = ODFixedToFloat(matrix.m[1][1]);
   // xform.eDx  = ODFixedToFloat(matrix.m[2][0]);
   // xform.eDy  = ODFixedToFloat(matrix.m[2][1]);
   // SetWorldTransform(fHDC, &xform);

   localToGlobal->GetPreScaleOffset( ev, &offset );
   localToGlobal->GetScale( ev, &scale );

   // Save the device context state.  We'll restore it in EndFocus.
   fSaveDC = SaveDC( fHDC );

   if( !isMetafileDC ) {
      fOldMapMode = SetMapMode( fHDC, MM_ANISOTROPIC ); 
      SetWindowOrgEx( fHDC,-(FixedToInt(offset.x)), -(FixedToInt(offset.y)), &fOldWinOrg );

      scale.x          = ODFixedMultiply( scale.x, IntToFixed(1000) );
      scale.y          = ODFixedMultiply( scale.y, IntToFixed(1000) );
      SetWindowExtEx( fHDC, 1000, 1000, &fOldWinExtent );
      SetViewportExtEx( fHDC, FixedToInt( scale.x ), FixedToInt( scale.y ), &fOldVPExtent );

      // Get the region from the clipshape
      if( fclipShape != kODNULL ) {
         HRGN clip = fclipShape->GetRegion( ev );

         // If a region was retrieved
         if ( clip ) {
            // Set the window's nt clip region
            SelectClipRgn( fHDC, clip );
         }
      }

   } 
   else {

      // We can't arbitrarily set the window extent on a metafile DC.  The
      // window extent we'll use is the metafile extent stored in the
      // platform canvas.  This should have been set up by the code 
      // requesting the redraw into the metafile.   

      ODPlatformCanvas *pc = facet->GetCanvas( ev )->GetPlatformCanvas( ev, kODWin32 );
      ODBoolean valChk = ( (ODWin32Canvas*)pc )->GetMetafileExtent( ev, &fOldWinExtent );

      fOldMapMode = SetMapMode( fHDC, MM_ANISOTROPIC ); 

      // The viewport is scaled to be proportional to the window extent
      // of the metafile.
      scale.x = ODFixedMultiply( scale.x, IntToFixed( fOldWinExtent.cx ) );
      scale.y = ODFixedMultiply( scale.y, IntToFixed( fOldWinExtent.cy ) );


      // Set the clip region in the metafile.  The clip region for embedded 
      // facets is the intersection of the used shape and the aggregate clip 
      // shape.  
      fclipShape = facet->CreateShape( ev );
      ODShape *usedshape = facet->GetFrame( ev )->AcquireUsedShape( ev, kODNULL );
      ODShape *aggshape = facet->AcquireAggregateClipShape( ev, kODNULL );
      fclipShape->CopyFrom( ev, aggshape );

      fclipShape->Intersect( ev, usedshape );

      // If an invalid shape was passed in
      if ( invalShape ) {
         // Intersect the facet's aggregate clip shape and the invalid 
         // shape.  They should both be in the facet's frame coordinates.
         fclipShape->Intersect( ev, invalShape );
      }

      // The new clip shape is in it's own local coordinates. Transform it by 
      // the frame transform to position it correctly in the metafile.
      ODTransform *frameTransform = facet->AcquireFrameTransform( ev, kODNULL );
      fclipShape->Transform( ev, frameTransform );

      // Get the region from the clipshape
      // NOTE: when drawing to a metafile on Windows 95 only, SelectClipRgn 
      // must be called before setting the window and viewport of the DC.
      // If SelectClipRgn is called after it appears as though the clip
      // region is transformed by the window/viewport settings.  This
      // will give the appearance that the part is drawing outside it's
      // clipping area.
      if( fclipShape != kODNULL ) {
         HRGN clip = fclipShape->GetRegion( ev );

         // If a region was retrieved
         if ( clip ) {
            // Set the window's nt clip region
            SelectClipRgn( fHDC, clip );
         }
      }

      SetWindowOrgEx( fHDC,-(FixedToInt(offset.x)), -(FixedToInt(offset.y)), &fOldWinOrg );
      SetWindowExtEx( fHDC, fOldWinExtent.cx, fOldWinExtent.cy, kODNULL );
      SetViewportExtEx( fHDC, FixedToInt( scale.x ), FixedToInt( scale.y ), &fOldVPExtent );

      frameTransform->Release( ev );
      aggshape->Release( ev );
      usedshape->Release( ev );
   }
}




WIN32_DLLEXPORT void
FocusState::EndFocus( )
{
   // Restore any old state

   Environment *ev = somGetGlobalEnvironment();

   if( fSaveDC ) {
      RestoreDC( fHDC, fSaveDC);
      fSaveDC = kODNULL;
   }
   else {
      SetViewportExtEx( fHDC, fOldVPExtent.cx, fOldVPExtent.cy, kODNULL );
      SetMapMode( fHDC, fOldMapMode );
      SetWindowOrgEx( fHDC, fOldWinOrg.x, fOldWinOrg.y, kODNULL );
      SetWindowExtEx( fHDC, fOldWinExtent.cx, fOldWinExtent.cy, kODNULL );

      // Set a null clip region so we can delete the one attached
      // to the shape in the shape's destructor.
      SelectClipRgn( fHDC, kODNULL );
   }

   if( fclipShape )
      fclipShape->Release( ev );

   // Release the DC
   if ( fToWindow ) {
      ReleaseDC( fHWnd, fHDC );
   } 
   else {
      ODWin32Canvas *platcanv = ( ODWin32Canvas * ) fFacet->GetCanvas( ev )->GetPlatformCanvas( ev, kODWin32 );
      platcanv->ReleaseDC( ev );
   }
}


WIN32_DLLEXPORT void 
BeginFocus( FocusState* foc, ODFacet *facet, ODShape* invalShape, HDC *theHDC )
{
   foc->BeginFocus( facet, invalShape, kODFalse );
   *theHDC = foc->fHDC;
}

WIN32_DLLEXPORT void
EndFocus( FocusState* foc )
{
   foc->EndFocus();
}



#endif // _PLATFORM_WIN32_
