316 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			316 lines
		
	
	
		
			7.6 KiB
		
	
	
	
		
			C
		
	
	
	
| /* $XFree86: xc/programs/Xserver/mi/midash.c,v 1.4 2001/12/14 20:00:21 dawes Exp $ */
 | |
| /***********************************************************
 | |
| 
 | |
| Copyright 1987, 1998  The Open Group
 | |
| 
 | |
| Permission to use, copy, modify, distribute, and sell this software and its
 | |
| documentation for any purpose is hereby granted without fee, provided that
 | |
| the above copyright notice appear in all copies and that both that
 | |
| copyright notice and this permission notice appear in supporting
 | |
| documentation.
 | |
| 
 | |
| The above copyright notice and this permission notice shall be included in
 | |
| all copies or substantial portions of the Software.
 | |
| 
 | |
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | |
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | |
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
 | |
| OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
 | |
| AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 | |
| CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 | |
| 
 | |
| Except as contained in this notice, the name of The Open Group shall not be
 | |
| used in advertising or otherwise to promote the sale, use or other dealings
 | |
| in this Software without prior written authorization from The Open Group.
 | |
| 
 | |
| 
 | |
| Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
 | |
| 
 | |
|                         All Rights Reserved
 | |
| 
 | |
| Permission to use, copy, modify, and distribute this software and its 
 | |
| documentation for any purpose and without fee is hereby granted, 
 | |
| provided that the above copyright notice appear in all copies and that
 | |
| both that copyright notice and this permission notice appear in 
 | |
| supporting documentation, and that the name of Digital not be
 | |
| used in advertising or publicity pertaining to distribution of the
 | |
| software without specific, written prior permission.  
 | |
| 
 | |
| DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
 | |
| ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
 | |
| DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
 | |
| ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
 | |
| WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
 | |
| ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
 | |
| SOFTWARE.
 | |
| 
 | |
| ******************************************************************/
 | |
| /* $Xorg: midash.c,v 1.4 2001/02/09 02:05:20 xorgcvs Exp $ */
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include "regionstr.h"
 | |
| #include "mistruct.h"
 | |
| #include "mifpoly.h"
 | |
| 
 | |
| static miDashPtr CheckDashStorage(miDashPtr *ppseg, int nseg, int *pnsegMax);
 | |
| 
 | |
| /* return a list of DashRec.  there will be an extra
 | |
| entry at the end holding the last point of the polyline.
 | |
|    this means that the code that actually draws dashes can
 | |
| get a pair of points for every dash.  only the point in the last
 | |
| dash record is useful; the other fields are not used.
 | |
|    nseg is the number of segments, not the number of points.
 | |
| 
 | |
| example:
 | |
| 
 | |
|    dash1.start
 | |
|    dash2.start
 | |
|    dash3.start
 | |
|    last-point
 | |
| 
 | |
| defines a list of segments
 | |
|    (dash1.pt, dash2.pt)
 | |
|    (dash2.pt, dash3.pt)
 | |
|    (dash3.pt, last-point)
 | |
| and nseg == 3.
 | |
| 
 | |
| NOTE:
 | |
|     EVEN_DASH == ~ODD_DASH
 | |
| 
 | |
| NOTE ALSO:
 | |
|     miDashLines may return 0 segments, going from pt[0] to pt[0] with one dash.
 | |
| */
 | |
| 
 | |
| miDashPtr
 | |
| miDashLine(npt, ppt, nDash, pDash, offset, pnseg)
 | |
| int npt;
 | |
| DDXPointPtr ppt;
 | |
| unsigned int nDash;
 | |
| unsigned char *pDash;
 | |
| unsigned int offset;
 | |
| int *pnseg;
 | |
| {
 | |
|     DDXPointRec pt1, pt2;
 | |
|     int lenCur;		/* npt used from this dash */
 | |
|     int lenMax;		/* npt in this dash */
 | |
|     int iDash = 0;	/* index of current dash */
 | |
|     int which;		/* EVEN_DASH or ODD_DASH */
 | |
|     miDashPtr pseg;	/* list of dash segments */
 | |
|     miDashPtr psegBase;	/* start of list */
 | |
|     int nseg = 0;	/* number of dashes so far */
 | |
|     int nsegMax = 0;	/* num segs we can fit in this list */
 | |
| 
 | |
|     int x, y, len;
 | |
|     int adx, ady, signdx, signdy;
 | |
|     int du, dv, e1, e2, e, base_e = 0;
 | |
| 
 | |
|     lenCur = offset;
 | |
|     which = EVEN_DASH;
 | |
|     while(lenCur >= pDash[iDash])
 | |
|     {
 | |
| 	lenCur -= pDash[iDash];
 | |
| 	iDash++;
 | |
| 	if (iDash >= nDash)
 | |
| 	    iDash = 0;
 | |
| 	which = ~which;
 | |
|     }
 | |
|     lenMax = pDash[iDash];
 | |
| 
 | |
|     psegBase = (miDashPtr)NULL;
 | |
|     pt2 = ppt[0];		/* just in case there is only one point */
 | |
| 
 | |
|     while(--npt)
 | |
|     {
 | |
| 	if (PtEqual(ppt[0], ppt[1]))
 | |
| 	{
 | |
| 	    ppt++;
 | |
| 	    continue;		/* no duplicated points in polyline */
 | |
| 	}
 | |
| 	pt1 = *ppt++;
 | |
| 	pt2 = *ppt;
 | |
| 
 | |
| 	adx = pt2.x - pt1.x;
 | |
| 	ady = pt2.y - pt1.y;
 | |
| 	signdx = sign(adx);
 | |
| 	signdy = sign(ady);
 | |
| 	adx = abs(adx);
 | |
| 	ady = abs(ady);
 | |
| 
 | |
| 	if (adx > ady)
 | |
| 	{
 | |
| 	    du = adx;
 | |
| 	    dv = ady;
 | |
| 	    len = adx;
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    du = ady;
 | |
| 	    dv = adx;
 | |
| 	    len = ady;
 | |
| 	}
 | |
| 
 | |
| 	e1 = dv * 2;
 | |
| 	e2 = e1 - 2*du;
 | |
| 	e = e1 - du;
 | |
| 	x = pt1.x;
 | |
| 	y = pt1.y;
 | |
| 
 | |
| 	nseg++;
 | |
| 	pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
 | |
| 	if (!pseg)
 | |
| 	    return (miDashPtr)NULL;
 | |
| 	pseg->pt = pt1;
 | |
| 	pseg->e1 = e1;
 | |
| 	pseg->e2 = e2;
 | |
| 	base_e = pseg->e = e;
 | |
| 	pseg->which = which;
 | |
| 	pseg->newLine = 1;
 | |
| 
 | |
| 	while (len--)
 | |
| 	{
 | |
| 	    if (adx > ady)
 | |
| 	    {
 | |
| 		/* X_AXIS */
 | |
| 		if (((signdx > 0) && (e < 0)) ||
 | |
| 		    ((signdx <=0) && (e <=0))
 | |
| 		   )
 | |
| 		{
 | |
| 		    e += e1;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 		    y += signdy;
 | |
| 		    e += e2;
 | |
| 		}
 | |
| 		x += signdx;
 | |
| 	    }
 | |
| 	    else
 | |
| 	    {
 | |
| 		/* Y_AXIS */
 | |
| 		if (((signdx > 0) && (e < 0)) ||
 | |
| 		    ((signdx <=0) && (e <=0))
 | |
| 		   )
 | |
| 		{
 | |
| 		    e +=e1;
 | |
| 		}
 | |
| 		else
 | |
| 		{
 | |
| 		    x += signdx;
 | |
| 		    e += e2;
 | |
| 		}
 | |
| 		y += signdy;
 | |
| 	    }
 | |
| 
 | |
| 	    lenCur++;
 | |
| 	    if (lenCur >= lenMax && (len || npt <= 1))
 | |
| 	    {
 | |
| 		nseg++;
 | |
| 		pseg = CheckDashStorage(&psegBase, nseg, &nsegMax);
 | |
| 		if (!pseg)
 | |
| 		    return (miDashPtr)NULL;
 | |
| 		pseg->pt.x = x;
 | |
| 		pseg->pt.y = y;
 | |
| 		pseg->e1 = e1;
 | |
| 		pseg->e2 = e2;
 | |
| 		pseg->e = e;
 | |
| 		which = ~which;
 | |
| 		pseg->which = which;
 | |
| 		pseg->newLine = 0;
 | |
| 
 | |
| 		/* move on to next dash */
 | |
| 		iDash++;
 | |
| 		if (iDash >= nDash)
 | |
| 		    iDash = 0;
 | |
| 		lenMax = pDash[iDash];
 | |
| 		lenCur = 0;
 | |
| 	    }
 | |
| 	} /* while len-- */
 | |
|     } /* while --npt */
 | |
| 
 | |
|     if (lenCur == 0 && nseg != 0)
 | |
|     {
 | |
| 	nseg--;
 | |
| 	which = ~which;
 | |
|     }
 | |
|     *pnseg = nseg;
 | |
|     pseg = CheckDashStorage(&psegBase, nseg+1, &nsegMax);
 | |
|     if (!pseg)
 | |
| 	return (miDashPtr)NULL;
 | |
|     pseg->pt = pt2;
 | |
|     pseg->e = base_e;
 | |
|     pseg->which = which;
 | |
|     pseg->newLine = 0;
 | |
|     return psegBase;
 | |
| } 
 | |
| 
 | |
| 
 | |
| #define NSEGDELTA 16
 | |
| 
 | |
| /* returns a pointer to the pseg[nseg-1], growing the storage as
 | |
| necessary.  this interface seems unnecessarily cumbersome.
 | |
| 
 | |
| */
 | |
| 
 | |
| static
 | |
| miDashPtr
 | |
| CheckDashStorage(
 | |
|     miDashPtr *ppseg,		/* base pointer */
 | |
|     int nseg,			/* number of segment we want to write to */
 | |
|     int *pnsegMax)		/* size (in segments) of list so far */
 | |
| {
 | |
|     if (nseg > *pnsegMax)
 | |
|     {
 | |
| 	miDashPtr newppseg;
 | |
| 
 | |
| 	*pnsegMax += NSEGDELTA;
 | |
| 	newppseg = (miDashPtr)xrealloc(*ppseg,
 | |
| 				       (*pnsegMax)*sizeof(miDashRec));
 | |
| 	if (!newppseg)
 | |
| 	{
 | |
| 	    xfree(*ppseg);
 | |
| 	    return (miDashPtr)NULL;
 | |
| 	}
 | |
| 	*ppseg = newppseg;
 | |
|     }
 | |
|     return(*ppseg+(nseg-1));
 | |
| }
 | |
| 
 | |
| _X_EXPORT void
 | |
| miStepDash (dist, pDashIndex, pDash, numInDashList, pDashOffset)
 | |
|     int dist;			/* distance to step */
 | |
|     int *pDashIndex;		/* current dash */
 | |
|     unsigned char *pDash;	/* dash list */
 | |
|     int numInDashList;		/* total length of dash list */
 | |
|     int *pDashOffset;		/* offset into current dash */
 | |
| {
 | |
|     int	dashIndex, dashOffset;
 | |
|     int totallen;
 | |
|     int	i;
 | |
|     
 | |
|     dashIndex = *pDashIndex;
 | |
|     dashOffset = *pDashOffset;
 | |
|     if (dist < pDash[dashIndex] - dashOffset)
 | |
|     {
 | |
| 	*pDashOffset = dashOffset + dist;
 | |
| 	return;
 | |
|     }
 | |
|     dist -= pDash[dashIndex] - dashOffset;
 | |
|     if (++dashIndex == numInDashList)
 | |
| 	dashIndex = 0;
 | |
|     totallen = 0;
 | |
|     for (i = 0; i < numInDashList; i++)
 | |
| 	totallen += pDash[i];
 | |
|     if (totallen <= dist)
 | |
| 	dist = dist % totallen;
 | |
|     while (dist >= pDash[dashIndex])
 | |
|     {
 | |
| 	dist -= pDash[dashIndex];
 | |
| 	if (++dashIndex == numInDashList)
 | |
| 	    dashIndex = 0;
 | |
|     }
 | |
|     *pDashIndex = dashIndex;
 | |
|     *pDashOffset = dist;
 | |
| }
 |