/*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 = PRDICLIP
 *
 * DESCRIPTIVE NAME =
 *
 *
 * VERSION
 *
 * DATE
 *
 * DESCRIPTION
 *
 * FUNCTIONS   prdi_NotifyClipChange
 *             prdi_DefaultClip
 *             prdi_ClipIntSect
 *             prdi_GetNextClip
 *             prdi_CacheClipRects
 *
 * ENTRY POINTS:
 *
 * DEPENDENCIES:
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/

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

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

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

#include <prdconse.h>
#include <prdicone.h>

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

#include <prdaextf.h>
#include <prdgextf.h>
#include <prdiextf.h>

/******************************************************************************/
/*  Set up access to the engine function.                                     */
/******************************************************************************/
extern PFNL da_NotifyClipChange;

/******************************************************************************/
/*                                                                            */
/*  FUNCTION: prdi_NotifyClipChange                                           */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  See "OS/2 Technical Reference: I/O Subsytems and Device Drivers"          */
/*                                                                            */
/*  HDC     DcH;                                                              */
/*  PRECTL  ArgBoundClip;                                                     */
/*  ULONG   ArgComplexity;                                                    */
/*  ULONG   bClipPath;                                                        */
/*  lpDCI   DCIData;                                                          */
/*  ULONG   FunN;                                                             */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This routine is called when there is a change in the clip region          */
/*  intersected with the visible region.  The main processing here is done by */
/*  prdi_GetClipRects which obtains the new clip rectangles.                  */
/******************************************************************************/
ULONG EXPENTRY prdi_NotifyClipChange( HDC     DcH,
                                      PRECTL  ArgBoundClip,
                                      LONG    ArgComplexity,
                                      ULONG   bClipPath,
                                          /* release 1: always FALSE          */
                                      lpDCI   DCIData,
                                      ULONG   FunN)

{
#define TFUNC "prdi_NtfyClipCh"

    /**************************************************************************/
    /*  Local Variables                                                       */
    /**************************************************************************/
    lpClipRectangle  NewClipRects;     /* Pointer to the position of the clip */
                                       /* rectangle array                     */
    USHORT           ValidClipRects;   /* Number of clip rectangles which     */
                                       /* intersect current band/form clip    */
                                       /* region.                             */
    USHORT           rc;               /* Return code for prdi_GetClipRects   */
    ULONG            Command;          /* Command part of FUNN     PD00769   */

    prdm_EnterDriver(DCIData);

#ifdef PRD_TIMING
    DEKHOOK0(A,7,03)
#endif

    DCIData->DCIClipNum    = (USHORT)ArgComplexity;
    DCIData->DCIClipsValid = FALSE;    /* PD00305...                          */

    /**************************************************************************/
    /* PD00769:  Store away the clip rectangle if there is only one.          */
    /* This is a fast path for prdl_FillPath.                                 */
    /**************************************************************************/
    if (ArgComplexity == 1L)
    {
        Command = FunN & DCIData->CommandMask;
        prdg_Convert((PULONG)ArgBoundClip, (PULONG)&DCIData->DCIFillPathRect,
                         COORD_WORLD, COORD_DEVICE_WORD, 2L, (hanDC)DcH,
                         Command);
    }

    /**************************************************************************/
    /*  Pass control to the engine.                                           */
    /**************************************************************************/

#ifdef PRD_TIMING
    DEKHOOK0(A,7,83)
#endif

    prdm_LeaveDriver(DCIData);
    return(da_NotifyClipChange(DcH, ArgBoundClip, ArgComplexity, bClipPath,
                               DCIData, FunN));
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prdi_DefaultClip                                                */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  lpDCI  DCIData;  Pointer to DC Instance data                              */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  In the case when there are no clip rectangles this function is called to  */
/*  set up the default clip regions for the current DC.                       */
/******************************************************************************/
VOID prdi_DefaultClip(lpDCI DCIData)


{
#define TFUNC "prdi_DfltClip"

    /**************************************************************************/
    /*  Set up default clip region to page for Direct, Info and Queued DCs (ie*/
    /*  DCs that have Bands).  If the Memory DC has a selected Bitmap, set    */
    /*  default clip region also.                                             */
    /**************************************************************************/
    DCIData->DCIClipNum = 0;
    if (DCIData->DCIDCType  == OD_DIRECT ||
        DCIData->DCIDCType  == OD_INFO   ||
        DCIData->DCIDCType  == OD_QUEUED ||
        (DCIData->DCIDCType == OD_MEMORY && DCIData->DCISelBitmap != NULL))
    {

        /**********************************************************************/
        /*  These coordinates will describe the page if there is no banding   */
        /*  (ie only one band).                                               */
        /**********************************************************************/
        DCIData->DCIClipRects[0].X0 = DCIData->DCICurrBand.BDCoords[0].X;
        DCIData->DCIClipRects[0].Y0 = DCIData->DCICurrBand.BDCoords[0].Y;
        DCIData->DCIClipRects[0].X1 = DCIData->DCICurrBand.BDCoords[1].X;
        DCIData->DCIClipRects[0].Y1 = DCIData->DCICurrBand.BDCoords[1].Y;
        DCIData->DCIClipRects[0].YRaw = DCIData->DCIPdbInstance->PageDepthPels;

        /**********************************************************************/
        /*  Adjust the default clip region to take the DC origin into account.*/
        /*  Either the start or end coordinate is adjusted depending on the   */
        /*  sign of the DC origin for that coordinate.                        */
        /**********************************************************************/
        if (DCIData->DCIOrigin.X > 0)
        {
            DCIData->DCIClipRects[0].X1 -= DCIData->DCIOrigin.X;
        }
        else
        {
            DCIData->DCIClipRects[0].X0 -= DCIData->DCIOrigin.X;
        }
        if (DCIData->DCIOrigin.Y > 0)
        {
            DCIData->DCIClipRects[0].Y1 -= DCIData->DCIOrigin.Y;
        }
        else
        {
            DCIData->DCIClipRects[0].Y0 -= DCIData->DCIOrigin.Y;
        }
    }
    return;
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prdi_ClipIntSect                                                */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  DevRect     *  pSrcRect; Pointer to the clip rectangle                    */
/*  DevRect     *  pTrgRect; Pointer to the rectangle to be clipped (returns  */
/*                           as the clipped rectangle)                        */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function clips the rectangle specified by pTrgRect to the clip       */
/*  rectangle specified by pSrcRect.  The function works with EXCLUSIVE       */
/*  rectangles only.  The function returns FALSE if the intersection is empty,*/
/*  TRUE if non-empty.                                                        */
/******************************************************************************/
BOOL  prdi_ClipIntSect( DevRect * pSrcRect,
                        DevRect * pTrgRect)

{
#define TFUNC "prdi_ClipIntSct"

    /**************************************************************************/
    /*  Check for the case of no intersection.                                */
    /**************************************************************************/
    if (((SHORT)(*pTrgRect)[0].X >= (SHORT)(*pSrcRect)[1].X ) ||
        ((SHORT)(*pTrgRect)[1].X <= (SHORT)(*pSrcRect)[0].X ) ||
        ((SHORT)(*pTrgRect)[0].Y >= (SHORT)(*pSrcRect)[1].Y ) ||
        ((SHORT)(*pTrgRect)[1].Y <= (SHORT)(*pSrcRect)[0].Y ))
        return(FALSE);

    /**************************************************************************/
    /*  Set the bottom left hand corner in TrgRect to the highest x and y     */
    /*  coordinates from TrgRect or SrcRect.                                  */
    /**************************************************************************/
    if ((SHORT)(*pSrcRect)[0].X > (SHORT)(*pTrgRect)[0].X)
        (*pTrgRect)[0].X = (*pSrcRect)[0].X;
    if ((SHORT)(*pSrcRect)[0].Y > (SHORT)(*pTrgRect)[0].Y)
        (*pTrgRect)[0].Y = (*pSrcRect)[0].Y;

    /**************************************************************************/
    /*  Set the top right hand corner in TrgRect to the lowest x and y        */
    /*  coordinates from TrgRect and SrcRect.                                 */
    /**************************************************************************/
    if ((SHORT)(*pSrcRect)[1].X < (SHORT)(*pTrgRect)[1].X)
        (*pTrgRect)[1].X = (*pSrcRect)[1].X;
    if ((SHORT)(*pSrcRect)[1].Y < (SHORT)(*pTrgRect)[1].Y)
        (*pTrgRect)[1].Y = (*pSrcRect)[1].Y;
    return(TRUE);
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prdi_GetNextClip                                                */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  lpDCI          DCIData;     Pointer to DC Instance data                   */
/*  USHORT         iClipRects;  Index to next clip rectangle                  */
/*  DevRect     *  pClipRect;   Pointer to returned clip rectangle            */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function checks for an iClipRects'th clip rectangle and if it exists */
/*  then it returns it at pClipRect.  If one does not exist then return FALSE;*/
/*  else return TRUE.  Note that iClipRects is counted from 1, not 0.         */
/******************************************************************************/
BOOL prdi_GetNextClip( lpDCI          DCIData,
                       USHORT         Index,
                       DevRect      * pClipRect,
                       PRECTL         pBoundRect)

{
#define TFUNC "prdi_GetNxtClip"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    USHORT  result;
    USHORT  ModIndex;

    ModIndex = (Index - 1) % MAX_CLIP_RECTS;
    if (DCIData->DCIClipsValid)
    {
        if (Index > DCIData->DCIClipsInCache)
        {
            return(FALSE);
        }
        else
        {
            (*pClipRect)[0].X = DCIData->DCIClipRects[ModIndex].X0;
            (*pClipRect)[0].Y = DCIData->DCIClipRects[ModIndex].Y0;
            (*pClipRect)[1].X = DCIData->DCIClipRects[ModIndex].X1;
            (*pClipRect)[1].Y = DCIData->DCIClipRects[ModIndex].Y1;
            return(TRUE);
        }
    }
    else
    {
        if (Index == 1)
        {
            DCIData->DCIClipIndex = 0;
        }
        if (ModIndex == 0)
        {
            prdi_CacheClipRects(DCIData, Index, pBoundRect);
            if (DCIData->DCIClipsInCache == 0)
            {
                return(FALSE);
            }
            (*pClipRect)[0].X = DCIData->DCIClipRects[ModIndex].X0;
            (*pClipRect)[0].Y = DCIData->DCIClipRects[ModIndex].Y0;
            (*pClipRect)[1].X = DCIData->DCIClipRects[ModIndex].X1;
            (*pClipRect)[1].Y = DCIData->DCIClipRects[ModIndex].Y1;
            return(TRUE);
        }
        else
        {
            if (ModIndex >= DCIData->DCIClipsInCache)
            {
                return(FALSE);
            }
            (*pClipRect)[0].X = DCIData->DCIClipRects[ModIndex].X0;
            (*pClipRect)[0].Y = DCIData->DCIClipRects[ModIndex].Y0;
            (*pClipRect)[1].X = DCIData->DCIClipRects[ModIndex].X1;
            (*pClipRect)[1].Y = DCIData->DCIClipRects[ModIndex].Y1;
            return(TRUE);
        }
    }
}
#undef TFUNC

/******************************************************************************/
/*  FUNCTION: prdi_CacheClipRects                                             */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  USHORT         iClipRects;  Index to next clip rectangle                  */
/*  DevRect     *  pClipRect;   Pointer to returned clip rectangle            */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function assigns the coordinates for the clip rectangle.  It ensures */
/*  that the clip requested is currently in the clip cache.  If it's not, call*/
/*  the engine and get the next cache, then assign the clip coordinates.      */
/******************************************************************************/
VOID prdi_CacheClipRects( lpDCI   DCIData,
                          USHORT  iClipRects,
                          PRECTL  pBoundRect)

{
#define TFUNC "prdi_CacheClipRects"

    /**************************************************************************/
    /*  Local variables                                                       */
    /**************************************************************************/
    RECTL    NextClipRect;             /* Next clip rectangle from the engine */
    DevRect  NextClip;                 /* Next clip rectangle to add to list  */
    RGNRECT  Control;                  /* structure to control GreGetClipRects*/
    USHORT   i;                        /* Number of valid clips found so far  */
    USHORT   result;

    /**************************************************************************/
    /*  If ArgComplexity is less than the max cache size, don't bother to     */
    /*  pass in a bounding rectangle... and keep the clips around until they  */
    /*  get invalidated by NotifyClipChange.                                  */
    /**************************************************************************/
    if (DCIData->DCIClipNum <= MAX_CLIP_RECTS)
    {
        pBoundRect = FNULL;
        DCIData->DCIClipsValid = TRUE;
    }
    else
    {
        DCIData->DCIClipsValid = FALSE;
    }
    DCIData->DCIClipsInCache = 0;
    Control.crc              = 1;
    Control.crcReturned      = 0;
/*  Control.usDirection      = RECTDIR_LFRT_TOPBOT;  CON3201 */
    Control.ulDirection      = RECTDIR_LFRT_TOPBOT;

    /**************************************************************************/
    /*  We need to get the next n clips and clip them to the current form     */
    /*  clips.  If they intersect, then plug them into the DCIData.           */
    /**************************************************************************/
    while (TRUE)
    {

        /**********************************************************************/
        /*  ircStart enumerates the clip we want from the engine out of all   */
        /*  the active clips.                                                 */
        /**********************************************************************/
        Control.ircStart = ++DCIData->DCIClipIndex;

        /**********************************************************************/
        /*  Call the engine to get the next clip rectangle (in device         */
        /*  coordinates but in LONG format).                                  */
        /**********************************************************************/
        TRACE4(TFUNC, "Control", &Control, 2);
        result = GreGetClipRects(DCIData->DcH, pBoundRect, &Control,
                                 &NextClipRect); /* PD00267...                */

        /**********************************************************************/
        /*  PD00267 :  Hmmm... here we need to see if the engine told us there*/
        /*  were no clips returned.  If there were none returned, we need to  */
        /*  return but in such a way as to identify whether or not the        */
        /*  requested clip was actually put into the cache or not.            */
        /*                                                                    */
        /*  PD00305: If we received an error from the engine or we didn't get */
        /*  any clips, let's get out of here.                                 */
        /**********************************************************************/
        if ((result != OK) || (Control.crcReturned == 0))
        {
            return;
        }

        /**********************************************************************/
        /*  Cast clip rectangle to word length coordinates.  (The clip        */
        /*  rectangle has been passed as device coordinates)                  */
        /**********************************************************************/
        NextClip[0].X = (USHORT)NextClipRect.xLeft;
        NextClip[0].Y = (USHORT)NextClipRect.yBottom;
        NextClip[1].X = (USHORT)NextClipRect.xRight;
        NextClip[1].Y = (USHORT)NextClipRect.yTop;

        /**********************************************************************/
        /*  Check for an intersect with the current form clip region and if   */
        /*  there is none do not store clip rectangle.  If this is a memory DC*/
        /*  then we should not be using any form clip region.                 */
        /**********************************************************************/
        if (DCIData->DCIDCType != OD_MEMORY)
        {
            if (OK != prdi_ClipIntSect(
                      (DevRect  *)DCIData->DCIPdbInstance->FormClipRegion,
                      (DevRect  *)NextClip))
            {
                continue;
            }
        }

        /**********************************************************************/
        /*  Check for an intersect with the current band and if there is none */
        /*  do not store clip rectangle.                                      */
        /**********************************************************************/
        if (OK != prdi_ClipIntSect(
                  (DevRect  *)DCIData->DCICurrBand.BDCoords,
                  (DevRect  *)NextClip))
        {
            continue;
        }

        /**********************************************************************/
        /*  Now save the rectangle in the array held in the DC instance Data  */
        /*  (adjusting for the DC Origin).  PD00170 : Use local variable i to */
        /*  store clip rectangles.                                            */
        /**********************************************************************/
        i = DCIData->DCIClipsInCache++;
        DCIData->DCIClipRects[i].X0   = NextClip[0].X - DCIData->DCIOrigin.X;
        DCIData->DCIClipRects[i].Y0   = NextClip[0].Y - DCIData->DCIOrigin.Y;
        DCIData->DCIClipRects[i].X1   = NextClip[1].X - DCIData->DCIOrigin.X;
        DCIData->DCIClipRects[i].Y1   = NextClip[1].Y - DCIData->DCIOrigin.Y;
        DCIData->DCIClipRects[i].YRaw = NextClip[1].Y;
        if (DCIData->DCIClipsInCache == MAX_CLIP_RECTS)
        {
            return;
        }
    }
}
#undef TFUNC
