322 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			322 lines
		
	
	
		
			7.9 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * Id: fbgc.c,v 1.1 1999/11/02 03:54:45 keithp Exp $
 | |
|  *
 | |
|  * Copyright © 1998 Keith Packard
 | |
|  *
 | |
|  * 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 Keith Packard not be used in
 | |
|  * advertising or publicity pertaining to distribution of the software without
 | |
|  * specific, written prior permission.  Keith Packard makes no
 | |
|  * representations about the suitability of this software for any purpose.  It
 | |
|  * is provided "as is" without express or implied warranty.
 | |
|  *
 | |
|  * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 | |
|  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
 | |
|  * EVENT SHALL KEITH PACKARD 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.
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_DIX_CONFIG_H
 | |
| #include <dix-config.h>
 | |
| #endif
 | |
| 
 | |
| #include <stdlib.h>
 | |
| 
 | |
| #include "fb.h"
 | |
| 
 | |
| const GCFuncs fbGCFuncs = {
 | |
|     fbValidateGC,
 | |
|     miChangeGC,
 | |
|     miCopyGC,
 | |
|     miDestroyGC,
 | |
|     miChangeClip,
 | |
|     miDestroyClip,
 | |
|     miCopyClip,
 | |
| };
 | |
| 
 | |
| const GCOps	fbGCOps = {
 | |
|     fbFillSpans,
 | |
|     fbSetSpans,
 | |
|     fbPutImage,
 | |
|     fbCopyArea,
 | |
|     fbCopyPlane,
 | |
|     fbPolyPoint,
 | |
|     fbPolyLine,
 | |
|     fbPolySegment,
 | |
|     fbPolyRectangle,
 | |
|     fbPolyArc,
 | |
|     miFillPolygon,
 | |
|     fbPolyFillRect,
 | |
|     fbPolyFillArc,
 | |
|     miPolyText8,
 | |
|     miPolyText16,
 | |
|     miImageText8,
 | |
|     miImageText16,
 | |
|     fbImageGlyphBlt,
 | |
|     fbPolyGlyphBlt,
 | |
|     fbPushPixels
 | |
| };
 | |
| 
 | |
| Bool
 | |
| fbCreateGC(GCPtr pGC)
 | |
| {
 | |
|     pGC->clientClip = NULL;
 | |
|     pGC->clientClipType = CT_NONE;
 | |
| 
 | |
|     pGC->ops = (GCOps *) &fbGCOps;
 | |
|     pGC->funcs = (GCFuncs *) &fbGCFuncs;
 | |
| 
 | |
|     /* fb wants to translate before scan conversion */
 | |
|     pGC->miTranslate = 1;
 | |
| 
 | |
|     fbGetRotatedPixmap(pGC) = 0;
 | |
|     fbGetExpose(pGC) = 1;
 | |
|     fbGetFreeCompClip(pGC) = 0;
 | |
|     fbGetCompositeClip(pGC) = 0;
 | |
|     fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Pad pixmap to FB_UNIT bits wide
 | |
|  */
 | |
| void
 | |
| fbPadPixmap (PixmapPtr pPixmap)
 | |
| {
 | |
|     int	    width;
 | |
|     FbBits  *bits;
 | |
|     FbBits  b;
 | |
|     FbBits  mask;
 | |
|     int	    height;
 | |
|     int	    w;
 | |
|     int     stride;
 | |
|     int     bpp;
 | |
|     int     xOff, yOff;
 | |
| 
 | |
|     fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
 | |
| 
 | |
|     width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
 | |
|     height = pPixmap->drawable.height;
 | |
|     mask = FbBitsMask (0, width);
 | |
|     while (height--)
 | |
|     {
 | |
| 	b = READ(bits) & mask;
 | |
| 	w = width;
 | |
| 	while (w < FB_UNIT)
 | |
| 	{
 | |
| 	    b = b | FbScrRight(b, w);
 | |
| 	    w <<= 1;
 | |
| 	}
 | |
| 	WRITE(bits, b);
 | |
| 	bits += stride;
 | |
|     }
 | |
| 
 | |
|     fbFinishAccess (&pPixmap->drawable);
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Verify that 'bits' repeats every 'len' bits
 | |
|  */
 | |
| static Bool
 | |
| fbBitsRepeat (FbBits bits, int len, int width)
 | |
| {
 | |
|     FbBits  mask = FbBitsMask(0, len);
 | |
|     FbBits  orig = bits & mask;
 | |
|     int	    i;
 | |
|     
 | |
|     if (width > FB_UNIT)
 | |
| 	width = FB_UNIT;
 | |
|     for (i = 0; i < width / len; i++)
 | |
|     {
 | |
| 	if ((bits & mask) != orig)
 | |
| 	    return FALSE;
 | |
| 	bits = FbScrLeft(bits,len);
 | |
|     }
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * Check whether an entire bitmap line is a repetition of
 | |
|  * the first 'len' bits
 | |
|  */
 | |
| static Bool
 | |
| fbLineRepeat (FbBits *bits, int len, int width)
 | |
| {
 | |
|     FbBits  first = bits[0];
 | |
|     
 | |
|     if (!fbBitsRepeat (first, len, width))
 | |
| 	return FALSE;
 | |
|     width = (width + FB_UNIT-1) >> FB_SHIFT;
 | |
|     bits++;
 | |
|     while (--width)
 | |
| 	if (READ(bits) != first)
 | |
| 	    return FALSE;
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| /*
 | |
|  * The even stipple code wants the first FB_UNIT/bpp bits on
 | |
|  * each scanline to represent the entire stipple
 | |
|  */
 | |
| static Bool
 | |
| fbCanEvenStipple (PixmapPtr pStipple, int bpp)
 | |
| {
 | |
|     int	    len = FB_UNIT / bpp;
 | |
|     FbBits  *bits;
 | |
|     int	    stride;
 | |
|     int	    stip_bpp;
 | |
|     int	    stipXoff, stipYoff;
 | |
|     int	    h;
 | |
| 
 | |
|     /* can't even stipple 24bpp drawables */
 | |
|     if ((bpp & (bpp-1)) != 0)
 | |
| 	return FALSE;
 | |
|     /* make sure the stipple width is a multiple of the even stipple width */
 | |
|     if (pStipple->drawable.width % len != 0)
 | |
| 	return FALSE;
 | |
|     fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff);
 | |
|     h = pStipple->drawable.height;
 | |
|     /* check to see that the stipple repeats horizontally */
 | |
|     while (h--)
 | |
|     {
 | |
| 	if (!fbLineRepeat (bits, len, pStipple->drawable.width)) {
 | |
| 	    fbFinishAccess (&pStipple->drawable);
 | |
| 	    return FALSE;
 | |
| 	}
 | |
| 	bits += stride;
 | |
|     }
 | |
|     fbFinishAccess (&pStipple->drawable);
 | |
|     return TRUE;
 | |
| }
 | |
| 
 | |
| void
 | |
| fbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
 | |
| {
 | |
|     FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
 | |
|     FbBits	mask;
 | |
| 
 | |
|     pGC->lastWinOrg.x = pDrawable->x;
 | |
|     pGC->lastWinOrg.y = pDrawable->y;
 | |
| 
 | |
|     /*
 | |
|      * if the client clip is different or moved OR the subwindowMode has
 | |
|      * changed OR the window's clip has changed since the last validation
 | |
|      * we need to recompute the composite clip 
 | |
|      */
 | |
| 
 | |
|     if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
 | |
| 	(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
 | |
| 	)
 | |
|     {
 | |
| 	miComputeCompositeClip (pGC, pDrawable);
 | |
| 	pPriv->oneRect = REGION_NUM_RECTS(fbGetCompositeClip(pGC)) == 1;
 | |
|     }
 | |
|     
 | |
| #ifdef FB_24_32BIT    
 | |
|     if (pPriv->bpp != pDrawable->bitsPerPixel)
 | |
|     {
 | |
| 	changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask;
 | |
| 	pPriv->bpp = pDrawable->bitsPerPixel;
 | |
|     }
 | |
|     if ((changes & GCTile) && fbGetRotatedPixmap(pGC))
 | |
|     {
 | |
| 	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
 | |
| 	fbGetRotatedPixmap(pGC) = 0;
 | |
|     }
 | |
| 	
 | |
|     if (pGC->fillStyle == FillTiled)
 | |
|     {
 | |
| 	PixmapPtr	pOldTile, pNewTile;
 | |
| 
 | |
| 	pOldTile = pGC->tile.pixmap;
 | |
| 	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
 | |
| 	{
 | |
| 	    pNewTile = fbGetRotatedPixmap(pGC);
 | |
| 	    if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
 | |
| 	    {
 | |
| 		if (pNewTile)
 | |
| 		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
 | |
| 		pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel);
 | |
| 	    }
 | |
| 	    if (pNewTile)
 | |
| 	    {
 | |
| 		fbGetRotatedPixmap(pGC) = pOldTile;
 | |
| 		pGC->tile.pixmap = pNewTile;
 | |
| 		changes |= GCTile;
 | |
| 	    }
 | |
| 	}
 | |
|     }
 | |
| #endif
 | |
|     if (changes & GCTile)
 | |
|     {
 | |
| 	if (!pGC->tileIsPixel && 
 | |
| 	    FbEvenTile (pGC->tile.pixmap->drawable.width *
 | |
| 			pDrawable->bitsPerPixel))
 | |
| 	    fbPadPixmap (pGC->tile.pixmap);
 | |
|     }
 | |
|     if (changes & GCStipple)
 | |
|     {
 | |
| 	pPriv->evenStipple = FALSE;
 | |
| 
 | |
| 	if (pGC->stipple) {
 | |
| 
 | |
| 	    /* can we do an even stipple ?? */
 | |
| 	    if (FbEvenStip (pGC->stipple->drawable.width,
 | |
| 						pDrawable->bitsPerPixel) &&
 | |
| 	       (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel)))
 | |
| 	   	pPriv->evenStipple = TRUE;
 | |
| 
 | |
| 	    if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT)
 | |
| 		fbPadPixmap (pGC->stipple);
 | |
| 	}
 | |
|     }
 | |
|     /*
 | |
|      * Recompute reduced rop values
 | |
|      */
 | |
|     if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction))
 | |
|     {
 | |
| 	int	s;
 | |
| 	FbBits	depthMask;
 | |
| 	
 | |
| 	mask = FbFullMask(pDrawable->bitsPerPixel);
 | |
| 	depthMask = FbFullMask(pDrawable->depth);
 | |
| 	
 | |
| 	pPriv->fg = pGC->fgPixel & mask;
 | |
| 	pPriv->bg = pGC->bgPixel & mask;
 | |
| 	
 | |
| 	if ((pGC->planemask & depthMask) == depthMask)
 | |
| 	    pPriv->pm = mask;
 | |
| 	else
 | |
| 	    pPriv->pm = pGC->planemask & mask;    
 | |
| 	
 | |
| 	s = pDrawable->bitsPerPixel;
 | |
| 	while (s < FB_UNIT)
 | |
| 	{
 | |
| 	    pPriv->fg |= pPriv->fg << s;
 | |
| 	    pPriv->bg |= pPriv->bg << s;
 | |
| 	    pPriv->pm |= pPriv->pm << s;
 | |
| 	    s <<= 1;
 | |
| 	}
 | |
| 	pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm);
 | |
| 	pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm);
 | |
| 	pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm);
 | |
| 	pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm);
 | |
|     }
 | |
|     if (changes & GCDashList)
 | |
|     {
 | |
| 	unsigned short	n = pGC->numInDashList;
 | |
| 	unsigned char	*dash = pGC->dash;
 | |
| 	unsigned int	dashLength = 0;
 | |
| 
 | |
| 	while (n--)
 | |
| 	    dashLength += (unsigned int ) *dash++;
 | |
| 	pPriv->dashLength = dashLength;
 | |
|     }
 | |
| }
 |