320 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			320 lines
		
	
	
		
			7.8 KiB
		
	
	
	
		
			C
		
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
    }
 | 
						|
}
 |