/*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 =  PATFILL.C
 *
 * DESCRIPTIVE NAME =  Pattern Filling Routines
 *
 *
 * VERSION = V2.0
 *
 * DATE
 *
 * DESCRIPTION : This module contains the code for pattern filling for the
 *               PostScript driver.
 *
 * FUNCTIONS                  ps_patfill_common
 *                            ps_patfill_base
 *                            ps_patfill_font
 *                            ps_patfill
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

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

LONG   prdc_GetColor(PDDC,LONG); /* prdcctab.c                      */
#define  RGB_HALF_GRAY 0x07f7f7fL

/*
** The pattern gray table gives the percentage of the
** input color present in the output color.
** A value of 100% produces the original color.
** A value of 0% produces black.
*/

FIXED afxPatGray[] =
{
  0x00001999,                /* .1                                          */
  0x00003333,                /* .2                                          */
  0x0000433B,                /* .3                                          */
  0x00006664,                /* .4                                          */
  0x00009996,                /* .6 note: no .5                              */
  0x0000B32F,                /* .7                                          */
  0x0000CCC8,                /* .8                                          */
  0x0000E661                 /* .9                                          */
} ;

/*
** the following block of stuff is postscript code which is
** downloaded to the postscript printer to create a font
** which consists of one character.  this character is used
** for pattern filling.
**
** !!CR make into a resource
*/

static PSZ apszFillFont[] =
{
  "/definepattern { 7 dict begin",
  "/FontDict 10 dict def FontDict begin",
  "/originy exch def /originx exch def /key exch def",
  "/proc exch cvx def /mtx exch matrix invertmatrix def",
  "/height exch def /width exch def /ctm matrix currentmatrix def",               "\
/ptm matrix identmatrix def /str (12345678901234567890123456789012) def end",
  "/FontBBox [ 0 0 FontDict /width get FontDict /height get ] def",
  "/FontMatrix FontDict /mtx get def /Encoding StandardEncoding def",
  "/FontType 3 def /BuildChar { pop begin FontDict begin",
  "width 0 0 0 width height setcachedevice gs proc gr end end } def",
  "FontDict /key get currentdict definefont end } B",
  "/patternpath { begin FontDict /ctm get sm",
  "currentdict setfont FontDict begin FontMatrix concat width 0 dtransform",
  "round width div exch round width div exch",
  "0 height dtransform round height div exch round height div exch",
  "0 0 transform round exch round exch ptm astore sm pathbbox",
  "height div ceiling height mul 4 1 roll",
  "width div ceiling width mul 4 1 roll height div floor height mul 4 1 roll",    "\
width div floor width mul 4 1 roll 2 index sub height div ceiling cvi exch",
  "3 index sub width div ceiling cvi exch 4 2 roll m",
  "originx neg originy neg rmoveto 1 add exch 1 add exch",
  "FontMatrix ptm invertmatrix pop { gs ptm concat dup str length idiv",
  "{ str show } repeat dup str length mod str exch",
  "0 exch getinterval show gr 0 height rmoveto } repeat pop end end } B",
  "/patternfill { gs clip patternpath gr n } B",
  "/patterneofill { gs eoclip patternpath gr n } B",
  "/fontfill { findfont patternfill } B",
  "/fonteofill { findfont patterneofill } B",     NULL
} ;

/*
**                                                                    
** Modifications:
**
** 1.The pattern fill for the patterns PATSYM_HORIZ, PATSYM_VERT and
**   PATSYM_DIAG1 thru PATSYM_DIAG4 will be drawn at printer pel
**   (device coordinates).
**   Hence, the these pattern fill will no longer be dependent on
**   CTM and xfx value.
** 2. The slope of PATSYM_DIAG1 and PATSYM_DIAG3 are modified
**    to 45 and 135 degrees respectively.
** 3. The pitch width for PATSYM_DIAG2 and PATSYM_DIAG4
**    is same as PATSYM_DIAG1 along the device X-axis and
**    is half of PATSYM_DIAG1 along the device Y-axis.
** 4. The linewidth for PATSYM_VERT, PATSYM_HORIZ, PATSYM_DIAG1 and
**    PATSYM_DIAG3 is 2/300 of an inch.
** 5. The linewidth for PATSYM_DIAG2 and PATSYM_DIAG4 is 1/600 of an inch.
** 6. The whole apszBase array is modified.
*/

static PSZ apszBase[] =
{

/*
** Removed the division by xfx.
** The pitchwidth pw is 4 points (1/18 of an inch)
**
*/

  "/halfpw dpi 36 div round cvi def /pw halfpw halfpw add def",

/*
** Removed the division by xfx.
** The linewidth for PATSYM_VERT, PATSYM_HORIZ, PATSYM_DIAG1 and
** PATSYM_DIAG3 is 2/300 of an inch.
*/

  "/plw1 dpi 300 div dup add def",

/*
** The linewidth for PATSYM_DIAG2 and PATSYM_DIAG4 is 1/600 of an inch.
*/

  "/plw2 dpi 300 div 2 div def",

/*
** Current path bounding box size.
*/

"/getpsize {pathbbox ceiling cvi /ptop exch def ceiling cvi /pright exch def",
  "floor cvi /pbottom exch def floor cvi /pleft exch def",
  "ptop pbottom sub /pheight exch def pright pleft sub /pwidth exch def} B",

/*
** Inetersection of the current path and the current clipping path.
*/

  "/psize {clip getpsize} B",
  "/eopsize {eoclip getpsize} B /cpt {currentpoint} B",

/*
** Adjust the pattern origin X/Y to aligin with
** the Xpitch/Ypitch (pw) of the pattern.
*/

"/AdjustPatOrg1 {dup 0 ge {dup pw mod sub} {dup pw mod sub pw sub} ifelse} B",

/*
** Adjust the pattern origin X/Y to aligin with
** the Xpitch/Ypitch (halfpw) of the pattern.
*/

"/AdjustPatOrg2 {dup 0 ge {dup halfpw mod sub} {dup halfpw mod sub halfpw sub\
} ifelse} B",

/*
** PATSYM_HORIZ
*/

  "/phoriz {pheight pw div ceiling cvi 1 add n pleft pbottom AdjustPatOrg1 m",
  "{ pwidth 0 rlineto cpt s m pwidth neg pw rmoveto} repeat} B",

/*
** PATSYM_VERT
*/

  "/pvert {pwidth pw div ceiling cvi 1 add n pleft AdjustPatOrg1 pbottom m",
  "{ 0 pheight rlineto cpt s m pw pheight neg rmoveto} repeat} B",

/*
**PATSYM_DIAG1
**                                                                    
** The slope of the PATSYM_DIAG1 is modified from 2/1 to 1/1
** to match with PM.
*/

  "/pdiag1 {pwidth pheight add pw div ceiling cvi 1 add",
  "n pheight neg pleft add AdjustPatOrg1 pbottom AdjustPatOrg1 m",
  "{pheight pw add pheight pw add rlineto cpt s m",
  "pheight neg pheight neg pw sub rmoveto} repeat} B",

/*
** PATSYM_DIAG2
** The pitch width is pw along the device X-axis and
** is halfpw along the device Y-axis.
*/

  "/pdiag2 {/phalfwidth  pwidth .5 mul round cvi def",
  "/pwidth phalfwidth 2 mul def",
  "phalfwidth pheight add halfpw div ceiling cvi 1 add",
  "n pleft AdjustPatOrg1 phalfwidth neg pbottom add AdjustPatOrg2 m",
  "{pwidth pw add phalfwidth halfpw add rlineto cpt s m",
  "pwidth neg pw sub phalfwidth neg rmoveto} repeat} B",

/*
** PATSYM_DIAG3
**                                                                    
** The slope of the PATSYM_DIAG3 is modified from -1/-2 to -1/-1
** to match with PM.
*/

  "/pdiag3 {pwidth pheight add pw div ceiling cvi 1 add",
  "n pleft AdjustPatOrg1 pbottom AdjustPatOrg1 m",
  "{pheight neg pw sub pheight pw add rlineto cpt s m",
  "pheight pw add pw add pheight neg pw sub rmoveto} repeat} B",

/*
** PATSYM_DIAG4
** The pitch width is pw along the device X-axis and
** is halfpw along the device Y-axis.
*/

  "/pdiag4 {/phalfwidth  pwidth .5 mul round cvi def",
  "/pwidth phalfwidth 2 mul def",
  "phalfwidth pheight add halfpw div ceiling cvi 1 add",
  "n pleft AdjustPatOrg1 pbottom AdjustPatOrg2 m",
  "{pwidth pw add phalfwidth neg halfpw sub rlineto cpt s m",
  "pwidth neg pw sub phalfwidth pw add rmoveto} repeat} B",       NULL
} ;

       /*
       **                                                             
       **  This PostScript code will generate a logical font pattern with the
       **  current user font and size. Used for filling the current path.
       **  The character symbol is user defined.
       **  CALL: [Font Size] [Character Symbol] fontpatfill.
       */

static PSZ apszLogFontPat[] =
{
  "/fontpatfill{",                "     /Symbol exch def",
  "     /BoxSz exch def",

/*
** Get bounding box of the current path in current user coordinates.
*/

  "     pathbbox /Y2 exch BoxSz div ceiling BoxSz mul def",
  "              /X2 exch BoxSz div ceiling BoxSz mul def",
  "              /Y1 exch BoxSz div floor BoxSz mul def",
  "              /X1 exch BoxSz div floor BoxSz mul def",

/*
**Loop through height and width through the area, printing the character symbol.
*/

  "      Y1 BoxSz Y2{/ypos exch def X1 BoxSz X2",
  "      { ypos moveto Symbol show} for } for",   "}def",         NULL
} ;

/***************************************************************************
 *
 * FUNCTION NAME = ps_patfill_common
 *
 * DESCRIPTION   = This routine is called by several places in ps_patfill to
 *                 download postscript code common to pattern filling to the
 *                 postscript printer.
 *
 * INPUT         = PDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void ps_patfill_common( PDDC pddc )
{
  PSZ *ppsz;

  if (!(pddc->pddcb->pat.usfFontLoaded & FILLFONTLOADED))
  {
    ppsz = apszFillFont;

    while (*ppsz)
    {
      PrintChannel( pddc, (PSZ)"%ls\n", (PSZ) *ppsz++ );
    }

    /*
    **  indicate the font is loaded
    */
    pddc->pddcb->pat.usfFontLoaded |= FILLFONTLOADED;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = ps_patfill_base
 *
 * DESCRIPTION   = This routine is called by several places in ps_patfill to
 *                 download postscript code common to pattern filling to the
 *                 postscript printer.
 *
 * INPUT         = PDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void ps_patfill_base( PDDC pddc )
{
  PSZ *ppsz;

  if (!(pddc->pddcb->pat.usfFontLoaded & BASEPATLOADED))
  {
    ppsz = apszBase;

    while (*ppsz)
    {
      PrintChannel( pddc, (PSZ) "%ls\n", (PSZ) *ppsz++ );
    }

    /*
    **  indicate the font is loaded
    */
    pddc->pddcb->pat.usfFontLoaded |= BASEPATLOADED;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = ps_patfill_font
 *
 * DESCRIPTION   = This routine is called by ps_patfill if the pattern
 *                 to be use is a Logical Font. Once used it will be
 *                 rememberd by pddc->pddcb->pat.usfFontLoaded.
 *
 * INPUT         = PDDC
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

void ps_patfill_font( PDDC pddc )
{
  PSZ *ppsz;

  if (!(pddc->pddcb->pat.usfFontLoaded & LOGFONTLOADED))
  {
    ppsz = apszLogFontPat;

    while (*ppsz)
    {
      PrintChannel( pddc, (PSZ) "%ls\n", (PSZ) *ppsz++ );
    }

    /*
    **  indicate the font is loaded
    */
    pddc->pddcb->pat.usfFontLoaded |= LOGFONTLOADED;
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = ps_patfill
 *
 * DESCRIPTION   = This routine is called for all path or area filling in the
 *                 postscript driver.  If there is no path defined it simply
 *                 returns SUCCESS.  This routine supports all of the standard
 *                 PM patterns as well as user defined bitmap patterns.
 *
 * INPUT         = HDC
 *                 PDDC
 *                 ULONG        flag determing WINDING or ALTERNATE filling
 *                 BOOL         fill associated with an area or path
 *                 PBITBLTATTRS Ptr to the attributes
 *                 BOOL         is gsave/grestore is done by the caller
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = SUCCESS or FAILURE
 *
 *
 * RETURN-ERROR  = NONE
 *                                                                    
 *                                                                    
 *                                                                    
 *                                                                    
 *
 ****************************************************************************/

ULONG ps_patfill( HDC myhdc, PDDC pddc, ULONG fillmethod, BOOL fType,
                  PBITBLTATTRS pbbAttrs, BOOL fgSaved )
{
  HBITMAP           hbm;               /* bitmap handle          */
  BITMAPINFOHEADER  bmInfohdr;
  PB                pbBits;
  PBITMAPINFO       pbmInfo;
  CHAR             *pmysz;
  CHAR             *pmysz2;
  LONG              mylcid;
  LONG              loriginX;
  LONG              loriginY;
  LONG              lPatColor;
  LONG              lRed, lGreen, lBlue;
  ULONG             ulProduct;
  ULONG             ulReturn;
  SHORT             usProduct;
  SHORT             usMySymbol;
  SHORT             usSkipCount;
  SHORT             usIndex;
  SHORT             usXCount;
  SHORT             usYCount;
  SHORT             usMyX;
  SHORT             usMyY;
  SHORT             usBitmapFactor;
  FIXED             fxBlue, fxGreen, fxRed, fxGray;
  /*
  **                                                                
  */
  LONG              lColorSaved;

  #if      DEBUG
    PrintLog( (PSZ)"Entering ps_patfill:\n");
    PrintLog( (PSZ)"ps_patfill: pddc->pddcb->cgs.fPathExists = %d\n",
              pddc->pddcb->cgs.fPathExists );

    if (fillmethod == FPATH_WINDING)
    {
      PrintLog( (PSZ)"ps_patfill: fillmethod = FPATH_WINDING\n" );
    }
    else
    {
      PrintLog( (PSZ)"ps_patfill: fillmethod = FPATH_ALTERNATE\n" );
    }
  #endif                       /* DEBUG                                       */

  /*
  **                                                                
  */
  if (!pddc->pddcb->cgs.fPathExists)
  {
    /*
    ** Since there is no path, return.
    */
    return( SUCCESS );
  }

  /*
  **  just kill the path and return success if nothing is to be drawn
  **  but remenber that PATSYM_NOSHADE & FM_LEAVALONE only test for
  **  Pattern Symbol & Foreground format; What about Back Ground.
  **                                                                    
  */
  if (((pddc->pddcb->pat.usFgMix == FM_LEAVEALONE) ||
      (pddc->pddcb->pat.usSymbol == PATSYM_NOSHADE)) &&
      (pddc->pddcb->pat.usBgMix == BM_LEAVEALONE))
  {
    ps_newpath( pddc );
    return( SUCCESS );
  }

  if (fillmethod == FPATH_WINDING)
  {
    pmysz = "f";
    pmysz2 = "fontfill";
  }
  else
  {
    pmysz = "e";
    pmysz2 = "fonteofill";
  }

  /*
  **                                                                
  ** Background filling.
  ** Do the background filling for any one of the following:
  ** 1. User defined pattern irrespective of background mix mode.
  ** 2. PATSYM_NOSHADE or PATSYM_BLANK is selected as pattern and
  **    the background mix mode is not BM_LEAVEALONE.
  ** 3. PATSYM_VERT or PATSYM_HORZ or PATSYM_DIAG1 thro PATSYM_DIAG4
  **    or PATSYM_HALFTONE is selceted as pattern and
  **    the background mix mode is not BM_LEAVEALONE.
  **
  ** For the background filling :
  ** if the foreground mix mode is FM_LEAVEALONE then
  ** fills the background color and return, otherwise
  ** do a gsave, fills the background color, and then a grestore and
  ** falls to foreground filling.
  **
  **
  ** Save the current color in the cgs.
  */
  lColorSaved = pddc->pddcb->cgs.lColor;

  if (pddc->pddcb->pat.usSet != 0)
  {
    /*
    ** User defined pattern.
    */
    if (pddc->pddcb->pat.usFgMix == FM_LEAVEALONE)
    {
      ps_setrgbcolor( pddc, prdc_GetColor( pddc, pddc->pddcb->pat.ulBgColor ) );
      PrintChannel( pddc, (PSZ)"%ls\n", pmysz );

      if (!fgSaved)
      {
        /*
        ** Reset the current color to the saved one.
        */
        ps_setrgbcolor(pddc, lColorSaved);
      }
      else
      {
        /*
        ** restore the saved current color in the cgs.
        */
        pddc->pddcb->cgs.lColor = lColorSaved;
      }

      /*
      ** Since no foreground filling return.
      */
      pddc->pddcb->cgs.fPathExists = FALSE;
      return( SUCCESS );
    }
    else
    {
      PrintChannel( pddc, (PSZ)"gs\n" );
      ps_setrgbcolor( pddc, prdc_GetColor( pddc, pddc->pddcb->pat.ulBgColor ) );
      PrintChannel( pddc, (PSZ)"%ls gr\n", pmysz );

      /*
      ** restore the saved current color in the cgs.
      */
      pddc->pddcb->cgs.lColor = lColorSaved;
    }
  }
  else
  {
    /*
    ** Standard pattern.
    */
    usMySymbol = pddc->pddcb->pat.usSymbol;

    /*
    ** Default to solid.
    */
    if ((usMySymbol < PATSYM_DENSE1) || ((usMySymbol > PATSYM_HALFTONE) &&
       (usMySymbol != PATSYM_BLANK)))
    {
      usMySymbol = PATSYM_SOLID;
    }

    if (pddc->pddcb->pat.usBgMix != BM_LEAVEALONE)
    {
      if (usMySymbol == PATSYM_NOSHADE || usMySymbol == PATSYM_BLANK)
      {
        /*
        **                                                          
        ** Use Back ground only . If we set color to
        ** white, that's what we'll get...!
        ** added case PATSYM_NOSHADE & setrgbcolor to
        ** current back ground color if Background Mix to be done.
        */
        ps_setrgbcolor( pddc, prdc_GetColor( pddc, pddc->pddcb->pat.ulBgColor ) );
        PrintChannel( pddc, (PSZ)"%ls\n", pmysz );

        if (!fgSaved)
        {
          /*
          ** Reset the current color to the saved one.
          */
          ps_setrgbcolor( pddc, lColorSaved );
        }
        else
        {
          /*
          ** restore the saved current color in the cgs.
          */
          pddc->pddcb->cgs.lColor = lColorSaved;
        }

        /*
        ** Since no foreground filling return.
        */

        pddc->pddcb->cgs.fPathExists = FALSE;
        return( SUCCESS );
      }
      else if ((usMySymbol >= PATSYM_VERT && usMySymbol <= PATSYM_DIAG4) ||
           usMySymbol == PATSYM_HALFTONE)
      {
        if (pddc->pddcb->pat.usFgMix == FM_LEAVEALONE)
        {
          ps_setrgbcolor( pddc, prdc_GetColor( pddc,
                          pddc->pddcb->pat.ulBgColor ) );
          PrintChannel( pddc, (PSZ)"%ls\n", pmysz );

          if (!fgSaved)
          {
            /*
            ** Reset the current color to the saved one.
            */
            ps_setrgbcolor(pddc, lColorSaved);
          }
          else
          {
            /*
            ** restore the saved current color in the cgs.
            */
            pddc->pddcb->cgs.lColor = lColorSaved;
          }

          /*
          ** Since no foreground filling return.
          */
          pddc->pddcb->cgs.fPathExists = FALSE;
          return( SUCCESS );
        }
        else
        {
          PrintChannel( pddc, (PSZ)"gs\n" );
          ps_setrgbcolor( pddc, prdc_GetColor( pddc,
                          pddc->pddcb->pat.ulBgColor ) );
          PrintChannel( pddc, (PSZ)"%ls gr\n", pmysz );

          /*
          ** restore the saved current color in the cgs.
          */
          pddc->pddcb->cgs.lColor = lColorSaved;
        }
      }
      else if (pddc->pddcb->pat.usFgMix == FM_LEAVEALONE)
      {
        /*
        ** (usMySymbol >= PATSYM_DENSE1 && usMySymbol <= PATSYM_DENSE8) ||
        ** (usMySymbol == PATSYM_SOLID)
        */
        ps_newpath( pddc );
        return( SUCCESS );
      }
    }  /* End of background mix mode not BM_LEAVEALONE.                     */
  }                          /* End of background filling.                  */

  /*
  **                                                                
  ** Foreground filling.
  */
  /*
  ** set up the proper gray scale
  */
  PrintLog( (PSZ) "ps_patfill: Calling prdc_GetColor to set gray scale\n" );

  switch (fType)
  {
  case PF_ENDAREA:
       lPatColor = prdc_GetColor( pddc, pddc->pddcb->path.ulAreaFgColor );
       break;

  case PF_BLT_ATTRS:
       lPatColor = pbbAttrs->lColor;
       break;

  default:
       lPatColor = prdc_GetColor( pddc, pddc->pddcb->pat.ulFgColor );
       break;
  }
  PrintLog( (PSZ) "ps_patfill: Back from prdc_GetColor\n" );

  /*
  ** PM supports 18 standard patterns as well as user defined
  ** patterns.  if the pattern set is zero, then we have one
  ** of the standard base patterns.  if the pattern set is not
  ** zero, it is the lcid of a bitmap defining the user
  ** defined pattern.  the standard patterns are as follows:
  ** PATSYM_DENSE1 thru PATSYM_DENSE8, PATSYM_VERT,
  ** PATSYM_HORIZ, PATSYM_DIAG1 thru PATSYM_DIAG4,
  ** PATSYM_NOSHADE, PATSYM_SOLID (default), PATSYM_HALFTONE,
  ** and PATSYM_BLANK.
  */
  PrintLog( (PSZ) "ps_patfill: pattern set = %d\n", pddc->pddcb->pat.usSet );
  PrintLog( (PSZ) "ps_patfill: pattern symbol = %d\n",
                  pddc->pddcb->pat.usSymbol );

  if (!pddc->pddcb->pat.usSet)/* we have a standard pattern                 */
  {
    /*
    ** if we have one of the shaded patterns we need to adjust the
    ** gray scale of the pattern.
    */
    if ((usMySymbol >= PATSYM_DENSE1) && (usMySymbol <= PATSYM_DENSE8))
    {
      PrintLog( (PSZ) "ps_patfill: we have one of the shaded patterns\n" );

      /*
      ** Seperate the Red, Green, and Blue color triplets
      */
      lBlue = lPatColor & 0x0ffL;
      lPatColor >>= 8;
      lGreen = lPatColor & 0x0ffL;
      lPatColor >>= 8;
      lRed = lPatColor & 0x0ffL;

      /*
      ** Adjust their intensities by the pattern percentage gray
      */
      lBlue = lBlue + FxToLong( frmul( LongToFx( 255L - lBlue ), afxPatGray[usMySymbol
                                - 1] ) );
      lGreen = lGreen + FxToLong( frmul( LongToFx( 255L - lGreen ), afxPatGray
                                  [usMySymbol - 1] ) );
      lRed = lRed + FxToLong( frmul( LongToFx( 255L - lRed ), afxPatGray
                              [usMySymbol - 1] ));

      /*
      ** Recombine the Red, Green, and Blue values into an RGB color
      */
      lPatColor = lBlue + (lGreen << 8) + (lRed << 16);
    }

    if ((usMySymbol == PATSYM_SOLID) || ((usMySymbol >= PATSYM_DENSE1) &&
       (usMySymbol <= PATSYM_DENSE8)))
    {
      ps_setrgbcolor( pddc, lPatColor );
      PrintChannel( pddc, (PSZ)"%ls\n", pmysz );

      if (!fgSaved)
      {
        /*
        ** Reset the current color to the saved one.
        */
        ps_setrgbcolor( pddc, lColorSaved );
      }
      else
      {
        /*
        ** restore the saved current color in the cgs.
        */
        pddc->pddcb->cgs.lColor = lColorSaved;
      }
    }
    else
    {
      switch (usMySymbol)
      {
      case PATSYM_HALFTONE:
           /*
           ** Seperate the Red, Green, and Blue color triplets
           */
           lBlue = lPatColor & 0x0ffL;
           lPatColor >>= 8;
           lGreen = lPatColor & 0x0ffL;
           lPatColor >>= 8;
           lRed = lPatColor & 0x0ffL;

           /*
           ** Adjust their intensities by the pattern
           ** percentage gray
           */
           lBlue = lBlue + ((255L - lBlue) >> 1);
           lGreen = lGreen + ((255L - lGreen) >> 1);
           lRed = lRed + ((255L - lRed) >> 1);

           /*
           ** Recombine the Red, Green, and Blue values
           ** into an RGB color
           */
           lPatColor = lBlue + (lGreen << 8) + (lRed << 16);
           ps_setrgbcolor( pddc, lPatColor );
           PrintChannel( pddc, (PSZ)"%ls\n", pmysz );

           if (!fgSaved)
           {
             /*
             ** Reset the current color to the saved one.
             */
             ps_setrgbcolor(pddc, lColorSaved);
           }
           else
           {
             /*
             ** restore the saved current color in the cgs.
             */
             pddc->pddcb->cgs.lColor = lColorSaved;
           }
           break;

      case PATSYM_HORIZ:
           /*
           **                                                
           ** Draw the pattern in printer pels
           ** (device coordinates)
           ** The line width is plw1 (2/300 of an inch).
           */
           ps_patfill_base( pddc );

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gs\n" );
           }
           ps_setrgbcolor( pddc, lPatColor );

           if (fillmethod == FPATH_WINDING)
           {
             PrintChannel( pddc, (PSZ)"mdevice sm psize plw1 w phoriz\n" );
           }
           else
           {
             PrintChannel( pddc, (PSZ)"mdevice sm eopsize plw1 w phoriz\n" );
           }

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gr\n" );
           }
           pddc->pddcb->cgs.lColor = lColorSaved;
           break;

      case PATSYM_VERT:
           /*
           **                                                
           ** Draw the pattern in printer pels
           ** (device coordinates)
           ** The line width is plw1 (2/300 of an inch).
           */
           ps_patfill_base( pddc );

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gs\n" );
           }
           ps_setrgbcolor( pddc, lPatColor );

           if (fillmethod == FPATH_WINDING)
           {
             PrintChannel( pddc, (PSZ)"mdevice sm psize plw1 w pvert\n" );
           }
           else
           {
             PrintChannel( pddc, (PSZ)"mdevice sm eopsize plw1 w pvert\n" );
           }

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gr\n" );
           }
           pddc->pddcb->cgs.lColor = lColorSaved;
           break;

      case PATSYM_DIAG1:
           /*
           **                                                
           ** Draw the pattern in printer pels
           ** (device coordinates)
           ** The line width is plw1 (2/300 of an inch).
           */
           ps_patfill_base( pddc );

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gs\n" );
           }
           ps_setrgbcolor( pddc, lPatColor );

           if (fillmethod == FPATH_WINDING)
           {
             PrintChannel( pddc, (PSZ)"mdevice sm psize plw1 w pdiag1\n" );
           }
           else
           {
             PrintChannel( pddc, (PSZ)"mdevice sm eopsize plw1 w pdiag1\n" );
           }

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gr\n" );
           }
           pddc->pddcb->cgs.lColor = lColorSaved;
           break;

      case PATSYM_DIAG2:
           /*
           **                                                
           ** Draw the pattern in printer pels
           ** (device coordinates)
           ** The line width is plw2 (1/600 of an inch).
           */
           ps_patfill_base( pddc );

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gs\n" );
           }
           ps_setrgbcolor( pddc, lPatColor );

           if (fillmethod == FPATH_WINDING)
           {
             PrintChannel( pddc, (PSZ)"mdevice sm psize plw2 w pdiag2\n" );
           }
           else
           {
             PrintChannel( pddc, (PSZ)"mdevice sm eopsize plw2 w pdiag2\n" );
           }

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gr\n" );
           }
           pddc->pddcb->cgs.lColor = lColorSaved;
           break;

      case PATSYM_DIAG3:
           /*
           **                                                
           ** Draw the pattern in printer pels
           ** (device coordinates)
           ** The line width is plw1 (2/300 of an inch).
           */
           ps_patfill_base( pddc );

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gs\n" );
           }
           ps_setrgbcolor( pddc, lPatColor );

           if (fillmethod == FPATH_WINDING)
           {
             PrintChannel( pddc, (PSZ)"mdevice sm psize plw1 w pdiag3\n" );
           }
           else
           {
             PrintChannel( pddc, (PSZ)"mdevice sm eopsize plw1 w pdiag3\n" );
           }

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gr\n" );
           }
           pddc->pddcb->cgs.lColor = lColorSaved;
           break;

      case PATSYM_DIAG4:
           /*
           **                                                
           ** Draw the pattern in printer pels
           ** (device coordinates)
           ** The line width is plw2 (1/600 of an inch).
           */
           ps_patfill_base( pddc );

           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gs\n" );
           }
           ps_setrgbcolor( pddc, lPatColor );

           if (fillmethod == FPATH_WINDING)
           {
             PrintChannel( pddc, (PSZ)"mdevice sm psize plw2 w pdiag4\n" );
           }
           else
           {
             PrintChannel( pddc, (PSZ)"mdevice sm eopsize plw2 w pdiag4\n" );
           }
           if (!fgSaved)
           {
             PrintChannel( pddc, (PSZ)"gr\n" );
           }
           pddc->pddcb->cgs.lColor = lColorSaved;
           break;
      }                      /* end of outer switch block                   */
    }                        /* end of else                                 */
    PrintLog( (PSZ) "ps_patfill: done outputting standard pattern\n" );
  }                          /* end of if                                   */
  else                       /* not a base pattern                          */
  {
    /*
    ** we have a user defined pattern.  the pattern is
    ** defined by a bitmap.  call GetBitmapBits to get the
    ** necessary information about the bitmap.  first we have
    ** to find the bitmap
    **
    ** get the user defined LCID.  this LCID will give us
    ** the handle to the bitmap which defines the pattern
    */
    mylcid = (LONG) pddc->pddcb->pat.usSet;

    if (!(hbm = GreQueryBitmapHandle( myhdc, mylcid )))
    {
       /*
       ** Take care of a Logical Font Pattern                    
       */
       if (pddc->pddcb->text.ChrBundle.usSet == pddc->pddcb->pat.usSet)
       {
         /*
         ** See if the font pattern was loaded
         */
         ps_patfill_font( pddc );

         if (!fgSaved)
         {
           PrintChannel( pddc, (PSZ)"gs\n" );
         }

         PrintChannel( pddc, (PSZ)"clip\n" );
         PrintChannel( pddc, (PSZ)"%f (%c) fontpatfill\n",
                       pddc->pddcb->text.transformmatrix.mx_fxM11,
                       pddc->pddcb->pat.usSymbol );

         if (!fgSaved)
         {
           PrintChannel( pddc, (PSZ)"gr\n" );
         }

         return( SUCCESS );
       }
       ps_newpath( pddc );
       return( FAILURE );
    }

    /*
    ** GetBitmapParameters gives us the size of the source
    ** bitmap.  From this we can allocate the correct space
    ** to read the bitmap bits into.  We need these bits
    ** since they define our pattern filling font character
    ** the amount of space required is :
    ** ((bitcount * width + 31)/32)*#planes*4*height
    ** NOTE: the code is currently set up to handle bitmaps
    ** < 64K
    */
    if (!(GreGetBitmapParameters( hbm, &bmInfohdr )))
    {
      ps_newpath( pddc );
      return( FAILURE );      /* !!!CR need some error handling              */
    }
    ulProduct = ((LONG) bmInfohdr.cBitCount * (LONG)bmInfohdr.cx) + 31L;
    usProduct = (SHORT) (ulProduct / 32);
    usProduct *= bmInfohdr.cy;   /* times height                            */
    usProduct *= bmInfohdr.cPlanes;  /* times # planes                      */
    usProduct *= 4;

    /*
    ** get memory for the bitmap bits
    */
    if (!(pbBits = (PB)GplMemoryAlloc( pddc->pdv->pDCHeap, usProduct )))
    {
      GplErrSetError(  PMERR_INSUFFICIENT_MEMORY);
      GplMemoryFree( (PB)pbBits );
      ps_newpath( pddc );
      return( FAILURE );
    }

    /*
    ** now calculate the space required for the BITMAPINFO structure
    */
    if (bmInfohdr.cBitCount == 24)
    {
      usSkipCount = 0;
    }
    else
    {
      usSkipCount = 2 << bmInfohdr.cBitCount;
    }

    if (!(pbmInfo = (PBITMAPINFO)GplMemoryAlloc( pddc->pdv->pDCHeap, 
                              sizeof(BITMAPINFO)+usSkipCount * sizeof(LONG) )))
    {
      GplErrSetError(  PMERR_INSUFFICIENT_MEMORY );
      GplMemoryFree((PB)pbmInfo );
      ps_newpath( pddc );
      return( FAILURE );
    }
    pbmInfo->cbFix = bmInfohdr.cbFix;
    pbmInfo->cx = bmInfohdr.cx;
    pbmInfo->cy = bmInfohdr.cy;
    pbmInfo->cPlanes = bmInfohdr.cPlanes;
    pbmInfo->cBitCount = bmInfohdr.cBitCount;

    ulReturn = (ULONG) GreGetBitmapBits (myhdc, hbm, 0, (LONG) bmInfohdr.cy,
                                         (PBYTE) pbBits, pbmInfo);
    /*
    ** GetBitmapBits should return the number of scanlines
    ** which were copied over.  this should be equal to
    ** the height of the bitmap
    */
    if (ulReturn == -1)
    {
      ps_newpath( pddc );
      return( FAILURE );
    }

    if (ulReturn != (LONG) pbmInfo->cy)
    {
      GplErrSetError(  PMERR_INCOMPATIBLE_BITMAP );
      ps_newpath( pddc );
      return( FAILURE );
    }
    ps_patfill_common( pddc );
    loriginX = pddc->pddcb->pat.ptlOrg.x % pbmInfo->cx;
    loriginY = pddc->pddcb->pat.ptlOrg.y % pbmInfo->cy;

    if (pbmInfo->cy > 50)
    {
      usBitmapFactor = 1;
    }
    else
    {
      usBitmapFactor = 100 / pbmInfo->cy;
    }

    if (!fgSaved)
    {
      PrintChannel( pddc, (PSZ)"gs\n" );
    }
    PrintChannel( pddc, (PSZ) "mdevice sm\n" );
    ps_setrgbcolor( pddc, lPatColor );

    /*
    **                                                                    
    **  use mdevice and unity matrix instead of xformCTM
    **        PrintChannel(pddc, (PSZ) "%d %d [%f 0 0 %f 0 0]\n",pbmInfo->cx,
    **                     (pbmInfo->cy*usBitmapFactor),
    **                     pddc->pddcb->xformCTM.fxM11,
    **                     pddc->pddcb->xformCTM.fxM22);
    */
    PrintChannel( pddc, (PSZ)"%d %d [1 0 0 1 0 0]\n", pbmInfo->cx, (pbmInfo->cy
                  * usBitmapFactor));
    PrintChannel( pddc, (PSZ)"{%d %d scale %d %d true\n", pbmInfo->cx,
                  (pbmInfo->cy *usBitmapFactor), pbmInfo->cx, (pbmInfo->cy
                  * usBitmapFactor));
    PrintChannel( pddc, (PSZ)"[%d 0 0 %d -0.5 %d.5] { <\n", pbmInfo->cx, -
                  (pbmInfo->cy * usBitmapFactor), (pbmInfo->cy * usBitmapFactor - 1));

    /*
    ** Bitmaps from the engine have their scanlines padded out
    ** to DWORD boundarys.  PostScript font bitmaps have their
    ** scanlines padded out to BYTE boundaries.  So we have to
    ** munge with the bytes we pass to PostScript.
    */
    usSkipCount = ((32 - (pbmInfo->cx % 32)) / 8) % 4;

    /*
    ** we are outputting a byte at a time
    **
    ** Ravi : 10/03/91
    ** Output 40 bytes in a line.
    ** Reusing "usProduct" to keep a count on the number bytes
    ** in a line.
    */
    usProduct = 0;
    usMyX = ((pbmInfo->cx + 7) / 8);

    for (usMyY = 0; usMyY < usBitmapFactor; usMyY++)
    {
      usIndex = 0;

      for (usYCount = 0; usYCount < pbmInfo->cy; usYCount++)
      {

        for (usXCount = 0; usXCount < usMyX; usXCount++)
        {
          PrintChannel( pddc, (PSZ)"%02x", *(pbBits + usIndex) );
          usIndex++;

          /*
          ** Ravi : 10/03/91
          ** Output 40 bytes in a line.
          */
          /*
          ** Output 40 bytes in a line.
          */
          usProduct++;

          if (usProduct == 40)
          {
            PrintChannel( pddc, (PSZ)"\n" );
            usProduct = 0;
          }
        }
        usIndex += usSkipCount;
      }
    }
    PrintChannel( pddc, (PSZ)"\n" );
    PrintChannel( pddc, (PSZ)
           "> }imagemask } bind /patrn %ld %ld definepattern pop\n", loriginX,
           loriginY );
    PrintChannel( pddc, (PSZ)"/patrn %ls\n", pmysz2 );

    if (!fgSaved)
    {
      PrintChannel( pddc, (PSZ)"gr\n" );
    }
    pddc->pddcb->cgs.lColor = lColorSaved;
    GplMemoryFree((PB)pbmInfo );
    GplMemoryFree((PB)pbBits );
  }

  /*
  ** The fill operator deletes the current path.
  */
  pddc->pddcb->cgs.fPathExists = FALSE;
  return( SUCCESS );
}
