/*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 = PRDLSHRT
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdl_PolyShortLine
 *
 * 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
#include <os2.h>
#undef INCL_DOSPROCESS           /* CON3201 */
#undef INCL_DOSSEMAPHORES
#undef INCL_GPIPRIMITIVES
#undef INCL_WINHEAP
#undef INCL_GPIBITMAPS
#undef INCL_GPIERRORS

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

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

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

#include <prdconse.h>
#include <prdlcone.h>
#include <prdltypt.h>
#include <prdbtyp1.h>
#include <prdbextf.h>
#include <prdcextf.h>
#include <prdgextf.h>
#include <prdiextf.h>
#include <prdlextf.h>
#include <prdnextf.h>
#include <prdncone.h>

/******************************************************************************/
/*  Set up access to default line attributes and linetype table.              */
/******************************************************************************/
extern DLINEBUNDLE prda_DefLinAts;
extern USHORT LineTypeTable [NUMBER_LINETYPES];

/******************************************************************************/
/*  FUNCTION: prdl_PolyShortLine                                              */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  See "OS/2 Technical Reference: I/O Subsytems and Device Drivers"          */
/*                                                                            */
/*  hanDC       DcH;                                                          */
/*  PSHORTLINE  pShortLines;                                                  */
/*  lpDCI       DCIData;                                                      */
/*  USHORT      FunN;                                                         */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function draws a series of shortlines as specified in the structure  */
/*  at pShortLines.  The current position is not updated by this function.    */
/*                                                                            */
/*  CHANGES:                                                                  */
/*                                                                            */
/*  Note that this function does not implement line styling, relying instead  */
/*  on a line style mask which is shifted after every pel is printed.         */
/******************************************************************************/
ULONG prdl_PolyShortLine( hanDC       DcH,
                          PSHORTLINE  pShortLines,
                          lpDCI       DCIData,
                          ULONG       FunN)

{
#define TFUNC "prdl_PolyShLine"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    ULONG                Command;      /* Command part of FunN                */
    BitmapListEntry     *ListEntry;    /* Pointer to bitmap list entry        */
    BYTE                 LineColor;    /* Foreground line color               */
    USHORT               LineMix;      /* Foreground line mix                 */
    SHORT                XIncrement,   /* 1 or -1 depending on direction of   */
                         YIncrement;   /* the line                            */
    USHORT               NumberOfXSteps;/* Number of steps in array           */
    USHORT               StepCounter;  /* Loop variable                       */
    DevRect              lcClipReg;    /* Clip region                         */
    DevPoint             CoordLeft;    /* Start coord of line                 */
    DevPoint             CoordRight;   /* End coord of line                   */
    DevPoint             CpCoordLeft;  /* Start coord of clipped line         */
    DevPoint             CpCoordRight; /* End coord of clipped line           */
    USHORT               ClipRectNumber;/* Loop counter for clipping          */
    SHORT                XPelPos;      /* Loop counter for drawing            */
    DevRect              Bounds;       /* Bounding rectangle                  */
    USHORT               LineType;     /* Line type to draw line with         */
    USHORT               StartX;       /* Start and end x positions of short  */
    USHORT               EndX;         /* line                                */
    PUSHORT              Steps;        /* Array of x positions for steps      */
    PDLINEBUNDLE         CurLinAts;    /* ptr to line attribute bundle        */
    SHORT                Result;
    RECTL                BoundsRectL;  /* Bounds for clipping processing      */

    /**************************************************************************/
    /*                                                                        */
    /*   0    1   2  3  4                                                     */
    /*   XXXXX                                                                */
    /*        XXXX                                                            */
    /*            XXX                                                         */
    /*               XX                                                       */
    /*                 X                                                      */
    /*                                                                        */
    /*  A polyshortline where X indicates a pel to be drawn and 0..4          */
    /*  corresponds to the x values in Steps.  Note that when drawing each    */
    /*  shortline we must draw up to but not including the next x position    */
    /*  (unless the start and finish x positions are equal in the case of a   */
    /*  straight vertical line).  Note that the last point (below the 4) is   */
    /*  not drawn.                                                            */
    /**************************************************************************/
#ifdef PRD_TIMING
    DEKHOOK0(A,8,14)
#endif
    prdm_EnterDriver(DCIData);
    Command = FunN & DCIData->CommandMask;

    /**************************************************************************/
    /*  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)
    {
        prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,8,94)
#endif
        return((Result == ERR_PURGE) ? OK : ERROR_ZERO);
    }

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

    /**************************************************************************/
    /*  Reset bit 0 of the style high word, indicating that a figure in a path*/
    /*  is not starting                                                       */
    /**************************************************************************/
    DCIData->StyleNumber &= 0xfffeffff;

    /**************************************************************************/
    /*  Check that there is a currently selected bitmap for this device       */
    /*  context.                                                              */
    /**************************************************************************/
/*  if (!((PBYTE)ListEntry = DCIData->DCISelBitmap))            CON3201 */
    if (!(ListEntry = (pBMListEntry)DCIData->DCISelBitmap))
    {
        LOGERR(TFUNC, "No Bitmap", FNULL, 0, PMERR_NO_BITMAP_SELECTED);
        prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,8,94)
#endif
        return (ERROR_ZERO);
    }
    CurLinAts = DCIData->DCICurLinAts;

    /**************************************************************************/
    /*  If bounds determination required then accumulate bounds.  Use the     */
    /*  start and end coords passed as parameters to determine enclosing      */
    /*  rectangle.                                                            */
    /**************************************************************************/
    if (Command & COM_BOUND)
    {

        /**********************************************************************/
        /*  These will give us the correct x limits for the bounding          */
        /*  rectangle.                                                        */
        /**********************************************************************/
        Bounds[0].X = pShortLines->slh.lxLeft;
        Bounds[1].X = pShortLines->slh.lxRight;

        /**********************************************************************/
        /*  Allow for the shortline going from top to bottom or vice- versa.  */
        /**********************************************************************/
        if (pShortLines->slh.ptlStart.y < pShortLines->slh.ptlStop.y)
        {
            Bounds[0].Y = pShortLines->slh.ptlStart.y;
            Bounds[1].Y = pShortLines->slh.ptlStop.y;
        }
        else
        {
            Bounds[0].Y = pShortLines->slh.ptlStop.y;
            Bounds[1].Y = pShortLines->slh.ptlStart.y;
        }

        /**********************************************************************/
        /*  Accumulate the bounds                                             */
        /**********************************************************************/
        (VOID)prdg_AddBounds((DevRect  *)Bounds, DCIData);
    }

    /**************************************************************************/
    /*  First-level checks have been completed and bounds have been calculated*/
    /*  (if required) so if the Draw Bit is not on, it is safe to exit OK     */
    /*  because there is nothing else to do.                                  */
    /**************************************************************************/
    if (!(Command & COM_DRAW))
    {
        prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,8,94)
#endif
        return(OK);
    }

    /**************************************************************************/
    /*  The polyshortline must be drawn so determine the attributes to use.   */
    /*  Determine line color and mix (use the default mix if necessary.       */
    /**************************************************************************/
    LineColor = prdc_ColorToPelBits(CurLinAts->lbnd.lColor, DCIData,
                                    ListEntry->DCTPtr);
    LineMix = CurLinAts->lbnd.usMixMode;
    if (LineMix == 0)
        LineMix = prda_DefLinAts.lbnd.usMixMode;

    /**************************************************************************/
    /*  If linetype is default then find out what the default is and use as   */
    /*  index into LineTypeTable.  Also use the default if the line type is   */
    /*  not in the range 0 - (NUMBER_LINETYPES-1)                             */
    /**************************************************************************/
    if ((CurLinAts->lbnd.usType == 0) ||
        (CurLinAts->lbnd.usType >= NUMBER_LINETYPES))
        LineType = LineTypeTable[prda_DefLinAts.lbnd.usType];
    else
        LineType = LineTypeTable[CurLinAts->lbnd.usType];

    /**************************************************************************/
    /*  Traverse the linked list of shortline definitions                     */
    /**************************************************************************/
    for( ;pShortLines != FNULL; pShortLines =
                                        (PSHORTLINE)pShortLines-> slh.pslhNext)
    {

        /**********************************************************************/
        /*  Determine the x and y increments and number of rows in the        */
        /*  shortline                                                         */
        /**********************************************************************/
        if ((SHORT)(pShortLines->slh.ptlStart.y) <
            (SHORT)(pShortLines->slh.ptlStop.y))
        {

            /******************************************************************/
            /*  StartY < StopY so direction is bottom to top                  */
            /******************************************************************/
            YIncrement = 1;
            NumberOfXSteps = (SHORT)(pShortLines->slh.ptlStop.y) -
                             (SHORT)(pShortLines->slh.ptlStart.y);
        }
        else
        {

            /******************************************************************/
            /*  StartY > StopY so direction is bottom to top                  */
            /******************************************************************/
            YIncrement = -1;
            NumberOfXSteps = (SHORT)(pShortLines->slh.ptlStart.y) -
                             (SHORT)(pShortLines->slh.ptlStop.y);
        }
        if ((SHORT)(pShortLines->slh.ptlStart.x) <
            (SHORT)(pShortLines->slh.ptlStop.x))
            XIncrement = 1;
        else
            XIncrement = -1;
        CoordLeft.Y = pShortLines->slh.ptlStart.y;

        /**********************************************************************/
        /*  Steps contains a list of the x values including the start and end */
        /*  position.                                                         */
        /**********************************************************************/
        Steps = (PUSHORT)pShortLines->ax;

        /**********************************************************************/
        /*  Loop through each row in the shortline                            */
        /**********************************************************************/
        for (StepCounter = 0; StepCounter < NumberOfXSteps; StepCounter++)
        {
            if (XIncrement == 1)
            {

                /**************************************************************/
                /*  X values increase in Steps array so assign the left and   */
                /*  right endpoints of the shortline correctly                */
                /**************************************************************/
                CoordLeft.X = Steps[StepCounter];
                CoordRight.X = Steps[StepCounter+1];

                /**************************************************************/
                /*  Don't print the last pel of each shortline unless it is a */
                /*  vertical line.                                            */
                /**************************************************************/
                if (CoordLeft.X != CoordRight.X)
                {
                    CoordRight.X = (USHORT)((SHORT)CoordRight.X - (SHORT)1);
                }
            }
            else
            {

                /**************************************************************/
                /*  X values decrease in Steps array so assign the left and   */
                /*  right endpoints of the shortline correctly                */
                /**************************************************************/
                CoordLeft.X = Steps[StepCounter+1];
                CoordRight.X = Steps[StepCounter];

                /**************************************************************/
                /*  Don't print the last pel of each shortline unless it is a */
                /*  vertical line.                                            */
                /**************************************************************/
                if (CoordLeft.X != CoordRight.X)
                {
                    CoordLeft.X = (USHORT)((SHORT)CoordLeft.X + (SHORT)1);
                }
            }
            CoordRight.Y = CoordLeft.Y;

            /******************************************************************/
            /*  CoordRight and CoordLeft now describe the current shortline.  */
            /******************************************************************/
            BoundsRectL.xLeft   = (ULONG)pShortLines->slh.lxLeft;
            BoundsRectL.xRight  = (ULONG)pShortLines->slh.lxRight + 1;
            if (pShortLines->slh.ptlStart.y < pShortLines->slh.ptlStop.y)
            {
                BoundsRectL.yBottom = (ULONG)pShortLines->slh.ptlStart.y;
                BoundsRectL.yTop    = (ULONG)pShortLines->slh.ptlStop.y + 2;
            }
            else
            {
                BoundsRectL.yBottom = (ULONG)pShortLines->slh.ptlStop.y;
                BoundsRectL.yTop    = (ULONG)pShortLines->slh.ptlStart.y + 2;
            }

            /******************************************************************/
            /*  For each clip rectangle currently valid (ie each one that     */
            /*  prdi_GetNextClip will return) draw the part of current        */
            /*  shortline that falls within it.  All coordinates are device   */
            /*  coordinates and so no conversion is required                  */
            /******************************************************************/
            for (ClipRectNumber = 1; prdi_GetNextClip(DCIData, ClipRectNumber++,
                                                      (DevRect  *)lcClipReg,
                                                      &BoundsRectL) == OK; )
            {
                /**************************************************************/
                /*  Set CpCoordLeft and CpCoordRight to the left and right of */
                /*  the whole shortline before each clipping operation.       */
                /**************************************************************/
                CpCoordLeft = CoordLeft;
                CpCoordRight = CoordRight;

                /**************************************************************/
                /*  Clip the shortline to the current clip rectangle.         */
                /**************************************************************/
                if (prdi_ClipLine((DevRect  *) lcClipReg,
                                  (DevPoint *) &CpCoordLeft,
                                  (DevPoint *) &CpCoordRight) != OK )
                {

                    /**********************************************************/
                    /*  The line is wholly outside current clip rectangle so  */
                    /*  do not draw it.                                       */
                    /**********************************************************/
                    continue;
                }

                /**************************************************************/
                /*  Part of the line lies in clip rectangle - Left and Right  */
                /*  have been updated with the coordinates of the clipped     */
                /*  line.  The line must be drawn in the correct direction (ie*/
                /*  from the start of the polyshortline to its end) so        */
                /*  determine whether it should run from left to right or     */
                /*  vice-versa from the XIncrement which was determined from  */
                /*  the endpoints of the polyshortline.  The line has to be   */
                /*  drawn in the correct direction the line type is correctly */
                /*  output.                                                   */
                /**************************************************************/
                if (XIncrement == 1)
                {
                    StartX = CpCoordLeft.X;
                    EndX = CpCoordRight.X;
                }
                else
                {
                    StartX = CpCoordRight.X;
                    EndX = CpCoordLeft.X;
                }

                /**************************************************************/
                /*  Set all required pixels on current row (StartX and EndX   */
                /*  are inclusive).                                           */
                /**************************************************************/
                for (XPelPos = StartX;
                     ((XIncrement == 1) && (XPelPos <= (SHORT)EndX)) ||
                     ((XIncrement == -1) && (XPelPos >= (SHORT)EndX));
                     XPelPos += XIncrement)
                {

                    /**********************************************************/
                    /*  If pel should be on in linestyle then print it using  */
                    /*  prdb_MixPel.  PD00188 : Since prdb_MixPel adjusts for */
                    /*  the DC Origin (when drawing into the band) we do not  */
                    /*  have to allow for it here.                            */
                    /**********************************************************/
                    if (LineType & DCIData->DCILineTypMask)
                        (VOID)prdb_MixPel(ListEntry, (USHORT)XPelPos,
                                          CoordLeft.Y, LineColor, LineMix);

                    /**********************************************************/
                    /*  Update LineTypeMask to mask next pixel in line type   */
                    /**********************************************************/
                    if (DCIData->DCILineTypMask == 0x0001)
                        DCIData->DCILineTypMask = 0x8000;
                    else
                        DCIData->DCILineTypMask >>= 1;
                }
            }

            /******************************************************************/
            /*  Move to next row using YIncrement                             */
            /******************************************************************/
            CoordLeft.Y += YIncrement;
        }
    }
    prdm_LeaveDriver(DCIData);
#ifdef PRD_TIMING
    DEKHOOK0(A,8,94)
#endif
    return(OK);
}
#undef TFUNC
