/*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          = EDDLSETO                                       */
/*                                                                    */
/*   Description     = Display Device Driver minor function handler   */
/*                     SetLineOrigin                                  */
/*                                                                    */
/*   Function        = Sets the current style state in the DC         */
/*                     instance data                                  */
/*                                                                    */
/*   Reference       = Winthorn Functional Specification              */
/*                     Device Driver Interface Specification          */
/*                     Display Device Driver Design Specification     */
/*                                                                    */
/*                                                                    */
/**********************************************************************/
#define INCL_DDIMISC
#define INCL_DDIPATHS
#define INCL_DDICOMFLAGS
#define INCL_GRE_XFORMS
#include <eddinclt.h>

#include <edddtypt.h>
#include <eddgextf.h>

extern BYTE LinePatStep;
extern PPFNL            EnginesDispatchTable;

/**********************************************************************/
/* SetLineOrigin sets the current style state. This is a ULONG in the */
/* DC instance data; the high word indicates whether the first pel is */
/* being drawn while the high byte (of the low word) is the style     */
/* error value, the low byte is the style mask.                       */
/**********************************************************************/
DDIENTRY eddl_SetLineOrigin (HDC        hdc,
                             PPOINTL    pptlCurrPos,
                             ULONG      Style,
                             PDC        pdcArg,
                             ULONG      FunN)

{
    /******************************************************************/
    /* Local variables                                                */
    /******************************************************************/
    ULONG           DriverPatCnt;    /* contains engine pat count bits*/
    ULONG           EnginePatCnt;    /* above but in driver format    */
    POINTL          LocalCurrPos;

    /******************************************************************/
    /* Get driver semaphore and perform entry checks                  */
    /******************************************************************/
    EnterDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);

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

    /******************************************************************/
    /* Store the new style state in the DC.                           */
    /*                                                                */
    /* The high word gives the "draw first pel state": 1 means draw   */
    /* the first pel, 0 means dont.  This is stored in the high       */
    /* word of DCIStyleNumber.                                        */
    /*                                                                */
    /* The low word gives the current position in the line style      */
    /* pattern: the high byte contains the error, the low byte        */
    /* contains the position in the mask.                             */
    /*                                                                */
    /* See EDDDATA.C for details of how the current position in the   */
    /* line style pattern is handled.                                 */
    /******************************************************************/
    pdc->StyleNumber = (Style & 0xFFFF0000);

    EnginePatCnt = Style & 0x0000FF07;

    ((PBYTE)&DriverPatCnt)[0] = HIBYTE(EnginePatCnt);
    ((PBYTE)&DriverPatCnt)[1] = LOBYTE(EnginePatCnt);

    pdc->DCILinePatCnt = DriverPatCnt / LinePatStep;

    /******************************************************************/
    /* Take a local copy of the passed value for manipulating.        */
    /******************************************************************/
    LocalCurrPos = *pptlCurrPos;

    /******************************************************************/
    /* If the COM_TRANSFORM bit is set then we are given the new      */
    /* current position in WORLD coordinates, otherwise they are in   */
    /* SCREEN coordinates.                                            */
    /******************************************************************/
    if (FunNTest(COM_TRANSFORM))
    {
        /**************************************************************/
        /* Convert world coordinates to device coordinates, but avoid */
        /* calling the engine if we can!                              */
        /**************************************************************/
        if ( !pdc->DCIXFrmSimple )
        {
            /**********************************************************/
            /* Call the engine convert function directly (for         */
            /* performance reasons).                                  */
            /**********************************************************/
            if ( OK != EnginesDispatchTable[NGreConvert & 0xff](
                                          pdc->DCIhdc,
                                          CVTC_WORLD,
                                          CVTC_DEVICE,
                                          (PPOINTL)&LocalCurrPos,
                                          1,
                                          NULL,
                                          NGreConvert) )
            {
                LogError(PMERR_COORDINATE_OVERFLOW);
                goto SETLINEORIGIN_ERR_EXIT;
            }

            /**********************************************************/
            /* Check that we are not going to lose any significant    */
            /* bits when we convert from a LONG to a SHORT.           */
            /* We can do this by casting the value to a SHORT, sign-  */
            /* extending it to a LONG, and then comparing the top     */
            /* 16 bits with the original 16 bits. If the upper bits   */
            /* are different then we are going to lose information    */
            /* when converting to a SHORT.                            */
            /**********************************************************/
            if ( ( HIUSHORT(LocalCurrPos.x) !=
                             HIUSHORT((LONG)((SHORT)LocalCurrPos.x)) ) ||
                 ( HIUSHORT(LocalCurrPos.y) !=
                              HIUSHORT((LONG)((SHORT)LocalCurrPos.y)) ) )
            {
                /******************************************************/
                /* We have an invalid coordinate. Log an error and    */
                /* return.                                            */
                /******************************************************/
                LogError(PMERR_COORDINATE_OVERFLOW);
                goto SETLINEORIGIN_ERR_EXIT;
            }
        }

        /**************************************************************/
        /* LocalCurrPos now contains the new current position in      */
        /* DEVICE coords. Convert it to HW coords and store it in     */
        /* DC data.                                                   */
        /**************************************************************/
        pdc->DCICurrPosAI.X = pdc->DCIOrigin.X + (SHORT)LocalCurrPos.x;
        pdc->DCICurrPosAI.Y = pdc->DCIConvFactor - (SHORT)LocalCurrPos.y;

        /**************************************************************/
        /* Now we know everything is OK, store the new world coords   */
        /* as well.                                                   */
        /**************************************************************/
        pdc->DCICurrPosWorld = *pptlCurrPos;
    }
    else
    {
        /**************************************************************/
        /* Do the SCREEN to WORLD conversion.                         */
        /**************************************************************/
        /**************************************************************/
        /* The given point is in SCREEN coords.  First we convert it  */
        /* to DEVICE coords.                                          */
        /**************************************************************/
        LocalCurrPos.x -= pdc->DCIOrigin.X;
        LocalCurrPos.y -= pdc->DCIOrigin.Y;

        if ( !pdc->DCIXFrmSimple )
        {
            /**********************************************************/
            /* Call the engine convert function directly (for         */
            /* performance reasons).                                  */
            /**********************************************************/
            if ( OK != EnginesDispatchTable[NGreConvert & 0xff](
                                          hdc,
                                          CVTC_DEVICE,
                                          CVTC_WORLD,
                                          &LocalCurrPos,
                                          1,
                                          NULL,
                                          NGreConvert) )
            {
                /******************************************************/
                /* The conversion failed so log an error.             */
                /******************************************************/
                LogError(PMERR_COORDINATE_OVERFLOW);
                goto SETLINEORIGIN_ERR_EXIT;
            }
        }

        /**********************************************************/
        /* Copy the new WORLD current position into DC Data.      */
        /**********************************************************/
        pdc->DCICurrPosWorld = LocalCurrPos;

        /**********************************************************/
        /* Now we know everything is OK, store the new position   */
        /* in HW coords.                                          */
        /**********************************************************/
        pdc->DCICurrPosAI.X = (SHORT)pptlCurrPos->x;
        pdc->DCICurrPosAI.Y = pdc->DCIBoundingClip[1].Y
                                      - (SHORT)pptlCurrPos->y;
    }

    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
    return(TRUE);

SETLINEORIGIN_ERR_EXIT:
    /******************************************************************/
    /* Release driver semaphore                                       */
    /******************************************************************/
    ExitDriver(pdcArg, FunN, EDF_STANDARD | EDF_DONT_CLEAN);
    return(FALSE);
}
