/*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 = ATTRS.C
 *
 * DESCRIPTIVE NAME = Contains attribute related routines.
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION  This file contains DeviceSetAttributes, DeviceGetAttributes,
 *              SetCurrentPosition, GetCurrentPosition, and support routines.
 *
 * FUNCTIONS     prda_GetTextAttrs
 *               prda_GetLineAttrs
 *               prda_GetMarkAttrs
 *               prda_GetPtrnAttrs
 *               prda_GetImagAttrs
 *               prda_DeviceGetAttributes
 *               prda_SetTextAttrs
 *               prda_SetLineAttrs
 *               prda_SetMarkAttrs
 *               prda_SetPtrnAttrs
 *               prda_SetImagAttrs
 *               prda_DeviceSetAttributes
 *               prda_DeviceSetGlobalAttribute
 *               prdl_SetCurrentPosition
 *               prdl_SetStyleRatio
 *               prdl_GetCurrentPosition
 *               prdl_PatGray
 *               prdl_PenGray
 *
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_DDIMISC
#define  LINE_ATTR   0x0001
#define  TEXT_ATTR   0x0002
#define  MARK_ATTR   0x0003
#define  PTRN_ATTR   0x0004
#define  IMAG_ATTR   0x0005
#include "inc\prdinclt.h"
#include "inc\prdgextf.h"
#include "inc\prdatypt.h"
#include "inc\prdtextf.h"
#include "inc\utl.h"
#include "inc\prdmath.h"
#include "inc\prdtcone.h"
#include "inc\prdlextf.h"
#include "inc\prdcextf.h"
#include "inc\pspagtun.h"              /* V2.174057   Page Tuning */
#define  INCL_GENPLIB_ERROR
#include <genplib.h>

#include <pmfont.h>
#define  OD_MEMORY  8L

extern PDDC  EnterDriver(PDDC);
extern VOID  ExitDriver(PDDC);
extern PFNL  pfnlSetCurrentPosition ;
/*
** Text bundle of attributes
*/

/*
** !!!CR 9-15-88 changed default char cell to 12 pt: this makes more
** sense to me than to have it set to zero, since when we pass back
** fontmetrics, we must scale them to the current cell.  THIS MUST BE
** CHECKED WITH PAULK
*/

/*
** !!!CR DEFAULT_BACKGROUND_MIX is an invalid value, fix it
** !!!CR default character size is based on hardcoded 300 dpi, fix it
** !!!CR use define for precision mode 3
*/

CHARBUNDLE DefCharBundle = {
        DEFAULT_FOREGROUND_COL,        /* foreground color            */
        DEFAULT_BACKGROUND_COL,        /* background color            */
        DEFAULT_FOREGROUND_MIX,        /* foreground mix              */
        DEFAULT_BACKGROUND_MIX,        /* background mix              */
        0x00,                          /* char set - base font lcid   */
        0x3,                           /* precision mode - 3          */
        {0x320000L,0x320000L},         /* cell width, height (12 pt)  */
        {0x1L,0x0L},                   /* Angle                       */
        {0x0L,0x1L},                   /* Shear                       */
        0x1,                           /* Direction - left to right   */
        TA_NORMAL_HORIZ,               /* TextAlign - Normal alignment*/
        FX_ZERO,                       /* fxExtra - normal            */
        FX_ZERO,                       /* fxBreakExtra - normal       */
   };

/*
** !!!CR change the hardcoded constants below to use defines
*/

/*
** Line bundle of attributes
*/

LINEBUNDLE  DefLineBundle =
    {
    DEFAULT_FOREGROUND_COL,        /* foreground color            */
    DEFAULT_BACKGROUND_COL,        /* background color            */
    DEFAULT_FOREGROUND_MIX,        /* foreground mix              */
    DEFAULT_BACKGROUND_MIX,        /* background mix              */
    0x00010000L,                   /* width - normal              */
    0xFFFFFFFFL,                   /* geometric width - cosmetic  */
    0x7,                           /* type - solid                */
    0x1,                           /* end - flat                  */
    0x1                            /* joint - bevel               */
    };

/*
** !!!CR marker bundle has hardcode marker resolution built in 300 dpi
** !!!CR
*/

/*
** Marker bundle of attributes
** A device bundle is used so that we can access the magic cookie for
** the marker font.
*/

DMARKERBUNDLE DefMarkerBundle =
    {
    24,                        /* attribute count (bytes)          */
    8,                         /* definition count (bytes)         */
    DEFAULT_FOREGROUND_COL,    /* foreground colour                */
    DEFAULT_BACKGROUND_COL,    /* background colour                */
    DEFAULT_FOREGROUND_MIX,    /* mix                              */
    DEFAULT_BACKGROUND_MIX,    /* background mix                   */
    0,                         /* set                              */
    1,                         /* symbol (cross)                   */
    0x00210000,                /* box x dimension 8 point          */
    0x00210000,                /* box y dimension 8 point          */
    FNULL,                     /* pointer to current set           */
    0,                         /* flags                            */
    0                          /* codepage                         */
    };


/*
** Pattern bundle of attributes
*/


DAREABUNDLE   prda_DefPtnAts = {
        0x00,
        0x00,
        DEFAULT_FOREGROUND_COL,        /* foreground color            */
        DEFAULT_BACKGROUND_COL,        /* background color            */
        DEFAULT_FOREGROUND_MIX,        /* foreground mix              */
        DEFAULT_BACKGROUND_MIX,        /* background mix              */
        0x00,                          /* set - BASE                  */
        0x00,                          /* symbol - solid shading      */
        {0x0L,0x0L}
   };

/*
** Image bundle of attributes
*/

ImageBundle   prda_DefImgAts = {
        0x0L,
        DEFAULT_FOREGROUND_COL,        /* foreground color            */
        DEFAULT_BACKGROUND_COL,        /* background color            */
        DEFAULT_FOREGROUND_MIX,        /* foreground mix              */
        DEFAULT_BACKGROUND_MIX,        /* background mix              */
   };

/***************************************************************************
 *
 * FUNCTION NAME = prda_GetTextAttrs
 *
 *
 * DESCRIPTION   = Returns the selected text attributes.
 *
 *
 * INPUT         = (usAttrMask, pArgBundle, pddc)
 *
 *
 * OUTPUT        = NONE
 *
 *
 * RETURN-NORMAL = NONE
 *
 *
 * RETURN-ERROR  = NONE
 *
 *
 *
 **************************************************************************/

void prda_GetTextAttrs( USHORT usAttrMask, PDCHARBUNDLE pArgBundle, PDDC pddc )
  /* SHORT         usAttrMask;          The attributes mask               */
  /* PDCHARBUNDLE   pArgBundle;          pointer to char. text bundle      */
{
  CHARBUNDLE *pBundle;              /* Local ref. to attributes    */

  #if DEBUG
    LogCall( "prda_GetTextAttrs(%04x, %lp, %lp)",
             ((PB) &usAttrMask) + sizeof(usAttrMask) );
  #endif /* DEBUG */

  PrintLog( (PB) "\tRequested mask = %x\n", usAttrMask );

  /*
  ** !!!CR Check for undefined attributes and return area
  */


  /*
  ** Look at the attribute mask one bit at a time and copy data to
  ** the caller's attribute bundle as requested.  Don't interfere
  ** with parts of the caller's bundle for which information was
  ** not requested.
  */
  pBundle = &pArgBundle->cbnd;

  PrintLog( (PB) "Requested attributes:\n" );

  if (usAttrMask & CBB_COLOR)
  {
    pBundle->lColor = pddc->pddcb->text.ChrBundle.lColor;
    PrintLog( (PB) "\tlColor = %04x\n", pBundle->lColor);
  }

  if (usAttrMask & CBB_BACK_COLOR)
  {
    pBundle->lBackColor = pddc->pddcb->text.ChrBundle.lBackColor;
    PrintLog( (PB) "\tlBackColor = %04x\n", pBundle->lBackColor );
  }

  if (usAttrMask & CBB_MIX_MODE)
  {
    pBundle->usMixMode = pddc->pddcb->text.ChrBundle.usMixMode;
    PrintLog( (PB) "\tusMix = %d\n", pBundle->usMixMode );
  }

  if (usAttrMask & CBB_BACK_MIX_MODE)
  {
    pBundle->usBackMixMode = pddc->pddcb->text.ChrBundle.usBackMixMode;
    PrintLog( (PB) "\tusBackMix = %d\n", pBundle->usBackMixMode );
  }

  if (usAttrMask & CBB_SET)                      /* Font name (LCID) */
  {
    pBundle->usSet = pddc->pddcb->text.ChrBundle.usSet;
    PrintLog( (PB) "\tLCID = %d\n", pBundle->usSet );
  }

  if (usAttrMask & CBB_MODE)                            /* precision */
  {
    pBundle->usPrecision = pddc->pddcb->text.ChrBundle.usPrecision;
    PrintLog( (PB) "\tusPrecision = %d\n", pBundle->usPrecision );
  }

  if (usAttrMask & CBB_BOX)                             /* cell size */
  {
    pBundle->sizfxCell.cx = pddc->pddcb->text.ChrBundle.sizfxCell.cx;
    pBundle->sizfxCell.cy = pddc->pddcb->text.ChrBundle.sizfxCell.cy;
    PrintLog( (PB) "\tCellSize = {%f, %f}\n",
              pBundle->sizfxCell.cx, pBundle->sizfxCell.cy );
  }

  if (usAttrMask & CBB_ANGLE)
  {
    pBundle->ptlAngle.x = pddc->pddcb->text.ChrBundle.ptlAngle.x;
    pBundle->ptlAngle.y = pddc->pddcb->text.ChrBundle.ptlAngle.y;
    PrintLog( (PB) "\tAngle = {%ld, %ld}\n",
              pBundle->ptlAngle.x, pBundle->ptlAngle.y );
  }

  if (usAttrMask & CBB_SHEAR)
  {
    pBundle->ptlShear.x = pddc->pddcb->text.ChrBundle.ptlShear.x;
    pBundle->ptlShear.y = pddc->pddcb->text.ChrBundle.ptlShear.y;
    PrintLog( (PB) "\tShear = {%ld, %ld}\n",
             pBundle->ptlShear.x, pBundle->ptlShear.y );
  }

  if (usAttrMask & CBB_DIRECTION)
  {
    pBundle->usDirection = pddc->pddcb->text.ChrBundle.usDirection;
    PrintLog( (PB) "\tusDirection = %d\n", pBundle->usDirection);
  }

  if (usAttrMask & CBB_TEXT_ALIGN)
  {
    pBundle->usTextAlign = pddc->pddcb->text.ChrBundle.usTextAlign;
    PrintLog( (PB) "\tusTextAlign = %d\n", pBundle->usTextAlign );
  }

  if (usAttrMask & CBB_EXTRA)
  {
    pBundle->fxExtra = pddc->pddcb->text.ChrBundle.fxExtra;
    PrintLog( (PB) "\tfxExtra = %d\n", pBundle->fxExtra );
  }

  if (usAttrMask & CBB_BREAK_EXTRA)
  {
    pBundle->fxBreakExtra = pddc->pddcb->text.ChrBundle.fxBreakExtra;
    PrintLog( (PB) "\tfxBreakExtra = %d\n", pBundle->fxBreakExtra );
  }

  return;
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_GetLineAttrs
 *
 * DESCRIPTION   = Returns the selected line attributes.
 *
 * INPUT         = (usAttrMask, pArgBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void prda_GetLineAttrs( USHORT usAttrMask, PDLINEBUNDLE pArgBundle, PDDC pddc )
  /* SHORT         usAttrMask;       The pen bundle attributes mask */
  /* PDLINEBUNDLE   pArgBundle;       Pointer to the pen attr bundle */
{
  LINEBUNDLE     *pBundle;

  /*
  ** !!!CR Check for illegal attributes tbroughout the rest of the file
  */

  #if DEBUG
    LogCall( "prda_GetLineAttrs(%04x, %lp, %lp)",
             ((PB) &usAttrMask) + sizeof( usAttrMask ) );
  #endif /* DEBUG */

  PrintLog((PB) "\tRequested mask = %x\n", usAttrMask);

  /*
  ** Look at the attribute mask one bit at a time and copy data to
  ** the caller's attribute bundle as requested.  Don't interfere
  ** with parts of the caller's bundle for which information was
  ** not requested.
  */


  pBundle = &pArgBundle->lbnd;

  PrintLog( (PB) "Requested attributes:\n") ;

  /*
  ** !!!CR use predefined constants instead of BIT1, BIT2, etc
  ** !!!CR Do this for whole file
  */
  if (usAttrMask & BIT0)
  {
    pBundle->lColor = pddc->pddcb->pen.ulFgColor ;
    PrintLog( (PB) "\tulFgColor = %08lx\n", pBundle->lColor) ;
  }

  if (usAttrMask & BIT2)
  {
    pBundle->usMixMode = pddc->pddcb->pen.usFgMix ;
      PrintLog( (PB) "\tusFgMix   = %0d\n", pBundle->usMixMode) ;
  }

  if (usAttrMask & BIT4)
  {
    pBundle->fxWidth = pddc->pddcb->pen.fxWidth ;
    PrintLog( (PB) "\tfxWidth = %f\n", pBundle->fxWidth) ;
  }

  if (usAttrMask & BIT5)
  {
    pBundle->lGeomWidth = pddc->pddcb->pen.lGeomWidth ;
    PrintLog( (PB) "\tlGeomWidth = %ld\n", pBundle->lGeomWidth) ;
  }

  if (usAttrMask & BIT6)
  {
    pBundle->usType = pddc->pddcb->pen.usType ;
    PrintLog( (PB) "\tusType = %d\n", pBundle->usType) ;
  }

  if (usAttrMask & BIT7)
  {
    pBundle->usEnd = pddc->pddcb->pen.usEnd ;
    PrintLog( (PB) "\tusEnd = %d\n", pBundle->usEnd) ;
  }

  if (usAttrMask & BIT8)
  {
    pBundle->usJoin = pddc->pddcb->pen.usJoin ;
    PrintLog( (PB) "\tusJoin = %d\n", pBundle->usJoin) ;
  }

  return;
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_GetMarkAttrs
 *
 * DESCRIPTION   = Returns the selected marker attributes.
 *
 * INPUT         = (usAttrMask, pArgBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void prda_GetMarkAttrs( USHORT usAttrMask, PDMARKERBUNDLE pArgBundle, PDDC pddc )
  /* SHORT          usAttrMask;          Mask of requested attributes */
  /* PDMARKERBUNDLE  pArgBundle;          Pointer to marker attr bundle */
{
  MARKERBUNDLE *pBundle;   /* Local ref to attr bundle */

  #if DEBUG
    LogCall("prda_GetMarkAttrs(%04x, %lp, %lp)",
             ((PB) &usAttrMask) + sizeof(usAttrMask));
  #endif /* DEBUG */

  PrintLog( (PB) "\tRequested mask = %x\n", usAttrMask );

  /*
  ** Look at the attribute mask one bit at a time and copy data to
  ** the caller's attribute bundle as requested.  Don't interfere
  ** with parts of the caller's bundle for which information was
  ** not requested.
  */
  pBundle = &pArgBundle->mbnd;

  PrintLog( (PB) "Requested attributes:\n" );

  if (usAttrMask & BIT0)
  {
    pBundle->lColor = pddc->pddcb->mkr.dmbnd.mbnd.lColor;
    PrintLog( (PB) "\tlColor = %d\n", pBundle->lColor);
  }

  if (usAttrMask & BIT1)
  {
    pBundle->lBackColor = pddc->pddcb->mkr.dmbnd.mbnd.lBackColor;
    PrintLog( (PB) "\tlBackColor = %d\n", pBundle->lBackColor);
  }

  if (usAttrMask & BIT2)
  {
    pBundle->usMixMode = pddc->pddcb->mkr.dmbnd.mbnd.usMixMode;
    PrintLog( (PB) "\tusMixMode = %d\n", pBundle->usMixMode);
  }

  if (usAttrMask & BIT3)
  {
    pBundle->usBackMixMode = pddc->pddcb->mkr.dmbnd.mbnd.usBackMixMode;
    PrintLog( (PB) "\tusBackMixMode = %d\n", pBundle->usBackMixMode);
  }

  if (usAttrMask & BIT4)
  {
    pBundle->usSet = pddc->pddcb->mkr.dmbnd.mbnd.usSet;
    PrintLog( (PB) "\tusSet = %d\n", pBundle->usSet);
  }

  if (usAttrMask & BIT5)
  {
    pBundle->usSymbol = pddc->pddcb->mkr.dmbnd.mbnd.usSymbol;
    PrintLog( (PB) "\tusSymbol = %d\n", pBundle->usSymbol);
  }

  if (usAttrMask & BIT6)
  {
    pBundle->sizfxCell = pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell;
    PrintLog( (PB) "\tMarker size = %f X %f\n", pBundle->sizfxCell.cx,
                    pBundle->sizfxCell.cy);
  }

  return;
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_GetPtrnAttrs
 *
 * DESCRIPTION   = Returns the selected pattern attributes.
 *
 * INPUT         = (usAttrMask, pBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void prda_GetPtrnAttrs( USHORT usAttrMask, lpPtrnAt pBundle, PDDC pddc )
  /* lpPtrnAt       pBundle;          !!!CR Use the standard typedef */
{
  #if DEBUG
    LogCall("prda_GetPtrnAttrs(%04x, %lp, %lp)",
             ((PB) &usAttrMask) + sizeof(usAttrMask));
  #endif /* DEBUG */

  PrintLog( (PB) "\tRequested mask = %x\n", usAttrMask );

  /*
  ** Look at the attribute mask one bit at a time and copy data to
  ** the caller's attribute bundle as requested.  Don't interfere
  ** with parts of the caller's bundle for which information was
  ** not requested.
  */
  PrintLog( (PB) "Requested attributes:\n" );

  if (usAttrMask & BIT0)
  {
    pBundle->ATPFgClr = pddc->pddcb->pat.ulFgColor;
    PrintLog( (PB) "\tulFgColor = %d\n", pBundle->ATPFgClr );
  }

  if (usAttrMask & BIT1)
  {
    pBundle->ATPBkClr = pddc->pddcb->pat.ulBgColor;
    PrintLog( (PB) "\tulBgColor = %d\n", pBundle->ATPBkClr );
  }

  if (usAttrMask & BIT2)
  {
    pBundle->ATPFgMix = pddc->pddcb->pat.usFgMix;
    PrintLog( (PB) "\tusFgMix = %d\n", pBundle->ATPFgMix );
  }

  if (usAttrMask & BIT3)
  {
    pBundle->ATPBkMix = pddc->pddcb->pat.usBgMix;
    PrintLog( (PB) "\tusBgMix = %d\n", pBundle->ATPBkMix );
  }

  if (usAttrMask & BIT4)
  {
    pBundle->ATPSet = pddc->pddcb->pat.usSet;
    PrintLog( (PB) "\tusSet = %d\n", pBundle->ATPSet );
  }

  if (usAttrMask & BIT5)
  {
    pBundle->ATPSymbol = pddc->pddcb->pat.usSymbol;
    PrintLog( (PB) "\tusSymbol = %d\n", pBundle->ATPSymbol );
  }

  if (usAttrMask & BIT6)
  {
    pBundle->ATPOrigin[0] = pddc->pddcb->pat.ptlOrg.x;
    pBundle->ATPOrigin[1] = pddc->pddcb->pat.ptlOrg.y;
    PrintLog( (PB) "\tOrigin = %d, %d\n", pBundle->ATPOrigin[0],
              pBundle->ATPOrigin[1] );
  }

  return;
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_GetImagAttrs
 *
 * DESCRIPTION   = Returns the selected image attributes.
 *
 * INPUT         = (usAttrMask, pBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

/* !!!CR get rid of definitions of lpImageAt */
void prda_GetImagAttrs( USHORT usAttrMask, lpImageAt pBundle, PDDC pddc )

  /* lpImageAt      pBundle ;          !!!CR use the standard typedef */

{

  #if DEBUG
    LogCall("prda_GetImagAttrs(%04x, %lp, %lp)\n",
             ((PB) &usAttrMask) + sizeof(usAttrMask) );
  #endif /* DEBUG */

  PrintLog( (PB) "\tRequested mask = %x\n", usAttrMask );

  /*
  ** Look at the attribute mask one bit at a time and copy data to
  ** the caller's attribute bundle as requested.  Don't interfere
  ** with parts of the caller's bundle for which information was
  ** not requested.
  */
  PrintLog( (PB) "Requested attributes:\n" );

    if (usAttrMask & BIT0)
    {
      pBundle->ATIFgClr = pddc->pddcb->image.ulFgColor;
      PrintLog( (PB) "\tulFgColor = %d\n", pBundle->ATIFgClr );
    }

    if (usAttrMask & BIT1)
    {
      pBundle->ATIBkClr = pddc->pddcb->image.ulBgColor;
      PrintLog( (PB) "\tulBgColor = %d\n", pBundle->ATIBkClr );
    }

    if (usAttrMask & BIT2)
    {
      pBundle->ATIFgMix = pddc->pddcb->image.usFgMix;
      PrintLog( (PB) "\tusFgMix = %d\n", pBundle->ATIFgMix );
    }

    if (usAttrMask & BIT3)
    {
      pBundle->ATIBkMix = pddc->pddcb->image.usBgMix;
      PrintLog( (PB) "\tusBgMix = %d\n", pBundle->ATIBkMix );
    }

    return;
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_DeviceGetAttributes
 *
 * DESCRIPTION   = Returns the selected device attributes.
 *
 * INPUT         = (hdc, ulType, ArgAttrMask,
 *                  pbBundle, pddc, FunN)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (usStatus)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prda_DeviceGetAttributes( HDC hdc, ULONG ulType, ULONG ArgAttrMask,
                                PB pbBundle, PDDC pddc, ULONG ulFunN)
  /* HDC            hdc;                  The DC handle */
  /* ULONG          ulType;               The bundle type */
  /* ULONG          ArgAttrMask;          The attributes mask */
  /* PB             pbBundle;             Ptr to the device attributes bundle */
{
  USHORT          usAttrMask;
  register USHORT usStatus;        /* !!!CR Delete this variable */

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

  EnterDriver( pddc );

  if (pddc->iType == OD_MEMORY)
  {
    usStatus = InnerGreDeviceGetAttributes( pddc->hdcMemory, ulType,
                                            ArgAttrMask,pbBundle, ulFunN );
    ExitDriver( pddc );
    return( usStatus );
  }

  PrintLog( (PB) "\tRequested mask = %x\n", ArgAttrMask );
  PrintLog( (PB) "\tBundle type = %ld\n", ulType );

  /*
  ** !!!CR Delete test for no attribute request
  **
  ** If there are no attributes to get, then we are done.
  **
  */
  if (!ArgAttrMask)
  {
    ExitDriver( pddc );
    return( SUCCESS );
  }
  usAttrMask = (USHORT) ArgAttrMask;
  usStatus = SUCCESS;

  /*
  ** Switch to appropriate subroutine according to bundle type.
  ** Subroutines always return OK
  */
  switch ((USHORT) ulType)
  {
  case 0x0001:
       prda_GetLineAttrs( usAttrMask, (PDLINEBUNDLE) pbBundle, pddc );
       break;

  case 0x0002:
       prda_GetTextAttrs( usAttrMask, (PDCHARBUNDLE)pbBundle, pddc );
       break;

  case 0x0003:
       prda_GetMarkAttrs( usAttrMask, (PDMARKERBUNDLE) pbBundle, pddc );
       break;

  case 0x0004:
       prda_GetPtrnAttrs( usAttrMask, (lpPtrnAt)pbBundle, pddc );
       break;

  case 0x0005:
       prda_GetImagAttrs( usAttrMask, (lpImageAt)pbBundle, pddc );
       break;

  default:
       PrintLog( (PSZ) "Unknown bundle type = %ld\n", ulType );

       /*
       ** !!!CR Save an error code such as INVALID ATTRIBUTE TYPE, ETC.
       */
       usStatus = FAILURE;
       break;
  }

  ExitDriver( pddc );
  return( usStatus );
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_SetTextAttrs
 *
 * DESCRIPTION   = Sets the selected text attributes.
 *
 * INPUT         = (usDefMask, usAttrMask, pArgBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (SUCCESS)
 *
 * RETURN-ERROR  = (FAILURE)
 *
 **************************************************************************/

USHORT prda_SetTextAttrs( USHORT usDefMask, USHORT usAttrMask, PDCHARBUNDLE pArgBundle, PDDC  pddc)
  /* SHORT         usDefMask;           The default mask                  */
  /* SHORT         usAttrMask;          The attributes mask               */
  /* PDCHARBUNDLE   pArgBundle;          pointer to char. text bundle      */
{
  register int  i;
  USHORT         usMask;         /* Local ref. to new attrs     */
  CHARBUNDLE   *pBundle;        /* Local ref. to attributes    */
  USHORT         usOrMask;
  FIXED         fxScale;
  SHORT         sEntry ;
  PCHAR         pChar ;         /* Change name to pb */

  #if DEBUG
    LogCall( "prda_SetTextAttrs(%04x, %04x, %lp, %lp)",
    ((PB) &usDefMask) + sizeof(usDefMask) );
  #endif /* DEBUG */

  PrintLog( (PB) "\tDefault mask = %x\n", usDefMask );
  PrintLog( (PB) "\tRequested mask = %x\n", usAttrMask );

  /*
  ** The new set of current attributes are set up in two passes.
  ** The first pass sets any default values requested, the second
  ** sets any values supplied.
  */
  pBundle =  &DefCharBundle;
  usMask = usDefMask;

  /*
  ** compute a mask which will tell us which options have been changed,
  ** ie, either changed outright or set to defaults.
  */

  usOrMask = usDefMask;
  usOrMask |= usAttrMask;

  for (i = 0 ; i < 2 ; ++i)
  {
    #if DEBUG
      (i) ? PrintLog( (PB) "Requested settings:\n") : PrintLog((PB) "Default settings:\n" );
    #endif /* DEBUG */

    if (usMask & CBB_COLOR)
    {
      pddc->pddcb->text.ChrBundle.lColor = pBundle->lColor;
      PrintLog( (PB) "\tlColor = %04x\n", pddc->pddcb->text.ChrBundle.lColor );
    }

    if (usMask & CBB_BACK_COLOR)
    {
      pddc->pddcb->text.ChrBundle.lBackColor = pBundle->lBackColor;
      PrintLog( (PB) "\tlBackColor = %04x\n", pddc->pddcb->text.ChrBundle.lBackColor );
    }

    if (usMask & CBB_MIX_MODE)
    {

      /*
      ** !!!CR Check for invalid mix mode and error if invalid
      **
      ** since the only allowed foreground mix mode is OVERPAINT (the
      ** default), just use the DefCharBundle value.  pArgBundle
      ** requests will be ignored.
      */

      pddc->pddcb->text.ChrBundle.usMixMode = DefCharBundle.usMixMode;
      PrintLog( (PB) "\tusMix = %d\n", pddc->pddcb->text.ChrBundle.usMixMode );
    }

    if (usMask & CBB_BACK_MIX_MODE)
    {
      /*
      ** !!!CR Check for invalid mix mode and error if invalid
      **
      ** check to see if the mix mode requested is one allowed.
      ** If not, use the default mix mode (LEAVEALONE)
      */

      if ( (pBundle->usBackMixMode == BM_LEAVEALONE) ||
                      (pBundle->usBackMixMode == BM_OVERPAINT) )
      {
        pddc->pddcb->text.ChrBundle.usBackMixMode = pBundle->usBackMixMode;
      }
      else
      {
        pddc->pddcb->text.ChrBundle.usBackMixMode = DefCharBundle.usBackMixMode;
        PrintLog( (PB) "\tInvalid usBackMix request (%d): defaulting\n",
                                             pBundle->usBackMixMode );
      }

      PrintLog( (PB) "\tusBackMix = %d\n", pddc->pddcb->text.ChrBundle.usBackMixMode );
    }

    if (usMask & CBB_SET)                                   /* font name */
    {
      /*
      ** we are going to be setting a new font, so it is
      ** time to reset the text necessary text attributes
      ** in the pddc.
      */
      /*
      ** start out by setting the character set, since that's
      ** what the mask tells us to do.  the character set is the
      ** LCID passed into GpiSetCharSet.
      */
      pddc->pddcb->text.ChrBundle.usSet = pBundle->usSet;

      PrintLog( (PB) "\tLCID = %d\n", pddc->pddcb->text.ChrBundle.usSet );
      PrintLog( (PSZ) "\tThis printer has %d fonts\n",
                                      prda_NumPrinterFonts(pddc) );

      /*
      ** initialize some text attributes in the pddc as if
      ** we are choosing the default font.
      */
      pddc->pddcb->text.usFont = prda_DefaultFontIndex (pddc );
      pddc->pddcb->text.pusCurCodePgVector = pddc->pddcb->text.pusDefCodePgVector ;
      pddc->pddcb->text.bFontHasKerning = FALSE;
      pddc->pddcb->text.bFontHasUnderscore = FALSE;
      pddc->pddcb->text.bFontHasStrikeout = FALSE;
      pddc->pddcb->text.bFontIsOutline = FALSE;
      pddc->pddcb->text.bLogFontEntry = 0 ;
      sEntry = 0 ;

      /*
      ** check (pArgBundle->cdef.fFlags & BIT0 ); in the case of engine
      ** fonts, we want to pass all future font calls back to the engine
      ** for simulation.
      */
      if (pArgBundle && (pArgBundle->cdef.fFlags & CDEF_GENERIC))
      {
        /*
        ** set a global flag to indicate that we're going to let the
        ** engine to font simulations, and don't set any attributes
        */
        PrintLog( (PB)"\tENGINE SIMULATION REQUEST: returning\n" );
          pddc->pddcb->text.fFontSimulation = TRUE;

        /*
        ** we need to fall through here so our attributes are in sync
        ** with the engine.  - kentse
        */
      }
      else
      {
        pddc->pddcb->text.fFontSimulation = FALSE;
      }

      /*
      ** if the user passed in a pointer to the default character
      ** bundle, or passed in an LCID of zero, then the default
      ** font is being asked for, and we have no other mapping to do.
      */
      if ((pBundle == &DefCharBundle) || (pArgBundle->cdef.defSet == 0L))
      {
        /*
        ** NOTE: in this case, nothing will be done in the
        ** retail driver.  but don't just remove this without
        ** thinking.
        */
        PrintLog( (PSZ) "Caller asked for default font or gave\n" );
        PrintLog( (PSZ) "an LCID of zero.\n" );
      }

      /*
      ** if the cookie is negative, it identifies a device font, and
      ** we convert it to an index of the font in our printer
      ** font list.
      */
      else if ((pBundle == &pArgBundle->cbnd) &&
               (!((LONG)pArgBundle->cdef.fFlags & CDEF_GENERIC)))
      {
        sEntry = (SHORT) CookieToOffset(pArgBundle->cdef.defSet );

        /*
        ** make sure we got a valid font index.
        */

        if ((sEntry < (MIN_FONT_LCID - 1)) || (sEntry > MAX_FONT_LCID))
        {
            RIP("SetTextAttrs: Invalid font index" );

            GplErrSetError(PMERR_INV_DRIVER_DATA );
            return (FAILURE );
        }

        /*
        ** now that we have the index into the font list,
        ** we can get, and save, the offset of the logical
        ** font.  this offset is used for font data, such
        ** as kerning, underscore, etc.
        */
        pddc->pddcb->text.usFont =
          (SHORT) pddc->pddcb->text.lfiEntry[sEntry].bOffset;

        /*
        ** set some flags for the current font.
        */
        pddc->pddcb->text.bFontHasKerning =
          pddc->pddcb->text.lfiEntry[sEntry].bFlags & LFONT_HAS_KERNING;

        pddc->pddcb->text.bFontHasUnderscore =
          pddc->pddcb->text.lfiEntry[sEntry].bFlags & LFONT_HAS_UNDERSCORE;

        pddc->pddcb->text.bFontHasStrikeout =
          pddc->pddcb->text.lfiEntry[sEntry].bFlags & LFONT_HAS_STRIKEOUT;

        pddc->pddcb->text.bFontIsOutline =
          pddc->pddcb->text.lfiEntry[sEntry].bFlags & LFONT_IS_OUTLINE;

        pddc->pddcb->text.bLogFontEntry = (BYTE) sEntry;
      }

      /*
      ** load the font resources.  we need the resources so
      ** we can get the font metrics for the current font.
      */
      if (!prda_CheckFontResource( pddc ))
      {
        RIP( "SetTextAttrs: CheckFontResource failed" );
        return( FAILURE );  /* Minor function saves error code */
      }

      /*
      ** get the pointer to the font metrics.
      */
      pChar = (PCHAR) pddc->pddcb->text.pfdfFontDef;
      pChar += pddc->pddcb->text.pfdfFontDef->Header.usMetricsOffset;
      pddc->pddcb->text.pfmFontMetrics = (PFONTMETRICS) pChar;

      /*
      ** if the font we are now selecting is a device font, then:
      ** if the logical font will have a different codepage than
      ** the device font, we must get a mapping from the engine.
      ** otherwise, we must sen the current codepage mapping to
      ** NULL to show the mapping is not necessary.
      */
      if ((pBundle == &pArgBundle->cbnd) &&
          (!((LONG)pArgBundle->cdef.fFlags & CDEF_GENERIC)))
      {
        if ((pArgBundle->cdef.CodePage) &&
            (pddc->pddcb->text.pfmFontMetrics->usCodePage == 850))
        {
          pddc->pddcb->text.pusCurCodePgVector =
            (PSHORT) GreQueryCodePageVector ((ULONG) pArgBundle->cdef.CodePage );
        }
        else
        {
          pddc->pddcb->text.pusCurCodePgVector = 0L;
        }
      }

      /*
      ** set the font facename in the pddc text attributes.
      */
      pChar = (PCHAR) pddc->pddcb->text.pfdfFontDef;
      pChar += pddc->pddcb->text.pfdfFontDef->Header.usStringsOffset;
      szCopy ((PSZ) pddc->pddcb->text.szFont, (PSZ) pChar, FACESIZE );

      #if DEBUG
        PrintLog( (PSZ) "\tFont Index in printer font list = %ld (%ls)\n",
                  (LONG)pddc->pddcb->text.usFont, (PSZ)pddc->pddcb->text.szFont  );
        PrintLog( (PSZ) "\tCurrent code page vector = %lp\n",
                  pddc->pddcb->text.pusCurCodePgVector );
        PrintLog( (PSZ) "\tCurrent font's remapping flag: " );

          if (QueryFontRemap(sEntry))
          {
            PrintLog( (PSZ) "1\n" );
          }
          else
          {
            PrintLog( (PSZ) "0\n" );
          }
        PrintLog( (PSZ) "\tCurrent logical font info entry: %d\n\n",
                  pddc->pddcb->text.bLogFontEntry );
      #endif /* DEBUG */
    }

    if (usMask & CBB_MODE)                                 /* precision */
    {
      pddc->pddcb->text.ChrBundle.usPrecision = pBundle->usPrecision;
      PrintLog( (PB) "\tusPrecision = %d\n", pddc->pddcb->text.ChrBundle.usPrecision );
    }

    if (usMask & CBB_BOX)
    {
      PrintLog( (PSZ) "Requested cell size = %f X %f\n",
                pBundle->sizfxCell.cx, pBundle->sizfxCell.cy );

      pddc->pddcb->text.ChrBundle.sizfxCell.cx = pBundle->sizfxCell.cx;
      pddc->pddcb->text.ChrBundle.sizfxCell.cy = pBundle->sizfxCell.cy;

      /*
      ** Calculate and save some scaling factors for future use
      */
      pddc->pddcb->text.fxXScale = frdiv (pddc->pddcb->text.ChrBundle.sizfxCell.cx,
                                          FX_1000 );
      pddc->pddcb->text.fxYScale = frdiv (pddc->pddcb->text.ChrBundle.sizfxCell.cy,
                                          FX_1000 );

      PrintLog( (PB) "\tNew cellSize = {%f, %f}\n",
                pddc->pddcb->text.ChrBundle.sizfxCell.cx, pddc->pddcb->text.ChrBundle.sizfxCell.cy );
    }

    if (usMask & CBB_ANGLE)
    {
      pddc->pddcb->text.ChrBundle.ptlAngle.x = pBundle->ptlAngle.x;
      pddc->pddcb->text.ChrBundle.ptlAngle.y = pBundle->ptlAngle.y;
      PrintLog( (PB) "\tAngle = {%ld, %ld}\n",
                pddc->pddcb->text.ChrBundle.ptlAngle.x, pddc->pddcb->text.ChrBundle.ptlAngle.y );
    }

    if (usMask & CBB_SHEAR)
    {
      pddc->pddcb->text.ChrBundle.ptlShear.x = pBundle->ptlShear.x;
      pddc->pddcb->text.ChrBundle.ptlShear.y = pBundle->ptlShear.y;
      PrintLog( (PB) "\tShear = {%ld, %ld}\n",
                pddc->pddcb->text.ChrBundle.ptlShear.x, pddc->pddcb->text.ChrBundle.ptlShear.y );
    }

    if (usMask & CBB_DIRECTION)
    {
      pddc->pddcb->text.ChrBundle.usDirection = pBundle->usDirection;
      PrintLog( (PB) "\tusDirection = %d\n", pddc->pddcb->text.ChrBundle.usDirection );
    }

    if (usMask & CBB_TEXT_ALIGN)
    {
      pddc->pddcb->text.ChrBundle.usTextAlign = pBundle->usTextAlign;
    }

    if (usMask & CBB_EXTRA)
    {
      pddc->pddcb->text.ChrBundle.fxExtra = pBundle->fxExtra;
      /*
      ** pddc->pddcb->text.fxCharExtra = pBundle->fxExtra;
      */
    }

    if (usMask & CBB_BREAK_EXTRA)
    {
      pddc->pddcb->text.ChrBundle.fxBreakExtra = pBundle->fxBreakExtra;
      /*
      ** pddc->pddcb->text.fxBreakExtra = pBundle->fxBreakExtra;
      */
    }

    /*
    ** the second pass sets attributes selected in the attribute mask.
    ** however, we do not want to set attributes which we have just
    ** set to the default.  by ANDing both masks, then XORing that with
    ** the attribute mask, we will only set the attributes we want to set.
    */
    pBundle = &pArgBundle->cbnd;
    usMask = usAttrMask & usDefMask;
    usMask = usMask ^ usAttrMask;
  }

  /*
  ** now we have set all the pddc records: output postscript commands
  */
  if (usOrMask & (CBB_BOX|CBB_SHEAR|CBB_ANGLE) )
  {
    prda_ComputeTextTransformMatrix(pddc );
  }

  if (usOrMask & CBB_SET)                     /* font name */
  {
    if (QueryFontRemap(sEntry))
    {
      ps_SetDownloadedFont( pddc );  /* font we downloaded before */
    }
    else
    {
      ps_setfont( pddc, (PSZ)pddc->pddcb->text.szFont );  /* device font */
    }
  }

  if (usOrMask & CBB_BOX)                     /* char. cell */
  {
    ps_scalefont( pddc, pddc->pddcb->text.ChrBundle.sizfxCell.cx,
                  pddc->pddcb->text.ChrBundle.sizfxCell.cy );
  }

  if (usOrMask & CBB_SHEAR)                   /* char shear */
  {
    ps_shearfont( pddc, pddc->pddcb->text.ChrBundle.ptlShear.x,
                  pddc->pddcb->text.ChrBundle.ptlShear.y );
  }

  if (usOrMask & CBB_ANGLE)                   /* baseline rotation */
  {
    ps_rotatefont (pddc, pddc->pddcb->text.ChrBundle.ptlAngle.x,
                   pddc->pddcb->text.ChrBundle.ptlAngle.y );
  }

  return( SUCCESS );
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_SetLineAttrs
 *
 * DESCRIPTION   = Sets the selected line attributes.
 *
 * INPUT         = (DefMask, AttrMask, pArgBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (SUCCESS)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

USHORT prda_SetLineAttrs( USHORT DefMask, USHORT AttrMask, PDLINEBUNDLE pArgBundle, PDDC pddc )
  /* SHORT         DefMask;          The pen bundle default mask    */
  /* SHORT         AttrMask;         The pen bundle attributes mask */
  /* PDLINEBUNDLE   pArgBundle;       Ptr to the engine's pen bundle */
  /* PDDC           pddc;             Ptr to the DC instance data    */
{
  USHORT       Mask;
  LINEBUNDLE *pBundle;
  int         i;

  #if DEBUG
    LogCall( "prda_SetLineAttrs(%04x, %04x, %lp, %lp)",
        ((PB) &DefMask) + sizeof(DefMask) );

    if (pArgBundle)
    {
      PrintLog( (PB) "ulFgColor = %08lx\n", pArgBundle->lbnd.lColor );
      PrintLog( (PB) "usFgMix   = %0d\n", pArgBundle->lbnd.usMixMode );
      PrintLog( (PB) "fxWidth = %f\n", pArgBundle->lbnd.fxWidth );
      PrintLog( (PB) "lGeomWidth = %ld\n", pArgBundle->lbnd.lGeomWidth );
      PrintLog( (PB) "usType = %d\n", pArgBundle->lbnd.usType );
      PrintLog( (PB) "usEnd = %d\n", pArgBundle->lbnd.usEnd );
      PrintLog( (PB) "usJoin = %d\n", pArgBundle->lbnd.usJoin );
    }
  #endif /* DEBUG */

  /*
  ** !!!CR all line drawing code should not draw if type = 8
  */

  /*
  ** The new set of current attributes are set up in two passes.
  ** The first pass sets any default values requested, the second
  ** sets any values supplied.
  */

  /*
  ** The first pass sets the defaults, so prepare pBundle and Mask
  */

  pBundle = &DefLineBundle;
  Mask = DefMask;

  for (i = 0 ; i < 2 ; ++i)
  {
    if (Mask & BIT0)
    {
      pddc->pddcb->pen.ulFgColor = pBundle->lColor;
    }

    if (Mask & BIT2)
    {
      pddc->pddcb->pen.usFgMix = pBundle->usMixMode;
    }

    if (Mask & BIT4)
    {
      pddc->pddcb->pen.fxWidth = pBundle->fxWidth;
    }

    if (Mask & BIT5)
    {
      pddc->pddcb->pen.lGeomWidth = pBundle->lGeomWidth;
    }

    if (Mask & BIT6)
    {
      /*
      ** !!!CR Should this return an error ?
      */
      if (pBundle->usType > LINETYPE_ALTERNATE)
      {
        pddc->pddcb->pen.usType = LINETYPE_SOLID ;
      }
      else
      {
        pddc->pddcb->pen.usType = pBundle->usType ;
      }
      ps_setdash( pddc, pddc->pddcb->pen.usType );
    }

    if (Mask & BIT7)
    {
      /*
      ** !!!CR for invalid line caps, return error
      */

      pddc->pddcb->pen.usEnd = pBundle->usEnd;
      if (pddc->pddcb->pen.usEnd <= 3)
      {
        ps_setlinecap( pddc, aiLineCap[pddc->pddcb->pen.usEnd] );
      }
    }

    /*
    ** !!!CR for invalid line join return error
    */
    if (Mask & BIT8)
    {
      pddc->pddcb->pen.usJoin = pBundle->usJoin;
      if (pddc->pddcb->pen.usJoin <= 3)
      {
        ps_setlinejoin( pddc, aiLineJoin[pddc->pddcb->pen.usJoin] );
      }
    }

    /*
    ** The second pass sets the attributes, so prepare pBundle and Mask
    */
    pBundle = &pArgBundle->lbnd;
    Mask = AttrMask;
  }

  return( SUCCESS );
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_SetMarkAttrs
 *
 * DESCRIPTION   = Sets the selected marker attributes.
 *
 * INPUT         = (DefMask, AttrMask, pArgBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void prda_SetMarkAttrs( USHORT DefMask, USHORT AttrMask, PDMARKERBUNDLE pArgBundle, PDDC pddc )
{
  USHORT          Mask;        /* Local ref. to new attrs     */
  PDMARKERBUNDLE pBundle;     /* Ptr to the marker bundle    */
  int            i;

  #if DEBUG
    LogCall("prda_SetMarkAttrs(%04x, %04x, %lp, %lp)",
        ((PB) &DefMask) + sizeof(DefMask) );
  #endif /* DEBUG */

  if (pArgBundle)
  {
    pBundle = pArgBundle;
  }
  else
  {
    pBundle = &DefMarkerBundle;
  }

  /*
  ** copy the device bundle definitions fields
  */
  pddc->pddcb->mkr.dmbnd.cAttr = pBundle->cAttr;
  pddc->pddcb->mkr.dmbnd.cDefs = pBundle->cDefs;
  pddc->pddcb->mkr.dmbnd.mdef.defSet = pBundle->mdef.defSet;
  pddc->pddcb->mkr.dmbnd.mdef.fFlags = pBundle->mdef.fFlags;
  pddc->pddcb->mkr.dmbnd.mdef.CodePage = pBundle->mdef.CodePage;

  /*
  ** the loop is processed exactly twice, for the second pass the
  ** mask and attributes are updated to provide the values given
  ** in the function call
  */
  Mask = AttrMask;
  for (i = 0 ; i < 2 ; ++i)
  {
    if (Mask & BIT0)
    {
      pddc->pddcb->mkr.dmbnd.mbnd.lColor = pBundle->mbnd.lColor;
    }

    if (Mask & BIT1)
    {
      pddc->pddcb->mkr.dmbnd.mbnd.lBackColor = pBundle->mbnd.lBackColor;
    }

    if (Mask & BIT2)
    {
      pddc->pddcb->mkr.dmbnd.mbnd.usMixMode = pBundle->mbnd.usMixMode;
    }

    if (Mask & BIT3)
    {
      pddc->pddcb->mkr.dmbnd.mbnd.usBackMixMode = pBundle->mbnd.usBackMixMode;
    }

    if (Mask & BIT4)
    {
      pddc->pddcb->mkr.dmbnd.mbnd.usSet = pBundle->mbnd.usSet;
    }

    if (Mask & BIT5)
    {
      pddc->pddcb->mkr.dmbnd.mbnd.usSymbol = pBundle->mbnd.usSymbol;
      PrintLog( (PSZ) "Setting symbol to %d\n", pddc->pddcb->mkr.dmbnd.mbnd.usSymbol );
    }

    if (Mask & BIT6)
    {
      if ( !pBundle->mbnd.sizfxCell.cx || !pBundle->mbnd.sizfxCell.cy )
      {
        PrintLog( (PSZ)"\tWill set cell size to the default\n" );
        pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cx = DefMarkerBundle.mbnd.sizfxCell.cx;
        pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cy = DefMarkerBundle.mbnd.sizfxCell.cy;
      }
      else
      {
        pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell = pBundle->mbnd.sizfxCell;
      }
    }

    pBundle = &DefMarkerBundle;
    Mask = DefMask;
  }

  PrintLog( (PSZ) "Marker size = %f X %f\n", pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cx,
             pddc->pddcb->mkr.dmbnd.mbnd.sizfxCell.cy );
}

/* #pragma loop_opt(off)          Turn off loop opt for this function. Opt */
/***************************************************************************
 *
 * FUNCTION NAME = prda_SetPtrnAttrs
 *
 * DESCRIPTION   = Sets the selected pattern attributes.
 *
 * INPUT         = (DefMask, AttrMask, pBundle, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void prda_SetPtrnAttrs( USHORT DefMask, USHORT AttrMask, DAREABUNDLE *pBundle, PDDC pddc )
{
  USHORT Mask;           /* Local ref. to new attrs     */
  int   i;              /* loop control variable       */

  #if DEBUG
    LogCall( "prda_SetPtrnAttrs(%08lx, %08lx, %lp, %lp)",
        ((PB) &DefMask) + sizeof(DefMask) );
  #endif /* DEBUG */

  /*
  ** If the attributes pointer is NULL, we'll use the default bundle
  */
  if (!pBundle)
  {
    pBundle = &prda_DefPtnAts;
  }

  /*
  ** the loop is processed exactly twice, for the second pass the
  ** mask and attributes are updated to provide the values given
  ** in the function call
  */
  Mask = AttrMask;
  for (i = 0 ; i < 2 ; ++i)
  {
    if (Mask & BIT0)
    {
      pddc->pddcb->pat.ulFgColor = pBundle->abnd.lColor;
      PrintLog( (PSZ) "pddc->pddcb->pat.ulFgColor = %08lx\n",
               pddc->pddcb->pat.ulFgColor );
    }

    if (Mask & BIT1)
    {
      pddc->pddcb->pat.ulBgColor = pBundle->abnd.lBackColor;
    }

    if (Mask & BIT2)
    {
      pddc->pddcb->pat.usFgMix = pBundle->abnd.usMixMode;
    }

    if (Mask & BIT3)
    {
      pddc->pddcb->pat.usBgMix = pBundle->abnd.usBackMixMode;
    }

    if (Mask & BIT4)
    {
      pddc->pddcb->pat.usSet = pBundle->abnd.usSet;
    }

    if (Mask & BIT5)
    {
      pddc->pddcb->pat.usSymbol = pBundle->abnd.usSymbol;
    }

    if (Mask & BIT6)
    {
      pddc->pddcb->pat.ptlOrg.x = pBundle->abnd.ptlRefPoint.x;
      pddc->pddcb->pat.ptlOrg.y = pBundle->abnd.ptlRefPoint.y;
    }

    pBundle = &prda_DefPtnAts;
    Mask = DefMask;
  }                       /* for defaults then values    */

  PrintLog( (PSZ) "Return from SetPtrnAttrs\n" );
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_SetImagAttrs
 *
 * DESCRIPTION   = Sets the selected image attributes.
 *
 * INPUT         = (DefMask, AttrMask, Attributes, pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/
#undef Word
#define Word USHORT

void prda_SetImagAttrs( Word DefMask, Word AttrMask, lpImageAt Attributes, PDDC pddc )
  /* lpImageAt      Attributes;      !!!CR use the standard typedef */
{
  /*
  ** !!!CR Change declarations for Word and Dword to SHORT AND ULONG
  ** !!!CR This should be done for the whole file.
  */
  Dword     Mask;           /* Local ref. to new attrs     */
  lpImageAt Attrs;          /* Local ref. to attributes    */
  Word      i;              /* loop control variable       */

  #if DEBUG
    LogCall( "prda_SetImagAttrs(%04x, %04x, %lp, %lp)\n",
        ((PB) &DefMask) + sizeof(DefMask) );
  #endif /* DEBUG */

  /*
  ** The new set of current attributes are set up in two passes.
  ** The first pass sets any default values requested, the second
  ** sets any values supplied.
  */


  /*
  ** the loop is processed exactly twice, for the second pass the
  ** mask and attributes are updated to provide the values given
  ** in the function call
  */
  for (Mask = DefMask, Attrs = &prda_DefImgAts, i = 2 ; i-- ;
       Mask = AttrMask, Attrs = Attributes)
  {
    if (Mask & BIT0)
    {
      pddc->pddcb->image.ulFgColor = Attrs->ATIFgClr;
    }

    if (Mask & BIT1)
    {
      pddc->pddcb->image.ulBgColor = Attrs->ATIBkClr;
    }

    if (Mask & BIT2)
    {
      pddc->pddcb->image.usFgMix = Attrs->ATIFgMix;
    }

    if (Mask & BIT3)
    {
      pddc->pddcb->image.usBgMix = Attrs->ATIBkMix;
    }
  }                       /* for defaults then values    */

  PrintLog( (PSZ) "Return from SetImagAttrs\n" );
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_DeviceSetAttributes
 *
 * DESCRIPTION   = Sets the selected device attributes.
 *
 * INPUT         = (hdc,ulType,ArgDefMask,ArgAttrMask,pbBundle,pddc,FunN)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (SUCCESS), (usStatus)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prda_DeviceSetAttributes( HDC hdc, ULONG ulType, ULONG ArgDefMask,
                                ULONG ArgAttrMask, PB pbBundle,
                                PDDC pddc, ULONG ulFunN)
  /* HDC            hdc;                  The DC handle */
  /* ULONG          ulType;               The bundle type */
  /* ULONG          ArgDefMask;           The default mask */
  /* ULONG          ArgAttrMask;          The attributes mask */
  /* PB             pbBundle;             Ptr to the device attributes bundle */

{
  USHORT          usDefMask;
  USHORT          usAttrMask;
  register USHORT usStatus;

  EnterDriver( pddc );

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

  PrintLog( (PB) "\tDefault mask = %x\n", ArgDefMask );
  PrintLog( (PB) "\tRequested mask = %x\n", ArgAttrMask );
  PrintLog( (PB) "\tBundle type = %ld\n", ulType );

  /*
  ** !!!CR Delete the following optimization because applications shouldn't
  ** !!!CR be so dumb as to call  us with no options
  */
  /*
  ** If there are no attributes to set, then we are done.
  */
  if (!ArgAttrMask)
  {
    ExitDriver( pddc );
    return( SUCCESS );
  }

  if (pddc->iType == OD_MEMORY)
  {
   ULONG ulDevSetAttr = 0;
   ULONG ulDefSet = 0;

   if (ulType == PRIM_CHAR && ArgAttrMask & CBB_SET)
   {
     ArgAttrMask &= ~CBB_SET;
     ulDevSetAttr = CBB_SET;
   }
   else if (ulType == PRIM_MARKER && ArgAttrMask & MBB_SET)
   {
     ArgAttrMask &= ~MBB_SET;
     ulDevSetAttr = MBB_SET;
   }
   else if (ulType == PRIM_AREA && ArgAttrMask & ABB_SET)
   {
     ulDefSet = ((PDAREABUNDLE)pbBundle)->adef.defSet;

     /*
     ** Check if the defSet is handle to a bitmap.
     ** I hate to do this kind of hardcoded values!
     */
     if (ulDefSet >> 16 == 0x0400)
     {
       ULONG ulDevHandle;

       ulDevHandle = GetDriverInfo( (HBITMAP) ulDefSet, 1L, pddc->hdcMemory );

       if (ulDevHandle != GPI_ALTERROR)
       {
         ((PDAREABUNDLE) pbBundle)->adef.defSet = ulDevHandle;
         ArgAttrMask &= ~ABB_SET;
         ulDevSetAttr = ABB_SET;
       }
       else
       {
         ulDefSet = 0;
       }
     }
     else
     {
       ulDefSet = 0;
     }
   }

   usStatus = InnerGreSetAttributes (pddc->hdcMemory, ulType, ArgDefMask,
                                     ArgAttrMask, (PB) ((ULONG) pbBundle +
                                     sizeof (((PDLINEBUNDLE)pbBundle)->cAttr) +
                                     sizeof (((PDLINEBUNDLE)pbBundle)->cDefs)),
                                     ulFunN );

   if (usStatus && ulDevSetAttr)
   {
     usStatus = InnerGreDeviceSetAttributes( pddc->hdcMemory, ulType,
                                             ArgDefMask,
                                             ulDevSetAttr,
                                             pbBundle, ulFunN );
     if (ulDefSet)
     {
       ((PDAREABUNDLE) pbBundle)->adef.defSet = ulDefSet ;
     }
   }
   ExitDriver( pddc );
   return( usStatus );
  }

  usDefMask = (USHORT) ArgDefMask & (USHORT) ArgAttrMask;
  usAttrMask = (USHORT) ArgAttrMask & (~(USHORT) ArgDefMask );
  usStatus = SUCCESS;

  /*
  ** Switch to appropriate subroutine according to bundle type.
  ** Some subroutines always return OK.
  */
  switch ((USHORT) ulType)
  {
  case LINE_ATTR:
       /*
       ** !!!CR return status directly
       */
       usStatus = prda_SetLineAttrs( usDefMask, usAttrMask,
                                     (PDLINEBUNDLE) pbBundle, pddc );
       break;

  case TEXT_ATTR:
       /*
       ** !!!CR return status directly
       */
       usStatus = prda_SetTextAttrs( usDefMask, usAttrMask,
                                     (PDCHARBUNDLE) pbBundle, pddc );

       break;

  case MARK_ATTR:
      prda_SetMarkAttrs( usDefMask, usAttrMask,
                         (PDMARKERBUNDLE) pbBundle, pddc );
      break;

  case PTRN_ATTR:
       prda_SetPtrnAttrs( usDefMask, usAttrMask,
                          (DAREABUNDLE *) pbBundle, pddc );
      break;

  case IMAG_ATTR:
      prda_SetImagAttrs( usDefMask, usAttrMask,
                         (lpImageAt) pbBundle, pddc );
      break;

  default:
      PrintLog( (PSZ) "Unknown bundle type = %ld\n", ulType );
      usStatus = FAILURE;
      break;
  }

  ExitDriver( pddc );
  return( usStatus );
}

/***************************************************************************
 *
 * FUNCTION NAME = prda_DeviceSetGlobalAttribute
 *
 * DESCRIPTION   = Sets the selected device global attributes.
 *
 * INPUT         = (hdc, iAttr,  iVal,  fDefault,  pddc,  FunN)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (SUCCESS)
 *
 * RETURN-ERROR  = (FAILURE)
 *
 **************************************************************************/

ULONG prda_DeviceSetGlobalAttribute( HDC hdc, ULONG iAttr, ULONG iVal, ULONG fDefault, PDDC pddc, ULONG ulFunN )
  /* HDC           hdc;           The display context handle */
  /* ULONG         iAttr;         The attribute index */
  /* ULONG         iVal;          The attribute value */
  /* ULONG         fDefault;      The option bits */
  /* PDDC          pddc;          Ptr to the DC instance data */
  /* ULONG         FunN;          The function number */
{
  ULONG ulRet;

  EnterDriver( pddc );

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

  if (pddc->iType == OD_MEMORY)
  {
    ulRet = InnerGreSetGlobalAttribute( pddc->hdcMemory,iAttr,
                                        iVal, fDefault, ulFunN );
    ExitDriver( pddc );
    return( SUCCESS );
  }

  /*
  ** !!!CR Check for invalid bits in fDefault
  */
  /*
  ** Convert the options value to a boolean by testing its default bit.
  ** If the GATTR_DEFAULT bit is on, then the desired attribute
  ** is set to its default value. For attribute types 3 and 4 the
  ** engine sets the default and passes to the driver the default
  ** value as well as clearing the option flag
  */
  fDefault &= GATTR_DEFAULT;

  /*
  ** !!!CR Check for invalid attributes and return error
  */
  switch ((USHORT) iAttr)
  {
  case ATYPE_COLOR:
       /*
       ** !!!CR Check attributes and return error if necessary
       */
       if (fDefault)
       {
         iVal = DEFAULT_FOREGROUND_COL;
       }

       pddc->pddcb->pen.ulFgColor = iVal;
       pddc->pddcb->pat.ulFgColor = iVal;
       pddc->pddcb->text.ChrBundle.lColor = iVal;
       pddc->pddcb->mkr.dmbnd.mbnd.lColor = iVal;
       pddc->pddcb->image.ulFgColor = iVal;
       break;

  case ATYPE_BACK_COLOR:
       /*
       ** !!!CR Check attribute and return error if invalid
       */
       if (fDefault)
       {
         iVal = DEFAULT_BACKGROUND_COL;
       }

       /*
       ** For things where the background shows through, the
       ** driver should blank the area behind it with the
       ** background color depending on the mix mode.
       */
       pddc->pddcb->text.ChrBundle.lBackColor = iVal;
       pddc->pddcb->mkr.dmbnd.mbnd.lBackColor = iVal;
       pddc->pddcb->pat.ulBgColor = iVal;
       pddc->pddcb->image.ulBgColor = iVal;
       break;

  case ATYPE_MIX_MODE:
       /*
       ** !!!CR Check for invalid mix type
       ** !!!CR Check for invalid mix types
       */
       /*
       ** !!!CR OVERPAINT only
       */
       /*
       ** !!!CR Missing default mix mode
       */
       pddc->pddcb->pen.usFgMix =  (USHORT) iVal;
       pddc->pddcb->text.ChrBundle.usMixMode = (USHORT) iVal;
       pddc->pddcb->mkr.dmbnd.mbnd.usMixMode = (USHORT) iVal;
       pddc->pddcb->pat.usFgMix = (USHORT) iVal;
       pddc->pddcb->image.usFgMix = (USHORT) iVal;
       break;

  case ATYPE_BACK_MIX_MODE:
       /*
       ** !!!CR Check for invalid mix modes OVERPAINT, LEAVALONE
       */

       /*
       ** !!!CR Missing default background mix
       */
       pddc->pddcb->text.ChrBundle.usBackMixMode = (USHORT) iVal;
       pddc->pddcb->mkr.dmbnd.mbnd.usBackMixMode = (USHORT) iVal;
       pddc->pddcb->pat.usBgMix = (USHORT) iVal;
       pddc->pddcb->image.usBgMix = (USHORT) iVal;
       break;

  default:
       /*
       ** !!!CR Set an error code
       */
       ExitDriver( pddc );
       return( FAILURE );
       break;
  }

  ExitDriver( pddc );
  return( SUCCESS );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdl_SetCurrentPosition
 *
 * DESCRIPTION   = This routine sets the current position in the ddc, and outputs
 *                 a moveto command to the postscript printer.  Once this command
 *                 is completed, the postscript printer and the ddc will have the
 *                 same current position.
 *
 * INPUT         = (hdc, pptlNew, pddc, FunN)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (ps_status(pddc))
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG  prdl_SetCurrentPosition( HDC hdc, PPOINTL pptlNew, PDDC pddc, ULONG ulFunN )
  /* HDC           hdc;           The display context handle */
  /* PPOINTL       pptlNew;       Pointer to the new position */
  /* PDDC          pddc;          Ptr to the DC instance data */
{
  ULONG ulRet;

  EnterDriver( pddc );

  #if DEBUG
    LogCall( "prdl_SetCurrentPosition(%08lx, %lp, %lp, %08lx)\n",
             ((PB) &hdc) + sizeof(hdc) );

    PrintLog( (PSZ) "Coordinate in world space = %ld, %ld\n",
                            pptlNew->x, pptlNew->y );
  #endif /* DEBUG */

  if (pddc->iType == OD_MEMORY)
  {
    if ((ulRet = InnerGreSetCurrentPosition (pddc->hdcMemory, pptlNew, ulFunN)) &&
       (ulFunN & (COM_PATH | COM_AREA)))
    {
      /*
      ** Call back to engine.
      */
      ulRet = (ULONG) (*pfnlSetCurrentPosition) (pddc->hdc, pptlNew, pddc, ulFunN );
    }
    ExitDriver( pddc );
    return( ulRet );
  }

  if (pddc->pddcb->path.fAreaIsOpen)
  {
    /*
    ** update the current position for the area bracket.
    */
    pddc->pddcb->path.ptlAreaCP.x = pptlNew->x;
    pddc->pddcb->path.ptlAreaCP.y = pptlNew->y;

    /*
    ** if we are in an area bracket, force a newpath command to
    ** the postscript printer.  the reason for this is that
    ** BeginArea outputs a moveto to the current position, and the
    ** first moveto will be included in the pathbbox.  this can
    ** cause a much greater than necessary amount of pattern filling
    ** to occur.  However, we don't want to do the moveto if the
    ** current position is valid, is in BeginArea, PolyLine
    ** SetCurrentPositon.  Doing a newpath for this SetCurrentPosition
    ** will destroy the impending path.
    */
    if (!pddc->pddcb->cgs.fPathExists)
    {
      PrintChannel( pddc, (PSZ)"n\n" );
    }
  }

  ps_moveto( pddc,pptlNew );

  ulRet = ps_status( pddc );
  ExitDriver( pddc );
  return( ulRet );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdl_SetStyleRatio()
 *
 * DESCRIPTION   = This function informs the display driver what the aspect
 *                 ratio of the pixels are.  Since PostScript does its own
 *                 drawing, this function has no effect.
 *
 * INPUT         = NONE
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prdl_SetStyleRatio( HDC hdc, PB pb, PDDC pddc, ULONG FunN )
{
  EnterDriver( pddc );

  /*
  ** We are not a raster printer and we aren't using the
  ** display driver and no one cares about what the aspect
  ** ratio of our pixels are so we don't do anything with
  ** this call.
  */
  ExitDriver( pddc );

  return( SUCCESS );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdl_GetCurrentPosition
 *
 * DESCRIPTION   = This routine returns the current position in pptlWorld.
 *
 * INPUT         = (hdc, pptlWorld, pddc, FunN)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = (SUCCESS)
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

ULONG prdl_GetCurrentPosition( HDC hdc, PPOINTL pptlWorld, PDDC pddc, ULONG ulFunN )
  /* PPOINTL     pptlWorld;       Place to store the current position */
  /* PDDC        pddc;            Ptr to the DC instance data */
{
  ULONG ulRet;

  EnterDriver( pddc );

  #if DEBUG
    LogCall( (PSZ)"prdl_GetCurrentPosition(%08lx, %lp, %lp, %08lx)\n",
                                           ((PB) &hdc) + sizeof(hdc) );
  #endif /* DEBUG */

  if (pddc->iType == OD_MEMORY)
  {
    ulRet = InnerGreGetCurrentPosition (pddc->hdcMemory, pptlWorld, ulFunN );
    ExitDriver( pddc );
    return( ulRet );
  }

  /*
  ** just return the pen location.
  */
  pptlWorld[0] = pddc->pddcb->pen.ptlCur;
  ExitDriver( pddc );
  return( SUCCESS );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdl_PatGray()
 *
 * DESCRIPTION   = This routine is responsible for establishing the current
 *                 pattern attributes used to fill a path.
 *
 * INPUT         = (pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void prdl_PatGray( PDDC pddc )
{
  PrintLog( (PSZ) "prdl_PatGray(%lp)\n", pddc );
  ps_setrgbcolor( pddc, prdc_GetColor(pddc, pddc->pddcb->pat.ulFgColor) );
}

/***************************************************************************
 *
 * FUNCTION NAME = prdl_PenGray()
 *
 * DESCRIPTION   = This routine is responsible for establishing the current
 *                 pen attributes used to stroke a path.
 *
 * INPUT         = (pddc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

void prdl_PenGray( PDDC pddc )
{
  PrintLog( (PSZ) "prdl_PenGray(%lp)\n", pddc );

  /*            */
  /*
  ** The cosmetic lines will not be drawn in gray shades for
  ** monochrome devices.
  **
  ** The RGB values for black and white.
  */
  #define _BLACK          0x000000L
  #define _WHITE          0x0ffffffL

  if (pddc->pdv->jobProperties.fIsColorDevice)
  {
    ps_setrgbcolor(pddc, prdc_GetColor(pddc, pddc->pddcb->pen.ulFgColor) );
  }
  else if (prdc_GetColor(pddc, pddc->pddcb->pen.ulFgColor) == _WHITE)
  {
    ps_setrgbcolor( pddc, _WHITE );
  }
  else
  {
    ps_setrgbcolor( pddc, _BLACK );
  }
}
