/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Microsoft Corporation, 1989                                 */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/
/****************************************************************************
 *
 * SOURCE FILE NAME = PATH2.C
 *
 * DESCRIPTIVE NAME = Path and area related routines for Postscript driver.
 *
 *
 * VERSION = V2.0
 *
 * DATE        : 05/09/89
 *
 * DESCRIPTION :
 *
 * This module redirects the path that is currently being built
 * into a RAM segment so we can play it back when we know what
 * we're going to do with it. If it is going to be used for any
 * thing other than a clip path, then we can just play it right
 * before the stroke or fill commands.
 *
 * If this is going to be a clip path, then we will need to grestore
 * to the correct level, append our path the the current clip path
 * (if one exists), gsave, then play any clip rects that may exist.
 * It shoul look something like this:
 *
 *             BeginPath()
 *                   Save Current Graphics State locally
 *                   Create segment and redirect PrintChannel() to segment
 *
 *             EndPath()
 *                   end redirection
 *
 *             Stroke or Fill
 *                   discard saved graphics state info
 *                   play segment
 *                   discard segment
 *                   stroke/fill...
 *
 *             ClipPath
 *                   grestore to correct level
 *                   play and discard graphics state info
 *                   play and discard segment
 *                   gsave/play clip rects/etc...
 *
 *
 * FUNCTIONS : init_path_buf
 *             discard_path_buf
 *             sync_graphics_states
 *             play_path_buf
 *             grow_path_buf
 *             init_clip_path_buf
 *             play_clip_path_buf
 *             discard_clip_path_buf
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#include "inc\prdinclt.h"
#include "inc\prdmath.h"
#include "inc\utl.h"
#include "inc\prdgextf.h"
#include "inc\prdeextf.h"
#include "inc\pspagtun.h"             /* V2.174057  Page Tuning */
#define  INCL_GENPLIB_MEMORY
#include <genplib.h>

extern void   LoadMarkerFont(PDDC);

typedef struct _PBSAVE
{
  SHORT usLineJoin;
  SHORT usLineCap;
  FIXED fxLineWidth;
  LONG lColor;               /* Current RGB color                           */
} PBSAVE, *PPBSAVE;

/***************************************************************************
 *
 * FUNCTION NAME =  init_path_buf
 *
 * DESCRIPTION   = init_path_seg will allocate the Path Buffer segment to
 *                 PATH_BUF_INIT_SIZE and init pddc vars.
 *
 * INPUT         = PDDC pddc
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 ****************************************************************************/

BOOL init_path_buf( PDDC pddc )
{
  register PPBSAVE ppbsave;
  register CGS     cgs;

  ps_saveclipmatrix( pddc );

  if ( pddc->pddcb->lpPathBuf == NULL )
  {
    if (!(pddc->pddcb->lpPathBuf = GplMemoryAlloc( pddc->pdv->pDCHeap,
                                                   PATH_BUF_INIT_SIZE )))
    {
      pddc->pddcb->lpPathBufSave = NULL;
      return (FALSE);        /* add error log reporting !!!                 */
    }
    pddc->pddcb->lpPathBufSave = pddc->pddcb->lpPathBuf;
  }
  else
  {
    /* Reset the pointer */
    pddc->pddcb->lpPathBuf = pddc->pddcb->lpPathBufSave;
  }

  /*
  ** Save Graphic State Info
  */
  ppbsave = (PPBSAVE) pddc->pddcb->lpPathBuf;
  cgs = pddc->pddcb->cgs;
  ppbsave->usLineJoin = cgs.usLineJoin;
  ppbsave->usLineCap = cgs.usLineCap;
  ppbsave->fxLineWidth = cgs.fxLineWidth;
  ppbsave->lColor = cgs.lColor;

  /*
  ** set the offset past the struct
  */
  pddc->pddcb->lpPathBuf = (CHAR *) pddc->pddcb->lpPathBuf + sizeof( PBSAVE );
  pddc->pddcb->lPathBufSize = (LONG) PATH_BUF_INIT_SIZE - sizeof( PBSAVE );
  pddc->pddcb->lPathBufCount = (LONG) PATH_BUF_INIT_SIZE - sizeof( PBSAVE );
  return (TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME =  discard_path_buf
 *
 * DESCRIPTION   = Discards the current path buffer.
 *
 * INPUT         = PDDC pddc
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 ****************************************************************************/

BOOL discard_path_buf( PDDC pddc )
{
  SHORT usReturn;

  /*
  ** a memory seg is allocated.
  */
  if ( pddc->pddcb->lpPathBuf != NULL )
  {
    pddc->pddcb->lpPathBuf = pddc->pddcb->lpPathBufSave;
  }

  pddc->pddcb->lPathBufSize = (LONG) PATH_BUF_INIT_SIZE;
  pddc->pddcb->lPathBufCount = (LONG) PATH_BUF_INIT_SIZE;

  return( TRUE );

}

/***************************************************************************
 *
 * FUNCTION NAME =  sync_graphics_states
 *
 * DESCRIPTION   = Resets the correct values in the printers graphic
 *                 state. Usually used after a grestore.
 *
 * INPUT         = PDDC    pddc
 *                 SHORT  uslj     line join
 *                 SHORT  uslc     line cap
 *                 FIXED   fxlw     line width
 *                 LONG    lColor   color
 *
 * OUTPUT        = void
 *
 * RETURN-NORMAL = NONE
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void sync_graphic_states( PDDC pddc, SHORT uslj, SHORT uslc, FIXED fxlw, LONG lColor)
  /*
  ** PDDC    pddc
  ** SHORT  uslj           line join
  ** SHORT  uslc           line cap
  ** FIXED   fxlw     line width
  ** LONG    lColor   color
  */
{
  /*
  ** make sure that we have the right pat fill font
  */
  pddc->pddcb->pat.usfFontLoaded &= ~FILLFONTLOADED;

  /*
  ** make sure that we have the right dash pattern
  */
  ps_setdashnow( pddc  );

  /*
  ** make sure that we have the right font;
  */
  pddc->pddcb->cgs.fValidFont = FALSE;
  ps_setlinejoin( pddc, uslj );
  ps_setlinecap( pddc, uslc );
  ps_setlinewidth( pddc, fxlw, FALSE );
  pddc->pddcb->cgs.lColor = lColor + 1;              /* invalidate current color            */
  ps_setrgbcolor( pddc, lColor );
  ps_setmatrix( pddc, (FIXED *) &pddc->pddcb->xformCTM );
}

/***************************************************************************
 *
 * FUNCTION NAME =  play_path_buf
 *
 * DESCRIPTION   = Plays the current path buffer to the channel.
 *
 * INPUT         = PDDC    pddc
 *                 BOOL    fSetGS
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = discard_path_buf(pddc)
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL play_path_buf( PDDC pddc, BOOL fSetGS )
{
  register PPBSAVE  ppbsave;
  SHORT            *piDash;

  pddc->pddcb->path.fPathIsOpen = FALSE;
  pddc->pddcb->path.fPathOrArea = FALSE;

  /*
  ** If fSetGS is set, then we will want to restore the graphic
  ** state from the snapshot that we took when we began the path.
  */
  if (fSetGS)
  {
    pddc->pddcb->lpPathBuf = pddc->pddcb->lpPathBufSave;
    ppbsave = (PPBSAVE) pddc->pddcb->lpPathBuf;

    /*
    ** restore proper xform matrix
    */
    ps_restoreclipmatrix( pddc );
    sync_graphic_states( pddc, ppbsave->usLineJoin, ppbsave->usLineCap,
                         ppbsave->fxLineWidth, ppbsave->lColor );
  }

  /*
  ** Play the path. Just dump the whole thing on WriteChannel()
  */
  /*
  **    begin at the beginning
  */
  /*
  ** pddc->pddcb->lpPathBuf = (CHAR *) ((ULONG)pddc->pddcb->lpPathBuf & 0xFFFF0000 );
  */

  pddc->pddcb->lpPathBuf = (CHAR *) pddc->pddcb->lpPathBufSave + sizeof( PBSAVE );

  /*
  ** If the PostScript header wasn't sent then send it now.  The
  ** reason that it was delayed till now is to handle the case
  ** where the spooler is just copying raw data to the driver.
  ** If this is the case, then the driver must be careful not
  ** to send multiple headers.
  */
  if (!pddc->fHeaderSent)
  {
    ps_startdoc( pddc );
  }

  /*
  ** Number of bytes = size - free.
  */
  WriteChannel( pddc, (PB) pddc->pddcb->lpPathBuf,
                (SHORT) (pddc->pddcb->lPathBufSize - pddc->pddcb->lPathBufCount) );
  return( discard_path_buf(pddc) );
}

/***************************************************************************
 *
 * FUNCTION NAME =  init_clip_path_buf
 *
 * DESCRIPTION   =  Allocate memory for the clip path buffer and
 *                  copy the current path buffer into it.
 *
 * INPUT         = PDDC
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 ****************************************************************************/

BOOL   init_clip_path_buf(PDDC pddc)
{
  CHAR  *lpPathBuf = pddc->pddcb->lpPathBuf;
  CHAR  *lpPathBufSave = pddc->pddcb->lpPathBufSave;
  LONG   lPathBufLen = pddc->pddcb->lPathBufSize -
                       pddc->pddcb->lPathBufCount;

  /*
  ** Defect 75156 - check for zero length paths
  */
  if ( lPathBufLen == 0 )
  {
    return TRUE;
  }

  /*
  ** Save the CTM at the beginning of this path
  */
  PrintChannel( pddc, (PSZ) "/msclippath msclp def\n" );

  if (pddc->pddcb->lClipPathBufSize == 0L)
  {
    /*
    ** Clip path buffer is not existing, then
    ** allocate memory for clip path buffer.
    */
    pddc->pddcb->lClipPathBufSize = lPathBufLen;

    if (!(pddc->pddcb->lpClipPathBuf = GplMemoryAlloc ( pddc->pdv->pDCHeap,
                                              pddc->pddcb->lClipPathBufSize )))
    {
      PrintLog( (PSZ) "init_clip_path_buf:AllocMem failed " );
      PrintLog( (PSZ) "pddc->pddcb->lpClipPathBuf = %lp\n",
                pddc->pddcb->lpClipPathBuf );
      return( FALSE );               /* add error log reporting !!!                 */
    }
    pddc->pddcb->lpClipPathBufSave = pddc->pddcb->lpClipPathBuf;

    /*
    ** We are allocating the required number of bytes.
    ** Hence, free bytes are 0.
    */
    pddc->pddcb->lClipPathBufCount = 0L;
  }
  else if (pddc->pddcb->lClipPathBufSize < lPathBufLen)
  {
    /*
    ** Free the current clip path buffer and
    ** allocate a new one.
    */
    if ( GplMemoryFree(pddc->pddcb->lpClipPathBufSave ))
    {
      PrintLog( (PSZ) "init_clip_path_buf: FreeMem failed " );
      PrintLog( (PSZ) "lpClipPathBuf = %lp\n", pddc->pddcb->lpClipPathBuf );
      return( FALSE );         /* add error log reporting !!!               */
    }

    /*
    ** Allocate segment for clip path buffer.
    */
    pddc->pddcb->lClipPathBufSize = lPathBufLen;
    if (!(pddc->pddcb->lpClipPathBuf = GplMemoryAlloc ( pddc->pdv->pDCHeap,
                                              pddc->pddcb->lClipPathBufSize )))
    {
      PrintLog( (PSZ) "init_clip_path_buf:AllocMem failed " );
      PrintLog( (PSZ) "pddc->pddcb->lpClipPathBuf = %lp\n",
                pddc->pddcb->lpClipPathBuf );
      return( FALSE );         /* add error log reporting !!!               */
    }

    pddc->pddcb->lpClipPathBufSave = pddc->pddcb->lpClipPathBuf;

    /*
    ** We are alloacting the required number of bytes.
    ** Hence, free bytes are 0.
    */
    pddc->pddcb->lClipPathBufCount = 0L;
  }
  else               /* lClipPathBufSize >= lPathBufLen             */
  {
    /*
    ** Buffer size is sufficient.
    */
    pddc->pddcb->lClipPathBufCount = pddc->pddcb->lClipPathBufSize -
                                     lPathBufLen;
  }

  /*
  ** Copy the path buffer into clip path buffer.
  */
  /*
  ** lpPathBuf = (CHAR *) ((ULONG)lpPathBuf & 0xFFFF0000 );
  */
  lpPathBuf = lpPathBufSave + sizeof( PBSAVE );
  utl_memcopy( (PSZ) pddc->pddcb->lpClipPathBuf, (PSZ) lpPathBuf,
               (SHORT) lPathBufLen );
  return( TRUE );
}

/***************************************************************************
 *
 * FUNCTION NAME =  play_clip_path_buf
 *
 * DESCRIPTION   =  Plays clip path buffer to the channel.
 *
 * INPUT         = PDDC
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 ****************************************************************************/

BOOL play_clip_path_buf( PDDC pddc )
{
  pddc->pddcb->cgs.fValidCP = FALSE;

  /*
  ** Defect 75156 - check for zero length paths
  */
  if ( pddc->pddcb->lClipPathBufSize == 0 )
  {
    return TRUE;
  }

  /*
  ** Restore the saved CTM at the beginning of this path.
  */
  PrintChannel( pddc, (PSZ) "msclippath SM\n" );

  /*
  ** Play the clip path. Just dump the whole thing on WriteChannel()
  */
  WriteChannel( pddc, (PB)pddc->pddcb->lpClipPathBuf,
                (SHORT) (pddc->pddcb->lClipPathBufSize-pddc->pddcb->lClipPathBufCount) );
  return  TRUE;
}

/***************************************************************************
 *
 * FUNCTION NAME =  discard_clip_path_buf
 *
 * DESCRIPTION   =  Discards the clip path buffer.
 *
 * INPUT         = PDDC
 *
 * OUTPUT        = BOOL
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 ****************************************************************************/

BOOL discard_clip_path_buf( PDDC pddc )
{
  if (pddc->pddcb->lClipPathBufSize > 0L)
  {
    if (GplMemoryFree(pddc->pddcb->lpClipPathBufSave ))
    {
      PrintLog( (PSZ) "discard_clip_path_buf: FreeMem failed " );
      PrintLog( (PSZ) "pddc->pddcb->lpClipPathBuf = %lp\n",
                pddc->pddcb->lpClipPathBuf );
      return( FALSE );               /* add error log reporting !!!                 */
    }
    pddc->pddcb->lClipPathBufSize = 0L;
    pddc->pddcb->lClipPathBufCount = 0L;
    pddc->pddcb->lpClipPathBuf = NULL;
    pddc->pddcb->lpClipPathBufSave = NULL;
  }
  else
  {
    pddc->pddcb->lClipPathBufCount = 0L;
    pddc->pddcb->lClipPathBufSize = 0L;
  }
  return( TRUE );
}
