/*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.                                */
/*                                                                           */
/*****************************************************************************/
/**********************************************************************/
/*                                                                    */
/*   Module          = EDDLDRAW                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor function handler   */
/*                     DrawLinesInPath                                */
/*                                                                    */
/*   Function        = Draws the straight lines in a path. The lines  */
/*                     are contained in a linked list of line records */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDICOMFLAGS
#define INCL_DDIMISC
#define INCL_DDIPATHS
#include <eddinclt.h>

#include <eddbextf.h>
#include <eddgextf.h>
#include <eddlextf.h>
#include <eddmextf.h>
#include <eddsextf.h>

#include <eddhcone.h>
#include <eddhtype.h>

/**********************************************************************/
/* Externals                                                          */
/* StaticCoordStore - storage for the coordinates as we batch them up */
/**********************************************************************/
extern USHORT                   StaticCoordStore[];

extern ClipRectangle            SingleClipRect;
extern BYTE                     LinePatStep;
extern POLYLINEPB               AIxfer;

/**********************************************************************/
/* eddl_DrawLinesInPath                                               */
/* ====================                                               */
/* DrawLinesInPath draws the straight lines in a path.  Each line has */
/* its own record which has details about start point end point etc.  */
/* This record also has a field for the line type which can - in      */
/* theory - be other than LINE.  However the MS DDK says that only    */
/* straight lines will be passed.  The code still checks this field   */
/* anyway as the OS/2 documentation does not say it will only be      */
/* lines.  We handle this call as a one or more polylines and collect */
/* up the parameters and bundle them off to the polyline work routine.*/
/**********************************************************************/
DDIENTRY eddl_DrawLinesInPath (HDC              hdc,
                               PULONG           ArgPath,
                               PLINE            ArgLine,
                               ULONG            ArgCount,
                               PDC              pdcArg,
                               ULONG            FunN)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG               Result;         /* Result of correlation      */
    PULONG              DriverCoords;   /* Static storage             */
#ifdef oldscheme
    PULONG              CoordPoint;     /* Pointer for above          */
    USHORT              i;              /* Loop control               */
#endif /* oldscheme */
    DevPoint            AIPosStore;     /* Temporary storage          */
    USHORT              Swap;
    ULONG               SaveStyle;

    /******************************************************************/
    /* Prevent compiler warnings.                                     */
    /******************************************************************/
    IgnoreParam(hdc);
    IgnoreParam(ArgPath);

    /******************************************************************/
    /* We do not need exclusive access as a LockDevice call will      */
    /* always be made before a DrawLinesPath call. BUT we do it just  */
    /* in case (because we have been loosing semaphor protection in   */
    /* stress tests and this is one of the potential holes).          */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD);

    /******************************************************************/
    /* Apply the DC command mask to the command bits                  */
    /******************************************************************/
    COMMANDBITS(FunN) &= pdc->DCICommandMask;

    /******************************************************************/
    /* Check that the count is reasonable                             */
    /******************************************************************/
    if (HIUSHORT(ArgCount))
    {
        /**************************************************************/
        /* Count is invalid.                                          */
        /**************************************************************/
        LogError(PMERR_INV_LENGTH_OR_COUNT);
        goto DRAWLINES_ERR_EXIT;
    }

    /******************************************************************/
    /* If ArgCount is zero then leave immediately.                    */
    /******************************************************************/
    if (ArgCount == 0)
    {
        Result = OK;
        goto DRAWLINES_OK_EXIT;
    }

    if ( FunNTest(COM_CORRELATE) && (pdc->DCICorrInvalid))
    {
        /**************************************************************/
        /* Will be doing correlation so get the correlation rectangles*/
        /* up to date                                                 */
        /**************************************************************/
        if (! eddg_ClipPickWindow())
        {
            goto DRAWLINES_ERR_EXIT;
        }
    }

    /******************************************************************/
    /* Copy the current AI coords away..                              */
    /******************************************************************/
    AIPosStore = pdc->DCICurrPosAI;

    /******************************************************************/
    /* Set up driver coords to point to our coordinate storage in DS  */
    /******************************************************************/
    DriverCoords = (PULONG)StaticCoordStore;

    /******************************************************************/
    /* We want to call PolyLineWork with COM_TRANSFORM reset so that  */
    /* it will set up the device offsets correctly                    */
    /*                                                                */
    /* This indicates to PolyLineWork that the passed coords are      */
    /* SCREEN coords.                                                 */
    /* If the COM_TRANSFORM bit was set on the call to DrawLinesInPath*/
    /* experience has shown that the passed coords are actually       */
    /* WORLD cords with an transform that does nothing - ie they      */
    /* are actually SCREEN coords.                                    */
    /******************************************************************/
    COMMANDBITS(FunN) &= ~((USHORT)(COM_TRANSFORM >> 16));

    /******************************************************************/
    /* Start with result OK - before correlation                      */
    /******************************************************************/
    Result = OK;
    SaveStyle = pdc->StyleNumber;

    /******************************************************************/
    /* Now loop through all the line records..                        */
    /* Where possible we will bunch up lines (ie if the last endpoint */
    /* equals the next startpoint).  There is a limit of MAX_STATIC-  */
    /* _COORDS to this bunching because we are using the static space */
    /* which is normally used by polyline.                            */
    /******************************************************************/
    for (;;)
    {
        /**************************************************************/
        /* First find the next LINE in the list while there are more  */
        /* items in the list                                          */
        /**************************************************************/
        while (ArgCount && (ArgLine->bType != LINE_IDENTIFIER))
        {
            /**********************************************************/
            /* Step to the next line                                  */
            /**********************************************************/
            if (--ArgCount)
            {
                ArgLine = (PLINE)ArgLine->pcvNext;
            }
        }

        if (!ArgCount)
        {
            /**********************************************************/
            /* That's it - there are no more lines so go home.        */
            /**********************************************************/
            break;
        }

        /**************************************************************/
        /* Put the start point into the DC data                       */
        /**************************************************************/
        pdc->DCICurrPosAI.X = ArgLine->ptlA.x;
        DriverCoords[0] = (ULONG)pdc->DCICurrPosAI.X;
        pdc->DCICurrPosAI.Y = pdc->DCISelListEntry->Info.Height -
                                                  1 - ArgLine->ptlA.y;
        DriverCoords[1] = (ULONG)ArgLine->ptlA.y;

#ifdef oldscheme
        /**************************************************************/
        /* Now start batching up coordinates..                        */
        /**************************************************************/
        for ( i=0,
              CoordPoint = DriverCoords;

              /********************************************************/
              /* Here we have all the getout clauses..  Keep going    */
              /* until we hit one of these.                           */
              /********************************************************/
             ( (i < MAX_STATIC_COORDS) &&
               ArgCount &&
               (ArgLine->bType == LINE_IDENTIFIER) &&
               (CoordPoint[0] == (ULONG)ArgLine->ptlA.x) &&
               (CoordPoint[1] == (ULONG)ArgLine->ptlA.y) );

              /********************************************************/
              /* Increase the count and move to the next line and the */
              /* next space in the coordinate buffer.                 */
              /********************************************************/
              i++,
              ArgCount--,
              ArgLine = (PLINE)ArgLine->pcvNext;
              CoordPoint += 2
            )

        {
            /**********************************************************/
            /* Put the end point into the array                       */
            /**********************************************************/
            CoordPoint[2] = (ULONG)ArgLine->ptlC.x;
            CoordPoint[3] = (ULONG)ArgLine->ptlC.y;
        }

        /**************************************************************/
        /* Now draw the lines we have accumulated (if there are any)  */
        /**************************************************************/
        if (i)
        {
            /**********************************************************/
            /* Call the workhorse - this will handle bounds and       */
            /* correlation and the actual drawing will handle all     */
            /* cases.                                                 */
            /**********************************************************/
            if (eddl_PolyLineWork(&(DriverCoords[2]),
                                  (ULONG)i,
                                  FunN) == OK_CORR)
                {
                    Result = OK_CORR;
                }

            /**********************************************************/
            /* Reset bit 0 of the style high word to indicate that we */
            /* are in a figure and the first pel should be omitted.   */
            /* PolyLineWork will look at this bit so if we do this    */
            /* after every call it means that if we get lots of lines */
            /* in a DLIP call and have to call PolyLineWork because   */
            /* the buffer gets full the next line will be correctly   */
            /* drawn without the first pel.                           */
            /* Note that we _have_ to assume that the lines in a DLIP */
            /* call are contiguous.  This is the only way the patterns*/
            /* will match correctly.                                  */
            /**********************************************************/
            pdc->StyleNumber &= 0xFFFEFFFF;
        }
#else /* newscheme */

        /**************************************************************/
        /* work out the clipping values                               */
        /* the rectangle must be correctly ordered                    */
        /**************************************************************/
        if (abs(ArgLine->ptlA.x - ArgLine->ptlC.x) >
            abs(ArgLine->ptlA.y - ArgLine->ptlC.y))
        {
            /**********************************************************/
            /* line is x-major                                        */
            /* clip in the x direction                                */
            /**********************************************************/
            if (ArgLine->ptlA.x <= ArgLine->ptlC.x)
            {
                SingleClipRect.X0 = FIXEDINT(ArgLine->ptfxA.x);
                SingleClipRect.X1 = FIXEDINT(ArgLine->ptfxC.x);
                /******************************************************/
                /* adjust for non integer values                      */
                /******************************************************/
                if (FIXEDFRAC(ArgLine->ptfxA.x))
                {
                    SingleClipRect.X0++;
                }
            }
            else
            {
                SingleClipRect.X0 = FIXEDINT(ArgLine->ptfxC.x);
                SingleClipRect.X1 = FIXEDINT(ArgLine->ptfxA.x);
                /******************************************************/
                /* adjust for non integer values                      */
                /******************************************************/
                if (FIXEDFRAC(ArgLine->ptfxC.x))
                {
                    SingleClipRect.X0++;
                }
            }

            SingleClipRect.Y0 = 0;
            SingleClipRect.Y1 = pdc->DCISelListEntry->Info.HWHeight;
        }
        else
        {
            /**********************************************************/
            /* line is y-major                                        */
            /* clip in the y direction                                */
            /**********************************************************/
            if (ArgLine->ptlA.y <= ArgLine->ptlC.y)
            {
                SingleClipRect.Y0 = FIXEDINT(ArgLine->ptfxA.y);
                SingleClipRect.Y1 = FIXEDINT(ArgLine->ptfxC.y);
                /******************************************************/
                /* adjust for non integer values                      */
                /******************************************************/
                if (FIXEDFRAC(ArgLine->ptfxA.y))
                {
                    SingleClipRect.Y0++;
                }
            }
            else
            {
                SingleClipRect.Y0 = FIXEDINT(ArgLine->ptfxC.y);
                SingleClipRect.Y1 = FIXEDINT(ArgLine->ptfxA.y);
                /******************************************************/
                /* adjust for non integer values                      */
                /******************************************************/
                if (FIXEDFRAC(ArgLine->ptfxC.y))
                {
                    SingleClipRect.Y0++;
                }
            }
            SingleClipRect.X0 = 0;
            SingleClipRect.X1 = pdc->DCISelListEntry->Info.HWWidth;
        }
        /**************************************************************/
        /* adjust the clip rectangles to AI coordinates               */
        /**************************************************************/
        Swap              = pdc->DCIConvFactor + pdc->DCIOrigin.Y
                                           - SingleClipRect.Y0;
        SingleClipRect.Y0 = pdc->DCIConvFactor + pdc->DCIOrigin.Y
                                           - SingleClipRect.Y1;
        SingleClipRect.Y1 = Swap;

        if ((SingleClipRect.X0 <= SingleClipRect.X1) &&
            (SingleClipRect.Y0 <= SingleClipRect.Y1))
        {
            DriverCoords[0] = (ULONG)ArgLine->ptlC.x;
            DriverCoords[1] = (ULONG)ArgLine->ptlC.y;

            /**********************************************************/
            /* Set the line pattern count using the value in the      */
            /* given structure.                                       */
            /**********************************************************/
            AIxfer.usPatPos = (ArgLine->flStyle & 0x7FF) / LinePatStep;

            /**********************************************************/
            /* Decide whether the first pel needs to be drawn         */
            /**********************************************************/
            if (ArgLine->fl & CURVE_DO_FIRST_PEL)
            {
                pdc->StyleNumber |= 0x00010000;
            }
            else
            {
                pdc->StyleNumber &= 0xFFFEFFFF;

                /*****************************************************/
                /* The line pattern count refers to the next pel to  */
                /* be drawn but as we're going to draw the first pel */
                /* null we need to decrease it by one so that first  */
                /* pel we draw is from the correct position in the   */
                /* pattern.                                          */
                /*****************************************************/
                AIxfer.usPatPos = (AIxfer.usPatPos - 1) & 0x0F;
            }

            if (eddl_PolyLineWork(DriverCoords,
                                  1,
                                  FunN) == OK_CORR)
            {
                Result = OK_CORR;
            }
        }


        /**********************************************************/
        /* Reset bit 0 of the style high word to indicate that we */
        /* are in a figure and the first pel should be omitted.   */
        /* PolyLineWork will look at this bit so if we do this    */
        /* after every call it means that if we get lots of lines */
        /* in a DLIP call and have to call PolyLineWork because   */
        /* the buffer gets full the next line will be correctly   */
        /* drawn without the first pel.                           */
        /* Note that we _have_ to assume that the lines in a DLIP */
        /* call are contiguous.  This is the only way the patterns*/
        /* will match correctly.                                  */
        /**********************************************************/
/*      pdc->StyleNumber &= 0xFFFEFFFF; */

        ArgCount--;
        ArgLine = (PLINE)ArgLine->pcvNext;
#endif

    }

    /******************************************************************/
    /* Restore the AI current position which we have overwritten and  */
    /* exit                                                           */
    /******************************************************************/
    pdc->DCICurrPosAI = AIPosStore;
    pdc->StyleNumber = SaveStyle;

DRAWLINES_OK_EXIT:
    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(Result);

DRAWLINES_ERR_EXIT:
    ExitDriver(pdcArg, FunN, EDF_STANDARD);
    return(ERROR_ZERO);
}
