/*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 = PRDLPOLY.C
 *
 * DESCRIPTIVE NAME = Contains arc drawing routines.
 *
 *
 * VERSION = V2.0
 *
 * DATE      09/16/88
 *
 * DESCRIPTION :
 *
 * This module contains PolyFillet, PolyFilletSharp, PolySpline,
 * PolyLine, PolyMarker and support rountines.
 *
 *
 * FUNCTIONS : prdl_DrawConic
 *             prdl_PolyFilletSharp
 *             prdl_PolyFillet
 *             prdl_PolySpline
 *             prdl_SetLineOrigin
 *             prdl_GetLineOrigin
 *             prdl_PolyLine
 *             prdl_PolyMarker
 *             LoadMarkerFont
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define  INCL_GRE_DEVSUPPORT
#include "inc\prdinclt.h"
#include "inc\prdlextf.h"
#include "inc\prdmath.h"
#include "inc\utl.h"
#include "inc\prdbextf.h"
#include "inc\prdgextf.h"
#include "inc\prdcextf.h"
#include "inc\fillet.h"
#include "inc\prdtextf.h"
#include "inc\pspagtun.h"             /* V2.174057  Page Tuning */
#define  INCL_GENPLIB_ERROR
#include <genplib.h>

#include <pmfont.h>
#define  OD_MEMORY 8L
/*
** !!!CR Copy comment drawings from the engine
*/

extern VOID   _System FarSubDivide(PFILLETSHARP,PFILLETSHARP,PFILLETSHARP);
extern PDDC  EnterDriver(PDDC);
extern VOID  ExitDriver(PDDC);
FIXED  prdl_FilletSharpness(PPOINTL);
VOID  ConicToBezier(PPOINTL,FIXED);
void  prdl_DrawConic(PDDC,PPOINTL,FIXED);
extern unsigned long  _System LongShiftRight(unsigned long,short);
#define  LDIV2(x)      LongShiftRight(x, 1)
extern PFNL pfnlPolyLine;
extern PFNL pfnlPolyMarker;
void  LoadMarkerFont(PDDC);

void prdl_DrawSubConic (PDDC, FIXED, FIXED, FIXED, FIXED, FIXED, FIXED,
                                   FIXED, ULONG );
BOOL prdl_CheckConic (LONG, LONG, LONG, LONG, LONG, LONG, FIXED) ;

#define  FX_HALF       0x08000L
/*
** !!!CR turn all this PostScript code into a resource
**
**
** This PostScript code defines the marker font.  It is downloaded
** to the printer only once, and only in the event that a PolyMarker
** call has been made.
*/

static PSZ apszFontCode[] =
{
  "10 dict dup begin /FontType 3 def",
  "/FontMatrix [.01 0 0 .01 0 0] def /FontBBox [0 0 100 100]def",
  "/Encoding 256 array def 0 1 255 {Encoding exch /.nodef put} for Encoding",
  "dup (A) 0 get /mBLANK put dup (B) 0 get /mCROSS put",
  "dup (C) 0 get /mPLUS put dup (D) 0 get /mDIAMOND put",
  "dup (E) 0 get /mSQUARE put dup (F) 0 get /mSIXPTSTAR put",
  "dup (G) 0 get /mEIGHTPTSTAR put dup (H) 0 get /mFILLEDDIAMOND put",
  "dup (I) 0 get /mFILLEDSQUARE put dup (J) 0 get /mDOT put",
  "(K) 0 get /mSMALLCIRCLE put",
  "/Metrics 12 dict def Metrics begin /.notdef 0 def /mBLANK 100 def",
  "/mCROSS 50 def /mPLUS 100 def /mDIAMOND 100 def /mSQUARE 100 def",
  "/mSIXPTSTAR 86 def /mEIGHTPTSTAR 100 def /mFILLEDDIAMOND 100 def",
  "/mFILLEDSQUARE 100 def /mDOT 100 def /mSMALLCIRCLE 50 def end",                "\
/BBox 12 dict def BBox begin /.notdef [0 0 0 0] def /mBLANK [0 0 100 100] def"
  ,               "/mCROSS [0 0 100 100] def /mPLUS [0 0 100 100] def /mDIAMO\
ND [0 0 100 100] def",
  "/mSQUARE [0 0 100 100] def /mSIXPTSTAR [7 0 96 100] def",
  "/mEIGHTPTSTAR [0 0 100 100] def /mFILLEDDIAMOND [0 0 100 100] def",
  "/mFILLEDSQUARE [0 0 100 100] def /mDOT [0 0 100 100] def",
  "/mSMALLCIRCLE [25 25 75 75] def end",
  "/CharacterDefs 12 dict def CharacterDefs begin /.notdef { } def",
  "/mBLANK { } def",              "/mCROSS { 10 10 m 90 90 l 10 90 m 90 10 l",
  " cw 10 w s w } def",           "/mPLUS { 0 50 m 100 50 l 50 0 m 50 100 l",
  " cw 10 w s w} def",
  "/mDIAMOND { 0 50 m 50 100 l 100 50 l 50 0 l",  " cp cw 5 w s w } def",
  "/mSQUARE { 0 0 m 0 100 l 100 100 l 100 0 l",   " cp cw 5 w s w } def",
  "/mSIXPTSTAR { n 50 100 m 58 65 l 93 75 l 67 50 l",
  " 93 25 l 58 35 l 50 0 l 42 35 l 7 25 l 33 50 l",
  " 7 75 l 42 65 l cp f } def",
  "/mEIGHTPTSTAR { n 50 100 m 58 70 l 85 85 l 70 58 l",
  " 100 50 l 70 42 l 85 15 l 58 30 l 50 0 l",
  " 42 30 l 15 15 l 30 42 l 0 50 l 30 58 l",
  " 15 85 l 42 70 l cp f } def",
  "/mFILLEDDIAMOND { n 0 50 m 50 100 l 100 50 l 50 0 l",
  " cp f } def",  "/mFILLEDSQUARE { n 0 0 m 0 100 l 100 100 l 100 0 l",
  " cp f } def",  "/mDOT { n 50 50 50 0 360 arc cp f } def",
  "/mSMALLCIRCLE { n 50 50 25 0 360 arc cw 5 w",  " s w } def end",
  "/BuildChar { 0 begin /char exch def /fontdict exch def",
  "/charname fontdict /Encoding get char get def fontdict begin",
  "Metrics charname get 0 BBox charname get aload pop setcachedevice",
  "CharacterDefs charname get exec end end } def",
  "/BuildChar load 0 3 dict put /UniqueID 1 def end",
  "/MARKERfont exch definefont pop",              NULL
} ;

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_DrawConic
 *
 * DESCRIPTION   =
 *
 *  Given the three vertices of the conic triangle and the sharpness,
 *  this routine converts the conic to a Bezier curve and outputs the
 *  appropriate PostScript code to append the conic to the current path.
 *  The original conic is bisected into two sub-conics because it is
 *  impossible to closely approximate the conics with a large sharpness
 *  using a single Bezier.  A geometric derivation of the math is
 *  available in separate documentation.
 *
 *  Input:
 *      pptl[0] = pt A of the conic.
 *      pptl[1] = pt B of the conic.
 *      pptl[2] = pt C of the conic
 *      conic's sharpness.
 *
 * INPUT         = PDDC pddc      Ptr to the DC instance data
 *                 PPOINTL pptl   Ptr to the conic triangle
 *                 FIXED fxS      The conic's sharpness
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 * Fri-11-Jun-1993 -by-  Ravisankar
 * Rewrote it.
 ****************************************************************************/

void prdl_DrawConic( PDDC pddc, PPOINTL pptl, FIXED fxS )
{
  FIXED  sfxAx, sfxAy,      // Shifted fixed values.
         sfxBx, sfxBy,
         sfxCx, sfxCy ;

  ULONG  ulShift;
  LONG   i ;

  if (!prdl_CheckConic (pptl[0].x, pptl[0].y,
                        pptl[1].x, pptl[1].y,
                        pptl[2].x, pptl[2].y, fxS))
  {
    // Draw a line.
    PrintChannel( pddc, (PSZ) "%ld %ld l\n", pptl[2].x, pptl[2].y);

    // Expand the bounds accumulation to include the line
    prdl_ExpandBounds( pddc, pptl[0].x, pptl[0].y) ;
    prdl_ExpandBounds( pddc, pptl[2].x, pptl[2].y) ;
    return ;
  }

  // Find the maximum absolute value.
  sfxAx = 0 ;
  for (i = 0 ; i < 3 ; i++)
  {
      sfxBx = abs (pptl[i].x) ;
      sfxBy = abs (pptl[i].y) ;
      if (sfxBx > sfxAx)
          sfxAx = sfxBx ;
      if (sfxBy > sfxAx)
          sfxAx = sfxBy ;
  }

  // The maximum value we get in splitting the conics and
  // converting to bezier curves, is twice the maximum coordinate.
  //
  // Normalize it.
  if (sfxAx >= 0x4000)         // 32K is the limit for signed fixed integer.
                               // we need twice the maximum.
  {
     ulShift = ulNormalize (sfxAx) ;
     if (ulShift > 2)
     {
       ulShift -= 2 ;    // we need twice the maximum of signed value.
     }
     else
     {
       ulShift = 0 ;
     }

  }
  else
  {
     ulShift = 16 ;
  }

  // Shift the coordinates.
  sfxAx = pptl[0].x << ulShift;
  sfxAy = pptl[0].y << ulShift;
  sfxBx = pptl[1].x << ulShift;
  sfxBy = pptl[1].y << ulShift;
  sfxCx = pptl[2].x << ulShift;
  sfxCy = pptl[2].y << ulShift;

  // Subdivide the conic at the parameter t = 1/2.
  ps_movetoCPx( pddc, (PPOINTL) &pddc->pddcb->pen.ptlCur );
  prdl_DrawSubConic (pddc, sfxAx, sfxAy,
                           sfxBx, sfxBy,
                           sfxCx, sfxCy,
                           fxS, ulShift) ;
  return ;

}


/***************************************************************************
 *
 * FUNCTION NAME =  prdl_DrawSubConic
 *
 * DESCRIPTION   =
 *
 *  Given the three vertices of the conic triangle and the sharpness,
 *  this routine converts the conic to a Bezier curve and outputs the
 *  appropriate PostScript code to append the conic to the current path.
 *
 *  First the conic is subdivided at the parameter t = 1/2.
 *  If the sharpness of the subdivided conic is large then
 *  it is subdivided further.
 *
 *  Input:
 *       pt A of the conic.
 *       pt B of the conic.
 *       pt C of the conic.
 *       conic's sharpness.
 *       shift value
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 * Fri-11-Jun-1993 -by-  Ravisankar
 * Wrote it.
 ****************************************************************************/
void prdl_DrawSubConic (PDDC pddc, FIXED sfxAx, FIXED sfxAy,
                                   FIXED sfxBx, FIXED sfxBy,
                                   FIXED sfxCx, FIXED sfxCy,
                                   FIXED fxS, ULONG ulShift)
{

  FIXED  sfxDx, sfxDy,      // Shifted fixed values.
         sfxEx, sfxEy,
         sfxFx, sfxFy ;
  LONG   lPt1x, lPt1y,
         lPt2x, lPt2y,
         lPt3x, lPt3y ;

  FIXED  fxZ, fxQ, fxS2 ;
  LONG  lRound;


  if (!prdl_CheckConic (sfxAx, sfxAy,
                        sfxBx, sfxBy,
                        sfxCx, sfxCy, fxS))
  {
    if (ulShift) {
       lRound = 1 << ( ulShift - 1) ;
       sfxAx = (sfxAx + lRound) >> ulShift ;
       sfxAy = (sfxAy + lRound) >> ulShift ;
       sfxCx = (sfxCx + lRound) >> ulShift ;
       sfxCy = (sfxCy + lRound) >> ulShift ;
    }

    // Draw a line.
    PrintChannel( pddc, (PSZ) "%ld %ld l\n", sfxCx, sfxCy);

    // Expand the bounds accumulation to include the line
    prdl_ExpandBounds( pddc, sfxAx, sfxAy) ;
    prdl_ExpandBounds( pddc, sfxCx, sfxCy) ;
    return ;
  }

  // Subdivide the conic at the parameter t = 1/2
  // The sharpness of the subdivided conics = sqrt of ((sharpness + 1)/2)
  //

  if ((LONG) fxS >= FX_MAX)
  {
    // this is an approximation but close one
    fxZ = frdiv( fxS - FX_ONE, fxS );
  }
  else
  {
    fxZ = frdiv( fxS, fxS + FX_ONE );
  }

  // The conic ABC is subdivded into AED and DFC.
  // Calculate points E and F such that a line from E to F passes
  // through point D and is parallel to line segment AC (the base
  // of triangle ABC.)

  // Point E.
  sfxEx = sfxAx + frmul (sfxBx, fxZ) - frmul (sfxAx, fxZ);
  sfxEy = sfxAy + frmul (sfxBy, fxZ) - frmul (sfxAy, fxZ);;

  // Point F.
  sfxFx = sfxCx + frmul (sfxBx, fxZ) - frmul (sfxCx, fxZ);
  sfxFy = sfxCy + frmul (sfxBy, fxZ) - frmul (sfxCy, fxZ);;

  // Point D.
  // The order of arithmatic in the following is arranged to avoid overflow.
  sfxDx = sfxEx / 2 + sfxFx / 2 ;
  sfxDy = sfxEy / 2 + sfxFy / 2 ;

  // Compute the sharpness of the subconics.
  //
  fxS2 =  fxS / 2 + FX_HALF ;
  fxS2 =  frsqrt (fxS2);

  // Compute the bezier control points.
  //
  fxQ = (4 * frdiv (fxS2, fxS2 + FX_ONE)) / 3 ;

  // If fxQ exceeds FX_ONE subdivide the conics.
  if (fxQ > FX_ONE)
  {

    // Subdivide the first conic at the parameter t = 1/2.
    prdl_DrawSubConic (pddc, sfxAx, sfxAy,
                             sfxEx, sfxEy,
                             sfxDx, sfxDy,
                             fxS2, ulShift) ;


    // Subdivide the second conic at the parameter t = 1/2.
    prdl_DrawSubConic (pddc, sfxDx, sfxDy,
                             sfxFx, sfxFy,
                             sfxCx, sfxCy,
                             fxS2, ulShift) ;
  }
  else
  {
    // Compute the bezier control points and endpoint of the
    // first sub-conic and draw it.
    // Bezier point 0 is the current position.
    // The order of arithmatic in the following is arranged to avoid overflow.
    lPt3x = sfxDx ;
    lPt3y = sfxDy ;
    sfxDx = sfxDx - frmul (sfxDx, fxQ) ;
    sfxDy = sfxDy - frmul (sfxDy, fxQ) ;
    sfxEx = frmul (sfxEx, fxQ) ;
    sfxEy = frmul (sfxEy, fxQ) ;

    lPt1x = (sfxAx - frmul (sfxAx, fxQ)) + sfxEx ;
    lPt1y = (sfxAy - frmul (sfxAy, fxQ)) + sfxEy ;
    lPt2x =  sfxDx + sfxEx ;
    lPt2y =  sfxDy + sfxEy ;

    if (ulShift) {
       lRound = 1 << ( ulShift - 1) ;
       lPt1x = (lPt1x + lRound) >> ulShift ;
       lPt1y = (lPt1y + lRound) >> ulShift ;
       lPt2x = (lPt2x + lRound) >> ulShift ;
       lPt2y = (lPt2y + lRound) >> ulShift ;
       lPt3x = (lPt3x + lRound) >> ulShift ;
       lPt3y = (lPt3y + lRound) >> ulShift ;
    }

    PrintChannel( pddc, (PSZ)"%ld %ld %ld %ld %ld %ld c\n", lPt1x, lPt1y,
                  lPt2x, lPt2y, lPt3x, lPt3y );


    // Compute the bezier control points and endpoint of the
    // first sub-conic and draw it.
    // Bezier point 0 is the current position.
    // The order of arithmatic in the following is arranged to avoid overflow.
    sfxFx = frmul (sfxFx, fxQ) ;
    sfxFy = frmul (sfxFy, fxQ) ;

    lPt1x = sfxDx + sfxFx ;
    lPt1y = sfxDy + sfxFy ;
    lPt2x = (sfxCx - frmul (sfxCx, fxQ)) + sfxFx ;
    lPt2y = (sfxCy - frmul (sfxCy, fxQ)) + sfxFy ;
    lPt3x = sfxCx ;
    lPt3y = sfxCy ;

    if (ulShift) {
       // lRound = 1 << ( ulShift - 1) ;
       lPt1x = (lPt1x + lRound) >> ulShift ;
       lPt1y = (lPt1y + lRound) >> ulShift ;
       lPt2x = (lPt2x + lRound) >> ulShift ;
       lPt2y = (lPt2y + lRound) >> ulShift ;
       lPt3x = (lPt3x + lRound) >> ulShift ;
       lPt3y = (lPt3y + lRound) >> ulShift ;
    }

    PrintChannel( pddc, (PSZ)"%ld %ld %ld %ld %ld %ld c\n", lPt1x, lPt1y,
                  lPt2x, lPt2y, lPt3x, lPt3y );

    // Expand the bounds accumulation to include the convex
    // hull of the two sub-conics.
    if (ulShift) {
       // lRound = 1 << ( ulShift - 1) ;
       sfxAx = (sfxAx + lRound) >> ulShift ;
       sfxAy = (sfxAy + lRound) >> ulShift ;
       sfxEx = (sfxEx + lRound) >> ulShift ;
       sfxEy = (sfxEy + lRound) >> ulShift ;
       sfxFx = (sfxFx + lRound) >> ulShift ;
       sfxFy = (sfxFy + lRound) >> ulShift ;
       sfxCx = (sfxCx + lRound) >> ulShift ;
       sfxCy = (sfxCy + lRound) >> ulShift ;

    }

    prdl_ExpandBounds( pddc, sfxAx, sfxAy) ;
    prdl_ExpandBounds( pddc, sfxEx, sfxEy) ;
    prdl_ExpandBounds( pddc, sfxFx, sfxFy) ;
    prdl_ExpandBounds( pddc, sfxCx, sfxCy) ;
  }

  /*
  ** !!!! what about the current position
  */
  return ;

}

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_CheckConic
 *
 * DESCRIPTION   =
 *
 *  Given the three vertices of the conic triangle and the sharpness,

 *  this routine converts the conic to a Bezier curve and outputs the
 *  appropriate PostScript code to append the conic to the current path.
 *
 *  First the conic is subdivided at the parameter t = 1/2.
 *  If the sharpness of the subdivided conic is large then
 *  it is subdivided further.
 *
 *  Input:
 *       pt A of the conic.
 *       pt B of the conic.
 *       pt C of the conic.
 *       conic's sharpness.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 * Fri-11-Jun-1993 -by-  Ravisankar
 * Wrote it.
 ****************************************************************************/
BOOL prdl_CheckConic (LONG lAx, LONG lAy,
                      LONG lBx, LONG lBy,
                      LONG lCx, LONG lCy, FIXED fxS)
{

  QUAD  q1, q2 ;
  ULONG ulOFlag ;

  // If the sharpness is zero or
  // if all the 3 points are collinear
  // return false.

  if (!fxS)
  {
    return (FALSE) ;
  }
  else
  {

    // 2 vectors
    // [ BAx BAy ]
    // [ BCx BCy ]
    //
    // crossproduct = BAx*BCy - BCx*BAy
    //
    // BAx = lAx - lBx
    // BAy = lAy - lBy
    // BCx = lCx - lBx
    // BCy = lCy - lBy

    fxmultiply (&q1, (lAx - lBx), (lCy - lBy), &ulOFlag) ;
    fxmultiply (&q2, (lAy - lBy), (lCx - lBx), &ulOFlag) ;


    if (q1.lDWlo == q2.lDWlo && q1.lDWhi == q2.lDWhi)
       return (FALSE);   // points are collinear.
    else
      return (TRUE);

  }

}
/***************************************************************************
 *
 * FUNCTION NAME =  prdl_PolyFilletSharp
 *
 * DESCRIPTION   =  Draw a series of conic fillets. The fillet is
 *                  drawn from point A to point C of triangle ABC with
 *                  sharpness S.
 *
 * INPUT         = HDC hdc                  The display context handle
 *                 PPOINTL pptl             Ptr to the array of input points
 *                 LONG  npt                The number of points
 *                 FIXED  *pfxSharpness  Ptr to the sharpness array
 *                 PDDC pddc                Ptr to the DC instance data
 *                 ULONG FunN
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

ULONG prdl_PolyFilletSharp( HDC hdc, PPOINTL pptl, LONG npt,
                            FIXED *pfxSharpness, PDDC pddc, ULONG FunN)
  /*
  ** HDC hdc                  The display context handle
  ** PPOINTL pptl             Ptr to the array of input points
  ** LONG  npt                The number of points
  ** FIXED  *pfxSharpness    Ptr to the sharpness array
  ** PDDC pddc                Ptr to the DC instance data
  ** ULONG FunN
  */
{
  POINTL aptl[3];
  BOOL   fDraw;
  ULONG  tl;

  EnterDriver( pddc );

  #if    DEBUG
    LogCall( "prdl_PolyFilletSharp(%08lx, %lp, %ld, %f, %lp, %lp)", ((PB)&hdc)+
             sizeof(hdc) );
  #endif

  /*
  ** do nothing if we are passed zero points.
  */
  if (npt == 0)
  {
    ExitDriver( pddc );
    return( SUCCESS );
   }

   /*
   ** make sure we have a valid number of points.  ie >=0 and even.
   */
   if ((npt < 0) || (npt % 2))
   {
    GplErrSetError(  PMERR_INV_LENGTH_OR_COUNT );
    ExitDriver( pddc );
    return( FAILURE );
  }

  /*
  ** Issue drawing commands only if the draw bit is on.
  */
  fDraw = (BOOL) (FunN & COM_DRAW );
  pddc->pddcb->bounds.fAccumulate = (FunN & COM_BOUND );

  /*
  ** Move to the current pen position and use this as the first endpoint
  */
  if (fDraw)
  {
    ps_movetoCPx( pddc, (PPOINTL) &pddc->pddcb->pen.ptlCur );
  }
  aptl[0] = pddc->pddcb->pen.ptlCur;
  prdl_ExpandBounds( pddc, aptl[0].x, aptl[0].y );

  while (npt > 0)
  {
    /*
    ** Each iteration of the loop consumes two points, so decrement
    ** the point count and copy the next two points into the conic
    ** descriptor consisting of the three corners of the triangle.
    */
    npt -= 2;
    aptl[1] = pptl[0];
    ++pptl;
    aptl[2] = pptl[0];
    ++pptl;

    /*
    ** Convert the conic coordinates to bezier coordinates.
    */
    if (fDraw)
    {
      prdl_DrawConic( pddc, aptl, *pfxSharpness++ );
    }

    /*
    ** The last endpoint of this fillet becomes the first endpoint of
    ** the next fillet.
    */
    aptl[0] = aptl[2];
  }

  /*
  ** indicate the current path contains curves.
  */
  pddc->pddcb->cgs.fCurvesInPath = TRUE;

  /*
  ** Stroke the path that we just created.
  */
  if (!pddc->pddcb->path.fPathOrArea)
  {
    if (fDraw)
    {
      ps_strokecurrentpath( pddc );
    }
  }

  /*
  ** Set the current position to the last endpoint of the fillets.
  */
  /*
  ** ps_sync_cp(pddc, &aptl[0] ); prior to B790611
  */
  ps_sync_cp( pddc, &aptl[0], fDraw );
  tl = ps_status( pddc );
  ExitDriver( pddc );
  return( tl );
}

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_PolyFillet
 *
 * DESCRIPTION   =  Draws a series of fillets.
 *
 * INPUT         = HDC hdc                  The display context handle
 *                 PPOINTL pptlSrc          Ptr to the array of input points
 *                 LONG  npt                The number of points
 *                 PDDC pddc                Ptr to the DC instance data
 *                 ULONG FunN
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

ULONG prdl_PolyFillet( HDC hdc, PPOINTL pptlSrc, LONG npt, PDDC pddc,
                       ULONG FunN)

  /*
  ** HDC hdc         The display context handle
  ** PPOINTL pptlSrc   Ptr to the array of input points
  ** LONG  npt       The number of points
  ** PDDC pddc       Ptr to the DC instance data
  ** ULONG FunN
  */
{
  POINTL aptl[4];
  FIXED  fxSharpness;        /* The conic's sharpness                       */
  BOOL   fDraw;
  ULONG  tl;

  EnterDriver( pddc );

  #if    DEBUG
    LogCall( "prdl_PolyFillet(%08lx, %lp, %ld, %lp, %lp)", ((PB)&hdc)+sizeof(hdc) );
  #endif

  /*
  ** If there are no points, then there's nothing to draw.
  ** If there is only one point, then the input data is incomplete.
  */
  if (npt == 0)
  {
    ExitDriver( pddc );
    return( SUCCESS );
  }
  else if (npt == 1 || npt < 0)
  {
    GplErrSetError(  PMERR_INV_LENGTH_OR_COUNT );
    ExitDriver( pddc );
    return( FAILURE );
  }

  /*
  ** Issue drawing commands only if the draw bit is on.
  */
  fDraw = (BOOL) (FunN & COM_DRAW);
  fxSharpness = FX_ROOTHALF;
  pddc->pddcb->bounds.fAccumulate =( FunN & COM_BOUND );

  /*
  ** If a new path is requested, then do it.
  */
  if (!pddc->pddcb->path.fPathOrArea)
  {
    ps_clearpath(pddc );
  }

  /*
  ** Move to the current pen position and use this as the first endpoint
  */
  if (fDraw)
  {
    ps_movetoCPx( pddc, (PPOINTL) &pddc->pddcb->pen.ptlCur );
  }
  aptl[0] = pddc->pddcb->pen.ptlCur;
  prdl_ExpandBounds( pddc, aptl[0].x, aptl[0].y );

  while (npt > 0)
  {

    #if  DEBUG
      PrintLog((PSZ)"\n" );
      PrintLog((PSZ)"npt = %ld\n", npt );
      PrintLog((PSZ)"pptlSrc[0] = {%ld, %ld}\n", pptlSrc[0].x, pptlSrc[0].y );
      PrintLog((PSZ)"pptlSrc[1] = {%ld, %ld}\n", pptlSrc[1].x, pptlSrc[1].y );
    #endif

    aptl[1] = pptlSrc[0];

    /*
    ** If there are more than two points left the endpoint of the
    ** curve is the midpoint of the line connecting the last two
    ** points.
    */

    if (npt > 2)
    {
            /*
            ** Calculate the midpoints of the next line segment
            */
      aptl[2].x = (pptlSrc[0].x+pptlSrc[1].x) / 2;
      aptl[2].y = (pptlSrc[0].y+pptlSrc[1].y) / 2;
      ++pptlSrc;
      --npt;
    }
    else
    {
      aptl[2] = pptlSrc[1];
      npt -= 2;
    }

    #if  DEBUG
      PrintLog((PSZ)"aptl[0] = {%ld, %ld}\n", aptl[0].x, aptl[0].y );
      PrintLog((PSZ)"aptl[1] = {%ld, %ld}\n", aptl[1].x, aptl[1].y );
      PrintLog((PSZ)"aptl[2] = {%ld, %ld}\n", aptl[2].x, aptl[2].y );
      PrintLog((PSZ)"\n" );
    #endif

    /*
    ** Convert the conic coordinates to bezier coordinates.
    */
    if (fDraw)
    {
      prdl_DrawConic( pddc, aptl, fxSharpness );
    }

    /*
    ** The last endpoint of this fillet becomes the first endpoint of
    ** the next fillet.
    */
    aptl[0] = aptl[2];
  }

  /*
  ** indicate the current path contains curves.
  */
  pddc->pddcb->cgs.fCurvesInPath = TRUE;

  /*
  ** Stroke the path that we just created.
  */
  if (!pddc->pddcb->path.fPathOrArea)
  {
    if (fDraw)
    {
      ps_strokecurrentpath( pddc );
    }

    /*
    ** Set the current position to the last endpoint of the fillets.
    */
    /*
    **  ps_sync_cp(pddc, &aptl[0] ); prior to B790611
    */
  }
  ps_sync_cp( pddc, &aptl[0], fDraw );
  tl = ps_status( pddc );
  ExitDriver( pddc );
  return( tl );
}

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_PolySpline
 *
 *
 * DESCRIPTION   =  Draws a series of connected bezier curves
 *
 *
 *
 * INPUT         = HDC hdc             The display context handle
 *                 PPOINTL pptl        Ptr to the array of input points
 *                 LONG  npt           The number of points
 *                 PDDC pddc           Ptr to the DC instance data
 *                 ULONG FunN
 *
 * OUTPUT        = NONE
 *
 *
 * RETURN-NORMAL = TRUE
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 ****************************************************************************/

ULONG   prdl_PolySpline( HDC hdc, PPOINTL pptl, LONG npt, PDDC pddc, ULONG FunN)
  /*
  ** HDC hdc      The display context handle
  ** PPOINTL pptl   Ptr to the array of input points
  ** LONG  npt    The number of points
  ** PDDC pddc    Ptr to the DC instance data
  ** ULONG FunN
  */
{
  BOOL  fDraw;
  ULONG tl;

  EnterDriver( pddc );

  #if    DEBUG
    LogCall( "prdl_PolySpline(%08lx, %lp, %ld, %lp, %ld)", ((PB)&hdc)+sizeof(hdc) );
  #endif

  /*
  ** do nothing if we are passed zero points.
  */
  if (npt == 0)
  {
    ExitDriver( pddc );
    return( SUCCESS );
  }

  /*
  ** check for valid point count.  ie > 0 and divisible by 3.
  */
  if ((npt < 0) || (npt % 3))
  {
    GplErrSetError(  PMERR_INV_LENGTH_OR_COUNT );
    ExitDriver( pddc );
    return( FAILURE );
  }

  /*
  ** Issue drawing commands only if the draw bit is on.
  */
  fDraw = (BOOL) (FunN & COM_DRAW );
  pddc->pddcb->bounds.fAccumulate = (FunN & COM_BOUND );

  if (fDraw)
  {
    ps_movetoCPx(pddc, (PPOINTL)&pddc->pddcb->pen.ptlCur );
  }
  prdl_ExpandBounds( pddc, pddc->pddcb->pen.ptlCur.x, pddc->pddcb->pen.ptlCur.y );

  while (npt > 0)
  {
    /*
    ** draw the next curve.
    */
    if (fDraw)
    {
      PrintChannel( pddc, (PSZ)"%ld %ld %ld %ld %ld %ld c\n", pptl[0].x, pptl[0].y,
                    pptl[1].x, pptl[1].y, pptl[2].x, pptl[2].y );
    }

    /*
    ** Since the curve falls within the convex hull determined by the
    ** two endpoints and two control points, we can accumulate the
    ** curve bounds by expanding the bounds rectangle on each point.
    */
    prdl_ExpandBounds( pddc, pptl[0].x, pptl[0].y );
    prdl_ExpandBounds( pddc, pptl[1].x, pptl[1].y );
    prdl_ExpandBounds( pddc, pptl[2].x, pptl[2].y );

    /*
    ** Each iteration of the loop consumes three points, so decrement
    ** the point count and bump to the next set of points.
    */
    npt -= 3;
    pptl += 3;
  }

  /*
  ** update the current position to the last point.
  */
  pptl -= 3;

  /*
  **    ps_sync_cp(pddc, &pptl[2] ); prior to B790611
  */
  ps_sync_cp( pddc, &pptl[2], fDraw );

  /*
  ** indicate the current path contains curves.
  */
  pddc->pddcb->cgs.fCurvesInPath = TRUE;

  /*
  ** Stroke the path that we just created.
  */
  if (!pddc->pddcb->path.fPathOrArea)
  {
    if (fDraw)
    {
      ps_strokecurrentpath( pddc );
    }
  }
  tl = ps_status( pddc );
  ExitDriver( pddc );
  return( tl );
}

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_SetLineOrigin
 *
 * DESCRIPTION   =
 *
 *  Sets the current style state in the pddc, and the current position.
 *  Style is really two SHORTs.  The hi SHORT is 0 if no first pel and
 *  1 if first pel.  The postscript driver will ignore this.  The lo SHORT
 *  has 2 parts.  The lo BYTE is the position in the style mask.  The hi
 *  BYTE is the style error term.  The postscript driver will also ignore
 *  the style info, as PostScript strokes the whole path at once, and does
 *  the right thing with the style.
 *
 * INPUT         = HDC     hdc        The display context handle
 *                 PPOINTL pXY        pointer to new current position
 *                 ULONG   Style      style info
 *                 PDDC pddc          Ptr to the DC instance data
 *                 ULONG FunN
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

ULONG prdl_SetLineOrigin( HDC hdc, PPOINTL pXY, ULONG Style,
                          PDDC pddc, ULONG FunN )

  /*
  ** HDC           hdc        The display context handle
  ** PPOINTL pXY              pointer to new current position
  ** ULONG   Style      style info
  ** PDDC pddc        Ptr to the DC instance data
  ** ULONG FunN
  */
{

  ULONG ulRet;

  EnterDriver( pddc );

  if (pddc->iType == OD_MEMORY)
  {
    ulRet = InnerGreSetLineOrigin( pddc->hdcMemory, pXY, Style, FunN );
    ExitDriver( pddc );
    return( ulRet );
  }

  /*
  **  !!!CR should we return failure here
  **  !!!CR if not what about the line style?
  */
  /*
  **    set the current position
  */
  ps_moveto( pddc, pXY );
  ulRet = ps_status( pddc );
  ExitDriver( pddc );
  return( ulRet );
}

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_GetLineOrigin
 *
 * DESCRIPTION   =  GetLineOrigin
 *
 * INPUT         = HDC     hdc     The display context handle
 *                 PPOINTL pptl    pointer to new current position
 *                 PDDC pddc       Ptr to the DC instance data
 *                 ULONG FunN
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

ULONG   prdl_GetLineOrigin( HDC hdc, PPOINTL pptl, PDDC pddc, ULONG FunN )
  /*
  ** HDC           hdc     The display context handle
  ** PPOINTL pptl    pointer to new current position
  ** PDDC pddc     Ptr to the DC instance data
  ** ULONG FunN
  */
{

  ULONG ulRet;
  EnterDriver( pddc );

  if (pddc->iType == OD_MEMORY)
  {
    ulRet = InnerGreGetLineOrigin( pddc->hdcMemory, pptl, FunN );
    ExitDriver( pddc );
    return( ulRet );
  }

  /*
  ** !!!CR should we return failure here
  ** !!!CR if  not what about the line style?
  */
  /*
  **    get the current position
  */
  ulRet = prdl_GetCurrentPosition( hdc, pptl, pddc, FunN );
  ExitDriver( pddc );
  return( ulRet );
}

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_PolyLine
 *
 * DESCRIPTION   =  PolyLine
 *
 * INPUT         = HDC     hdc     The display context handle
 *                 PPOINTL pptl    pointer to new current position
 *                 ULONG   npt     The number of points in the array
 *                 PDDC    pddc    Ptr to the DC instance data
 *                 ULONG   FunN
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

ULONG   prdl_PolyLine( HDC hdc, PPOINTL pptl, ULONG npt, PDDC pddc, ULONG FunN)
  /*
  ** HDC           hdc     The display context handle
  ** PPOINTL pptl    pointer to new current position
  ** ULONG   npt           The number of points in the array
  ** PDDC    pddc    Ptr to the DC instance data
  ** ULONG   FunN
  */
{
  POINTL ptl;                /* A point from the PolyLine                   */
  BOOL   fDraw;
  ULONG  ulRet ;

  EnterDriver( pddc );

  if (pddc->iType == OD_MEMORY)
  {
    if (FunN & (COM_PATH | COM_AREA))
    {
       ulRet = (ULONG) (*pfnlPolyLine)( pddc->hdc, pptl, npt, pddc, FunN );
    }
    else
    {
       ulRet = InnerGrePolyLine( pddc->hdcMemory, pptl, npt, FunN );
    }
    ExitDriver( pddc );
    return( ulRet );
  }

  #if    DEBUG
    LogCall( "prdl_PolyLine(%08lx, %lp, %ld, %lp, %lp)", ((PB)&hdc)+sizeof(hdc) );
  PrintLog((PSZ)"pddc->pddcb->path.fPathOrArea = %d\n",
     pddc->pddcb->path.fPathOrArea );
  #endif

  fDraw = (BOOL) (FunN & COM_DRAW );

  /*
  ** do nothing if we are passed zero points.
  */

  if (npt == 0)
  {
    ExitDriver( pddc );
    return( SUCCESS );
  }

  /*
  ** make sure we have non-negative point count.
  */
  if (npt < 0)
  {
    GplErrSetError(  PMERR_INV_LENGTH_OR_COUNT );
    ExitDriver( pddc );
    return( FAILURE );
  }

  /*
  ** move to the current pen position.
  */

  if (fDraw)
  {
    ps_movetoCPx(pddc, (PPOINTL)&pddc->pddcb->pen.ptlCur );
  }
  pddc->pddcb->bounds.fAccumulate = (FunN&COM_BOUND );
  prdl_ExpandBounds( pddc, pddc->pddcb->pen.ptlCur.x, pddc->pddcb->pen.ptlCur.y );

  /*
  ** Loop for each point in the PolyLine
  */

  while (npt-- > 0)
  {
    /*
    ** Get a copy of the current point
    */

    ptl.x = pptl->x;
    ptl.y = pptl->y;

    /*
    ** Bump the pointer to the next point
    */

    ++pptl;
    prdl_ExpandBounds( pddc, ptl.x, ptl.y );

    /*
    ** Append the next point to the PostScript path
    */

    if (fDraw)
    {
      ps_lineto( pddc, &ptl );
    }
  }

  /*
  ** Check to see if the path should be stroked immediatly.  If not
  ** then the path is left intact for COM_PATH or COM_AREA.
  */

  if (!pddc->pddcb->path.fPathOrArea)
  {
    if (fDraw)
    {
      ps_strokecurrentpath( pddc );
    }
  }

  /*
  ** Update the current pen position
  */
  /*
  **    ps_sync_cp(pddc, &ptl ); prior to B790611
  */
  ps_sync_cp( pddc, &ptl, fDraw );
  ulRet  = ps_status( pddc );
  ExitDriver( pddc );
  return( ulRet );
}

/***************************************************************************
 *
 * FUNCTION NAME =  prdl_PolyMarker
 *
 * DESCRIPTION   =
 *
 * draws NumberOfPoints markers centred at the positions in the Points
 * array the marker definitions may be the defaults or a font and
 * are pointed to by the defSet field of the device marker bundle
 *
 * INPUT         = HDC      hdc      The DC handle
 *                 PPOINTL  pptlArg  Pointer to the array of points
 *                 LONG     npt      Number of points in Points array
 *                 PDDC     pddc     Pointer to the DC instance data
 *                 ULONG    FunN     The function number
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

ULONG   prdb_PolyMarker( HDC hdc, PPOINTL pptlArg, LONG npt, PDDC pddc,
                                               ULONG FunN)

   /*
   ** HDC           hdc      The DC handle
   ** PPOINTL  pptlArg  Pointer to the array of points
   ** LONG     npt      Number of points in Points array
   ** PDDC     pddc     Pointer to the DC instance data
   ** ULONG    FunN     The function number
   */

{
  SHORT  nxCell;            /* The marker cell width         */
  SHORT  nyCell;            /* The marker cell height        */
  RECTL  rclCell;           /* The cell's bounding rectangle */
  POINTL ptl;               /* The coordinates of the marker */
  ULONG  Command;
  SHORT  index;
  LONG   ll;
  ULONG  ulRet ;
  SHORT  sMarkerSet = 0;      /*            */
  MATRIX  mxSaveMatrix;
  MATRIX *pMatrix;
  UCHAR   achMarker[2];
  LONG    lCount;
  PCHAR   pchOutput;

  EnterDriver( pddc );

  #if    DEBUG
    LogCall( "prdb_PolyMarker(%08lx, %lp, %ld, %lp, %08lx)", ((PB)&hdc)+sizeof (HDC) );
  #endif /* DEBUG                                           */

  /*
  ** if memory dc dispach to gre
  */
  if (pddc->iType == OD_MEMORY)
  {
    ulRet = InnerGrePolyMarker( pddc->hdcMemory, pptlArg, npt, FunN );
    ExitDriver( pddc );
    return( ulRet );
  }

  /*
  ** If no points were passed in, then the PolyMaker call is a
  ** no-op according to the spec.
  */
  if (npt == 0)
  {
    ExitDriver( pddc );
    return( SUCCESS );
  }

  if ((!pptlArg) && (npt > 1L))
  {
    GplErrSetError(  PMERR_INV_COORDINATE );
    ExitDriver( pddc );
    return( FAILURE );
  }

  /*
  ** we can handle only our own default marker font.
  ** if a user font is passed in, let the Engine
  ** handle the call.
  */
  if (pddc->pddcb->mkr.dmbnd.cDefs & CDEF_GENERIC)
  {
    /*
    ** first make sure the engine's marker attributes agree with
    ** the driver's.
    */

    if (!(GreSetAttributes(hdc, PRIM_MARKER, 0L, -1L, (MARKERBUNDLE  *)
         &pddc->pddcb->mkr.dmbnd.mbnd)))
    {
      ExitDriver( pddc );
      return( FAILURE );
    }

    ulRet = (ULONG) (*pfnlPolyMarker) (hdc, pptlArg, npt, pddc, FunN );
    ExitDriver( pddc );
    return( ulRet );
  }

  /*
  ** we have the default marker font, we will handle the call.
  ** it is illegal to draw markers within an area
  */
  Command = FunN;

  if (Command & COM_AREA)
  {
    GplErrSetError(  PMERR_INV_NESTED_FIGURES );
    ExitDriver( pddc );
    return( FAILURE );
  }

  /*           
  ** If marker set not 0 means we are using current font as marker
  */
  if ( (sMarkerSet = pddc->pddcb->mkr.dmbnd.mbnd.usSet) != (SHORT)NULL )
  {
    index = pddc->pddcb->mkr.dmbnd.mbnd.usSymbol;
  }
  else
  {
    /*
    ** see if we have a valid marker symbol, if not set it to the
    ** default.
    --
    ** By moving character 64 down to zero, all markers can be in a
    ** single table.
    */
    if ((pddc->pddcb->mkr.dmbnd.mbnd.usSymbol >= MARKSYM_CROSS) &&
       (pddc->pddcb->mkr.dmbnd.mbnd.usSymbol <= MARKSYM_SMALLCIRCLE))
    {
       index = pddc->pddcb->mkr.dmbnd.mbnd.usSymbol;
    }
    else if (pddc->pddcb->mkr.dmbnd.mbnd.usSymbol == MARKSYM_BLANK)
    {
      index = 0;       /* remap 64 to 0 */
    }
    else
    {
      index = MARKSYM_CROSS; /* our default marker */
    }

    index += 65;
  }

  /*
  ** initialise marker cell size
  */
  nxCell = FIXEDINT( pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cx );
  nyCell = FIXEDINT( pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cy );

  /*
  ** see if the marker font has been loaded.    load it if not
  */
  if ( pddc->pddcb->mkr.usfMFont == FALSE &&
       sMarkerSet == 0                     )    /*            */
  {
    LoadMarkerFont( pddc );
  }

  /*           
  ** If we are using the current font set size
  */
  if ( sMarkerSet )
  {
    /*
    ** Since we are using the current font make sure it is the right
    ** size ( they should be the same though... )
    */
    pMatrix = (MATRIX *)&pddc->pddcb->text.transformmatrix;
    mxSaveMatrix = *pMatrix;  /* Save font matrix */
    /* Set up for font call with marker sizes */
    pMatrix->mx_fxM11 = pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cx;
    pMatrix->mx_fxM22 = pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cy;

    ps_SetDownloadedFont( pddc );

    achMarker[0] = (UCHAR)index;
    achMarker[1] = 0;
    lCount = prda_RemapString( achMarker, (LONG)1, pddc );
    pchOutput = pddc->pdv->chText;
    *(pchOutput+lCount) = 0;

    *pMatrix = mxSaveMatrix;

  }
  else
  {
    if (pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cx ==
       pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cy)
    {
      PrintChannel( pddc, (PSZ)"%f /MARKERfont SF\n",
                    pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cx );
    }
    else
    {
      PrintChannel( pddc, (PSZ)"[%f 0 0 %f 0 0] /MARKERfont MF\n",
                    pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cx,
                    pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cy );
    }
  }

  /*
  ** indicate the font has been changed, so the next time someone
  ** goes to print, they will need to reload the font they want.
  */
  pddc->pddcb->cgs.fValidFont = FALSE;

  /*
  ** set the marker color.
  */
  ps_setrgbcolor( pddc, prdc_GetColor(pddc, pddc->pddcb->mkr.dmbnd.mbnd.lColor) );
  ptl.x = pddc->pddcb->pen.ptlCur.x;
  ptl.y = pddc->pddcb->pen.ptlCur.y;

  for (ll = 0; ll < npt; ll++)
  {
    /*
    ** center the marker at the specified point
    */
    ptl.x -= nxCell / 2;
    ptl.y -= nyCell / 2;

    if (Command & COM_BOUND)
    {
      rclCell.xLeft = ptl.x;
      rclCell.yTop = ptl.y;
      rclCell.xRight = rclCell.xRight+nxCell;
      rclCell.yBottom = rclCell.yTop+nyCell;

      #if        0
        /*
        ** !!!CR fix bounds accumulation
        */
        prdg_AddBounds( &rclCell, pddc );
      #endif
    }

    if ((Command & COM_DRAW) && (pddc->pddcb->mkr.dmbnd.mbnd.usMixMode !=
       FM_LEAVEALONE))
    {
      /*
      ** Move the pen to the marker location
      */
      if ( sMarkerSet == 0 )  /*            */
        PrintChannel( pddc, (PSZ)"%ld %ld m <%x> t\n", ptl.x, ptl.y, index );
      else
        PrintChannel( pddc, (PSZ)"%ld %ld m (%s) t\n", ptl.x, ptl.y, pchOutput );
    }

    /*
    ** Get a copy of the coordinates of the next marker
    */
    if (npt > 1)
    {
      ptl.x = pptlArg->x;
      ptl.y = pptlArg->y;
      pptlArg++;
    }
  }

  /*
  ** make sure the current position is updated to the position
  ** of the last point given.
  */
  if (npt > 1)
  {
    pptlArg--;
    pptlArg--;
    ptl.x = pptlArg->x;
    ptl.y = pptlArg->y;
  }

  /*
  ** If npt == 1, then after positioning the marker,
  ** the current pen position has to be moved
  ** to the center of the marker (Current pen position before
  ** the marker is positioned).
  **                                                                
  */
  else if (npt == 1)
  {
    ptl.x = pddc->pddcb->pen.ptlCur.x;/* Current pen position before        */
    ptl.y = pddc->pddcb->pen.ptlCur.y;/* the marker is positioned.          */
  }

  /*
  ** Update the current pen position.
  */

  ps_moveto( pddc, &ptl );
  ExitDriver( pddc );
  return( SUCCESS );
}

/***************************************************************************
 *
 * FUNCTION NAME =  LoadMarkerFont
 *
 *
 * DESCRIPTION   = Downloads the code to the Postscript printer
 *                 which defines the marker font.
 *
 *
 * INPUT         = PDDC     pddc     Pointer to the DC instance data
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void LoadMarkerFont( PDDC pddc )
{
  PSZ  *ppsz;

  /*
  ** !!!CR Load marker stuff from a resource
  ** !!!CR This could be a common routine
  */
  ppsz = apszFontCode;

  while (*ppsz)
  {
    PrintChannel(pddc, (PSZ)"%ls\n", (PSZ)*ppsz++ );
  }
  pddc->pddcb->mkr.usfMFont = TRUE;/* indicate the font is loaded           */
}
