437 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			437 lines
		
	
	
		
			10 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Copyright © 2004 David Reveman
 | |
|  * 
 | |
|  * 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, and that the name of
 | |
|  * David Reveman not be used in advertising or publicity pertaining to
 | |
|  * distribution of the software without specific, written prior permission.
 | |
|  * David Reveman makes no representations about the suitability of this
 | |
|  * software for any purpose. It is provided "as is" without express or
 | |
|  * implied warranty.
 | |
|  *
 | |
|  * DAVID REVEMAN DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
 | |
|  * NO EVENT SHALL DAVID REVEMAN 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.
 | |
|  *
 | |
|  * Author: David Reveman <davidr@novell.com>
 | |
|  */
 | |
| 
 | |
| #include "xgl.h"
 | |
| #include "gcstruct.h"
 | |
| #include "fb.h"
 | |
| 
 | |
| Bool
 | |
| xglFill (DrawablePtr	pDrawable,
 | |
| 	 GCPtr		pGC,
 | |
| 	 xglGeometryPtr pGeometry,
 | |
| 	 int	  	x,
 | |
| 	 int		y,
 | |
| 	 int		width,
 | |
| 	 int		height,
 | |
| 	 BoxPtr		pBox,
 | |
| 	 int		nBox)
 | |
| {
 | |
|     XGL_GC_PRIV (pGC);
 | |
| 
 | |
|     switch (pGC->fillStyle) {
 | |
|     case FillSolid:
 | |
| 	if (xglSolid (pDrawable,
 | |
| 		      pGCPriv->op, &pGCPriv->fg,
 | |
| 		      pGeometry,
 | |
| 		      x, y,
 | |
| 		      width, height,
 | |
| 		      pBox, nBox))
 | |
| 	    return TRUE;
 | |
| 	break;
 | |
|     case FillStippled:
 | |
|     case FillOpaqueStippled:
 | |
| 	break;
 | |
|     case FillTiled:
 | |
| 	if (xglTile (pDrawable,
 | |
| 		     pGCPriv->op, pGC->tile.pixmap,
 | |
| 		     -(pGC->patOrg.x + pDrawable->x),
 | |
| 		     -(pGC->patOrg.y + pDrawable->y),
 | |
| 		     pGeometry,
 | |
| 		     x, y,
 | |
| 		     width, height,
 | |
| 		     pBox, nBox))
 | |
| 	    return TRUE;
 | |
| 	break;
 | |
|     }
 | |
| 
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| #define N_STACK_BOX 1024
 | |
| 
 | |
| static BoxPtr
 | |
| xglMoreBoxes (BoxPtr stackBox,
 | |
| 	      BoxPtr heapBox,
 | |
| 	      int    nBoxes)
 | |
| {
 | |
|     Bool stack = !heapBox;
 | |
| 	
 | |
|     heapBox = xrealloc (heapBox, sizeof (BoxRec) * nBoxes);
 | |
|     if (!heapBox)
 | |
| 	return NULL;
 | |
|     
 | |
|     if (stack)
 | |
| 	memcpy (heapBox, stackBox, sizeof (BoxRec) * N_STACK_BOX);
 | |
| 
 | |
|     return heapBox;
 | |
| }
 | |
| 
 | |
| #define ADD_BOX(pBox, nBox, stackBox, heapBox, size, box)	\
 | |
|     {								\
 | |
| 	if ((nBox) == (size))					\
 | |
| 	{							\
 | |
| 	    (size) *= 2;					\
 | |
| 	    (heapBox) = xglMoreBoxes (stackBox, heapBox, size);	\
 | |
| 	    if (!(heapBox))					\
 | |
| 		return;						\
 | |
| 	    (pBox) = (heapBox) + (nBox);			\
 | |
| 	}							\
 | |
| 	*(pBox)++ = (box);					\
 | |
| 	(nBox)++;						\
 | |
|     }
 | |
| 
 | |
| void
 | |
| xglFillRect (DrawablePtr pDrawable, 
 | |
| 	     GCPtr	 pGC, 
 | |
| 	     int	 nrect,
 | |
| 	     xRectangle  *prect)
 | |
| {
 | |
|     RegionPtr pClip = pGC->pCompositeClip;
 | |
|     BoxPtr    pClipBox;
 | |
|     BoxPtr    pExtent = REGION_EXTENTS (pGC->pScreen, pClip);
 | |
|     BoxRec    full, part;
 | |
|     BoxPtr    heapBox = NULL;
 | |
|     BoxRec    stackBox[N_STACK_BOX];
 | |
|     int       size = N_STACK_BOX;
 | |
|     BoxPtr    pBox = stackBox;
 | |
|     int	      n, nBox = 0;
 | |
| 
 | |
|     while (nrect--)
 | |
|     {
 | |
| 	full.x1 = prect->x + pDrawable->x;
 | |
| 	full.y1 = prect->y + pDrawable->y;
 | |
| 	full.x2 = full.x1 + (int) prect->width;
 | |
| 	full.y2 = full.y1 + (int) prect->height;
 | |
| 	
 | |
| 	prect++;
 | |
| 	
 | |
| 	if (full.x1 < pExtent->x1)
 | |
| 	    full.x1 = pExtent->x1;
 | |
| 
 | |
| 	if (full.y1 < pExtent->y1)
 | |
| 	    full.y1 = pExtent->y1;
 | |
| 	
 | |
| 	if (full.x2 > pExtent->x2)
 | |
| 	    full.x2 = pExtent->x2;
 | |
| 	
 | |
| 	if (full.y2 > pExtent->y2)
 | |
| 	    full.y2 = pExtent->y2;
 | |
| 	
 | |
| 	if (full.x1 >= full.x2 || full.y1 >= full.y2)
 | |
| 	    continue;
 | |
| 	
 | |
| 	n = REGION_NUM_RECTS (pClip);
 | |
| 
 | |
| 	if (n == 1)
 | |
| 	{
 | |
| 	    ADD_BOX (pBox, nBox, stackBox, heapBox, size, full);
 | |
| 	}
 | |
| 	else
 | |
| 	{
 | |
| 	    pClipBox = REGION_RECTS (pClip);
 | |
| 
 | |
| 	    while (n--)
 | |
| 	    {
 | |
| 		part.x1 = pClipBox->x1;
 | |
| 		if (part.x1 < full.x1)
 | |
| 		    part.x1 = full.x1;
 | |
| 		
 | |
| 		part.y1 = pClipBox->y1;
 | |
| 		if (part.y1 < full.y1)
 | |
| 		    part.y1 = full.y1;
 | |
| 		
 | |
| 		part.x2 = pClipBox->x2;
 | |
| 		if (part.x2 > full.x2)
 | |
| 		    part.x2 = full.x2;
 | |
| 		
 | |
| 		part.y2 = pClipBox->y2;
 | |
| 		if (part.y2 > full.y2)
 | |
| 		    part.y2 = full.y2;
 | |
|     
 | |
| 		pClipBox++;
 | |
| 		
 | |
| 		if (part.x1 < part.x2 && part.y1 < part.y2)
 | |
| 		    ADD_BOX (pBox, nBox, stackBox, heapBox, size, part);
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| 
 | |
|     if (!nBox)
 | |
| 	return;
 | |
|     
 | |
|     pBox = (heapBox) ? heapBox : stackBox;
 | |
| 
 | |
|     if (!xglFill (pDrawable, pGC, NULL,
 | |
| 		  pExtent->x1, pExtent->y1,
 | |
| 		  pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1,
 | |
| 		  pBox, nBox))
 | |
|     {
 | |
| 	RegionRec	region;
 | |
| 	RegionPtr       pDamageRegion;
 | |
| 	glitz_surface_t *surface;
 | |
| 	int             xOff, yOff;
 | |
| 
 | |
| 	XGL_DRAWABLE_PIXMAP (pDrawable);
 | |
| 	XGL_PIXMAP_PRIV (pPixmap);
 | |
| 
 | |
| 	if (!xglMapPixmapBits (pPixmap))
 | |
| 	    FatalError (XGL_SW_FAILURE_STRING);
 | |
| 
 | |
| 	switch (pGC->fillStyle) {
 | |
| 	case FillSolid:
 | |
| 	    break;
 | |
| 	case FillStippled:
 | |
| 	case FillOpaqueStippled:
 | |
| 	    if (!xglSyncBits (&pGC->stipple->drawable, NullBox))
 | |
| 		FatalError (XGL_SW_FAILURE_STRING);
 | |
| 	    break;
 | |
| 	case FillTiled:
 | |
| 	    if (!xglSyncBits (&pGC->tile.pixmap->drawable, NullBox))
 | |
| 		FatalError (XGL_SW_FAILURE_STRING);
 | |
| 	    break;
 | |
| 	}
 | |
| 
 | |
| 	pDamageRegion = DamageRegion (pPixmapPriv->pDamage);
 | |
| 	
 | |
| 	XGL_GET_DRAWABLE (pDrawable, surface, xOff, yOff);
 | |
| 	
 | |
| 	pPixmapPriv->damageBox = miEmptyBox;
 | |
| 	
 | |
| 	while (nBox--)
 | |
| 	{
 | |
| 	    fbFill (pDrawable, pGC,
 | |
| 		    pBox->x1, pBox->y1,
 | |
| 		    pBox->x2 - pBox->x1, pBox->y2 - pBox->y1);
 | |
| 
 | |
| 	    if (pPixmapPriv->format)
 | |
| 	    {
 | |
| 		part.x1 = pBox->x1 + xOff;
 | |
| 		part.y1 = pBox->y1 + yOff;
 | |
| 		part.x2 = pBox->x2 + xOff;
 | |
| 		part.y2 = pBox->y2 + yOff;
 | |
| 		
 | |
| 		REGION_INIT (pDrawable->pScreen, ®ion, &part, 1);
 | |
| 		REGION_UNION (pDrawable->pScreen,
 | |
| 			      pDamageRegion, pDamageRegion, ®ion);
 | |
| 		REGION_UNINIT (pDrawable->pScreen, ®ion);
 | |
| 	    }
 | |
| 	    
 | |
| 	    pBox++;
 | |
| 	}
 | |
|     } else
 | |
| 	xglAddCurrentBitDamage (pDrawable);
 | |
| 
 | |
|     if (heapBox)
 | |
| 	xfree (heapBox);
 | |
| }
 | |
| 
 | |
| Bool
 | |
| xglFillSpan (DrawablePtr pDrawable,
 | |
| 	     GCPtr	 pGC,
 | |
| 	     int	 n,
 | |
| 	     DDXPointPtr ppt,
 | |
| 	     int	 *pwidth)
 | |
| {
 | |
|     BoxPtr	   pExtent;
 | |
|     xglGeometryPtr pGeometry;
 | |
| 
 | |
|     if (n < 1)
 | |
| 	return TRUE;
 | |
| 
 | |
|     pExtent = REGION_EXTENTS (pDrawable->pScreen, pGC->pCompositeClip);
 | |
| 
 | |
|     pGeometry = xglGetScratchVertexGeometry (pGC->pScreen, 2 * n);
 | |
|     
 | |
|     GEOMETRY_ADD_SPAN (pGC->pScreen, pGeometry, ppt, pwidth, n);
 | |
| 
 | |
|     /* Spans are treated as lines so they need a 0.5 translate */
 | |
|     GEOMETRY_TRANSLATE_FIXED (pGeometry, 1 << 15, 1 << 15);
 | |
|     GEOMETRY_SET_VERTEX_PRIMITIVE (pGeometry, GLITZ_PRIMITIVE_LINES);
 | |
| 
 | |
|     if (xglFill (pDrawable, pGC, pGeometry,
 | |
| 		 pExtent->x1, pExtent->y1,
 | |
| 		 pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1,
 | |
| 		 REGION_RECTS (pGC->pCompositeClip),
 | |
| 		 REGION_NUM_RECTS (pGC->pCompositeClip)))
 | |
| 	return TRUE;
 | |
|     
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| xglFillLine (DrawablePtr pDrawable,
 | |
| 	     GCPtr       pGC,
 | |
| 	     int	 mode,
 | |
| 	     int	 npt,
 | |
| 	     DDXPointPtr ppt)
 | |
| {
 | |
|     BoxPtr	   pExtent;
 | |
|     xglGeometryPtr pGeometry;
 | |
|     Bool	   coincident_endpoints;
 | |
| 
 | |
|     if (npt < 2)
 | |
| 	return TRUE;
 | |
|     
 | |
|     pExtent = REGION_EXTENTS (pDrawable->pScreen, pGC->pCompositeClip);
 | |
| 
 | |
|     coincident_endpoints = FALSE;
 | |
|     if (mode == CoordModePrevious)
 | |
|     {
 | |
| 	DDXPointPtr pptTmp;
 | |
| 	int	    nptTmp;
 | |
| 	DDXPointRec pt;
 | |
| 
 | |
| 	pt = *ppt;
 | |
| 	
 | |
| 	nptTmp = npt - 1;
 | |
| 	pptTmp = ppt + 1;
 | |
| 
 | |
| 	while (nptTmp--)
 | |
| 	{
 | |
| 	    pt.x += pptTmp->x;
 | |
| 	    pt.y += pptTmp->y;
 | |
| 	    
 | |
| 	    pptTmp++;
 | |
| 	}
 | |
| 	
 | |
| 	if (pt.x == ppt->x && pt.y == ppt->y)
 | |
| 	    coincident_endpoints = TRUE;
 | |
|     }
 | |
|     else
 | |
|     {
 | |
| 	if (ppt[npt - 1].x == ppt->x && ppt[npt - 1].y == ppt->y)
 | |
| 	    coincident_endpoints = TRUE;
 | |
|     }
 | |
| 
 | |
|     if (coincident_endpoints)
 | |
| 	npt--;
 | |
| 
 | |
|     pGeometry = xglGetScratchVertexGeometry (pGC->pScreen, npt);
 | |
|     
 | |
|     GEOMETRY_ADD_LINE (pGC->pScreen, pGeometry,
 | |
| 		       coincident_endpoints, mode, npt, ppt);
 | |
| 
 | |
|     if (coincident_endpoints)
 | |
| 	GEOMETRY_SET_VERTEX_PRIMITIVE (pGeometry, GLITZ_PRIMITIVE_LINE_LOOP);
 | |
|     else
 | |
| 	GEOMETRY_SET_VERTEX_PRIMITIVE (pGeometry, GLITZ_PRIMITIVE_LINE_STRIP);
 | |
| 
 | |
|     /* Lines need a 0.5 translate */
 | |
|     GEOMETRY_TRANSLATE_FIXED (pGeometry, 1 << 15, 1 << 15);
 | |
|     
 | |
|     GEOMETRY_TRANSLATE (pGeometry, pDrawable->x, pDrawable->y);
 | |
| 
 | |
|     pExtent = REGION_EXTENTS (pDrawable->pScreen, pGC->pCompositeClip);
 | |
| 	
 | |
|     if (xglFill (pDrawable, pGC, pGeometry,
 | |
| 		 pExtent->x1, pExtent->y1,
 | |
| 		 pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1,
 | |
| 		 REGION_RECTS (pGC->pCompositeClip),
 | |
| 		 REGION_NUM_RECTS (pGC->pCompositeClip)))
 | |
| 	return TRUE;
 | |
|     
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| xglFillSegment (DrawablePtr pDrawable,
 | |
| 		GCPtr	    pGC, 
 | |
| 		int	    nsegInit,
 | |
| 		xSegment    *pSegInit)
 | |
| {
 | |
|     BoxPtr	   pExtent;
 | |
|     xglGeometryPtr pGeometry;
 | |
| 
 | |
|     if (nsegInit < 1)
 | |
| 	return TRUE;
 | |
| 
 | |
|     pExtent = REGION_EXTENTS (pDrawable->pScreen, pGC->pCompositeClip);
 | |
| 
 | |
|     pGeometry = xglGetScratchVertexGeometry (pGC->pScreen, 2 * nsegInit);
 | |
| 	
 | |
|     GEOMETRY_ADD_SEGMENT (pGC->pScreen, pGeometry, nsegInit, pSegInit);
 | |
| 
 | |
|     /* Line segments need 0.5 translate */
 | |
|     GEOMETRY_TRANSLATE_FIXED (pGeometry, 1 << 15, 1 << 15);
 | |
|     GEOMETRY_SET_VERTEX_PRIMITIVE (pGeometry, GLITZ_PRIMITIVE_LINES);
 | |
|     
 | |
|     GEOMETRY_TRANSLATE (pGeometry, pDrawable->x, pDrawable->y);
 | |
| 	
 | |
|     if (xglFill (pDrawable, pGC, pGeometry,
 | |
| 		 pExtent->x1, pExtent->y1,
 | |
| 		 pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1,
 | |
| 		 REGION_RECTS (pGC->pCompositeClip),
 | |
| 		 REGION_NUM_RECTS (pGC->pCompositeClip)))
 | |
| 	return TRUE;
 | |
|     
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| Bool
 | |
| xglFillGlyph (DrawablePtr  pDrawable,
 | |
| 	      GCPtr	   pGC,
 | |
| 	      int	   x,
 | |
| 	      int	   y,
 | |
| 	      unsigned int nGlyph,
 | |
| 	      CharInfoPtr  *ppci,
 | |
| 	      pointer      pglyphBase)
 | |
| {
 | |
|     BoxPtr	   pExtent;
 | |
|     xglGeometryRec geometry;
 | |
| 
 | |
|     if (nGlyph < 1)
 | |
| 	return TRUE;
 | |
| 
 | |
|     pExtent = REGION_EXTENTS (pDrawable->pScreen, pGC->pCompositeClip);
 | |
| 
 | |
|     x += pDrawable->x;
 | |
|     y += pDrawable->y;
 | |
| 
 | |
|     GEOMETRY_INIT (pDrawable->pScreen, &geometry,
 | |
| 		   GLITZ_GEOMETRY_TYPE_BITMAP,
 | |
| 		   GEOMETRY_USAGE_SYSMEM, 0);
 | |
| 
 | |
|     GEOMETRY_FOR_GLYPH (pDrawable->pScreen,
 | |
| 			&geometry,
 | |
| 			nGlyph,
 | |
| 			ppci,
 | |
| 			pglyphBase);
 | |
| 
 | |
|     GEOMETRY_TRANSLATE (&geometry, x, y);
 | |
| 
 | |
|     if (xglFill (pDrawable, pGC, &geometry,
 | |
| 		 pExtent->x1, pExtent->y1,
 | |
| 		 pExtent->x2 - pExtent->x1, pExtent->y2 - pExtent->y1,
 | |
| 		 REGION_RECTS (pGC->pCompositeClip),
 | |
| 		 REGION_NUM_RECTS (pGC->pCompositeClip)))
 | |
|     {
 | |
| 	GEOMETRY_UNINIT (&geometry);
 | |
| 	return TRUE;
 | |
|     }
 | |
|     
 | |
|     GEOMETRY_UNINIT (&geometry);
 | |
|     return FALSE;
 | |
| }
 |