/*DDK*************************************************************************/
/*                                                                           */
/* 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.                                */
/*                                                                           */
/*****************************************************************************/
/****************************************************************************/
/*                                                                          */
/*   FILE: STRETCH.C                                                        */
/*                                                                          */
/*   DESCRIPTION: External functions used to perform image stretching for   */
/*                BitBlt calls.                                             */
/*                                                                          */
/*   FUNCTIONS: IsValidStretchRequest                                       */
/*              StretchInitialize                                           */
/*              StretchCopyChunkToPhunk                                     */
/*                                                                          */
/*   LOCAL ROUTINES: SourceMajorDessimate                                   */
/*                   DestinationMajorReplicate                              */
/*                                                                          */
/*                   Stretch1BppScanlineIGNORE                              */
/*                   Stretch1BppScanlineOR                                  */
/*                   Stretch1BppScanlineAND                                 */
/*                                                                          */
/*                   Stretch8BppScanlineIGNORE                              */
/*                   Stretch16BppScanlineIGNORE                             */
/*                                                                          */
/*   REFERENCE:                                                             */
/*                                                                          */
/*                                                                          */
/*   CHANGE HISTORY:                                                        */
/*                                                                          */
/*          21May93 <KJE, GAM> Creation                                     */
/*                                                                          */
/* DEFECT RELEASE FLAG     COMMENTS                                         */
/* ------ ------- -------  -------------------------------------------------*/
/* @001 r206 930823 Change  Modified IsValidStretchRequest because it was   */
/*                  Team    using pdc rather than pdcArg.(Defect 72883 - BZ)*/
/*           931222 CT      Put the above fix back in (Defect 76753) - JN   */
/*                                                                          */
/* 76965              The strectblt code does not handle palette changes or */
/*                    non-trivial transformations properly so send it back  */
/*                    to the engine for execution.                          */
/*                                                                          */
/* @002 r206 930823 Change  Modified IsValidStretchRequest and StretchCopy- */
/*                  Team    ChunkToPhunk to compute the ratio difference    */
/*                          between the Source and Destination from the     */
/*                          HW scaled extents. (Defect 77274) - BZ          */
/*                                                                          */
/* 81815     940502 Change  Remove @002 above.  It caused a regression      */
/*                  Team    where the display driver would sometimes trap   */
/*                          when stretch blting part of a bitmap.           */
/*                                                                          */
/* 83099     940712 Change  Modified IsValidStretchRequest to scale the     */
/*                  Team    phunk properly.                                 */
/*                                                                          */
/* 086248 r207    @BJT001  Back out 76753(72883) because it caused 86248.   */
/*                         72883 will be re-tested and re-opened if needed  */
/*                                                                          */
/****************************************************************************/

#define INCL_DDICOMFLAGS
#define INCL_DOSMEMMGR
#define INCL_DDIMISC
#define INCL_GRE_BITMAPS
#include <eddinclt.h>

#include <eddbcone.h>
#include <eddecone.h>
#include <eddicone.h>
#include <eddhcone.h>
#include <eddmcone.h>

#include <eddbtypt.h>
#include <edddtypt.h>
#include <eddhtype.h>

#include <eddbextf.h>
#include <eddcextf.h>
#include <eddgextf.h>
#include <eddaextf.h>
#include <eddmextf.h>
#include <eddhextf.h>
#include <eddmextf.h>
#ifdef DCAF                                                             //DCAF
#include <dcafextf.h>                                                   //DCAF
#endif                                                                  //DCAF

#include <eddhmacr.h>

#include <eddfcone.h>
#include <eddftype.h>

#include <cursor.h>
#include <hwaccess.h>
#include <memman.h>
#ifdef VRAMPTR
#include <eddncach.h>
#endif /* VRAMPTR */

/****************************************************************************/
/* Include definitions for XGA display driver stretch function definitions  */
/* and prototypes.                                                          */
/****************************************************************************/
#include <strchext.h>

/****************************************************************************/
/* Global variables                                                         */
/****************************************************************************/
extern PPFNL               EnginesDispatchTable;
extern BITBLTPB            AIxfer;
extern USHORT              usHorPixelVector[];
extern BitmapHeader        DirectListEntry;

extern BYTE                bSrcMaskLeftOR[];     /* Masks for extracting    */
extern BYTE                bSrcMaskRightOR[];    /* 1bpp pixels during      */
extern BYTE                bSrcMaskLeftAND[];    /* dessimation with OR     */
extern BYTE                bSrcMaskRightAND[];   /* or AND option.          */

/****************************************************************************/
/* Internal routines                                                        */
/****************************************************************************/
VOID NEAR Stretch1BppScanlineIGNORE(USHORT usSrcY,
                                    USHORT usDstY,
                                    USHORT usSrcXStart,
                                    SHORT  sPhunkXLast);

VOID NEAR Stretch1BppScanlineOR    (USHORT usSrcY,
                                    USHORT usDstY,
                                    USHORT usSrcXStart,
                                    SHORT  sPhunkXLast);

VOID NEAR Stretch1BppScanlineAND   (USHORT usSrcY,
                                    USHORT usDstY,
                                    USHORT usSrcXStart,
                                    SHORT  sPhunkXLast);

VOID NEAR Stretch8BppScanlineIGNORE(USHORT usSrcY,
                                    USHORT usDstY,
                                    USHORT usSrcXStart,
                                    SHORT  sPhunkXLast);

VOID NEAR Stretch16BppScanlineIGNORE(USHORT usSrcY,
                                     USHORT usDstY,
                                     USHORT usSrcXStart,
                                     SHORT  sPhunkXLast);

/*  */
/*****************************************************************************

   Diagram showing how the stretched (replicated/dessimated) scanline is
   derived from the source bitmap scanline and placed into the relative
   destination bitmap scanline:


                            (SOURCE SCAN LINE)
                               Bitmap Width
                                    ³
  ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿

  ÃÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄoÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄoÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ´

      Source      ³                                    ³     Source
    Bottom-Left   ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ   Top-Right
   (ArgCoords[4]) /                 ³                  \ (ArgCoords[6])
                 /         Source Bitmap Width          \
                /                                        \
               /                                          \
              /                                            \
             /                                              \
            /                                                \
           /                                                  \
          /           Replication/Dessimation Vector           \
         ÚÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄ¿
         ³i ³i ³i ³i ³i ³i ³.................................³i ³
         ³ 0³ 1³ 2³ 3³ 4³ 5³                                 ³ N³
         ÀÄÄÁÄÄÁÄÄÁÄÄÁÄÄÁÄÄÁÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÁÄÄÙ
         ³            AIxfer.horizontalPixelVector[]            ³
         ³                                                      ³

  ÃÄÄÄÄÄÄoÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄoÄÄÄÄÄÄ´

         0ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄthroughÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄN (Pixels)

         ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
       Target                       ³                         Target
     Bottom-Left           Target Bitmap Width              Top-Right
    (ArgCoords[0])                                       (ArgCoords[2])

  ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÂÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ
                                    ³
                         Destination BitmapWidth
                         (DESTINATION SCAN LINE)

******************************************************************************/
/*  */

/*****************************************************************************/
/* FUNCTION                                                                  */
/*****************************************************************************/
VOID DestinationMajorReplicate (ULONG ArgCoords[])
{
   LONG     horizontalRemainder;
   ULONG    currentPixelIndex;
   USHORT   horizontalPixelVectorIndex;

   /**************************************************************************/
   /* Initialize ourselves before we replicate.                              */
   /**************************************************************************/
   horizontalRemainder = AIxfer.usXErrorTerm;
   horizontalPixelVectorIndex = 0;
   currentPixelIndex = ArgCoords[4];

   /**************************************************************************/
   /* Fill out an entry in the Pixel Vector that corresponds to each pixel   */
   /* in the destination bitmap up until the last pixel in the destination   */
   /* delimited by the X Extent of the Destination.                          */
   /**************************************************************************/
   while (horizontalPixelVectorIndex <= AIxfer.usDstXExt)
   {
      /***********************************************************************/
      /* While the remainder is above zero, replicate the current source     */
      /* pixel index in the Pixel Vector (scaling up).                       */
      /***********************************************************************/
      while (horizontalRemainder > 0)
      {
         /********************************************************************/
         /* Let's do that replicate thang.                                   */
         /********************************************************************/
         AIxfer.horizontalPixelVector [horizontalPixelVectorIndex] =
            (USHORT) currentPixelIndex;

         /********************************************************************/
         /* Subtract the X Source Extent to determine if we are through      */
         /* replicating the current pixel for the destination bitmap.        */
         /********************************************************************/
         horizontalRemainder -= AIxfer.usSrcXExt;

         /********************************************************************/
         /* Go to the next Pixel Vector entry.                               */
         /********************************************************************/
         horizontalPixelVectorIndex++;

      } /* while */

      /***********************************************************************/
      /* Go to the next source pixel to be replicated.                       */
      /***********************************************************************/
      currentPixelIndex++;

      /***********************************************************************/
      /* Add in the larger X extent (Destination in this case) to account    */
      /* for the mathimatical compensation in replication for extra pixels   */
      /* when going from a source to a destination size that are not even    */
      /* multiples of each other.                                            */
      /***********************************************************************/
      horizontalRemainder += AIxfer.usDstXExt;

   } /* while */

} /* DestinationMajorReplicate */

/*****************************************************************************/
/* FUNCTION                                                                  */
/*****************************************************************************/
VOID SourceMajorDessimate (ULONG ArgCoords[])
{
   LONG     horizontalRemainder;
   ULONG    currentPixelIndex;
   USHORT   horizontalPixelVectorIndex;


   /**************************************************************************/
   /* Initialize ourselves before we replicate.                              */
   /**************************************************************************/
   horizontalRemainder = AIxfer.usXErrorTerm;
   horizontalPixelVectorIndex = 0;
   currentPixelIndex = ArgCoords[4];

   /**************************************************************************/
   /* Fill out an entry in the Pixel Vector that corresponds to each pixel   */
   /* in the destination bitmap up until the last pixel in the destination   */
   /* delimited by the X Extent of the Destination.                          */
   /**************************************************************************/
   while (horizontalPixelVectorIndex <= AIxfer.usDstXExt)
   {
      /***********************************************************************/
      /* We got the next pixel index that we want to appear in the scaled    */
      /* down destination bitmap, so save that dessimated pixel index away.  */
      /***********************************************************************/
      AIxfer.horizontalPixelVector [horizontalPixelVectorIndex] =
         (USHORT) currentPixelIndex;

      /***********************************************************************/
      /* While the remainder is above zero, skip over the current source     */
      /* pixel index (scaling down).                                         */
      /***********************************************************************/
      while (horizontalRemainder > 0)
      {
         horizontalRemainder -= AIxfer.usDstXExt;
         currentPixelIndex++;

      } /* while */

      /***********************************************************************/
      /* Go to the next Pixel Vector entry.                                  */
      /***********************************************************************/
      horizontalPixelVectorIndex++;

      /***********************************************************************/
      /* Add in the larger X extent (Source in this case) to account         */
      /* for the mathimatical compensation in replication for extra pixels   */
      /* when going from a source to a destination size that are not even    */
      /* multiples of each other.                                            */
      /***********************************************************************/
      horizontalRemainder += AIxfer.usSrcXExt;

   } /* while */

} /* SourceMajorDessimate */

/*****************************************************************************/
/* FUNCTION                                                                  */
/*****************************************************************************/
ULONG IsValidStretchRequest (HDC hdc,
    LHANDLE ArgSource,
    PLONG   ArgCoords,
    ULONG   ArgRop,
    ULONG   ArgOptions,
    PDC     *pdcSrc,
    RECTS   *SrcRect,
    PDC     pdcArg,
    ULONG   FunN
)
{
    ULONG            returnCode;
    ULONG            SrcIsMemory;
    ULONG            DstIsMemory;
    pBitmapHeader    tempPbmhSrc;
    PDC              tempPdcSrc;

    LONG             usSrcXExt;
    LONG             usSrcYExt;
    LONG             usDstXExt;
    LONG             usDstYExt;

    /*************************************************************************/
    /* Assume execution of this function is in error by setting return code. */
    /* This return code will be set in to indicate success should this       */
    /* function complete execution with no problems.                         */
    /*************************************************************************/
    returnCode = RC_ERROR;

    /*************************************************************************/
    /* If the BitBlt() request is for a raster op that can not be done by    */
    /* the XGA coprocessor, than the request must be rejected.               */
    /*************************************************************************/
    if (!(ArgRop == ROP_SRCCOPY)     &&
        !(ArgRop == ROP_NOTSRCERASE) &&
        !(ArgRop == ROP_NOTSRCCOPY)  &&
        !(ArgRop == ROP_SRCINVERT)   &&
        !(ArgRop == ROP_SRCAND)      &&
        !(ArgRop == ROP_MERGEPAINT)  &&
        !(ArgRop == ROP_SRCPAINT)    &&
        !(ArgRop == ROP_SRCERASE))
    {
       returnCode = RC_UNSUPPORTED_ROP;
       goto STRETCH_REQUEST_INVALID;

    } /* if */

    /*************************************************************************/
    /* If Background mix is BM_SRCTRANSPARENT or BM_DESTTRANSPARENT, then    */
    /* we can not handle the stretch.                                        */
    /*************************************************************************/
    if ((pdcArg->DCICurImgAts.ibnd.usBackMixMode == BM_SRCTRANSPARENT) ||
        (pdcArg->DCICurImgAts.ibnd.usBackMixMode == BM_DESTTRANSPARENT))
    {
       returnCode = RC_TRANSPARENT_BLT;
       goto STRETCH_REQUEST_INVALID;

    } /* if */

    /*************************************************************************/
    /* The options parameter has a bit indicating if the source parameter    */
    /* is a bitmap handle or dc handle.                                      */
    /*************************************************************************/
    if (ArgOptions & BLTMODE_SRC_BITMAP)
    {
        /*********************************************************************/
        /* The source is a bitmap handle. Use Get Driver Info to get the     */
        /* driver magic cookie (a pointer to the bitmap header) associated   */
        /* with this handle.                                                 */
        /*********************************************************************/
        if ( ((tempPbmhSrc) =
              (pBitmapHeader)GetDriverInfo32(ArgSource, DI_HBITMAP, hdc)) ==
                (pBitmapHeader)ERROR_NEG)
        {
            returnCode = RC_GETDRIVERINFO_FAILS;
            goto STRETCH_REQUEST_INVALID;

        } /* if */

        /*********************************************************************/
        /* Calculate the bottom left x coordinate and the top right y        */
        /* coordinate the other two coordinates can be calculated later      */
        /* using these values and the target coordinates.                    */
        /*                                                                   */
        /* These values will be scaled later on to account for the           */
        /* stretching that will occur to the source to derive the            */
        /* destination.                                                      */
        /*********************************************************************/
        SrcRect->pts1.x = (USHORT)ArgCoords[4];
        SrcRect->pts2.y = (USHORT)(tempPbmhSrc->Info.HWHeight - ArgCoords[5]);

#ifdef PALETTE_MGR

        /*********************************************************************/
        /* Set pdcSrc to NULL so that we can pass it to                      */
        /* eddb_CreatePalMapping() so that it knows there is no source DC.   */
        /*********************************************************************/
        *pdcSrc = FNULL;

#endif /* PALETTE_MGR */

    } /* if */
    else
    {
        /*********************************************************************/
        /* The source is a DC handle. Use GetDriverInfo32 to get the driver  */
        /* magic cookie (a pointer to the DC instance data) associated with  */
        /* this handle.                                                      */
        /*********************************************************************/
        if ((tempPdcSrc =
            (PDC)GetDriverInfo32(ArgSource, DI_HDC, hdc)) == (PDC)ERROR_NEG)
        {
            returnCode = RC_GETDRIVERINFO_FAILS;
            goto STRETCH_REQUEST_INVALID;

        } /* if */

        /*********************************************************************/
        /* Set pdcSrc pointer that was passed in by caller to the value      */
        /* that was passed back from the GetDriverInfo() call made above.    */
        /*********************************************************************/
        *pdcSrc = tempPdcSrc;

        /*********************************************************************/
        /* The source must have a currently selected bitmap from which the   */
        /* image to be blitted is taken.                                     */
        /*********************************************************************/
        if (tempPdcSrc->DCIBitmapType == BITMAP_NOT_SELECTED)
        {
            returnCode = RC_BITMAP_NOT_SELECTED;
            goto STRETCH_REQUEST_INVALID;

        } /* if */

        /*********************************************************************/
        /* Setup the local temporary source bitmap field to point to the     */
        /* bitmap data associated with the DC provided.                      */
        /*********************************************************************/
        tempPbmhSrc = tempPdcSrc->DCISelListEntry;

        /*********************************************************************/
        /* Calculate the bottom left x coordinate and the top right y        */
        /* coordinate the other two coordinates can be calculated later      */
        /* using these values and the target coordinates.                    */
        /*********************************************************************/

        /*********************************************************************/
        /* Having to support the COM_TRANSFORM bit here is a new requirement */
        /* which occured due to the flood fill algorithm in the engine.      */
        /*                                                                   */
        /* This code for when the transform bit is set works, but this is    */
        /* not really documented, so be aware that this may need further     */
        /* work.                                                             */
        /*                                                                   */
        /* These values will be scaled later on to account for the           */
        /* stretching that will occur to the source to derive the            */
        /* destination.                                                      */
        /*********************************************************************/
        if ( FunNTest(COM_TRANSFORM) )
        {
            /*****************************************************************/
            /* The source coordinates are relative to the DC origin, convert */
            /* them.                                                         */
            /*****************************************************************/
            SrcRect->pts1.x = (USHORT) (tempPdcSrc->DCIOrigin.X + ArgCoords[4]);

            SrcRect->pts2.y =
               (USHORT) (tempPdcSrc->DCIConvFactor - ArgCoords[5]);

        } /* if */
        else
        {
            /*****************************************************************/
            /* The source coordinates are not relative to the DC, simply     */
            /* flip the Y coordinate.                                        */
            /*****************************************************************/
            SrcRect->pts1.x = (USHORT) ArgCoords[4];
            SrcRect->pts2.y = (USHORT)
                      (tempPdcSrc->DCISelListEntry->Info.HWHeight - ArgCoords[5]);

        } /* else */
    } /* else */

    /*************************************************************************/
    /* Determine if the Source is from Memory and the Destination is to      */
    /* Screen. If either is false, then we do not do the stretch thang.      */
    /*************************************************************************/
    /*************************************************************************/
    /* Check the source first.                                               */
    /*************************************************************************/
    if (ArgOptions & BLTMODE_SRC_BITMAP)
    {
        /*********************************************************************/
        /* Check the bitmap header information to determine if it is from    */
        /* the screen or from memory.                                        */
        /*********************************************************************/
        if (tempPbmhSrc == &DirectListEntry)
        {
           SrcIsMemory = FALSE;

        } /* if */
        /*********************************************************************/
        /* Else, the Source is a Bitmap from memory.                         */
        /*********************************************************************/
        else
        {
           SrcIsMemory = TRUE;

        } /* else */

    } /* if */
    /*************************************************************************/
    /* Else, we have a DC, so check the DC information structure to          */
    /* determine if we are dealing with an image in Memory or on the Screen. */
    /*************************************************************************/
    else
    {
        if (tempPdcSrc->DCIDCType == OD_DIRECT)
        {
           SrcIsMemory = FALSE;
           returnCode = RC_SRC_NOT_MEM;
           goto STRETCH_REQUEST_INVALID;

        } /* if */
        else
        {

           SrcIsMemory = TRUE;

        } /* else */

    } /* else */

    /*************************************************************************/
    /* Check the destination image type next.                                */
    /*************************************************************************/
    if ((pdc != NULL) && (pdc->DCIDCType == OD_DIRECT))     /* @001 @BJT001 */
    {
       DstIsMemory = FALSE;

    } /* if */
    else
    {

       DstIsMemory = TRUE;
       returnCode = RC_DST_NOT_SCREEN;
       goto STRETCH_REQUEST_INVALID;

    } /* else */

    /*
    **            The strectblt code does not handle palette changes or
    ** non-trivial transformations properly so send it back to the
    ** engine for execution.
    */

    if( pdcArg && (ArgOptions & BBO_TARGWORLD) && !pdcArg->DCIXFrmSimple )  /*            */
    {                                                                       /*            */
      returnCode = RC_UNSUPPORTED_OPTION;                                   /*            */
      goto STRETCH_REQUEST_INVALID;                                         /*            */
    }                                                                       /*            */
                                                                            /*            */
    if( pdcArg && pdcArg->DCIColFormat == LCOLF_PALETTE )                   /*            */
    {                                                                       /*            */
       returnCode = RC_UNSUPPORTED_OPTION;                                  /*            */
       goto STRETCH_REQUEST_INVALID;                                        /*            */
    }                                                                       /*            */

    /*************************************************************************/
    /* Verify that both the source bitmap format BPP and destination bitmap  */
    /* format BPP are the formats that we can handle for the stretch         */
    /* operation.                                                            */
    /*************************************************************************/
    if ((tempPbmhSrc->Info.BitCount != 1) &&
        (tempPbmhSrc->Info.BitCount != 8) &&
        (tempPbmhSrc->Info.BitCount != 16))
    {
       returnCode = RC_SRC_WRONG_BITCOUNT;
       goto STRETCH_REQUEST_INVALID;

    } /* if */

    if ((pdcArg->DCISelListEntry->Info.BitCount != 1) &&
        (pdcArg->DCISelListEntry->Info.BitCount != 8) &&
        (pdcArg->DCISelListEntry->Info.BitCount != 16))

    {
       returnCode = RC_DST_WRONG_BITCOUNT;
       goto STRETCH_REQUEST_INVALID;

    } /* if */

    /*************************************************************************/
    /* The BBO_OR and BBO_AND are meaningful only in 1BPP. If requested for  */
    /* color bitmaps, send the request back to the engine.                   */
    /*************************************************************************/
    if (!(ArgOptions & BBO_IGNORE) &&
        ((tempPbmhSrc->Info.BitCount == 8) ||
         (tempPbmhSrc->Info.BitCount == 16)))
    {
       returnCode = RC_UNSUPPORTED_OPTION;
       goto STRETCH_REQUEST_INVALID;

    } /* if */

    /*************************************************************************/
    /* Calculate source and destination extents and place them into local    */
    /* variables for use later on. Additionally, check and see if any of     */
    /* the extents are zero; if so, then there is no stretching to be done,  */
    /* therefore exit indicating that we can not support the stretch         */
    /* request.                                                              */
    /*************************************************************************/
    usSrcXExt = (USHORT) (ArgCoords[6] - ArgCoords[4]);
    usSrcYExt = (USHORT) (ArgCoords[7] - ArgCoords[5]);

    usDstXExt = (USHORT) (ArgCoords[2] - ArgCoords[0]);
    usDstYExt = (USHORT) (ArgCoords[3] - ArgCoords[1]);

    /*************************************************************************/
    /* Return from this function indicating that the stretch can not be      */
    /* supported for a zero extent source and/or destination in either the   */
    /* X or Y extents.                                                       */
    /*************************************************************************/
    if ( (usSrcXExt == 0) ||
         (usSrcYExt == 0) ||
         (usDstXExt == 0) ||
         (usDstYExt == 0) )
    {

       returnCode = RC_SRC_OR_DST_EXT_IS_ZERO;
       goto STRETCH_REQUEST_INVALID;

    } /* if */

    /*=======================================================================*/
    /*                        VALID STRETCH REQUEST                          */
    /*=======================================================================*/
    /* At this point in the code we have the proper conditions to do our     */
    /* own internal stretch. So, calculate the proper data values that are   */
    /* needed for the internal stretch functions and set the global data     */
    /* structures that will be used later by the stretch functions in this   */
    /* driver.                                                               */
    /*=======================================================================*/
    /*=======================================================================*/

    /*************************************************************************/
    /* Get exclusive access to the driver now that we know that we are       */
    /* difinitely going to do stretching. At this point in the code we       */
    /* need to initialize the fields of the global AIxfer buffer to the      */
    /* proper values for stretching. It is because of this need to set the   */
    /* AIxfer data area we need to execute EnterDriver so as to lock access  */
    /* to the global data area of AIxfer and usHorPixelVector.               */
    /*************************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD);

    /*************************************************************************/
    /* Setup the AI Global data stucture source bitmap field to point to     */
    /* bitmap header field calculated above and set in the temporary         */
    /* bitmap header field.                                                  */
    /*************************************************************************/
     AIxfer.pbmhSrc = tempPbmhSrc;

    /*************************************************************************/
    /* Set the address of the pixel vector that will be used to determine    */
    /* which pixels to replicate or dessimate.                               */
    /*************************************************************************/
    AIxfer.horizontalPixelVector = &usHorPixelVector[0];

    /*************************************************************************/
    /* Set the source and destination extents in the AIxfer buffer based on  */
    /* the values calculated previously from the ArgCoords array passed in   */
    /* by the Graphics Engine on the bitblt request.                         */
    /*************************************************************************/
    AIxfer.usSrcXExt = usSrcXExt;
    AIxfer.usSrcYExt = usSrcYExt;

    AIxfer.usDstXExt = usDstXExt;
    AIxfer.usDstYExt = usDstYExt;

    /*************************************************************************/
    /* Scale the source origin values that will be used by the BitBlt        */
    /* routines later so as to reflect the "stretched" source metrics.       */
    /*************************************************************************/

    SrcRect->pts1.x = (SrcRect->pts1.x * AIxfer.usDstXExt) / AIxfer.usSrcXExt;

    /*************************************************************************/
    /* Defect 83099                                                          */
    /* If the source parameter is a bitmap handle, the value previously      */
    /* placed into SrcRect->pts2.y has been scaled to the hardware height by */
    /* subtracting one.  This should not be done until after the following   */
    /* calculation has been completed.                                       */
    /*************************************************************************/
    if (ArgOptions & BLTMODE_SRC_BITMAP)
    {
       SrcRect->pts2.y =
           (((SrcRect->pts2.y + 1) * AIxfer.usDstYExt) / AIxfer.usSrcYExt) - 1;
    }
    else
    {
       SrcRect->pts2.y =
           (SrcRect->pts2.y * AIxfer.usDstYExt) / AIxfer.usSrcYExt;
    }

    /*************************************************************************/
    /* Save the source origin away for use by the stretch functions later    */
    /* on.                                                                   */
    /*************************************************************************/
    AIxfer.ptsStretchSrcOrig.x = SrcRect->pts1.x;
    AIxfer.ptsStretchSrcOrig.y = SrcRect->pts2.y;

    /*************************************************************************/
    /* Calculate Error Terms for Expanding OR Shrinking based on type of     */
    /* stretching to be done (Expand/Shrink).                                */
    /*************************************************************************/

    /*************************************************************************/
    /* Calculate X direction errorterm.                                      */
    /*************************************************************************/
    if (AIxfer.usSrcXExt > AIxfer.usDstXExt)
    {
       AIxfer.usXErrorTerm = (USHORT)
                               (AIxfer.usSrcXExt - (AIxfer.usDstXExt / 2));

    } /* if */
    else
    {
       AIxfer.usXErrorTerm = (USHORT)
                               (AIxfer.usDstXExt - (AIxfer.usSrcXExt / 2));
    } /* else */

    /*************************************************************************/
    /* Calculate Y direction errorterm.                                      */
    /*************************************************************************/
    if (AIxfer.usSrcYExt > AIxfer.usDstYExt)
    {
       AIxfer.usYErrorTerm = (USHORT)
                                      (AIxfer.usSrcYExt - (AIxfer.usDstYExt / 2));

    } /* if */
    else
    {
       AIxfer.usYErrorTerm = (USHORT)
                                      (AIxfer.usDstYExt - (AIxfer.usSrcYExt / 2));
    } /* else */

    /*************************************************************************/
    /* Now that we have determined the original source bitmap data structure */
    /* we must replace it with a "fake" bitmap header that reflects how the  */
    /* source bitmap will appear after it is stretched to fit the            */
    /* destination bitmap. The "original" source bitmap pointer will be      */
    /* saved in the global AIxfer data structure field for use later by the  */
    /* stretch functions in order to obtain the source bitmap image data     */
    /* that will be either replicated OR dessimated to the destination image */
    /* bitmap.                                                               */
    /*************************************************************************/

    /*************************************************************************/
    /* Save the "real McCoy" away for use later.                             */
    /*************************************************************************/
    AIxfer.pbmhRealStretchSrc = AIxfer.pbmhSrc;

    /*************************************************************************/
    /* Point the source bitmap pointer to the "dummy" bitmap header that is  */
    /* contained within the same AIxfer structure. This pbmhSrc pointer is   */
    /* the bitmap that the rest of the Display Driver code will use to       */
    /* perform the BitBlt() funtion; by overriding the bitmap here, we       */
    /* simplify the implementation of stretch in this driver, whereby we can */
    /* depend upon the same code as before to convert and blit the image to  */
    /* the destination.                                                      */
    /*************************************************************************/
    AIxfer.pbmhSrc = &(AIxfer.bmhStretchSrc);

    /*************************************************************************/
    /* Set the source destination bitmap fields to the proper settings to    */
    /* reflect the final stretched attributes of the source image.           */
    /*************************************************************************/
    AIxfer.pbmhSrc->Bitmap = NULL;
    AIxfer.pbmhSrc->BMPhys = NULL;
    AIxfer.pbmhSrc->BMSize = 0;

    /*************************************************************************/
    /* Calculate the stretched source width based on the scaling factor      */
    /* inferred by the Source and Destination widths calculated beforehand.  */
    /*************************************************************************/
    AIxfer.pbmhSrc->Info.Width =
       (AIxfer.pbmhRealStretchSrc->Info.Width * AIxfer.usDstXExt) /
       AIxfer.usSrcXExt;

    /*************************************************************************/
    /* Calculate the stretched destination width based on the scaling factor */
    /* inferred by the Source and Destination widths calculated beforehand.  */
    /*************************************************************************/
    AIxfer.pbmhSrc->Info.Height =
       (AIxfer.pbmhRealStretchSrc->Info.Height * AIxfer.usDstYExt) /
       AIxfer.usSrcYExt;

    AIxfer.pbmhSrc->Info.BitCount = AIxfer.pbmhRealStretchSrc->Info.BitCount;
    AIxfer.pbmhSrc->Info.HWWidth = AIxfer.pbmhSrc->Info.Width - (SHORT)1;
    AIxfer.pbmhSrc->Info.HWHeight = AIxfer.pbmhSrc->Info.Height - (SHORT)1;
    AIxfer.pbmhSrc->Info.HWFormat = AIxfer.pbmhRealStretchSrc->Info.HWFormat;

    AIxfer.pbmhSrc->DCHandle = NULL;
    AIxfer.pbmhSrc->BytesPerLine = 0;

    /*************************************************************************/
    /* Set the Cached Bitmap information to indicate the same state of the   */
    /* real bitmap.                                                          */
    /*************************************************************************/
    AIxfer.pbmhSrc->bm_cache_slot = AIxfer.pbmhRealStretchSrc->bm_cache_slot;

    AIxfer.pbmhSrc->MarkerInfo.MarginWidth = 0;
    AIxfer.pbmhSrc->MarkerInfo.MarginHeight = 0;

    /*************************************************************************/
    /* Now call the appropriate routine that will create the vector used     */
    /* to address the source bitmap image data to create the destination     */
    /* bitmap image. The determination as to which function is called is     */
    /* made pending upon the fact that we are either expanding the source    */
    /* image OR shrinking it in the X direction.                             */
    /*************************************************************************/
    if (AIxfer.usSrcXExt > AIxfer.usDstXExt)
    {
       SourceMajorDessimate (ArgCoords);

    } /* if */
    else
    {
       DestinationMajorReplicate (ArgCoords);

    } /* else */

    /*************************************************************************/
    /* Set AIxfer global flag to indicate we are stretching.                 */
    /*************************************************************************/
    AIxfer.fStretching = TRUE;

    /*************************************************************************/
    /* Pass the BitBlt options parameter so that StretchCopyChunkToPhunk     */
    /* can distinguish the IGNORE, OR, and AND cases.                        */
    /*************************************************************************/
    AIxfer.ArgOptions = ArgOptions;

    /*************************************************************************/
    /* Return to the caller, indicating that all went well and that we can   */
    /* do the stretch thang.                                                 */
    /*************************************************************************/
    returnCode = RC_OK;

/*****************************************************************************/
/* Label to allow return with proper return code error condition set         */
/* beforehand.                                                               */
/*****************************************************************************/
STRETCH_REQUEST_INVALID:

    return (returnCode);


} /* IsValidStretchRequest */


/****************************************************************************/
/****************************************************************************/
/*                                                                          */
/* FUNCTION: StretchCopyChunkToPhunk                                        */
/*                                                                          */
/* DESCRIPTION: Copies a rectangle from the original, unstretched source    */
/*              bitmap into the Phunk. As the rectangle is being copied, it */
/*              is stretched in both the X and Y dimension based on the     */
/*              relative dimensions of the source bitmap and the phunk      */
/*              bitmap. Stretching consists of deleting lines or pixels in  */
/*              the case of shrinking (compressing) or replicating lines or */
/*              pixels in the case of expanding.                            */
/*                                                                          */
/*              The input variables consist of the following:               */
/*                                                                          */
/*           1. "stretched" source bitmap (Only the bitmap header exists    */
/*                                         for this. BitBlt does clipping   */
/*              ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿           using the "stretched" source     */
/*              ³     ÚÄÄÄÄ¿   ³           coordinates and specifies the    */
/*              ³     ³    ³   ³           specific rectangle as point p1.) */
/*              ³   p1ÀÄÄÄÄÙ   ³                                            */
/*              ³              ³                                            */
/*              ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ           p1 = ptsChunkPos                 */
/*                                                                          */
/*                                                                          */
/*           2. Original, unstretched source bitmap (The rectangle inside   */
/*                                         this bitmap contains the pixels  */
/*              ÚÄÄÄÄÄÄÄÄÄÄÄÄ¿             that are to be stretched into    */
/*              ³    ÚÄÄ¿    ³             the Phunk. It's lower left corner*/
/*              ³    ³  ³    ³             will be defined by the value p1  */
/*              ³    ³  ³    ³             after conversion to unstretched  */
/*              ³    ³  ³    ³             coordinates.)                    */
/*              ³    ÀÄÄÙ    ³                                              */
/*              ³            ³                                              */
/*              ³            ³             Org Source = pbmhRealStretchSrc  */
/*              ³            ³                                              */
/*              ÀÄÄÄÄÄÄÄÄÄÄÄÄÙ                                              */
/*                                                                          */
/*                                                                          */
/*           3. Phunk                     (A bitmap header describes this   */
/*                                         64K system storage area with the */
/*            p2ÚÄÄÄÄ¿                     appropriate dimensions to hold   */
/*              ³    ³                     the rectangular chunk.)          */
/*              ÃÄÄÄÄ´p3                                                    */
/*              ÀÄÄÄÄÙ                     phunk = AIxfer.pbmhSrc           */
/*                                                                          */
/*                                         p2,p3 = AIxfer.rcsSrc            */
/*                                                                          */
/****************************************************************************/
/****************************************************************************/
VOID StretchCopyChunkToPhunk (POINTS ptsChunkPos) /* Lower-left corner of   */
                                                  /* chunk to stretch in    */
                                                  /* stretched source bitmap*/
{

USHORT             usSrcXStart;        /* First pixel to get from src line  */
USHORT             usSrcYCurr;         /* Current line in unstretched source*/

SHORT              sPhunkXLast;        /* Last pixel in a Phunk scanline    */
USHORT             usPhunkYCurr;       /* Current line in Phunk destination */
USHORT             usPhunkYLast;       /* Last line to stretch into Phunk   */

LONG               lTempYError;        /* Local copy of Y error term        */

VOID        (NEAR *StretchScanline)(USHORT, USHORT, USHORT, SHORT);
                                  /* Specific entry point (1bpp, 8bpp, etc.)*/


/****************************************************************************/
/* Setup address of appropriate scanline copy routine based on bits/pixel,  */
/* whether expanding or dessimating in X dimension, and user's option on    */
/* how to handle source pixels being deleted (IGNORE, OR, or AND).          */
/****************************************************************************/


   switch (AIxfer.pbmhSrc -> Info.BitCount)
   {
      case 1:
         if ((AIxfer.usSrcXExt <= AIxfer.usDstXExt) ||
             (AIxfer.ArgOptions & BBO_IGNORE))
            {
            StretchScanline = Stretch1BppScanlineIGNORE;
            }
         else
            {
            if (AIxfer.ArgOptions & BBO_AND)
               StretchScanline = Stretch1BppScanlineAND;
            else
               StretchScanline = Stretch1BppScanlineOR;
            }
         break;

      case 8:
         StretchScanline = Stretch8BppScanlineIGNORE;
         break;


      case 16:
         StretchScanline = Stretch16BppScanlineIGNORE;
         break;

      /**********************************************************************/
      /* The below case should not happen, however if it does, make sure    */
      /* the subroutine address is at least initialized.                    */
      /**********************************************************************/
      default:

         StretchScanline = Stretch1BppScanlineIGNORE;

   } /* switch */


/****************************************************************************/
/* Initialize variables:                                                    */
/* We will be working from TOP to BOTTOM here.                              */
/* Note that the original source bitmap uses PM coordinates (0,0 at bottom  */
/* left with Y dimension increasing upward).                                */
/* The source rectangle is specified in ptsChunkPos through its bottom left */
/* coordinates (size is taken to be the same as the phunk destination). The */
/* Y coordinate is adjusted to be the top of the rectangle and both X and Y */
/* are scaled from the "stretched" source back to the original, unstretched */
/* bitmap using the ratios of the source to destination extents.            */
/****************************************************************************/

   sPhunkXLast  = AIxfer.rcsSrc.pts2.x;         /* Pts2 is lower right      */
                                                /* Pts1 is always (0,0)     */
   usPhunkYLast = AIxfer.rcsSrc.pts2.y;

   usSrcYCurr   = ptsChunkPos.y;           /* ptsChunkPos is TL in AI coords*/

   usSrcYCurr   =  (usSrcYCurr * AIxfer.usSrcYExt) / AIxfer.usDstYExt;
                             /* Now scale line number from stretched coords */
                             /* back to unstretched coords                  */

   usSrcXStart  = ptsChunkPos.x - AIxfer.ptsStretchSrcOrig.x;
                 /* Map starting coord (stretched space) to index in vector*/

   lTempYError = AIxfer.usYErrorTerm;          /* MajYExt - 1/2 MinYExt    */

/****************************************************************************/
/* Need to be sure that the XGA hardware is idle before we start to use the */
/* Phunk, or else we may overlay data that it is currently using.           */
/****************************************************************************/

   WaitForRealHWFunction();

/****************************************************************************/
/* Now loop through the unstretched source scanlines and copy them line     */
/* by line to the Phunk. Two separate loops are used because of slight      */
/* differences in loop control between the expanding and shrinking cases.   */
/* In the 'expand' case, source lines are simply replicated in the          */
/* destination based on the ratio of the source and destination extents.    */
/* In the 'shrinking' case, the ratio of the source to destination extents  */
/* is used to determine how many source lines to skip after copying a       */
/* source line to the destination.                                          */
/****************************************************************************/
   if (AIxfer.usDstYExt < AIxfer.usSrcYExt)   /* Shrinking in Y dimension   */
   {
      for (usPhunkYCurr = 0;                  /* Always start at top        */
           usPhunkYCurr <= usPhunkYLast;      /* Loop for each dst line     */
           usPhunkYCurr++)
      {
         (*StretchScanline)(usSrcYCurr,  usPhunkYCurr,     /* Stretch 1 line*/
                            usSrcXStart, sPhunkXLast);
         usSrcYCurr++;
         lTempYError -= AIxfer.usDstYExt;

         /*******************************************************************/
         /* Now skip over source lines: This is done by subtracting the     */
         /* destination extent from the error term until the error term     */
         /* goes negative.                                                  */
         /* If the interviening lines are to be thrown away (BBO_IGNORE)    */
         /* then all that needs to be done is increment the source line     */
         /* count. For the BBO_OR and BBO_AND options, the scanline function*/
         /* must be called to merge these lines into the destination.       */
         /*******************************************************************/
         for ( ;                              /* Now see if there are lines */
               lTempYError >= 0;              /* to be dessimated           */
               lTempYError -= AIxfer.usDstYExt)
         {
            if (!AIxfer.ArgOptions & BBO_IGNORE)
            {
               (*StretchScanline)(usSrcYCurr,  usPhunkYCurr,/* Stretch 1 line*/
                                  usSrcXStart, (SHORT)(-sPhunkXLast));
                               /* Negative last parm is flag to merge pixels */
            }
            usSrcYCurr++;

         } /* for */

         lTempYError += AIxfer.usSrcYExt;    /* Adj error term for next    */
                                              /* source line run            */
      } /* for */

   } /* if */

   else /* Must be expanding in Y dimension                                 */
   {
      for (usPhunkYCurr = 0;                  /* Always start at 0          */
           usPhunkYCurr <= usPhunkYLast;      /* Loop once for each dst line*/
           usPhunkYCurr++)
      {
         (*StretchScanline)(usSrcYCurr,  usPhunkYCurr,     /* Stretch 1 line*/
                            usSrcXStart, sPhunkXLast);

         lTempYError -= AIxfer.usSrcYExt;

         if (lTempYError < 0)                 /* Repeat current source line */
         {                                    /* until error terms goes neg */
            usSrcYCurr++;
            lTempYError += AIxfer.usDstYExt;  /* Adjust error term for next */
                                              /* source line run            */
         } /* if */

      } /* for */

   } /* else */

   return;

} /* StretchCopyChunkToPhunk */


/****************************************************************************/
/****************************************************************************/
/*                                                                          */
/* FUNCTION: Stretch1BppScanlineIGNORE                                      */
/*                                                                          */
/* Stretch one 1bpp scanline, expanding in X dim or BBO_IGNORE option.      */
/*                                                                          */
/* First calculate the byte offset in the source and destination (phunk)    */
/* bitmaps for the specified scanline.                                      */
/* Then loop through each pixel in the destination scanline setting it to   */
/* the same value as a pixel from the source. The correct source pixel is   */
/* found by obtaining its index from the 'horizontalPixelVector' entry that */
/* corresponds to the current destination pixel.                            */
/****************************************************************************/
/****************************************************************************/
VOID NEAR Stretch1BppScanlineIGNORE (USHORT usSrcY,
                                     USHORT usDstY,
                                     USHORT usSrcXStart,
                                     SHORT  sPhunkXLast)
{
   USHORT   usSrcXCurr;
   USHORT   usDstXCurr;
   SHORT    i;

   BYTE     bTempDstByte;
   BYTE     bSrcByte;

   BYTE    *SrcPixels;                 /* Pointer to source pixel bytes     */
   BYTE    *DstPixels;                 /* Pointer to destination pixel bytes*/
   USHORT  *usHorizXStart;             /* Pointer to destination pixel bytes*/

   SrcPixels = AIxfer.pbmhRealStretchSrc->Bitmap +
               usSrcY * AIxfer.pbmhRealStretchSrc->BytesPerLine;

   DstPixels = AIxfer.pbmhSrc->Bitmap +
               usDstY * AIxfer.pbmhSrc->BytesPerLine;

   usHorizXStart = AIxfer.horizontalPixelVector + usSrcXStart;

/****************************************************************************/
/* Loop through the destination pixels. Outer loop handles one destination  */
/* byte and inner loop handles the individual pixels within the byte.       */
/* Note that for 1bpp, the source and destination indexes must be converted */
/* from bit offsets to byte offsets before fetching or storing.             */
/****************************************************************************/

   for (usDstXCurr = 0; usDstXCurr <= (USHORT) sPhunkXLast;  )
   {
      bTempDstByte = 0;                  /* Dst byte starts out all zeros   */

      for (i = 7; i >= 0; i--)           /* Loop for each bit in a dst byte */
      {
         usSrcXCurr = *(usHorizXStart + usDstXCurr++);

         bSrcByte   = *(SrcPixels + (usSrcXCurr >> 3));  /* Fetch 1 src byte*/

         bTempDstByte |= ((bSrcByte & (0x80 >> (usSrcXCurr & 0x7))) != 0)
                                                  << i  ;
      } /* for */

      *(DstPixels + ((usDstXCurr - 1) >> 3)) = bTempDstByte;
                                                      /* Store 1 phunk byte */
   } /* for */

} /* Stretch1BppScanlineIGNORE */

/****************************************************************************/
/****************************************************************************/
/*                                                                          */
/* FUNCTION: Stretch1BppScanlineOR                                          */
/*                                                                          */
/* Stretch one 1bpp scanline, BBO_OR option.                                */
/*                                                                          */
/* First calculate the byte offset in the source and destination (phunk)    */
/* bitmaps for the specified scanline.                                      */
/* Then loop through each pixel in the destination scanline setting it to   */
/* the same value as a pixel from the source. The correct source pixel is   */
/* found by obtaining its index from the 'horizontalPixelVector' entry that */
/* corresponds to the current destination pixel.                            */
/****************************************************************************/
/****************************************************************************/
VOID NEAR Stretch1BppScanlineOR     (USHORT usSrcY,
                                     USHORT usDstY,
                                     USHORT usSrcXStart,
                                     SHORT  sPhunkXLastParm)
{
   USHORT   usSrcXCurr;
   USHORT   usSrcXPrev;
   USHORT   usDstXCurr;
   SHORT    sPhunkXLast;
   SHORT    i;
   USHORT   usMergeFlag;

   BYTE     bTempDstByte;
   BYTE     bSrcByte;

   BYTE    *SrcPixels;                 /* Pointer to source pixel bytes     */
   BYTE    *DstPixels;                 /* Pointer to destination pixel bytes*/
   USHORT  *usHorizXStart;

   BYTE     WorkByte;
   BYTE     PixelAccumulate;

   USHORT   usMaxScanLineBitLength;


   if (sPhunkXLastParm < 0)             /* Distinguish between the case where*/
   {                                    /* the new pixels are to overlay the */
     usMergeFlag = 1;                   /* destination pixels or be merged   */
     sPhunkXLast = -sPhunkXLastParm;    /* with the current dest pixels.     */
   }                                    /* sPhunkXLast being < 0 means do the*/
   else                                 /* merge.                            */
   {
     usMergeFlag = 0;
     sPhunkXLast = sPhunkXLastParm;
   }

   SrcPixels = AIxfer.pbmhRealStretchSrc->Bitmap +
               usSrcY * AIxfer.pbmhRealStretchSrc->BytesPerLine;

   DstPixels = AIxfer.pbmhSrc->Bitmap +
               usDstY * AIxfer.pbmhSrc->BytesPerLine;

   usHorizXStart = AIxfer.horizontalPixelVector + usSrcXStart;

   /***************************************************************************/
   /* Loop through the destination pixels. Outer loop handles one destination */
   /* byte and inner loop handles the individual pixels within the byte.      */
   /* Note that for 1bpp, the source and destination indexes must be converted*/
   /* from bit offsets to byte offsets before fetching or storing.            */
   /*                                                                         */
   /* The two key indexes are:                                                */
   /*    'usSrcXCurr' - marks the last pixel which is to be used in forming   */
   /*                   the current destination pixel.                        */
   /*    'usSrcXPrev' - starts at the first pixel to clumped into the next    */
   /*                   destination pixel and moves along until it equals     */
   /*                   usSrcXCurr.                                           */
   /*                                                                         */
   /***************************************************************************/
   usSrcXPrev = AIxfer.horizontalPixelVector[usSrcXStart];

   bSrcByte = *(SrcPixels + (usSrcXPrev >> 3));

   /***************************************************************************/
   /* Calculate the maximum number of bits allowed per scanline based upon    */
   /* the real source bitmpa information. This calculation will aid us        */
   /* later on in determining when we are done processing all the pixels      */
   /* in the source within the process loop.                                  */
   /***************************************************************************/
   usMaxScanLineBitLength =
      (USHORT)AIxfer.pbmhRealStretchSrc->BytesPerLine * (USHORT)8;

   for (usDstXCurr = 0;
        usDstXCurr <= (USHORT) sPhunkXLast;
        )
   {
      bTempDstByte = 0;                  /* Dst byte starts out all zeros   */

      for (i = 7; i >= 0; i--)           /* Loop for each bit in a dst byte */
      {
         usSrcXCurr = *(usHorizXStart + usDstXCurr++);
                 /* This the ending point for current dst pixel accumulation*/

         PixelAccumulate = 0;            /* Accumulate interviening pixels  */
                                         /* For 'OR', we'll be looking for  */
                                         /* any bit being turned on         */
         for (;;)   /* FOREVER */
         {
            WorkByte = bSrcByte & bSrcMaskLeftOR[usSrcXPrev & 0x0007];
                             /* Set to zeros all bits to left of usSrcXPrev */

            if ((usSrcXCurr ^ usSrcXPrev) & (USHORT) 0xFFF8)
            {      /* If prev and current source byte addresses are different */

               PixelAccumulate |= WorkByte;   /* Collect these without masking*/
                                              /* the right end since there is */
                                              /* another byte of source       */
            } /* if */
            else
            {
               WorkByte &= bSrcMaskRightOR[usSrcXCurr & 0x0007];
                             /* Set to zeros all bits to right of current   */
                             /* source byte (which is the last one we need) */

               PixelAccumulate |= WorkByte;   /* Toss these into the bucket */

               break;  /* Normal (only) exit: prev and current are same addr*/

            } /* else */

            usSrcXPrev = (usSrcXPrev & (USHORT) 0xFFF8) + (USHORT) 8;
                                /* Advance to first pixel of next source byte */

            /******************************************************************/
            /* Determine if we have reached the end of the current source     */
            /* bitmap scanline and if so, exit out of this loop to go on to   */
            /* the next scanline.                                             */
            /******************************************************************/
            if (usSrcXPrev > usMaxScanLineBitLength)
            {
               break;
            } /* if */

            bSrcByte = *(SrcPixels + (usSrcXPrev >> 3)); /* Get next source   */

         } /* FOREVER */

         bTempDstByte |= (PixelAccumulate != 0) << i;
                         /* If any source bit was on then, set the dst pixel */

         /******************************************************************/
         /* Save away the current X source pixel offset into our previous  */
         /* index for reference the next time around in the loop.          */
         /******************************************************************/
         usSrcXPrev = usSrcXCurr;
                                   /* Ready to accumulate for next dst pixel*/

      } /* for i */

      /*********************************************************************/
      /* If the flag is on, then the new pixels must be merged with the    */
      /* existing destination pixels. If it is off, simply store the new   */
      /* byte of pixels in the destination.                                */
      /*********************************************************************/
      if (usMergeFlag)
         *(DstPixels + ((usDstXCurr - 1) >> 3)) |= bTempDstByte;
      else
         *(DstPixels + ((usDstXCurr - 1) >> 3))  = bTempDstByte;

   } /* for usDstXCurr */

} /* Stretch1BppScanlineOR */

/****************************************************************************/
/****************************************************************************/
/*                                                                          */
/* FUNCTION: Stretch1BppScanlineAND                                         */
/*                                                                          */
/* Stretch one 1bpp scanline, BBO_AND option.                               */
/*                                                                          */
/* First calculate the byte offset in the source and destination (phunk)    */
/* bitmaps for the specified scanline.                                      */
/* Then loop through each pixel in the destination scanline setting it to   */
/* the same value as a pixel from the source. The correct source pixel is   */
/* found by obtaining its index from the 'horizontalPixelVector' entry that */
/* corresponds to the current destination pixel.                            */
/****************************************************************************/
/****************************************************************************/
VOID NEAR Stretch1BppScanlineAND    (USHORT usSrcY,
                                     USHORT usDstY,
                                     USHORT usSrcXStart,
                                     SHORT  sPhunkXLastParm)
{
   USHORT   usSrcXCurr;
   USHORT   usSrcXPrev;
   USHORT   usDstXCurr;
   SHORT    sPhunkXLast;
   SHORT    i;
   USHORT   usMergeFlag;

   BYTE     bTempDstByte;
   BYTE     bSrcByte;

   BYTE    *SrcPixels;                 /* Pointer to source pixel bytes     */
   BYTE    *DstPixels;                 /* Pointer to destination pixel bytes*/
   USHORT  *usHorizXStart;

   BYTE     WorkByte;
   BYTE     PixelAccumulate;

   USHORT   usMaxScanLineBitLength;

   if (sPhunkXLastParm < 0)             /* Distinguish between the case where*/
   {                                    /* the new pixels are to overlay the */
     usMergeFlag = 1;                   /* destination pixels or be merged   */
     sPhunkXLast = -sPhunkXLastParm;    /* with the current dest pixels.     */
   }                                    /* sPhunkXLast being < 0 means do the*/
   else                                 /* merge.                            */
   {
      usMergeFlag = 0;
      sPhunkXLast = sPhunkXLastParm;
   }

   SrcPixels = AIxfer.pbmhRealStretchSrc->Bitmap +
               usSrcY * AIxfer.pbmhRealStretchSrc->BytesPerLine;

   DstPixels = AIxfer.pbmhSrc->Bitmap +
               usDstY * AIxfer.pbmhSrc->BytesPerLine;

   usHorizXStart = AIxfer.horizontalPixelVector + usSrcXStart;

   /***************************************************************************/
   /* Loop through the destination pixels. Outer loop handles one destination */
   /* byte and inner loop handles the individual pixels within the byte.      */
   /* Note that for 1bpp, the source and destination indexes must be converted*/
   /* from bit offsets to byte offsets before fetching or storing.            */
   /*                                                                         */
   /* The two key indexes are:                                                */
   /*    'usSrcXCurr' - marks the last pixel which is to be used in forming   */
   /*                   the current destination pixel.                        */
   /*    'usSrcXPrev' - starts at the first pixel to clumped into the next    */
   /*                   destination pixel and moves along until it equals     */
   /*                   usSrcXCurr.                                           */
   /*                                                                         */
   /***************************************************************************/
   usSrcXPrev = AIxfer.horizontalPixelVector[usSrcXStart];

   /***************************************************************************/
   /* Calculate the maximum number of bits allowed per scanline based upon    */
   /* the real source bitmpa information. This calculation will aid us        */
   /* later on in determining when we are done processing all the pixels      */
   /* in the source within the process loop.                                  */
   /***************************************************************************/
   usMaxScanLineBitLength =
      (USHORT)AIxfer.pbmhRealStretchSrc->BytesPerLine * (USHORT)8;

   bSrcByte = *(SrcPixels + (usSrcXPrev >> 3));

   for (usDstXCurr = 0;
        usDstXCurr <= (USHORT) sPhunkXLast;
        )
   {
      bTempDstByte = 0;                  /* Dst byte starts out all zeros   */

      for (i = 7; i >= 0; i--)           /* Loop for each bit in a dst byte */
      {
         usSrcXCurr = *(usHorizXStart + usDstXCurr++);
                 /* This the ending point for current dst pixel accumulation*/

         PixelAccumulate = 0xFF;         /* Accumulate interviening pixels  */
                                         /* For 'AND', we'll be looking for */
                                         /* any bit being turned off        */
         for (;;)   /* FOREVER */
         {
            WorkByte = bSrcByte | bSrcMaskLeftAND[usSrcXPrev & 0x0007];
                              /* Set to ones all bits to left of usSrcXPrev */

            if ((usSrcXCurr ^ usSrcXPrev) & (USHORT) 0xFFF8)
            {      /* If prev and current source byte addresses are different */

               PixelAccumulate &= WorkByte;   /* Collect these without masking*/
                                              /* the right end since there is */
                                              /* another byte of source       */
            } /* if */
            else
            {
               WorkByte |= bSrcMaskRightAND[usSrcXCurr & 0x0007];
                             /* Set to ones all bits to right of current    */
                             /* source byte (which is the last one we need) */

               PixelAccumulate &= WorkByte;   /* Toss these into the bucket */

               break;  /* Normal (only) exit: prev and current are same addr*/

            } /* else */

            usSrcXPrev = (usSrcXPrev & (USHORT) 0xFFF8) + (USHORT) 8;
                                /* Advance to first pixel of next source byte */

            /******************************************************************/
            /* Determine if we have reached the end of the current source     */
            /* bitmap scanline and if so, exit out of this loop to go on to   */
            /* the next scanline.                                             */
            /******************************************************************/
            if (usSrcXPrev > usMaxScanLineBitLength)
            {
               break;
            } /* if */

            bSrcByte = *(SrcPixels + (usSrcXPrev >> 3)); /* Get next source   */

         } /* FOREVER */

         bTempDstByte |= (PixelAccumulate == 0xFF) << i;
                      /* If all source bits were on then, the dst pixel is set*/

         /******************************************************************/
         /* Save away the current X source pixel offset into our previous  */
         /* index for reference the next time around in the loop.          */
         /******************************************************************/
         usSrcXPrev = usSrcXCurr;
                                     /* Ready to accumulate for next dst pixel*/

      } /* for i */

      /*********************************************************************/
      /* If the flag is on, then the new pixels must be merged with the    */
      /* existing destination pixels. If it is off, simply store the new   */
      /* byte of pixels in the destination.                                */
      /*********************************************************************/
      if (usMergeFlag)
         *(DstPixels + ((usDstXCurr - 1) >> 3)) &= bTempDstByte;
      else
         *(DstPixels + ((usDstXCurr - 1) >> 3))  = bTempDstByte;

   } /* for usDstXCurr */

} /* Stretch1BppScanlineAND */

/****************************************************************************/
/****************************************************************************/
/*                                                                          */
/* FUNCTION: Stretch8BppScanlineIGNORE                                      */
/*                                                                          */
/*      Stretch one 8bpp scanline, expanding in X dim or BBO_IGNORE option. */
/****************************************************************************/
/****************************************************************************/
VOID NEAR Stretch8BppScanlineIGNORE (USHORT usSrcY,
                                     USHORT usDstY,
                                     USHORT usSrcXStart,
                                     SHORT  sPhunkXLast)
{
   USHORT    usDstXCurr;

   BYTE     *SrcPixels;                /* Pointer to source pixel bytes     */
   BYTE     *DstPixels;                /* Pointer to destination pixel bytes*/

   USHORT   *usHorizXStart;

   SrcPixels = AIxfer.pbmhRealStretchSrc->Bitmap +
               usSrcY * AIxfer.pbmhRealStretchSrc->BytesPerLine;

   DstPixels = AIxfer.pbmhSrc->Bitmap +
               usDstY * AIxfer.pbmhSrc->BytesPerLine;

   usHorizXStart = AIxfer.horizontalPixelVector + usSrcXStart;

   for (usDstXCurr = 0;                  /* Phunk scanline always start at 0*/
        usDstXCurr <= (USHORT) sPhunkXLast;
        usDstXCurr++)
   {
      *(DstPixels + usDstXCurr) =                            /* Move 1 pixel*/
             *(SrcPixels + (*(usHorizXStart + usDstXCurr)));

   } /* for */

} /* Stretch8BppScanlineIGNORE */

/****************************************************************************/
/****************************************************************************/
/*                                                                          */
/* FUNCTION: Stretch16BppScanlineIGNORE                                     */
/*                                                                          */
/*      Stretch one 16bpp scanline, expanding in X dim or BBO_IGNORE option.*/
/*      This is the identical to 8bpp except for the bitmap pointer types   */
/****************************************************************************/
/****************************************************************************/
VOID NEAR Stretch16BppScanlineIGNORE (USHORT usSrcY,
                                      USHORT usDstY,
                                      USHORT usSrcXStart,
                                      SHORT  sPhunkXLast)
{
   USHORT    usDstXCurr;

   USHORT   *SrcPixels;                /* Pointer to source pixel bytes     */
   USHORT   *DstPixels;                /* Pointer to destination pixel bytes*/

   USHORT   *usHorizXStart;

   SrcPixels = (USHORT *)(AIxfer.pbmhRealStretchSrc->Bitmap +
               (usSrcY * AIxfer.pbmhRealStretchSrc->BytesPerLine));

   DstPixels = (USHORT *)(AIxfer.pbmhSrc->Bitmap +
               (usDstY * AIxfer.pbmhSrc->BytesPerLine));

   usHorizXStart = AIxfer.horizontalPixelVector + usSrcXStart;

   for (usDstXCurr = 0;                  /* Phunk scanline always start at 0*/
        usDstXCurr <= (USHORT) sPhunkXLast;
        usDstXCurr++)
   {
      *(DstPixels + usDstXCurr) =                            /* Move 1 pixel*/
             *(SrcPixels + (*(usHorizXStart + usDstXCurr)));

   } /* for */

} /* Stretch16BppScanlineIGNORE */
