/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT (C) Lexmark 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 = PRDSPOLY
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prds_PolyScanLine
 *             prds_GetPattern
 *             prds_GetMask
 *             prds_GetPattDword
 *             prds_InnerScanLine
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

#define INCL_32                   /* CON3201 */
#define INCL_DOSPROCESS           /* CON3201 */
#define INCL_DOSSEMAPHORES
#define INCL_GPIPRIMITIVES
#define INCL_WINHEAP
#define INCL_GPIBITMAPS
#define INCL_GPIERRORS
#define INCL_GPILOGCOLORTABLE
#include <os2.h>
#undef INCL_DOSPROCESS            /* CON3201 */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS
#undef INCL_GPILOGCOLORTABLE

#define INCL_DDIBUNDLES
#define INCL_DDIFONTSTRUCS
#define INCL_DDIDEFS
#define INCL_DDIMISC
#define INCL_DDICOMFLAGS
#define INCL_GREALL
#include <pmddi.h>
#undef INCL_DDIBUNDLES
#undef INCL_DDIFONTSTRUCS
#undef INCL_DDIDEFS
#undef INCL_DDIMISC
#undef INCL_DDICOMFLAGS
#undef INCL_GREALL

#define INCL_WINP_SELECTIVE
#define INCL_WINP_SEI
#include <pmwinx.h>
#undef INCL_WINP_SELECTIVE
#undef INCL_WINP_SEI
#undef INCL_32                    /* CON3201 */

#include <prdconse.h>
#include <prddcone.h>
#include <prdbcone.h>
#include <prdccone.h>
#include <prdncone.h>
#include <prdtcone.h>

#define NO_CONSTANT_INCL
#include <prdinclt.h>
#undef NO_CONSTANT_INCL

#include <prdbtyp4.h>
#include <prdupatt.h>

#include <prdbtyp1.h>
#include <prdbextf.h>
#include <prdcextf.h>
#include <prdgextf.h>
#include <prdiextf.h>
#include <prdnextf.h>
#include <prdsextf.h>
#include <prdtextf.h>
#include <prduextf.h>

/******************************************************************************/
/*  Now for a few externals...                                                */
/******************************************************************************/
extern PatternInfoType  PatternInfoTable[];
extern USHORT           PatternTabSize;
extern USHORT           usStartScan;
extern USHORT           usEndScan;
extern USHORT           usCurrentScan;
extern USHORT           usOld;

/******************************************************************************/
/*  FUNCTION: prds_PolyScanLine                                               */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  See "OS/2 Technical Reference: I/O Subsytems and Device Drivers"          */
/*                                                                            */
/*  hanDC      DcH;                                                           */
/*  PSCANDATA  lpPSLS;                                                        */
/*  lpDCI      DCIData;                                                       */
/*  ULONG      FunN;                                                          */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function fills shapes defined by polyshortlines.  The function is    */
/*  supplied with a list of one or more pairs of polyshortlines via lpPSLS and*/
/*  for each pair of shortlines the function fills the space between them     */
/*  (with the left hand edge inclusive and the right hand edge exclusive)     */
/*  using the required mix and pattern.                                       */
/*                                                                            */
/*  Note we assume that the target is at 1 or 4 bpp - no other formats are    */
/*  supported.                                                                */
/******************************************************************************/
ULONG EXPENTRY prds_PolyScanLine( hanDC      DcH,
                                  PSCANDATA  lpPSLS,
                                  lpDCI      DCIData,
                                  ULONG      FunN)

{

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    SHORT   Result;                    /* result field                        */
    ULONG   Command;                   /* command part of FunN                */
    USHORT  usPatFlags;                /* local copy of pattern flags         */
    USHORT  usDriverType;              /* driver type                         */
    BOOL    NoClipping;                /* COM_PRECLIP                         */
    pBMListEntry  lpLE;                /* P500348...                          */

#ifndef COM_PRECLIP
#define COM_PRECLIP             0x04000000 /* PD00791                         */
#endif

#ifdef PRD_TIMING

    DEKHOOK0(A, 9, 07)

#endif

    /**************************************************************************/
    /*  Get the driver and DCI Data semaphore                                 */
    /**************************************************************************/
    prdm_EnterDriver(DCIData);

    /**************************************************************************/
    /*  Mask the command bits                                                 */
    /**************************************************************************/
    GetCommand(DCIData);

    /**************************************************************************/
    /*  PD00791 : Need to initialize the NoClipping flag...                   */
    /**************************************************************************/
    if (Command & COM_PRECLIP)
    {
        NoClipping = TRUE;
    }
    else
    {
        NoClipping = FALSE;
    }

    /**************************************************************************/
    /*  Do the new framework drawing function - sets DRAWN_INTO flag if       */
    /*  COM_DRAW is set.  Returns error if not in a suitable state.           */
    /**************************************************************************/
    if ((Result = prdn_CheckDrawingState((PULONG)&Command, DCIData)) != OK)
    {
        Result = (Result == ERR_PURGE) ? OK : ERROR_ZERO;
        goto EXIT_FUNC;
    }

    /**************************************************************************/
    /*  Reset bit 0 of the style high word to indicate a figure is not        */
    /*  starting                                                              */
    /**************************************************************************/
    DCIData->StyleNumber &= 0xfffeffff;

    /**************************************************************************/
    /*  Make sure there is a bitmap selected for this DC                      */
    /**************************************************************************/
    if (!DCIData->DCISelBitmap)
    {
        LOGERR(TFUNC, "No Bitmap", FNULL, 0,PMERR_NO_BITMAP_SELECTED);
        Result = ERROR_ZERO;
        goto EXIT_FUNC;
    }

    /**************************************************************************/
    /*  If bounds determination required then accumulate bounds.  Just convert*/
    /*  the coords passed as parameter.                                       */
    /**************************************************************************/
    if (Command & COM_BOUND)
    {
        (VOID)prdg_AddBounds((DevRect  *)&lpPSLS->rclBound, DCIData);
    }

    /**************************************************************************/
    /*  First-level checks have been completed, and Bounds have been          */
    /*  calculated (if required).  So if the Draw Bit is not on we can now    */
    /*  exit OK.                                                              */
    /**************************************************************************/
    if (!(Command & COM_DRAW))
    {
        Result = OK;
        goto EXIT_FUNC;
    }

    /**************************************************************************/
    /*  Set the device text only flag to FALSE since we're about to draw into */
    /*  the band.                                                             */
    /**************************************************************************/
    DCIData->TextOnlyDC = FALSE;

    /**************************************************************************/
    /*  Local variable for clarity.                                           */
    /**************************************************************************/
    usDriverType = DCIData->DCIPdbInstance->DDT.DDTDriverType;

    /**************************************************************************/
    /*  Two ways to go here.  Either through the fast path code for (1,1)     */
    /*  bitmap drivers if the pattern can be speeded up, or through the old   */
    /*  code.                                                                 */
    /*                                                                        */
    /*  The new code resides in PRDSSUBR.C, thus drivers that do not use this */
    /*  do not need this module.  The old path code resides in this module.   */
    /**************************************************************************/
    lpLE = (pBMListEntry)DCIData->DCISelBitmap;       /* P500348...           */
    if (((usDriverType != DDT_IBM42XX_DRV) || ((usDriverType == DDT_IBM42XX_DRV)
         && (DCIData->DCIPdbInstance->PrinterType != IBM_4224_COLOR))) &&
        (lpLE->Parms.Bitcount == 1))                  /* P500348...           */
    {

        /**********************************************************************/
        /*  Get the polyscanline pattern information                          */
        /**********************************************************************/
        if (!DCIData->usPatValid)
        {

            /******************************************************************/
            /*  Make the pattern valid                                        */
            /******************************************************************/
            Result = prdu_GetPatternInfo(DCIData);

            /******************************************************************/
            /*  Remember that it is valid.                                    */
            /******************************************************************/
            DCIData->usPatValid = TRUE;
        }

        /**********************************************************************/
        /*  Local copy of pat data for speed.                                 */
        /**********************************************************************/
        usPatFlags = ((pPatType)(DCIData->lpPD))->usPatFlags;

        /**********************************************************************/
        /*  Fast path patterns that can be expanded into DWORDs.              */
        /**********************************************************************/
        if ((usPatFlags & PAT_MIX_OK ) && (usPatFlags & PAT_WIDTH_OK))
        {

            /******************************************************************/
            /*  Polyscanline fast path                                        */
            /*                                                                */
            /*  P00791 : Add parameter NoClipping to call.                   */
            /******************************************************************/
            Result = prds_FastScanLine(DcH, lpPSLS, DCIData, NoClipping, FunN);
            goto EXIT_FUNC;
        }
    }

    /**************************************************************************/
    /*  Do the real work                                                      */
    /*                                                                        */
    /*  PD00791 : Add parameter NoClipping to call.                           */
    /**************************************************************************/
    Result = prds_InnerScanLine(DcH, lpPSLS, DCIData, NoClipping, FunN);

    /**************************************************************************/
    /*  PD00801 :     return code from InnerScanLine.                         */
    /**************************************************************************/
    if (Result == GPI_ERROR)
        goto LOGERR_EXIT;

    /**************************************************************************/
    /*  And finished.                                                         */
    /**************************************************************************/

EXIT_FUNC:

    prdm_LeaveDriver(DCIData);

#ifdef PRD_TIMING

    DEKHOOK0(A, 9, 87)

#endif

    return(Result);

/******************************************************************************/
/*  PD00801 : Got an error back from innerscanline.                           */
/******************************************************************************/
LOGERR_EXIT:
    prdm_LeaveDriver(DCIData);
    LOGERR(TFUNC, "Invalid code page", FNULL, 0, PMERR_BITMAP_NOT_SELECTED);

#ifdef PRD_TIMING

    DEKHOOK0(A, 9, 87)

#endif

    return (GPI_ERROR);
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prds_GetPattern                                                 */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  Vars *BB;  Pointer to Bitblt working storage                              */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function sets up any pattern required for the blit.                  */
/*                                                                            */
/*  It uses the pattern origin to determine the offset into the pattern to    */
/*  start at and it sets up values which are used at the start of each row to */
/*  set up correct access to the pattern bitmap.                              */
/*                                                                            */
/*  The pattern is color expanded (to the target bitmap format) using either  */
/*  the given ArgAttrs colors or the pattern bundle colors.                   */
/*                                                                            */
/*  BUNNIES : Code which initializes method of picking up the pattern bytes   */
/*  ripped out and replaced.                                                  */
/******************************************************************************/
USHORT  prds_GetPattern(Vars *BB)

{

#define TFUNC "prds_GetPattern"

    /**************************************************************************/
    /*  Local Variables                                                       */
    /**************************************************************************/
    USHORT             Offset;         /* Offset to apply to pattern to allow */
                                       /* for pattern origin                  */
    USHORT             Work;           /* Work variable for working out Offset*/
    USHORT             StartPos;       /* The x starting position of the      */
                                       /* target bitmap rounded down to       */
                                       /* nearest 8                           */
    pBMListEntry       PatLE;          /* The pattern list entry for when we  */
                                       /* have to use non-default patterns    */
    SHORT              i, j;           /* Loop control variables              */
    PDAREABUNDLE       AreaAts;        /* pointer to current area ats         */
    FontDataType       FontData;       /* Font information                    */
    CHARDEFS           SaveCharDefs;   /* Temp character attributes           */
    PCHARDEFS          pCurTxtDefs;    /* Pointer to current txt defs         */
    lpDCI              DCIData;        /* pointer to target DC                */
    PBYTE              CodePtBuffer;   /* buffer for codepoint defn           */
    USHORT             PatBytesPerRow; /* no. of bytes in a pttrn row         */
    USHORT             CPtBytesPerRow; /* no. of bytes in a codept row        */
    USHORT             CPtHeight;      /* code point height                   */
    PBYTE              CPtDefn;        /* pointer to codepoint defn           */
    USHORT             DwordPaddingAdj;
    USHORT             PatternIndex;
    lpPatternInfoType  lpPatternInfo;
    BOOL               GreyScaling;    /* Grey scaling flag                   */
    ULONG              GS_Color;       /* Temporary color variable            */
    lpDDTType          pDDT;           /* DDT Pointer                         */
    FMFFileStrucType   FMFData;        /* FMF for current font                */
    USHORT             usPatType;      /* GreyScaleInfo flags...              */

    /**************************************************************************/
    /*  Initialize a few variables...                                         */
    /**************************************************************************/
    DCIData = BB->TargetDCI;
    AreaAts = DCIData->DCICurPtnAts;
    GreyScaling = FALSE;
    pDDT = &DCIData->DCIPdbInstance->DDT;
    BB->PatMonBmapReq = FALSE;

    /**************************************************************************/
    /*  If the pattern set is '0' then use our default pattern set.           */
    /**************************************************************************/
    if (AreaAts->adef.defSet == 0)
    {

        /**********************************************************************/
        /*  This is the default pattern set - get the pattern number.  If it  */
        /*  is blank (64) then set it to our blank pattern (PATSYM_NOSHADE) to*/
        /*  make the pattern set contiguous.  If the pattern is the default or*/
        /*  the pattern number is invalid for our pattern set then use the    */
        /*  default pattern.                                                  */
        /**********************************************************************/
        BB->PatternNumb = AreaAts->abnd.usSymbol;
        if (BB->PatternNumb == PATSYM_BLANK)
        {
            BB->PatternNumb = PATSYM_NOSHADE;
        }
        else
        {
            if (BB->PatternNumb == PATSYM_DEFAULT ||
                BB->PatternNumb == PATSYM_SOLID ||
                BB->PatternNumb > PatternTabSize)
            {
                BB->PatternNumb = PATSYM_SOLID;
            }
            else
            {

                /**************************************************************/
                /*  PD00599 : If the pattern is PATSYM_HALFTONE, switch it to */
                /*  PATSYM_DENSE4.                                            */
                /**************************************************************/
                if (BB->PatternNumb == PATSYM_HALFTONE)
                    BB->PatternNumb = PATSYM_DENSE4;
            }
        }

        /**********************************************************************/
        /*  We may be grey scaling - need to ensure that we're not in pure    */
        /*  color mode, that we're a monochrome printer, that there is not a  */
        /*  source bitmap involved and that the pattern set and symbol is the */
        /*  default.                                                          */
        /**********************************************************************/
        if (!(DCIData->DCIColOptions & LCOL_PURECOLOR) &&
             (pDDT->DDTMaxColors == DDT_TWO_COLORS) &&
             (BB->Source == NO_SOURCE) && (BB->PatternNumb == PATSYM_SOLID))
        {

            /******************************************************************/
            /*  We're definitely grey scaling.  Now see if the bit blit has   */
            /*  specified any colors to be used during the blit.  If so, we   */
            /*  need to use them.                                             */
            /******************************************************************/
            if (BB->ArgStyle & BLTMODE_ATTRS_PRES)
            {
                GS_Color = BB->ArgAttrs.lColor;
            }
            else
            {
                GS_Color = DCIData->DCICurPtnAts->abnd.lColor;
            }

            /******************************************************************/
            /*  Now get the greyscale pattern information                     */
            /*                                                                */
            /*  PD00462 : Changed the function call below to use the new      */
            /*  function prdb_GetGreyScaleInfo() which provides a consistent  */
            /*  interface for all other greyscale code.                       */
            /******************************************************************/
            (VOID)prdb_GetGreyScaleInfo(GS_Color, &usPatType, &(BB->GS_Pattern),
                                        DCIData);

            /******************************************************************/
            /*  PD00616 : Now that we have the pattern, we need to fill in the*/
            /*  BB structure for pattern-specific fields - used to be done by */
            /*  prds_GetGreyScalePattern(), eliminated so engine text grey-   */
            /*  scaling routines did not have to handle the BB structure.     */
            /******************************************************************/
            BB->PatBM          = (PBYTE)BB->GS_Pattern;
            BB->PatWidth       = GS_PATTERN_WIDTH;
            BB->PatHeight      = GS_PATTERN_HEIGHT;
            BB->PatBytesPerRow = GS_PATTERN_BYTES_PER_ROW;
            GreyScaling = TRUE;        /* Set flag to detect grey scaling     */
        }
        if (!GreyScaling)
        {

            /******************************************************************/
            /*  If we're not grey scaling, set up the pattern attributes in   */
            /*  the BB data.  If we are grey scaling, we've already set these */
            /*  values within prdb_GetGreyScaleInfo().  Patterns are ordinated*/
            /*  from 1 so we must decrement the index to access our array of  */
            /*  patterns.                                                     */
            /******************************************************************/
            if (DCIData->DCIPdbInstance->Orientation == PORTRAIT)
            {
                PatternIndex = pDDT->DDTRasterMode->PortPattIndex;
            }
            else
            {
                PatternIndex = pDDT->DDTRasterMode->LandPattIndex;
            }
            lpPatternInfo      = &PatternInfoTable[PatternIndex];
            BB->PatternNumb--;
            BB->PatBM          = lpPatternInfo->PatternTable[BB->PatternNumb];
            BB->PatWidth       = lpPatternInfo->PatternWidth;
            BB->PatHeight      = lpPatternInfo->PatternHeight;
            BB->PatBytesPerRow = lpPatternInfo->PatternBytesPerRow;
        }
    }
    else
    {

        /**********************************************************************/
        /*  The pattern is not one of our default ones so we must get its     */
        /*  bitmap handle and parameters.  If the generic flag is set then the*/
        /*  pattern is an engine font, otherwise it is a bitmap.              */
        /**********************************************************************/
        if (AreaAts->adef.fFlags & CDEF_GENERIC)
        {
            pCurTxtDefs = &DCIData->DCICurTxtAts->cdef;

            /******************************************************************/
            /*  Save the current text attribute bundle.                       */
            /******************************************************************/
            prdu_memcpy((PBYTE)&SaveCharDefs, (PBYTE)pCurTxtDefs,
                        sizeof(CHARDEFS));

            /******************************************************************/
            /*  Copy area attributes to text bundle.                          */
            /******************************************************************/
            prdu_memcpy((PBYTE)pCurTxtDefs, (PBYTE)&AreaAts->adef,
                        sizeof(AREADEFS));

            /******************************************************************/
            /*  Set up information about the font in our local copy of the    */
            /*  font data structure.                                          */
            /******************************************************************/
            FontData.Info.pFont = &FMFData;
            if (prdt_LocateFont(&FontData, DCIData) != OK)
            {
                prdu_memcpy((PBYTE)pCurTxtDefs, (PBYTE)&SaveCharDefs,
                            sizeof(CHARDEFS));
                return(ERROR_ZERO);
            }

            /******************************************************************/
            /*  If the font is not an engine image font then it cannot be used*/
            /*  as a pattern.                                                 */
            /******************************************************************/
            if ((FontData.Info.Type != FT_ENGINE) ||
                (FontData.pMetrics->fsDefn & FM_DEFN_OUTLINE))
            {
                prdu_memcpy((PBYTE)pCurTxtDefs, (PBYTE)&SaveCharDefs,
                            sizeof(CHARDEFS));
                return(ERROR_ZERO);
            }
            prdt_NextCodePoint(AreaAts->abnd.usSymbol, &FontData, DCIData);

            /******************************************************************/
            /*  Work out the amount of memory needed for the code point       */
            /*  definition in bitmap format.                                  */
            /******************************************************************/
            CPtHeight        = FontData.CPtInfo.Height;
            CPtBytesPerRow   = (FontData.CPtInfo.Width + 7) / 8;
            PatBytesPerRow   = ((CPtBytesPerRow + 3) / 4) * 4;
            DwordPaddingAdj  = (USHORT)(PatBytesPerRow - CPtBytesPerRow);
            BB->FontBMSize   = (USHORT)PatBytesPerRow * CPtHeight;
            if (prdg_AllocHeapItem(DCIData, BB->FontBMSize,
                                   (PUSHORT *)&CodePtBuffer) != OK)
            {
                prdu_memcpy((PBYTE)pCurTxtDefs, (PBYTE)&SaveCharDefs,
                            sizeof(CHARDEFS));
                return(ERROR_ZERO);
            }
            BB->FontBM = CodePtBuffer;
            BB->PatBM  = CodePtBuffer;

            /******************************************************************/
            /*  Copy the codepoint definition from the font format to the     */
            /*  bitmap format.                                                */
            /******************************************************************/
            CPtDefn = FontData.CPtInfo.Defn;
            for(i = CPtHeight - 1; i >= 0; i--)
            {
                for(j = 0; j < (USHORT)CPtBytesPerRow; j++)
                    *CodePtBuffer++ = CPtDefn[i + CPtHeight * j];
                CodePtBuffer += DwordPaddingAdj;
            }
            BB->PatHeight      = CPtHeight;
            BB->PatWidth       = FontData.CPtInfo.Width;
            BB->PatBytesPerRow = PatBytesPerRow;

            /******************************************************************/
            /*  Restore the current text attribute bundle values.             */
            /******************************************************************/
            prdu_memcpy((PBYTE)pCurTxtDefs, (PBYTE)&SaveCharDefs,
                        sizeof(CHARDEFS));
        }
        else
        {
            PatLE = (pBMListEntry)AreaAts->adef.defSet;
            BB->PatMonBmapReq  = PatLE->Parms.MonBmapReq;
            BB->PatBM          = PatLE->Bitmap;
            BB->PatHeight      = PatLE->Parms.Height;
            BB->PatWidth       = PatLE->Parms.Width;
            BB->PatBytesPerRow = PatLE->Parms.BytesPerRow;
        }
    }

    /**************************************************************************/
    /*  Get a local copy of the pattern origin, and adjust so that the        */
    /*  coordinates are negative - since we do calculations in ULONGs later,  */
    /*  we want to avoid getting a negative answer when subtracting the       */
    /*  pattern origin from a point in the target bitmap.                     */
    /*                                                                        */
    /*  BANDING : adjust for DCOrigin                                         */
    /**************************************************************************/
    BB->PatOrigin.X = DCIData->DCIPattOriDev.X;
    BB->PatOrigin.Y = DCIData->DCIPattOriDev.Y;

    /**************************************************************************/
    /*  Careful with brackets here.                                           */
    /**************************************************************************/
    BB->PatOrigin.X += (BB->TrgLE)->XOrigin;
    BB->PatOrigin.Y += (BB->TrgLE)->YOrigin;

    BB->PatOrigin.X %= BB->PatWidth;
    if (BB->PatOrigin.X > 0)
        BB->PatOrigin.X -= (USHORT)BB->PatWidth;
    BB->PatOrigin.Y %= BB->PatHeight;
    if (BB->PatOrigin.Y > 0)
        BB->PatOrigin.Y -= (USHORT)BB->PatHeight;

    if (GreyScaling)
    {

        /**********************************************************************/
        /*  If we're grey scaling, just set the foreground and background     */
        /*  colors to black and white respectively.                           */
        /**********************************************************************/
        BB->ConvPat0 = PRD_FOREGROUND;
        BB->ConvPat1 = PRD_BACKGROUND;
    }
    else
    {
        if (BB->ArgStyle & BLTMODE_ATTRS_PRES)
        {

            /******************************************************************/
            /*  Use the BitBltAttrs passed in to BitBlt.  Careful about       */
            /*  brakets on BB->TrgLE                                          */
            /******************************************************************/
            BB->ConvPat0 = prdc_ColorToPelBits(BB->ArgAttrs.lBackColor,
                                               BB->TargetDCI,
                                               (BB->TrgLE)->DCTPtr);
            BB->ConvPat1 = prdc_ColorToPelBits(BB->ArgAttrs.lColor,
                                               BB->TargetDCI,
                                               (BB->TrgLE)->DCTPtr);
        }
        else
        {

            /******************************************************************/
            /*  Use current pattern attributes.  Careful about brackets       */
            /******************************************************************/
            BB->ConvPat0 = prdc_ColorToPelBits(BB->TargetDCI->DCICurPtnAts->
                                               abnd.lBackColor, BB->TargetDCI,
                                               (BB->TrgLE)->DCTPtr);
            BB->ConvPat1 = prdc_ColorToPelBits(BB->TargetDCI->DCICurPtnAts->
                                               abnd.lColor, BB->TargetDCI,
                                               (BB->TrgLE)->DCTPtr);
        }
    }

    /**************************************************************************/
    /*  Save PatCopyMode for speed later on.                                  */
    /**************************************************************************/
    BB->PatCopyMode = (BB->ConvPat1 << 1) | BB->ConvPat0;
    if (GreyScaling)
        return(GS_FLAG);
    else
        return(OK);
}
#undef TFUNC

/******************************************************************************/
/*                                                                            */
/*  FUNCTION: prds_GetMask                                                    */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  ULONG  Number;                                                            */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This fn works out the mask needed to replace Number bits at the left of   */
/*  Dword.  The problem is that we store bits in a bitmap in this order:      */
/*                                                                            */
/*  Bits:                                                                     */
/*                                                                            */
/*  7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 ...                                 */
/*                                                                            */
/*  Bytes:                                                                    */
/*                                                                            */
/*  0               1               2     ...                                 */
/*                                                                            */
/*  whereas in a Dword the bits are stored:                                   */
/*                                                                            */
/*  Bits:                                                                     */
/*                                                                            */
/*  7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0 7 6 5 4 3 2 1 0           */
/*                                                                            */
/*  Bytes:                                                                    */
/*                                                                            */
/*  3               2               1               0                         */
/*                                                                            */
/*  So a mask to mask out the first 14 bits in the bitmap will look like this */
/*  in the Dword:                                                             */
/*                                                                            */
/*  1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 1 1 0 0 0 0 0 0 0 0           */
/*                                                                            */
/*  This is the mask we produce.                                              */
/******************************************************************************/
ULONG prds_GetMask( USHORT Number)

{

#define TFUNC "prds_GetMask"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    ULONG  Mask;

    Mask = 0;
    if (Number <= 8)
    {
        Mask = (ULONG)0xFFFFFF00 | ((ULONG)0x000000FF >> Number);
    }
    else
    {
        if (Number <= 16)
        {
            Mask = (ULONG)0xFFFF0000 | (((ULONG)0x0000FF00 >> (Number - 8)) &
                                        0x0000FF00);
        }
        else
        {
            if (Number <= 24)
            {
                Mask = (ULONG)0xFF000000 | (((ULONG) 0x00FF0000 >>
                                            (Number - 16)) & 0x00FF0000);
            }
            else
            {
                Mask = ((ULONG)0xFF000000 >> (Number - 24)) & 0xFF000000;
            }
        }
    }
    return Mask;
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prds_GetPattDword                                               */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  PULONG   pMask;                                                           */
/*  PULONG   pRealPattern;                                                    */
/*  PUSHORT  pPattIndex;                                                      */
/*  PBYTE    PattStart;                                                       */
/*  USHORT   PattWidth;                                                       */
/*  BOOL     PattMonBmapReq;                                                  */
/*  USHORT   TargBpp;                                                         */
/*  BYTE     FgCol;                                                           */
/*  BYTE     BgCol;                                                           */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function constructs the Mask and RealPattern Dwords starting at bit  */
/*  PattIndex in the pattern row which starts at PattStart.  We do some       */
/*  tortuous looping to accomodate the ordering of pels in the bitmap.        */
/*                                                                            */
/*  In a bitmap, within each byte the pels are written highest to lowest, so  */
/*  in CurrDword the pels are ordered:                                        */
/*                                                                            */
/*  7 6 5 4 3 2 1 0 15 14 13 12 11 10 9 8 23 22 ...  16 31 30 ...  24         */
/*                                                                            */
/*  We must match this order in constructing Mask and RealPattern.  In the    */
/*  loop, j goes through exactly this sequence at 1 bpp; at 4 bpp the nibbles */
/*  in CurrDword have their lowest bits in the following sequence:            */
/*                                                                            */
/*  4 0 12 8 20 16 28 24                                                      */
/*                                                                            */
/*  and j goes through exactly this sequence.                                 */
/******************************************************************************/
VOID prds_GetPattDword( PULONG   pMask,
                        PULONG   pRealPattern,
                        PUSHORT  pPattIndex,
                        PBYTE    PattStart,
                        USHORT   PattWidth,
                        BOOL     PattMonBmapReq,
                        USHORT   TargBpp,
                        BYTE     FgCol,
                        BYTE     BgCol)

{

#define TFUNC "prds_GetPattDwd"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    PBYTE   PattByte;                  /* byte in pattern                     */
    BYTE    PattBit;                   /* mask to pick up the right bit       */
    USHORT  i;
    BYTE    patbyte[5];
    BYTE    patshift;
    USHORT  patindex;


    /**************************************************************************/
    /*  PERFORMANCE : Split up function to allow for fast path for most common*/
    /*  case.                                                                 */
    /**************************************************************************/
    if ((PattWidth % 8) || (TargBpp != 1))
    {

        /**********************************************************************/
        /*  Clear Mask and RealPattern.                                       */
        /**********************************************************************/
        *pMask        = 0;
        *pRealPattern = 0;

        /**********************************************************************/
        /*  PD00508 : Here we go.  We have been asked for a 1,1 bitmap yet    */
        /*  the pattern that we're working with is actually a 4,1 pattern     */
        /*  (gee, thanks Aldus).  Anyway, we know that the resulting bitmap   */
        /*  is going to be a 4,1.  Now, if the pattern is a 4,1 bitmap and    */
        /*  a 1,1 bitmap was requested, we need to 'walk carefully and carry a*/
        /*  big stick...'.  We need to index through the pattern slightly     */
        /*  differently.                                                      */
        /**********************************************************************/
        if (PattMonBmapReq)
        {

            /******************************************************************/
            /*  4bpp, or non-bytelength pattern - use old method              */
            /******************************************************************/
            i = 8;
            while (i < 40)
            {

                /**************************************************************/
                /* Decrement i.                                               */
                /**************************************************************/
                i -= TargBpp;

                /**************************************************************/
                /* Check the bit in the pattern at position PattIndex.        */
                /**************************************************************/
                PattByte = PattStart + ((*pPattIndex) >> 1);
                PattBit  = (BYTE)0xf0 >> (((*pPattIndex) & 1) << 2);
                if (*PattByte & PattBit)
                {

                    /**********************************************************/
                    /* It is set. Use FgCol.                                  */
                    /**********************************************************/
                    *pMask |= (ULONG)0xf << i;
                    *pRealPattern |= ((ULONG)FgCol) << i;
                }
                else
                {

                    /**********************************************************/
                    /* It's not set. Use BgCol.                               */
                    /**********************************************************/
                    *pRealPattern |= ((ULONG)BgCol) << i;
                }

                /**************************************************************/
                /* If we've finished filling in one byte of the Dword, move   */
                /* on to the next.                                            */
                /**************************************************************/
                if (!(i % 8))
                {
                    i += 16;
                }

                /**************************************************************/
                /* Increment PattIndex.                                       */
                /**************************************************************/
                (*pPattIndex)++;
                if (*pPattIndex >= PattWidth)
                    *pPattIndex = 0;
            }
        }
        else
        {

            /******************************************************************/
            /*  4bpp, or non-bytelength pattern - use old method              */
            /******************************************************************/
            i = 8;
            while (i < 40)
            {

                /**************************************************************/
                /* Decrement i.                                               */
                /**************************************************************/
                i -= TargBpp;

                /**************************************************************/
                /* Check the bit in the pattern at position PattIndex.        */
                /**************************************************************/
                PattByte = PattStart + ((*pPattIndex) >> 3);
                PattBit  = (BYTE) 0x80 >> ((*pPattIndex) & 0x07);
                if (*PattByte & PattBit)
                {

                    /**********************************************************/
                    /* It is set. Use FgCol.                                  */
                    /**********************************************************/
                    if (TargBpp == 1)
                    {
                        *pMask |= (ULONG)0x1 << i;
                    }
                    else
                    {
                        *pMask |= (ULONG)0xf << i;
                    }
                    *pRealPattern |= ((ULONG)FgCol) << i;
                }
                else
                {

                    /**********************************************************/
                    /* It's not set. Use BgCol.                               */
                    /**********************************************************/
                    *pRealPattern |= ((ULONG)BgCol) << i;
                }

                /**************************************************************/
                /* If we've finished filling in one byte of the Dword, move   */
                /* on to the next.                                            */
                /**************************************************************/
                if (!(i % 8))
                {
                    i += 16;
                }

                /**************************************************************/
                /* Increment PattIndex.                                       */
                /**************************************************************/
                (*pPattIndex)++;
                if (*pPattIndex == PattWidth)
                    *pPattIndex = 0;
            }
        }
    }
    else
    {
        /**********************************************************************/
        /*  PERFORMANCE : Speed-ip for 1bpp, byte-aligned pattern (this case  */
        /*  will include the default pattern set).                            */
        /**********************************************************************/
        patindex = *pPattIndex;
        for (i = 0; i < 5; i++)
        {
            patbyte[i] = *(PattStart + (((i*8 + patindex) % PattWidth) >> 3));
        }
        patshift = ((BYTE)patindex) & 0x07; /* 0 to 7 shift                   */

        /**********************************************************************/
        /*  Now shift into 4 bytes and store in the mask...                   */
        /**********************************************************************/
        for (i = 0; i < 4; i++)
        {
            ((PBYTE)pMask)[i] = (BYTE)((0xff & (patbyte[i+1] >> (8-patshift))) |
                                       (0xff & (patbyte[i] << patshift)));
        }

        /**********************************************************************/
        /*  and into the pattern - depending on colors.                       */
        /**********************************************************************/
        switch ((FgCol << 1) | BgCol)
        {
            case 0  :

                /**************************************************************/
                /*  Fg = 0,Bg = 0 : clear                                     */
                /**************************************************************/
                *pRealPattern = 0L;
                break;
            case 1  :

                /**************************************************************/
                /*  Fg = 0, Bg = 1: invert                                    */
                /**************************************************************/
                *pRealPattern = ~(*pMask);
                break;

            case 2  :

                /**************************************************************/
                /*  Fg = 1, Bg = 0: leavealone                                */
                /**************************************************************/
                *pRealPattern = *pMask;
                break;

            case 3  :

                /**************************************************************/
                /*  Fg = 1, Bg = 1: set                                       */
                /**************************************************************/
                *pRealPattern = -1L;
                break;
            default :
                break;
        }

        /**********************************************************************/
        /*  Update PattIndex and then we are done.                            */
        /**********************************************************************/
        *pPattIndex = (patindex + 32) % PattWidth;
    }
    return;
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prds_InnerScanLine                                              */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  hanDC      DcH;                                                           */
/*  PSCANDATA  lpPSLS;                                                        */
/*  lpDCI      DCIData;                                                       */
/*  ULONG      FunN;                                                          */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function implements the non-fast path and (4,1) polyscan- line code. */
/******************************************************************************/
SHORT prds_InnerScanLine( hanDC      DcH,
                          PSCANDATA  lpPSLS,
                          lpDCI      DCIData,
                          BOOL       NoClipping,
                          ULONG      FunN)

{

    /**************************************************************************/
    /*  Local variables                                                       */
    /*                                                                        */
    /*  PERFORMANCE : Variables altered form ULONGS to USHORTS (or BYTES)     */
    /*  wherever possible.                                                    */
    /**************************************************************************/
    SHORT         Result;              /* result field                        */
    ULONG         Command;             /* Command part of FunN                */
    pBMListEntry  ListEntry;           /* Pointer to bitmap list entry        */
    DevPoint      CoordL;              /* Device coordinates of the           */
    DevPoint      CoordR;              /* left and right ends of each line to */
                                       /* fill                                */
    DevPoint      CpCoordL;            /* Clipped coordinates of the          */
    DevPoint      CpCoordR;            /* left and right ends of each line to */
                                       /* fill                                */
    BOOL          ClippedRight;        /* Flag determines whether a scanline  */
                                       /* has been clipped at  it's righthand */
                                       /* end                                 */
    PSHORTLINE    ShortLineL;          /* Pointer to the shortline which      */
                                       /* defines the left hand edge of the   */
                                       /* shape being filled                  */
    PSHORTLINE    ShortLineR;          /* Pointer to the shortline which      */
                                       /* defines the left hand edge of the   */
                                       /* shape being filled                  */
    SHORT         YInc;                /* The vertical increment of both      */
                                       /* shortlines                          */
    SHORT         NoOfXSteps;          /* The number of shortlines in each of */
                                       /* the current pair of polyshortlines  */
    DevRect       lcClipRect;          /* Clip rectangle being considered     */
    DevRect       lcBound;             /* Clip rectangle being considered     */
#if 0 /* CON3201 */
    PUSHORT       StepsL;              /* Pointer to the array of x positions */
                                       /* which make up the lefthand shortline*/
    PUSHORT       StepsR;              /* Pointer to the array of x positions */
                                       /* which make up the righthand         */
                                       /* shortline                           */
#endif
    PULONG        StepsL;              /* Pointer to the array of x positions */
                                       /* which make up the lefthand shortline*/
    PULONG        StepsR;              /* Pointer to the array of x positions */
                                       /* which make up the righthand         */
                                       /* shortline                           */
    PDAREABUNDLE  CurPtnAts;           /* current pattern attributes          */
    Vars          BB;                  /* for call to prds_GetPattern         */
    PBYTE         PattBitmap;          /* pattern                             */
    USHORT        PattWidth;
    USHORT        PattHeight;
    USHORT        PattBytesPerRow;
    USHORT        RealPattWidth;       /* PattWidth * TargBpp                 */
    DevPoint      PattOrigin;          /* pattern origin (local copy)         */
    PBYTE         TargBitmap;          /* target (= drawing surface)          */
    USHORT        TargBytesPerRow;
    USHORT        TargBpp;             /* bits per pel in target              */
    DevPoint      Start;               /* scanline start (inclusive)          */
    DevPoint      End;                 /* scanline end (exclusive)            */
    PULONG        CurrDword;           /* curr Dword in TargBitmap            */
    ULONG         RememberedDword;
    USHORT        LeftBitsToReplace;
    USHORT        BitsToDo;            /* in current scanline                 */
    PBYTE         PattStart;           /* start of current patt row           */
    USHORT        PattIndex;           /* index into current patt row         */
    ULONG         RealPattern;         /* Dword for mixing                    */
    ULONG         Mask;                /* Dword for mixing                    */
    ULONG         LeaveMask;           /* Dword for putting back bits to L    */
                                       /* and R of scanline                   */
    ULONG         RealPattArray[4];    /* stores values of RealPattern        */
    ULONG         MaskArray[4];        /* stores values of Mask               */
    USHORT        ArrayLength;         /* length of Mask & RealPattern arrays */
    ULONG         FgMixDword;          /* stores Fg mixed value               */
    ULONG         BgMixDword;          /* stores Bg mixed value               */
    BYTE          FgCol;               /* pattern fore colour                 */
    BYTE          BgCol;               /* pattern back colour                 */
    ULONG         Offset;
    USHORT        i, j;                /* Loop control variables              */
    BOOL          GreyScaling;         /* Grey scaling flag                   */
    RECTL         BoundsRectL;         /* Bounds for clipping processing      */
    BOOL          PattMonBmapReq;      /* Flag to indicate 1,1 bitmap request */

    /**************************************************************************/
    /*  PolyScanLines:                                                        */
    /*                                                                        */
    /*  Two polyshortlines (l and r) define the edges of the area and we can  */
    /*  they never cross and they start and end on the same lines.  The pels  */
    /*  which are defined to be on in this arrangement are all those from the */
    /*  first pel of the left hand shortline on every line to the last pel    */
    /*  before the right hand shortline.                                      */
    /*                                                                        */
    /*  So the shortlines:                                                    */
    /*                                                                        */
    /*    0     1        2    3  4  5  Steps in left hand shortline           */
    /*                                                                        */
    /*                           lll                      rrrr                */
    /*                        lll                    rrrrr                    */
    /*                   lllll                    rrr                         */
    /*          lllllllll                 rrrrrrrr                            */
    /*    llllll               rrrrrrrrrrr                                    */
    /*                                                                        */
    /*  Steps in right hand    0          1       2  3    4   5               */
    /*      shortline                                                         */
    /*                                                                        */
    /*  Produce:                                                              */
    /*                                                                        */
    /*                           XXXXXXXXXXXXXXXXXXXXXXXXX                    */
    /*                        XXXXXXXXXXXXXXXXXXXXXXX                         */
    /*                   XXXXXXXXXXXXXXXXXXXXXXXXX                            */
    /*          XXXXXXXXXXXXXXXXXXXXXXXXXX                                    */
    /*    XXXXXXXXXXXXXXXXXXXXX                                               */
    /*                                                                        */
    /*  From this you can see that the ith entry in the left and right hand   */
    /*  array defines the start point (inclusive) and the end point           */
    /*  (exclusive) of the ith scanline.                                      */
    /**************************************************************************/

    /**************************************************************************/
    /*  Set up pointer to pattern attribute bundle.                           */
    /**************************************************************************/
    CurPtnAts = DCIData->DCICurPtnAts;
    ListEntry = (pBMListEntry)DCIData->DCISelBitmap;

    /**************************************************************************/
    /*  Get hold of the target bitmap (the drawing surface).                  */
    /**************************************************************************/
    TargBitmap      = ListEntry->Bitmap;
    TargBpp         = (USHORT)ListEntry->Parms.Bitcount;
    TargBytesPerRow = (USHORT)ListEntry->Parms.BytesPerRow;

    /**************************************************************************/
    /*  Get hold of the pattern and check for grey scaling.                   */
    /**************************************************************************/
    BB.TargetDCI = DCIData;
    BB.TrgLE     = ListEntry;
    BB.ArgStyle  = 0;
    BB.Source    = NO_SOURCE;

    /**************************************************************************/
    /*  PD00337 : Must set result to OK because result is returned to the     */
    /*  system and a rc of 99 is unexpected.  It is okay to change this result*/
    /*  because prds_GetPattern will not return GS_FLAG if it is not ok.      */
    /**************************************************************************/
    Result = prds_GetPattern((Vars *)&BB);
    if (Result == GS_FLAG)
    {
        GreyScaling = TRUE;
        Result = OK;
    }
    else if (Result == ERROR_ZERO)
    {
        /**********************************************************************/
        /*  PD00801 : Didn't get a pattern, so return an error.               */
        /**********************************************************************/
        Result = GPI_ERROR;
        goto EXIT_FUNC;
    }
    else
    {
        GreyScaling = FALSE;
    }
    PattBitmap      = BB.PatBM;
    PattWidth       = (USHORT)BB.PatWidth;
    PattHeight      = (USHORT)BB.PatHeight;
    PattBytesPerRow = (USHORT)BB.PatBytesPerRow;
    PattMonBmapReq  = (BOOL)BB.PatMonBmapReq;

    /**************************************************************************/
    /*  Get the pattern fore and background colours.  These will be either 0  */
    /*  or 1 if we're b/w and a nibble if we're in colour.                    */
    /**************************************************************************/
    FgCol = BB.ConvPat1;
    BgCol = BB.ConvPat0;

    /**************************************************************************/
    /*  Get a local copy of the pattern origin, and adjust so that the        */
    /*  coordinates are negative - since we do calculations in ULONGs later,  */
    /*  we want to avoid getting a negative answer when subtracting the       */
    /*  pattern origin from a point in the target bitmap.                     */
    /*                                                                        */
    /*  BANDING : AK 22/5/91 adjust for DCOrigin                              */
    /**************************************************************************/
    PattOrigin.X = DCIData->DCIPattOriDev.X + ListEntry->XOrigin;
    PattOrigin.Y = DCIData->DCIPattOriDev.Y + ListEntry->YOrigin;

    if (PattOrigin.X > 0)
    {
        PattOrigin.X %= PattWidth;
        PattOrigin.X -= PattWidth;
    }

    if (PattOrigin.Y > 0)
    {
        PattOrigin.Y %= PattHeight;
        PattOrigin.Y -= PattHeight;
    }

    /**************************************************************************/
    /*  P500080 : If COM_PRECLIP has been set, then we don't need to do       */
    /*  any checking or looping through the clip rectangles.                  */
    /**************************************************************************/
    if (NoClipping)
    {
        /**********************************************************************/
        /*  Loop for each pair of polyscanlines                               */
        /**********************************************************************/
        for (ShortLineL = (PSHORTLINE)lpPSLS->pslFirstLeft,
             ShortLineR = (PSHORTLINE)lpPSLS->pslFirstRight;
             ShortLineL != FNULL | ShortLineR != FNULL;
             ShortLineL = (PSHORTLINE)ShortLineL->slh.pslhNext,
             ShortLineR = (PSHORTLINE)ShortLineR->slh.pslhNext)
        {
            /******************************************************************/
            /*  Set y coordinate for the left and right points of first       */
            /*  scanline.                                                     */
            /******************************************************************/
            CoordR.Y = ShortLineR->slh.ptlStart.y;
            CoordL.Y = CoordR.Y;

            /******************************************************************/
            /*  Initialize the control variables YInc and NoOfXSteps.  Both   */
            /*  lines will have the same Yinc and NoOfXSteps.  Ensure         */
            /*  NoOfXSteps is positive.  Note that the last step is ignored so*/
            /*  NoOfXSteps is simply the absolute of the difference between   */
            /*  the y start and y end (non-inclusive)                         */
            /******************************************************************/
            if ((NoOfXSteps = ShortLineR->slh.ptlStop.y - CoordR.Y) >= 0)
            {
                YInc = 1;
            }
            else
            {
                YInc = -1;
                NoOfXSteps = -NoOfXSteps;
            }

            /******************************************************************/
            /*  Steps points to a list of the x values which are inclusive of */
            /*  the start but exclusive of the end of the scanline.           */
            /******************************************************************/
            StepsR = (PULONG)ShortLineR->ax;
            StepsL = (PULONG)ShortLineL->ax;

            /******************************************************************/
            /*  Repeat for the difference in the start and end Y coords       */
            /******************************************************************/
            while (NoOfXSteps--)
            {

                /**************************************************************/
                /*  Get the right and left end points of each scan line if the*/
                /*  left is to the right of the right then there is nothing to*/
                /*  print                                                     */
                /**************************************************************/
                if ((CoordL.X = *StepsL++) >= (CoordR.X = *StepsR++))
                {
                    CoordR.Y += YInc;
                    CoordL.Y += YInc;
                    continue;
                }
                CpCoordL = CoordL;
                CpCoordR = CoordR;

                /**************************************************************/
                /*  We now have a particular scanline to do.  What we need to */
                /*  do is to find the corresponding place in the pattern, then*/
                /*  go along the scanline combining each pel with the pattern */
                /*  Fg colour and Fg mix if the corresponding pattern bit is  */
                /*  1, and combining a pel with the pattern Bg colour and Bg  */
                /*  mix if the pattern bit is 0.  The way we do this is as    */
                /*  follows:                                                  */
                /*                                                            */
                /*  Convert the scanline one Dword at a time (if only part of */
                /*  some Dword is in the scanline, we restore the bits in it  */
                /*  not in the scanline afterwards).  We define two Dwords, a */
                /*  RealPattern (with real colours in) and a Mask.  How we    */
                /*  define these depends on whether we're b/w or color.       */
                /*                                                            */
                /*  B/W:                                                      */
                /*                                                            */
                /*  Shift the pattern suitably to construct a Dword starting  */
                /*  at the right point.  This is the Mask.  The RealPattern   */
                /*  Dword is just the Mask but with 1 replaced by the FgColour*/
                /*  and 0 replaced by the BgColour.  There are 4 possibilities*/
                /*  for RealPattern: Mask, ~Mask, 0h, FFFFFFFFh.              */
                /*                                                            */
                /*  Color:                                                    */
                /*                                                            */
                /*  We've got to do some expanding.  Take the byte of pattern */
                /*  starting at the right place and expand it to RealPattern  */
                /*  by replacing 1 with the FgColour nibble and 0 with the    */
                /*  BgColour nibble.  Form the Mask from the pattern byte by  */
                /*  replacing a 1 with Fh and a 0 with 0h.  E.g.  if the      */
                /*  pattern byte in 01010011, the FgColour is 0010 and the    */
                /*  BgColour is 1001 then RealPattern is                      */
                /*                                                            */
                /*  10010010 10010010 10011001 00100010                       */
                /*                                                            */
                /*  and the Mask is                                           */
                /*                                                            */
                /*  00001111 00001111 00000000 11111111.                      */
                /*                                                            */
                /*  Use these as follows: where the mask is 1, use the FgMix  */
                /*  on the target and the RealPattern.  Where the mask is 0,  */
                /*  use the BgMix on the target and the RealPattern.  We do   */
                /*  this with 2 case statements, the first on FgMix and the   */
                /*  second on BgMix.                                          */
                /**************************************************************/

                /**************************************************************/
                /*  Set the start and end coords of the scanline to do.       */
                /*  Start.X is inclusive and End.X is exclusive.              */
                /**************************************************************/
                Start.X = CpCoordL.X;
                Start.Y = CpCoordL.Y;
                End.X   = CpCoordR.X;
                End.Y   = Start.Y;

                /**************************************************************/
                /*  BANDING : AK 5/21/91 adjust for DCOrigin                  */
                /**************************************************************/
                Start.X += ListEntry->XOrigin;
                Start.Y += ListEntry->YOrigin;
                End.X   += ListEntry->XOrigin;
                End.Y   += ListEntry->YOrigin;

                /**************************************************************/
                /*  Work out how many bits to do.  We count from the beginning*/
                /*  of the Dword in which Start.X occurs.  Note that 'Number &*/
                /*  ~31' gives the largest multiple of 32 that is <= Number.  */
                /**************************************************************/
                BitsToDo = (End.X * TargBpp) - ((Start.X * TargBpp) & ~31);

                /**************************************************************/
                /*  Deal with the pattern: work out what row we're using for  */
                /*  this scanline and the index of the first bit in that row  */
                /*  to use.                                                   */
                /*                                                            */
                /*  Get a pointer to the start of the correct row in the      */
                /*  pattern.                                                  */
                /**************************************************************/
                PattStart = PattBitmap +
                            ((Start.Y - PattOrigin.Y) % PattHeight) *
                            PattBytesPerRow;

                /**************************************************************/
                /*  Get the index (in bits) into the pattern row.             */
                /**************************************************************/
                if (TargBpp == 1)
                {

                    /**********************************************************/
                    /*  Start.X & ~31 gives the x-coordinate in the bitmap of */
                    /*  the start of the Dword in which Start.X occurs.       */
                    /**********************************************************/
                    PattIndex = (Start.X & ~31) - PattOrigin.X ;
                }
                else
                {

                    /**********************************************************/
                    /*  TargBpp == 4.                                         */
                    /*                                                        */
                    /*  Start.X & ~7 gives the x-coordinate in the bitmap of  */
                    /*  the start of the Dword in which Start.X occurs.       */
                    /**********************************************************/
                    PattIndex = (Start.X & ~7) - PattOrigin.X ;
                }

                /**************************************************************/
                /*  Get the index (in bits) into the pattern row.             */
                /**************************************************************/
                PattIndex %= PattWidth;

                /**************************************************************/
                /*  We use a fast path for the common cases.  The default     */
                /*  patterns have a width of 8, 16 or 32 depending on         */
                /*  resolution, so if we're at 1 bpp then the RealPattern and */
                /*  Mask Dwords will be unchanged throughout the scanline.  If*/
                /*  we're at 4 bpp then at the worst (pattern of width 32)    */
                /*  we'll have to go through 4 different RealPattern and Mask */
                /*  Dwords.  In this case calculate all these Dwords here.    */
                /**************************************************************/
                RealPattWidth = PattWidth * TargBpp;
                if (!(128 % RealPattWidth))
                {

                    /**********************************************************/
                    /*  Fast path.  Work out how many Dwords we need to use.  */
                    /**********************************************************/
                    ArrayLength = (min(RealPattWidth, BitsToDo) + 31) / 32;

                    /**********************************************************/
                    /*  Construct RealPattern and Mask.  PattIndex gets       */
                    /*  updated in GetPattDword.                              */
                    /**********************************************************/
                    for (i = 0; i < ArrayLength; i++)
                    {
                        prds_GetPattDword((PULONG)&MaskArray[i],
                                          (PULONG)&RealPattArray[i],
                                          (PUSHORT)&PattIndex, PattStart,
                                          PattWidth, PattMonBmapReq,
                                          TargBpp, FgCol, BgCol);
                    }

                    /**********************************************************/
                    /*  Set RealPattern and Mask to the first elements of     */
                    /*  these arrays; set the index into the arrays to 0.     */
                    /**********************************************************/
                    RealPattern = RealPattArray[0];
                    Mask = MaskArray[0];
                    i = 0;
                }
                else
                {

                    /**********************************************************/
                    /*  Not fast path.                                        */
                    /**********************************************************/
                    ArrayLength = 0;
                }

                /**************************************************************/
                /*  Get the first target Dword to do.                         */
                /*                                                            */
                /*  PERFORMANCE : While most everything else can be done in   */
                /*  USHORTS we require ULONG arithmetic here.                 */
                /**************************************************************/
                Offset = (((ULONG)Start.Y) * ((ULONG)TargBytesPerRow)) +
                          4L * (((ULONG)(Start.X * TargBpp)) / 32L);

                /**************************************************************/
                /*  Use Huge increment.  Note that TargBitmap is got via      */
                /*  SSALLOCSEG/Huge so it starts at the start of a segment.   */
              /****************************************************************
               * OLD CODE: CON3201 we are converting to 32bit model so no need*
               * for selectors  ---------------------------|                  *
               *                                           |                  *
               *OFFSETOF(CurrDword)   = OFFSETOF(Offset); \|/                                                           *
               *SELECTOROF(CurrDword) = SELECTOROF(TargBitmap) +              *
               *                        (SELECTOROF(Offset) * ListEntry->Huge);
               ****************************************************************/

              /****************************************************************/
              /* CON3201 - Add the Offset to the Pointer to the TargBitmap    */
              /*           to find the CurrDword to do                        */
              /****************************************************************/
                CurrDword = (PULONG)(TargBitmap + Offset);

                /**************************************************************/
                /*  Scanline to do might start in middle of this Dword -      */
                /*  record how many bits to leave alone.                      */
                /**************************************************************/
                LeftBitsToReplace = (Start.X * TargBpp) % 32;
                while (BitsToDo)
                {

                    /**********************************************************/
                    /*  Remember the target Dword we're about to change so    */
                    /*  that we can put back bits to L or R of the scanline.  */
                    /**********************************************************/
                    RememberedDword = *CurrDword;

                    /**********************************************************/
                    /*  If the Array is set (fast path) up then RealPattern   */
                    /*  and Mask are already set up.  If not do this now.     */
                    /**********************************************************/
                    if (ArrayLength == 0)
                    {
                        prds_GetPattDword((PULONG)&Mask, (PULONG)&RealPattern,
                                          (PUSHORT)&PattIndex, PattStart,
                                          PattWidth, PattMonBmapReq, TargBpp,
                                          FgCol, BgCol);
                    }

                    /**********************************************************/
                    /*  Work out the result of FgMix on CurrDword and         */
                    /*  RealPattern.                                          */
                    /**********************************************************/
                    switch (CurPtnAts->abnd.usMixMode)
                    {
                        case (USHORT)FM_OVERPAINT   :
                        case (USHORT)FM_DEFAULT     :
                            FgMixDword = RealPattern;
                            break;
                        case (USHORT)FM_AND         :
                            FgMixDword = *CurrDword & RealPattern;
                            break;
                        case (USHORT)FM_OR          :
                            FgMixDword = *CurrDword | RealPattern;
                            break;
                        case (USHORT)FM_ONE         :
                            FgMixDword = 0xFFFFFFFF;
                            break;
                        case (USHORT)FM_ZERO        :
                            FgMixDword = 0x0;
                            break;
                        case (USHORT)FM_SUBTRACT    :
                            FgMixDword = *CurrDword & ~RealPattern;
                            break;
                        case (USHORT)FM_XOR         :
                            FgMixDword = *CurrDword ^ RealPattern;
                            break;
                        case (USHORT)FM_INVERT      :
                            FgMixDword = ~*CurrDword;
                            break;
                        case (USHORT)FM_LEAVEALONE  :
                            FgMixDword = *CurrDword;
                            break;
                        case (USHORT)FM_NOTMERGESRC :
                            FgMixDword = ~(*CurrDword | RealPattern);
                            break;
                        case (USHORT)FM_NOTCOPYSRC  :
                            FgMixDword = ~RealPattern;
                            break;
                        case (USHORT)FM_MASKSRCNOT  :
                            FgMixDword = (~*CurrDword) & RealPattern;
                            break;
                        case (USHORT)FM_NOTMASKSRC  :
                            FgMixDword = ~(*CurrDword & RealPattern);
                            break;
                        case (USHORT)FM_NOTXORSRC   :
                            FgMixDword = ~(*CurrDword ^ RealPattern);
                            break;
                        case (USHORT)FM_MERGENOTSRC :
                            FgMixDword = *CurrDword | ~RealPattern;
                            break;
                        case (USHORT)FM_MERGESRCNOT :
                            FgMixDword = (~*CurrDword) | RealPattern;
                            break;
                        default                     :
                            FgMixDword = RealPattern;
                            break;
                    }

                    /**********************************************************/
                    /*  Work out the result of BgMix on CurrDword and         */
                    /*  RealPattern.                                          */
                    /**********************************************************/
                    switch (CurPtnAts->abnd.usBackMixMode)
                    {
                        case (USHORT)BM_LEAVEALONE :
                        case (USHORT)BM_DEFAULT    :
                            BgMixDword = *CurrDword;
                            break;
                        case (USHORT)BM_OVERPAINT  :
                            BgMixDword = RealPattern;
                            break;
                        case (USHORT)BM_OR         :
                            BgMixDword = *CurrDword | RealPattern;
                            break;
                        case (USHORT)BM_XOR        :
                            BgMixDword = *CurrDword ^ RealPattern;
                            break;
                        default                    :
                            BgMixDword = *CurrDword;
                            break;
                    }

                    /**********************************************************/
                    /*  Apply the mixes to CurrDword.  Note that the mix modes*/
                    /*  when we're grey scaling need to be the same for both  */
                    /*  foreground and background.                            */
                    /**********************************************************/
                    if (!GreyScaling)
                        *CurrDword = (Mask & FgMixDword) | (~Mask & BgMixDword);
                    else
                        *CurrDword = (Mask & FgMixDword) | (~Mask & FgMixDword);

                    /**********************************************************/
                    /*  We've finished changing the current Dword.  Replace   */
                    /*  bits to L or R of current scanline.                   */
                    /**********************************************************/
                    if (LeftBitsToReplace)
                    {
                        LeaveMask = prds_GetMask(LeftBitsToReplace);
                        *CurrDword = (*CurrDword & LeaveMask) |
                                     (RememberedDword & ~LeaveMask);
                        LeftBitsToReplace = 0;
                    }
                    if (BitsToDo <= 32)
                    {
                        LeaveMask = prds_GetMask(BitsToDo);
                        *CurrDword = (*CurrDword & ~LeaveMask) |
                                     (RememberedDword & LeaveMask);
                        BitsToDo = 0;
                    }
                    else
                    {

                        /******************************************************/
                        /*  There is another Dword to do.  Note that in       */
                        /*  incrementing CurrDword by 1 we move it along by 4 */
                        /*  bytes.                                            */
                        /******************************************************/
                        BitsToDo -= 32;
                        CurrDword++;

                      /********************************************************
                       * * CON3201 - Converting to 32bit no selectors or HUGE *
                       *                                                      *
                       *if (!OFFSETOF(CurrDword))                             *
                       *{                                                     *
                       *                                                      *
                       *     **************************************************
                       *     *  Cross huge boundary.                          *
                       *     **************************************************
                       *    SELECTOROF(CurrDword)+= ListEntry->Huge - 1;      *
                       *}                                                     *
                       ********************************************************/

                        /******************************************************/
                        /*  If the array was set up, then move to the next    */
                        /*  elements.  Note that if ArrayLength is 1 then we  */
                        /*  don't need to do anything.                        */
                        /******************************************************/
                        if (ArrayLength > 1)
                        {
                            i += 1;
                            if (i == ArrayLength)
                                i = 0;
                            RealPattern = RealPattArray[i];
                            Mask = MaskArray[i];
                        }
                    }
                }

                /**************************************************************/
                /*  move to next row using YInc                               */
                /**************************************************************/
                CoordR.Y += YInc;
                CoordL.Y += YInc;
            }
        }
    }
    else
    {
        /**************************************************************************/
        /*  Get the bounding clip rectangle of the whole drawing area (plus a     */
        /*  little extra).                                                        */
        /*                                                                        */
        /*  P500080: set up lcBound here instead of in the loop.  Will save       */
        /*  a few clock cycles.                                                   */
        /**************************************************************************/
        BoundsRectL.xLeft   = lpPSLS->rclBound.xLeft;
        lcBound[0].X = (SHORT)lpPSLS->rclBound.xLeft;      /* P500080             */

        BoundsRectL.yBottom = lpPSLS->rclBound.yBottom;
        lcBound[0].Y = (SHORT)lpPSLS->rclBound.yBottom;    /* P500080             */

        BoundsRectL.xRight  = lpPSLS->rclBound.xRight + 2; /* PD00308...          */
        lcBound[1].X = (SHORT)lpPSLS->rclBound.xRight + 2; /* P500080             */

        BoundsRectL.yTop    = lpPSLS->rclBound.yTop   + 2; /* PD00308...          */
        lcBound[1].Y = (SHORT)lpPSLS->rclBound.yTop   + 2; /* P500080             */


        /**************************************************************************/
        /*  Loop through each clip rectangle.  This loop exits when prdi_         */
        /*  GetNextClip returns FALSE                                             */
        /**************************************************************************/
        for (j = 1; prdi_GetNextClip(DCIData, j++, (DevRect *)lcClipRect,
                                     &BoundsRectL); )
        {
            /**********************************************************************/
            /*  Maybe do a bounding check here as well, because we cannot         */
            /*  guarantee that the bounds were used and it does not cost us much. */
            /*  Shouldn't be difficult, but may not be necessary.                 */
            /**********************************************************************/
            if (OK != prdi_ClipIntSect((DevRect *)lcClipRect,
                                       (DevRect *)lcBound))
            {
                /******************************************************************/
                /*  No intersection of any of the scanlines so go to the next clip*/
                /*  rectangle.                                                    */
                /******************************************************************/
                continue;
            }

            /**********************************************************************/
            /*  Loop for each pair of polyscanlines                               */
            /**********************************************************************/
            for (ShortLineL = (PSHORTLINE)lpPSLS->pslFirstLeft,
                 ShortLineR = (PSHORTLINE)lpPSLS->pslFirstRight;
                 ShortLineL != FNULL | ShortLineR != FNULL;
                 ShortLineL = (PSHORTLINE)ShortLineL->slh.pslhNext,
                 ShortLineR = (PSHORTLINE)ShortLineR->slh.pslhNext)
            {

                /******************************************************************/
                /*  Set y coordinate for the left and right points of first       */
                /*  scanline.                                                     */
                /******************************************************************/
                CoordR.Y = ShortLineR->slh.ptlStart.y;
                CoordL.Y = CoordR.Y;

                /******************************************************************/
                /*  Initialize the control variables YInc and NoOfXSteps.  Both   */
                /*  lines will have the same Yinc and NoOfXSteps.  Ensure         */
                /*  NoOfXSteps is positive.  Note that the last step is ignored so*/
                /*  NoOfXSteps is simply the absolute of the difference between   */
                /*  the y start and y end (non-inclusive)                         */
                /******************************************************************/
                if ((NoOfXSteps = ShortLineR->slh.ptlStop.y - CoordR.Y) >= 0)
                {
                    YInc = 1;
                }
                else
                {
                    YInc = -1;
                    NoOfXSteps = -NoOfXSteps;
                }

                /******************************************************************/
                /*  Steps points to a list of the x values which are inclusive of */
                /*  the start but exclusive of the end of the scanline.           */
                /******************************************************************/
                StepsR = (PULONG)ShortLineR->ax;
                StepsL = (PULONG)ShortLineL->ax;

                /******************************************************************/
                /*  Repeat for the difference in the start and end Y coords       */
                /******************************************************************/
                while (NoOfXSteps--)
                {

                    /**************************************************************/
                    /*  Get the right and left end points of each scan line if the*/
                    /*  left is to the right of the right then there is nothing to*/
                    /*  print                                                     */
                    /**************************************************************/
                    if ((CoordL.X = *StepsL++) >= (CoordR.X = *StepsR++))
                    {
                        CoordR.Y += YInc;
                        CoordL.Y += YInc;
                        continue;
                    }
                    CpCoordL = CoordL;
                    CpCoordR = CoordR;

                    /**************************************************************/
                    /*  PERFORMANCE : As this point we are clipping the rectangle */
                    /*  which we need to fill with the pattern to the current clip*/
                    /*  rectangle.  In fact the fill rectangle is a line whose y  */
                    /*  coords are the same and whose x coords are ordered to go  */
                    /*  left->right.  Hence we can use a simple clipping algorithm*/
                    /*  as below - there is no need t' use no fancy clipping      */
                    /*  function like prdi_ClipLine which does far more work than */
                    /*  necessary.                                                */
                    /**************************************************************/

                    /**********************************************************/
                    /*  Check for the case of no intersection.                    */
                    /**********************************************************/
                    if ((CpCoordL.X >= lcClipRect[1].X) ||
                        (CpCoordR.X <= lcClipRect[0].X) ||
                        (CpCoordL.Y >= lcClipRect[1].Y) ||
                        (CpCoordL.Y <  lcClipRect[0].Y)) /* NB: no =          */
                    {
                        CoordR.Y += YInc;
                        CoordL.Y += YInc;
                        continue;
                    }

                    /**********************************************************/
                    /*  Only need to clip the x coords.                           */
                    /**********************************************************/
                    if (lcClipRect[0].X > CpCoordL.X)
                        CpCoordL.X = lcClipRect[0].X;

                    if (lcClipRect[1].X < CpCoordR.X)
                        CpCoordR.X = lcClipRect[1].X - 1;

                    /**************************************************************/
                    /*  Part of line lies in clip rectangle - start and end have  */
                    /*  been updated with the coordinates of this clipped line.   */
                    /*                                                            */
                    /*  If the scanline has been clipped at the right hand end    */
                    /*  then we must set ClippedRight so we know the last x       */
                    /*  coordinate of the scanline is inclusive.                  */
                    /**************************************************************/
                    ClippedRight = (CpCoordR.X != CoordR.X);

                    /**************************************************************/
                    /*  We now have a particular scanline to do.  What we need to */
                    /*  do is to find the corresponding place in the pattern, then*/
                    /*  go along the scanline combining each pel with the pattern */
                    /*  Fg colour and Fg mix if the corresponding pattern bit is  */
                    /*  1, and combining a pel with the pattern Bg colour and Bg  */
                    /*  mix if the pattern bit is 0.  The way we do this is as    */
                    /*  follows:                                                  */
                    /*                                                            */
                    /*  Convert the scanline one Dword at a time (if only part of */
                    /*  some Dword is in the scanline, we restore the bits in it  */
                    /*  not in the scanline afterwards).  We define two Dwords, a */
                    /*  RealPattern (with real colours in) and a Mask.  How we    */
                    /*  define these depends on whether we're b/w or color.       */
                    /*                                                            */
                    /*  B/W:                                                      */
                    /*                                                            */
                    /*  Shift the pattern suitably to construct a Dword starting  */
                    /*  at the right point.  This is the Mask.  The RealPattern   */
                    /*  Dword is just the Mask but with 1 replaced by the FgColour*/
                    /*  and 0 replaced by the BgColour.  There are 4 possibilities*/
                    /*  for RealPattern: Mask, ~Mask, 0h, FFFFFFFFh.              */
                    /*                                                            */
                    /*  Color:                                                    */
                    /*                                                            */
                    /*  We've got to do some expanding.  Take the byte of pattern */
                    /*  starting at the right place and expand it to RealPattern  */
                    /*  by replacing 1 with the FgColour nibble and 0 with the    */
                    /*  BgColour nibble.  Form the Mask from the pattern byte by  */
                    /*  replacing a 1 with Fh and a 0 with 0h.  E.g.  if the      */
                    /*  pattern byte in 01010011, the FgColour is 0010 and the    */
                    /*  BgColour is 1001 then RealPattern is                      */
                    /*                                                            */
                    /*  10010010 10010010 10011001 00100010                       */
                    /*                                                            */
                    /*  and the Mask is                                           */
                    /*                                                            */
                    /*  00001111 00001111 00000000 11111111.                      */
                    /*                                                            */
                    /*  Use these as follows: where the mask is 1, use the FgMix  */
                    /*  on the target and the RealPattern.  Where the mask is 0,  */
                    /*  use the BgMix on the target and the RealPattern.  We do   */
                    /*  this with 2 case statements, the first on FgMix and the   */
                    /*  second on BgMix.                                          */
                    /**************************************************************/

                    /**************************************************************/
                    /*  Set the start and end coords of the scanline to do.       */
                    /*  Start.X is inclusive and End.X is exclusive.              */
                    /**************************************************************/
                    Start.X = CpCoordL.X;
                    Start.Y = CpCoordL.Y;
                    End.X   = (CpCoordR.X + ClippedRight);
                    End.Y   = Start.Y;

                    /**************************************************************/
                    /*  BANDING : AK 5/21/91 adjust for DCOrigin                  */
                    /**************************************************************/
                    Start.X += ListEntry->XOrigin;
                    Start.Y += ListEntry->YOrigin;
                    End.X   += ListEntry->XOrigin;
                    End.Y   += ListEntry->YOrigin;

                    /**************************************************************/
                    /*  Work out how many bits to do.  We count from the beginning*/
                    /*  of the Dword in which Start.X occurs.  Note that 'Number &*/
                    /*  ~31' gives the largest multiple of 32 that is <= Number.  */
                    /**************************************************************/
                    BitsToDo = (End.X * TargBpp) - ((Start.X * TargBpp) & ~31);

                    /**************************************************************/
                    /*  Deal with the pattern: work out what row we're using for  */
                    /*  this scanline and the index of the first bit in that row  */
                    /*  to use.                                                   */
                    /*                                                            */
                    /*  Get a pointer to the start of the correct row in the      */
                    /*  pattern.                                                  */
                    /**************************************************************/
                    PattStart = PattBitmap +
                                ((Start.Y - PattOrigin.Y) % PattHeight) *
                                PattBytesPerRow;

                    /**************************************************************/
                    /*  Get the index (in bits) into the pattern row.             */
                    /**************************************************************/
                    if (TargBpp == 1)
                    {

                        /**********************************************************/
                        /*  Start.X & ~31 gives the x-coordinate in the bitmap of */
                        /*  the start of the Dword in which Start.X occurs.       */
                        /**********************************************************/
                        PattIndex = (Start.X & ~31) - PattOrigin.X ;
                    }
                    else
                    {

                        /**********************************************************/
                        /*  TargBpp == 4.                                         */
                        /*                                                        */
                        /*  Start.X & ~7 gives the x-coordinate in the bitmap of  */
                        /*  the start of the Dword in which Start.X occurs.       */
                        /**********************************************************/
                        PattIndex = (Start.X & ~7) - PattOrigin.X ;
                    }

                    /**************************************************************/
                    /*  Get the index (in bits) into the pattern row.             */
                    /**************************************************************/
                    PattIndex %= PattWidth;

                    /**************************************************************/
                    /*  We use a fast path for the common cases.  The default     */
                    /*  patterns have a width of 8, 16 or 32 depending on         */
                    /*  resolution, so if we're at 1 bpp then the RealPattern and */
                    /*  Mask Dwords will be unchanged throughout the scanline.  If*/
                    /*  we're at 4 bpp then at the worst (pattern of width 32)    */
                    /*  we'll have to go through 4 different RealPattern and Mask */
                    /*  Dwords.  In this case calculate all these Dwords here.    */
                    /**************************************************************/
                    RealPattWidth = PattWidth * TargBpp;
                    if (!(128 % RealPattWidth))
                    {

                        /**********************************************************/
                        /*  Fast path.  Work out how many Dwords we need to use.  */
                        /**********************************************************/
                        ArrayLength = (min(RealPattWidth, BitsToDo) + 31) / 32;

                        /**********************************************************/
                        /*  Construct RealPattern and Mask.  PattIndex gets       */
                        /*  updated in GetPattDword.                              */
                        /**********************************************************/
                        for (i = 0; i < ArrayLength; i++)
                        {
                            prds_GetPattDword((PULONG)&MaskArray[i],
                                              (PULONG)&RealPattArray[i],
                                              (PUSHORT)&PattIndex, PattStart,
                                              PattWidth, PattMonBmapReq,
                                              TargBpp, FgCol, BgCol);
                        }

                        /**********************************************************/
                        /*  Set RealPattern and Mask to the first elements of     */
                        /*  these arrays; set the index into the arrays to 0.     */
                        /**********************************************************/
                        RealPattern = RealPattArray[0];
                        Mask = MaskArray[0];
                        i = 0;
                    }
                    else
                    {

                        /**********************************************************/
                        /*  Not fast path.                                        */
                        /**********************************************************/
                        ArrayLength = 0;
                    }

                    /**************************************************************/
                    /*  Get the first target Dword to do.                         */
                    /*                                                            */
                    /*  PERFORMANCE : While most everything else can be done in   */
                    /*  USHORTS we require ULONG arithmetic here.                 */
                    /**************************************************************/
                    Offset = (((ULONG)Start.Y) * ((ULONG)TargBytesPerRow)) +
                              4L * (((ULONG)(Start.X * TargBpp)) / 32L);

                 /*************************************************************/
                 /* CON3201 - Convert to 32bits no selectors                  */
                 /**************************************************************/
                 /*  Use Huge increment.  Note that TargBitmap is got via      */
                 /*  SSALLOCSEG/Huge so it starts at the start of a segment.   */
                 /**************************************************************/
                 /* OLD CODE - CON3201                                         */
                 /* OFFSETOF(CurrDword)   = OFFSETOF(Offset);
                  * SELECTOROF(CurrDword) = SELECTOROF(TargBitmap) +
                  *                         (SELECTOROF(Offset) * ListEntry->Huge);
                  *************************************************************/

                     /*********************************************************/
                     /* CON3201 - Add the Offset to TargBitmap to get the     */
                     /*           CurrDword to do                             */
                     /*********************************************************/
                    CurrDword = (PULONG)(TargBitmap + Offset);

                    /**************************************************************/
                    /*  Scanline to do might start in middle of this Dword -      */
                    /*  record how many bits to leave alone.                      */
                    /**************************************************************/
                    LeftBitsToReplace = (Start.X * TargBpp) % 32;
                    while (BitsToDo)
                    {

                        /**********************************************************/
                        /*  Remember the target Dword we're about to change so    */
                        /*  that we can put back bits to L or R of the scanline.  */
                        /**********************************************************/
                        RememberedDword = *CurrDword;

                        /**********************************************************/
                        /*  If the Array is set (fast path) up then RealPattern   */
                        /*  and Mask are already set up.  If not do this now.     */
                        /**********************************************************/
                        if (ArrayLength == 0)
                        {
                            prds_GetPattDword((PULONG)&Mask, (PULONG)&RealPattern,
                                              (PUSHORT)&PattIndex, PattStart,
                                              PattWidth, PattMonBmapReq, TargBpp,
                                              FgCol, BgCol);
                        }

                        /**********************************************************/
                        /*  Work out the result of FgMix on CurrDword and         */
                        /*  RealPattern.                                          */
                        /**********************************************************/
                        switch (CurPtnAts->abnd.usMixMode)
                        {
                            case (USHORT)FM_OVERPAINT   :
                            case (USHORT)FM_DEFAULT     :
                                FgMixDword = RealPattern;
                                break;
                            case (USHORT)FM_AND         :
                                FgMixDword = *CurrDword & RealPattern;
                                break;
                            case (USHORT)FM_OR          :
                                FgMixDword = *CurrDword | RealPattern;
                                break;
                            case (USHORT)FM_ONE         :
                                FgMixDword = 0xFFFFFFFF;
                                break;
                            case (USHORT)FM_ZERO        :
                                FgMixDword = 0x0;
                                break;
                            case (USHORT)FM_SUBTRACT    :
                                FgMixDword = *CurrDword & ~RealPattern;
                                break;
                            case (USHORT)FM_XOR         :
                                FgMixDword = *CurrDword ^ RealPattern;
                                break;
                            case (USHORT)FM_INVERT      :
                                FgMixDword = ~*CurrDword;
                                break;
                            case (USHORT)FM_LEAVEALONE  :
                                FgMixDword = *CurrDword;
                                break;
                            case (USHORT)FM_NOTMERGESRC :
                                FgMixDword = ~(*CurrDword | RealPattern);
                                break;
                            case (USHORT)FM_NOTCOPYSRC  :
                                FgMixDword = ~RealPattern;
                                break;
                            case (USHORT)FM_MASKSRCNOT  :
                                FgMixDword = (~*CurrDword) & RealPattern;
                                break;
                            case (USHORT)FM_NOTMASKSRC  :
                                FgMixDword = ~(*CurrDword & RealPattern);
                                break;
                            case (USHORT)FM_NOTXORSRC   :
                                FgMixDword = ~(*CurrDword ^ RealPattern);
                                break;
                            case (USHORT)FM_MERGENOTSRC :
                                FgMixDword = *CurrDword | ~RealPattern;
                                break;
                            case (USHORT)FM_MERGESRCNOT :
                                FgMixDword = (~*CurrDword) | RealPattern;
                                break;
                            default                     :
                                FgMixDword = RealPattern;
                                break;
                        }

                        /**********************************************************/
                        /*  Work out the result of BgMix on CurrDword and         */
                        /*  RealPattern.                                          */
                        /**********************************************************/
                        switch (CurPtnAts->abnd.usBackMixMode)
                        {
                            case (USHORT)BM_LEAVEALONE :
                            case (USHORT)BM_DEFAULT    :
                                BgMixDword = *CurrDword;
                                break;
                            case (USHORT)BM_OVERPAINT  :
                                BgMixDword = RealPattern;
                                break;
                            case (USHORT)BM_OR         :
                                BgMixDword = *CurrDword | RealPattern;
                                break;
                            case (USHORT)BM_XOR        :
                                BgMixDword = *CurrDword ^ RealPattern;
                                break;
                            default                    :
                                BgMixDword = *CurrDword;
                                break;
                        }

                        /**********************************************************/
                        /*  Apply the mixes to CurrDword.  Note that the mix modes*/
                        /*  when we're grey scaling need to be the same for both  */
                        /*  foreground and background.                            */
                        /**********************************************************/
                        if (!GreyScaling)
                            *CurrDword = (Mask & FgMixDword) | (~Mask & BgMixDword);
                        else
                            *CurrDword = (Mask & FgMixDword) | (~Mask & FgMixDword);

                        /**********************************************************/
                        /*  We've finished changing the current Dword.  Replace   */
                        /*  bits to L or R of current scanline.                   */
                        /**********************************************************/
                        if (LeftBitsToReplace)
                        {
                            LeaveMask = prds_GetMask(LeftBitsToReplace);
                            *CurrDword = (*CurrDword & LeaveMask) |
                                         (RememberedDword & ~LeaveMask);
                            LeftBitsToReplace = 0;
                        }
                        if (BitsToDo <= 32)
                        {
                            LeaveMask = prds_GetMask(BitsToDo);
                            *CurrDword = (*CurrDword & ~LeaveMask) |
                                         (RememberedDword & LeaveMask);
                            BitsToDo = 0;
                        }
                        else
                        {

                            /******************************************************/
                            /*  There is another Dword to do.  Note that in       */
                            /*  incrementing CurrDword by 1 we move it along by 4 */
                            /*  bytes.                                            */
                            /******************************************************/

                            BitsToDo -= 32;
                            CurrDword++;

                          /****************************************************
                           *   CON3201 - Convert to 32bit no need to worry    *
                           *             about selector                       *
                           *if (!OFFSETOF(CurrDword))                         *
                           *{                                                 *
                           *                                                  *
                           *     **************************************************
                           *     *  Cross huge boundary.                          *
                           *     **************************************************
                           *    SELECTOROF(CurrDword)+= ListEntry->Huge - 1;  *
                           *}                                                 *
                           ****************************************************/


                            /******************************************************/
                            /*  If the array was set up, then move to the next    */
                            /*  elements.  Note that if ArrayLength is 1 then we  */
                            /*  don't need to do anything.                        */
                            /******************************************************/
                            if (ArrayLength > 1)
                            {
                                i += 1;
                                if (i == ArrayLength)
                                    i = 0;
                                RealPattern = RealPattArray[i];
                                Mask = MaskArray[i];
                            }
                        }
                    }

                    /**************************************************************/
                    /*  move to next row using YInc                               */
                    /**************************************************************/
                    CoordR.Y += YInc;
                    CoordL.Y += YInc;
                }
            }
        }
    }

    /**************************************************************************/
    /*  PERF1 : And finished.                                                 */
    /**************************************************************************/

EXIT_FUNC:

    /**************************************************************************/
    /* PD00820 : Removed call to prdm_LeaveDriver                             */
    /**************************************************************************/

#ifdef PRD_TIMING

    /**************************************************************************/
    /*  Exit the PolyScanLine function.                                       */
    /**************************************************************************/
    DEKHOOK0(A, 9, 87)

#endif

    return(Result);
}
#undef TFUNC
