/********************************************************************
*   DrvRegions.c
*
*   Macintosh device specific region implementation.
*
*   Copyright (c) 1994-1997, Willows Software Inc.  All rights reserved.
*
********************************************************************/

static char *DrvRegions_c =  "IDENT:  @(#)DrvRegions.c	1.5 7/11/96 12:05:21";

#include "DrvRegions.h"
#include "DeviceData.h"
#include "DrvUtils.h"
#include "Log.h"


/* Local prototypes */
DWORD DrvCreateRectRegion(LPRECT lpRect);
static DWORD DrvUnionRectWithRegion(RgnHandle theRgn, LPRECT lpRect);	
static DWORD DrvCreatePolyRegion(LPARAM numPts, LPVOID ptArray);
static DWORD DrvCreateEllipticRegion(LPPOINT lpArc);
static DWORD DrvCreateRoundRectRegion(LPPOINT lpArc);

RgnHandle gRgnCache = NULL;
int gRgnCacheLock = 0;

/********************************************************************
* PrivateRegionsHook
*	
********************************************************************/
DWORD PrivateRegionsHook(WORD wFunc, LPARAM dwParm1, LPARAM dwParm2, LPVOID lpStruct)
{
LPRECT lpRect;
LPPOINT lppt;
Rect macR;
Point macPt;
RgnHandle hRgn;

    switch (wFunc) {
    /* (dwParm2)?INITIALIZE:DEINITIALIZE */
	case DSUBSYSTEM_INIT:
		if (dwParm2 == 1)
			gRgnCache = NewRgn();
		return (DWORD)TRUE;

	case DSUBSYSTEM_GETCAPS:
	    return (DWORD) (RSUB_CANDO_RECT 			| 
	    						  RSUB_CANDO_ROUNDRECT 	| 
	    						  RSUB_CANDO_ELLIPTIC);

	case DSUBSYSTEM_EVENTS:
	    return (DWORD)0;


	/* lpStruct - pointer to RECT */
	case PRH_CREATERECTREGION:
	    return DrvCreateRectRegion((LPRECT)lpStruct);


	/* no parameters */
	case PRH_CREATEREGION:	
		hRgn = NewRgn();
	    return((DWORD)hRgn);
		
		
	/* dwParm1 - Region to set empty */
	case PRH_SETREGIONEMPTY:
		SetEmptyRgn((RgnHandle) dwParm1);
	    return (DWORD)NULLREGION;			


	/* dwParm1 - Region to destroy */
	case PRH_DESTROYREGION:
		if ((gRgnCacheLock != 0) && (((RgnHandle)dwParm1) == gRgnCache))
			gRgnCacheLock = 0;
		else
			DisposeRgn((RgnHandle) dwParm1);
	    return (DWORD)SIMPLEREGION;


	/* dwParm1 - Region to set */
	/* lpStruct - pointer to RECT */
	case PRH_SETRECTREGION:
	    if (!(lpRect = (LPRECT)lpStruct))
			return (DWORD)ERROR;

		WINRECT2MACRECT(lpRect, &macR);	/* Map the windows rect to platform rect. */	
	
		/* Call mac implementation. */
		RectRgn((RgnHandle) dwParm1, &macR);
	    return (DWORD)SIMPLEREGION;


	/* dwParm1 - Region to union */
	/* lpStruct - pointer to RECT */
	case PRH_UNIONRECTWITHREGION:
		return DrvUnionRectWithRegion((RgnHandle) dwParm1, (LPRECT)lpStruct);


	/* dwParm1 - Region to offset */
	/* lpStruct - pointer to POINT */
	case PRH_OFFSETREGION:
	    if (!(lppt = (LPPOINT)lpStruct))
			return (DWORD)ERROR;
			
		OffsetRgn((RgnHandle)dwParm1, lppt->x, lppt->y);
	
		return (DWORD)COMPLEXREGION;

	/* dwParm1 - Region to test */
	/* lpStruct - pointer to POINT */
	case PRH_PTINREGION:
		if (!(lppt = (LPPOINT)lpStruct))
			return (DWORD)ERROR;
		
		macPt.h = lppt->x;
		macPt.v = lppt->y;
	
		return(DWORD)PtInRgn(macPt, (RgnHandle)dwParm1);


	/* dwParm1 - Region to test */
	/* lpStruct - pointer to RECT */
	case PRH_RECTINREGION:
	    if (!(lpRect = (LPRECT)lpStruct))
			return (DWORD)ERROR;

		WINRECT2MACRECT(lpRect, &macR);	/* Map the windows rect to platform rect. */	
			
		return (DWORD)RectInRgn(&macR, (RgnHandle)dwParm1);


	/* dwParm1 - first Region to compare */
	/* dwParm2 - second Region to compare */
	case PRH_EQUALREGION:
		return (DWORD)EqualRgn((RgnHandle) dwParm1, (RgnHandle) dwParm2);


	/* dwParm1 - number of points in the polygon */
	/* dwParm2 - polygon-filling mode */
	/* lpStruct - address of array of XPoints */
	case PRH_CREATEPOLYREGION:
	    if (!(lppt = (LPPOINT)lpStruct))
			return(ERROR);

	    return (DWORD)DrvCreatePolyRegion(dwParm1, lpStruct);


	/* dwParm1 - source Region 1 */
	/* dwParm2 - source Region 2 */
	/* lpStruct - dest Region */
	case PRH_UNIONREGION:
		UnionRgn((RgnHandle) dwParm1, (RgnHandle) dwParm2, (RgnHandle) lpStruct);
	
		return (DWORD)(EmptyRgn((RgnHandle) lpStruct) ? NULLREGION : COMPLEXREGION);
		

	/* dwParm1 - source Region 1 */
	/* dwParm2 - source Region 2 */
	/* lpStruct - dest Region */
	case PRH_INTERSECTREGION:
		SectRgn((RgnHandle) dwParm1, (RgnHandle) dwParm2, (RgnHandle) lpStruct);

		return (DWORD)(EmptyRgn((RgnHandle) lpStruct) ? NULLREGION : COMPLEXREGION);
	

	/* dwParm1 - source Region */
	/* dwParm2 - dest Region */
	case PRH_COPYREGION:
		CopyRgn((RgnHandle) dwParm1, (RgnHandle) dwParm2);

		return (DWORD)(EmptyRgn((RgnHandle) dwParm2) ? NULLREGION : COMPLEXREGION);


	/* dwParm1 - source Region 1 */
	/* dwParm2 - source Region 2 */
	/* lpStruct - dest Region */
	case PRH_DIFFREGION:
		DiffRgn((RgnHandle) dwParm1, (RgnHandle) dwParm2, (RgnHandle) lpStruct);

		return (DWORD)(EmptyRgn((RgnHandle) lpStruct) ? NULLREGION : COMPLEXREGION);


	/* dwParm1 - source Region 1 */
	/* dwParm2 - source Region 2 */
	/* lpStruct - dest Region */
	case PRH_XORREGION:
		XorRgn((RgnHandle) dwParm1, (RgnHandle) dwParm2, (RgnHandle) lpStruct);

		return (DWORD)(EmptyRgn((RgnHandle) lpStruct) ? NULLREGION : COMPLEXREGION);
				

	/* dwParm1 - Region to test */
	case PRH_ISEMPTYREGION:
		return (DWORD)EmptyRgn((RgnHandle) dwParm1);


	/* dwParm1 - Region to get bounds rect for */
	/* lpStruct - pointer to RECT */
	case PRH_REGIONBOX:
	    if (!(lpRect = (LPRECT)lpStruct))
			return (DWORD)ERROR;

	    lpRect->left = (**(RgnHandle)dwParm1).rgnBBox.left;
	    lpRect->top = (**(RgnHandle)dwParm1).rgnBBox.top;
	    lpRect->right = (**(RgnHandle)dwParm1).rgnBBox.right;
	    lpRect->bottom = (**(RgnHandle)dwParm1).rgnBBox.bottom;

	    return (DWORD)(EmptyRect(&((**(RgnHandle)dwParm1).rgnBBox)) ? NULLREGION : COMPLEXREGION);


	/* lpStruct - pointer to PGH_ARCP structure */
	case PRH_CREATEELLIPTICREGION:
	    return DrvCreateEllipticRegion((LPPOINT)((LPLSDS_PARAMS)lpStruct)->lsde.arc);

	
	/* lpStruct - pointer to PGH_ARCP structure */
	case PRH_CREATEROUNDRECTREGION:
	    return DrvCreateRoundRectRegion((LPPOINT)((LPLSDS_PARAMS)lpStruct)->lsde.arc);

	/* PRH_GETREGIONDATA
	 * dwParam1 - (REGION32) region
	 * dwParam2 - (DWORD) size of region data buffer (in bytes)
	 * lpStruct - (LPRGNDATA) region data buffer
	 */
	case PRH_GETREGIONDATA:
		ERRSTR((LF_ERR, "STUB: PRH_GETREGIONDATA\n"));
		return ((DWORD) 0);
	
	default:
	    return (DWORD)ERROR;
    }
}



/********************************************************************
* DrvCreateRectRegion
*
*  Create a new region with the specified rectangle.
********************************************************************/
DWORD DrvCreateRectRegion(LPRECT lpRect)
{
RgnHandle theRgn;
Rect macR;

	/* Verify a valid rect was passed. */
    if (!lpRect)
		return (DWORD)ERROR;

	WINRECT2MACRECT(lpRect, &macR);	/* Map the windows rect to platform rect. */	

	/* Allocate the memory, with an empty rectangle */
	if (gRgnCacheLock == 0) {
		theRgn = gRgnCache;
		gRgnCacheLock++;
	}
	else
		theRgn = NewRgn();
	
	/* Define the rectangle region, discards any previous region info */
	RectRgn(theRgn, &macR);

	return((DWORD) theRgn);
}



/********************************************************************
* DrvUnionRectWithRegion
*
*  Calculate the union of two regions (one being a rect).
*  Return true if resulting region is empty.
********************************************************************/
static DWORD DrvUnionRectWithRegion(RgnHandle theRgn, LPRECT lpRect)	
{
RgnHandle rectRgn;
Rect macR;

    if (!lpRect)
		return (DWORD)ERROR;

	WINRECT2MACRECT(lpRect, &macR);		/* Map the windows rect to mac rect. */	

	/* Create a region with the rect */
	rectRgn = NewRgn();
	RectRgn(rectRgn, &macR);
	
	/* Redefine theRgn containing the union of the two */
	UnionRgn(theRgn, rectRgn, theRgn);
	
	/* Get rid of temp region */
	DisposeRgn(rectRgn);

	/* Check to see if a region was created */
	if (EmptyRgn(theRgn))
		return(NULLREGION);
	else
		return(COMPLEXREGION);

}


/********************************************************************
* DrvCreatePolyRegion
*
*  Create a new polygon region.
********************************************************************/
static DWORD DrvCreatePolyRegion(LPARAM numPts, LPVOID ptArray)
{
RgnHandle theRgn;
LPPOINT lppt = ptArray;
short pt = 0;

	/* Allocate the memory, with an empty region */
	theRgn = NewRgn();

	/* Open a region to draw the polygon into */
	OpenRgn();
	
	/* Position at first point */
	MoveTo(lppt[pt].x, lppt[pt].y);
	
	/* Draw lines to remaining points */
	for(pt=1; pt < numPts; pt++)
		LineTo(lppt[pt].x, lppt[pt].y);
		
	/* Finish recording, save into the new region */
	CloseRgn(theRgn);
	
	return((DWORD) theRgn);
}



/********************************************************************
* DrvCreateEllipticRegion
*
*  Create a new region with the specified ellipse.
********************************************************************/
static DWORD DrvCreateEllipticRegion(LPPOINT lpArc)
{
RgnHandle theRgn;
Rect macR;

	if (!lpArc)
		return (DWORD)ERROR;


	SETRECTMAC(&macR, lpArc[0].x, lpArc[0].y, lpArc[1].x, lpArc[1].y);

	/* Allocate the memory, with an empty rectangle */
	theRgn = NewRgn();

	/* Open a region to draw the ellipse into */
	OpenRgn();
	
	/* Draw the elliptical region */
	FrameOval(&macR);

	/* Finish recording, save into the new region */
	CloseRgn(theRgn);
	
	return((DWORD) theRgn);
}



/********************************************************************
* DrvCreateRoundRectRegion
*
*  Create a new region with the specified rounded rectangle.
********************************************************************/
static DWORD DrvCreateRoundRectRegion(LPPOINT lpArc)
{
RgnHandle theRgn;
Rect macR;
short ovalW, ovalH;

    if (!lpArc)
		return (DWORD)ERROR;

	SETRECTMAC(&macR, lpArc[0].x, lpArc[0].y, lpArc[1].x, lpArc[1].y);

	ovalW = lpArc[2].x;
	ovalH = lpArc[2].y;


	/* Allocate the memory, with an empty rectangle */
	theRgn = NewRgn();

	/* Open a region to draw the round rect into */
	OpenRgn();
	
	/* Draw the rectangle region */
	FrameRoundRect(&macR, ovalW, ovalH);

	/* Finish recording, save into the new region */
	CloseRgn(theRgn);
	
	return((long) theRgn);
}



