fbgc.c revision 05b261ec
105b261ecSmrg/*
205b261ecSmrg * Copyright © 1998 Keith Packard
305b261ecSmrg *
405b261ecSmrg * Permission to use, copy, modify, distribute, and sell this software and its
505b261ecSmrg * documentation for any purpose is hereby granted without fee, provided that
605b261ecSmrg * the above copyright notice appear in all copies and that both that
705b261ecSmrg * copyright notice and this permission notice appear in supporting
805b261ecSmrg * documentation, and that the name of Keith Packard not be used in
905b261ecSmrg * advertising or publicity pertaining to distribution of the software without
1005b261ecSmrg * specific, written prior permission.  Keith Packard makes no
1105b261ecSmrg * representations about the suitability of this software for any purpose.  It
1205b261ecSmrg * is provided "as is" without express or implied warranty.
1305b261ecSmrg *
1405b261ecSmrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
1505b261ecSmrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
1605b261ecSmrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
1705b261ecSmrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
1805b261ecSmrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
1905b261ecSmrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
2005b261ecSmrg * PERFORMANCE OF THIS SOFTWARE.
2105b261ecSmrg */
2205b261ecSmrg
2305b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
2405b261ecSmrg#include <dix-config.h>
2505b261ecSmrg#endif
2605b261ecSmrg
2705b261ecSmrg#include <stdlib.h>
2805b261ecSmrg
2905b261ecSmrg#include "fb.h"
3005b261ecSmrg
3105b261ecSmrgconst GCFuncs fbGCFuncs = {
3205b261ecSmrg    fbValidateGC,
3305b261ecSmrg    miChangeGC,
3405b261ecSmrg    miCopyGC,
3505b261ecSmrg    miDestroyGC,
3605b261ecSmrg    miChangeClip,
3705b261ecSmrg    miDestroyClip,
3805b261ecSmrg    miCopyClip,
3905b261ecSmrg};
4005b261ecSmrg
4105b261ecSmrgconst GCOps	fbGCOps = {
4205b261ecSmrg    fbFillSpans,
4305b261ecSmrg    fbSetSpans,
4405b261ecSmrg    fbPutImage,
4505b261ecSmrg    fbCopyArea,
4605b261ecSmrg    fbCopyPlane,
4705b261ecSmrg    fbPolyPoint,
4805b261ecSmrg    fbPolyLine,
4905b261ecSmrg    fbPolySegment,
5005b261ecSmrg    fbPolyRectangle,
5105b261ecSmrg    fbPolyArc,
5205b261ecSmrg    miFillPolygon,
5305b261ecSmrg    fbPolyFillRect,
5405b261ecSmrg    fbPolyFillArc,
5505b261ecSmrg    miPolyText8,
5605b261ecSmrg    miPolyText16,
5705b261ecSmrg    miImageText8,
5805b261ecSmrg    miImageText16,
5905b261ecSmrg    fbImageGlyphBlt,
6005b261ecSmrg    fbPolyGlyphBlt,
6105b261ecSmrg    fbPushPixels
6205b261ecSmrg};
6305b261ecSmrg
6405b261ecSmrgBool
6505b261ecSmrgfbCreateGC(GCPtr pGC)
6605b261ecSmrg{
6705b261ecSmrg    pGC->clientClip = NULL;
6805b261ecSmrg    pGC->clientClipType = CT_NONE;
6905b261ecSmrg
7005b261ecSmrg    pGC->ops = (GCOps *) &fbGCOps;
7105b261ecSmrg    pGC->funcs = (GCFuncs *) &fbGCFuncs;
7205b261ecSmrg
7305b261ecSmrg    /* fb wants to translate before scan conversion */
7405b261ecSmrg    pGC->miTranslate = 1;
7505b261ecSmrg
7605b261ecSmrg    fbGetRotatedPixmap(pGC) = 0;
7705b261ecSmrg    fbGetExpose(pGC) = 1;
7805b261ecSmrg    fbGetFreeCompClip(pGC) = 0;
7905b261ecSmrg    fbGetCompositeClip(pGC) = 0;
8005b261ecSmrg    fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth);
8105b261ecSmrg    return TRUE;
8205b261ecSmrg}
8305b261ecSmrg
8405b261ecSmrg/*
8505b261ecSmrg * Pad pixmap to FB_UNIT bits wide
8605b261ecSmrg */
8705b261ecSmrgvoid
8805b261ecSmrgfbPadPixmap (PixmapPtr pPixmap)
8905b261ecSmrg{
9005b261ecSmrg    int	    width;
9105b261ecSmrg    FbBits  *bits;
9205b261ecSmrg    FbBits  b;
9305b261ecSmrg    FbBits  mask;
9405b261ecSmrg    int	    height;
9505b261ecSmrg    int	    w;
9605b261ecSmrg    int     stride;
9705b261ecSmrg    int     bpp;
9805b261ecSmrg    int     xOff, yOff;
9905b261ecSmrg
10005b261ecSmrg    fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
10105b261ecSmrg
10205b261ecSmrg    width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
10305b261ecSmrg    height = pPixmap->drawable.height;
10405b261ecSmrg    mask = FbBitsMask (0, width);
10505b261ecSmrg    while (height--)
10605b261ecSmrg    {
10705b261ecSmrg	b = READ(bits) & mask;
10805b261ecSmrg	w = width;
10905b261ecSmrg	while (w < FB_UNIT)
11005b261ecSmrg	{
11105b261ecSmrg	    b = b | FbScrRight(b, w);
11205b261ecSmrg	    w <<= 1;
11305b261ecSmrg	}
11405b261ecSmrg	WRITE(bits, b);
11505b261ecSmrg	bits += stride;
11605b261ecSmrg    }
11705b261ecSmrg
11805b261ecSmrg    fbFinishAccess (&pPixmap->drawable);
11905b261ecSmrg}
12005b261ecSmrg
12105b261ecSmrg/*
12205b261ecSmrg * Verify that 'bits' repeats every 'len' bits
12305b261ecSmrg */
12405b261ecSmrgstatic Bool
12505b261ecSmrgfbBitsRepeat (FbBits bits, int len, int width)
12605b261ecSmrg{
12705b261ecSmrg    FbBits  mask = FbBitsMask(0, len);
12805b261ecSmrg    FbBits  orig = bits & mask;
12905b261ecSmrg    int	    i;
13005b261ecSmrg
13105b261ecSmrg    if (width > FB_UNIT)
13205b261ecSmrg	width = FB_UNIT;
13305b261ecSmrg    for (i = 0; i < width / len; i++)
13405b261ecSmrg    {
13505b261ecSmrg	if ((bits & mask) != orig)
13605b261ecSmrg	    return FALSE;
13705b261ecSmrg	bits = FbScrLeft(bits,len);
13805b261ecSmrg    }
13905b261ecSmrg    return TRUE;
14005b261ecSmrg}
14105b261ecSmrg
14205b261ecSmrg/*
14305b261ecSmrg * Check whether an entire bitmap line is a repetition of
14405b261ecSmrg * the first 'len' bits
14505b261ecSmrg */
14605b261ecSmrgstatic Bool
14705b261ecSmrgfbLineRepeat (FbBits *bits, int len, int width)
14805b261ecSmrg{
14905b261ecSmrg    FbBits  first = bits[0];
15005b261ecSmrg
15105b261ecSmrg    if (!fbBitsRepeat (first, len, width))
15205b261ecSmrg	return FALSE;
15305b261ecSmrg    width = (width + FB_UNIT-1) >> FB_SHIFT;
15405b261ecSmrg    bits++;
15505b261ecSmrg    while (--width)
15605b261ecSmrg	if (READ(bits) != first)
15705b261ecSmrg	    return FALSE;
15805b261ecSmrg    return TRUE;
15905b261ecSmrg}
16005b261ecSmrg
16105b261ecSmrg/*
16205b261ecSmrg * The even stipple code wants the first FB_UNIT/bpp bits on
16305b261ecSmrg * each scanline to represent the entire stipple
16405b261ecSmrg */
16505b261ecSmrgstatic Bool
16605b261ecSmrgfbCanEvenStipple (PixmapPtr pStipple, int bpp)
16705b261ecSmrg{
16805b261ecSmrg    int	    len = FB_UNIT / bpp;
16905b261ecSmrg    FbBits  *bits;
17005b261ecSmrg    int	    stride;
17105b261ecSmrg    int	    stip_bpp;
17205b261ecSmrg    int	    stipXoff, stipYoff;
17305b261ecSmrg    int	    h;
17405b261ecSmrg
17505b261ecSmrg    /* can't even stipple 24bpp drawables */
17605b261ecSmrg    if ((bpp & (bpp-1)) != 0)
17705b261ecSmrg	return FALSE;
17805b261ecSmrg    /* make sure the stipple width is a multiple of the even stipple width */
17905b261ecSmrg    if (pStipple->drawable.width % len != 0)
18005b261ecSmrg	return FALSE;
18105b261ecSmrg    fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff);
18205b261ecSmrg    h = pStipple->drawable.height;
18305b261ecSmrg    /* check to see that the stipple repeats horizontally */
18405b261ecSmrg    while (h--)
18505b261ecSmrg    {
18605b261ecSmrg	if (!fbLineRepeat (bits, len, pStipple->drawable.width)) {
18705b261ecSmrg	    fbFinishAccess (&pStipple->drawable);
18805b261ecSmrg	    return FALSE;
18905b261ecSmrg	}
19005b261ecSmrg	bits += stride;
19105b261ecSmrg    }
19205b261ecSmrg    fbFinishAccess (&pStipple->drawable);
19305b261ecSmrg    return TRUE;
19405b261ecSmrg}
19505b261ecSmrg
19605b261ecSmrgvoid
19705b261ecSmrgfbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
19805b261ecSmrg{
19905b261ecSmrg    FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
20005b261ecSmrg    FbBits	mask;
20105b261ecSmrg
20205b261ecSmrg    pGC->lastWinOrg.x = pDrawable->x;
20305b261ecSmrg    pGC->lastWinOrg.y = pDrawable->y;
20405b261ecSmrg
20505b261ecSmrg    /*
20605b261ecSmrg     * if the client clip is different or moved OR the subwindowMode has
20705b261ecSmrg     * changed OR the window's clip has changed since the last validation
20805b261ecSmrg     * we need to recompute the composite clip
20905b261ecSmrg     */
21005b261ecSmrg
21105b261ecSmrg    if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
21205b261ecSmrg	(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
21305b261ecSmrg	)
21405b261ecSmrg    {
21505b261ecSmrg	miComputeCompositeClip (pGC, pDrawable);
21605b261ecSmrg	pPriv->oneRect = REGION_NUM_RECTS(fbGetCompositeClip(pGC)) == 1;
21705b261ecSmrg    }
21805b261ecSmrg
21905b261ecSmrg#ifdef FB_24_32BIT
22005b261ecSmrg    if (pPriv->bpp != pDrawable->bitsPerPixel)
22105b261ecSmrg    {
22205b261ecSmrg	changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask;
22305b261ecSmrg	pPriv->bpp = pDrawable->bitsPerPixel;
22405b261ecSmrg    }
22505b261ecSmrg    if ((changes & GCTile) && fbGetRotatedPixmap(pGC))
22605b261ecSmrg    {
22705b261ecSmrg	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
22805b261ecSmrg	fbGetRotatedPixmap(pGC) = 0;
22905b261ecSmrg    }
23005b261ecSmrg
23105b261ecSmrg    if (pGC->fillStyle == FillTiled)
23205b261ecSmrg    {
23305b261ecSmrg	PixmapPtr	pOldTile, pNewTile;
23405b261ecSmrg
23505b261ecSmrg	pOldTile = pGC->tile.pixmap;
23605b261ecSmrg	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
23705b261ecSmrg	{
23805b261ecSmrg	    pNewTile = fbGetRotatedPixmap(pGC);
23905b261ecSmrg	    if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
24005b261ecSmrg	    {
24105b261ecSmrg		if (pNewTile)
24205b261ecSmrg		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
24305b261ecSmrg		pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel);
24405b261ecSmrg	    }
24505b261ecSmrg	    if (pNewTile)
24605b261ecSmrg	    {
24705b261ecSmrg		fbGetRotatedPixmap(pGC) = pOldTile;
24805b261ecSmrg		pGC->tile.pixmap = pNewTile;
24905b261ecSmrg		changes |= GCTile;
25005b261ecSmrg	    }
25105b261ecSmrg	}
25205b261ecSmrg    }
25305b261ecSmrg#endif
25405b261ecSmrg    if (changes & GCTile)
25505b261ecSmrg    {
25605b261ecSmrg	if (!pGC->tileIsPixel &&
25705b261ecSmrg	    FbEvenTile (pGC->tile.pixmap->drawable.width *
25805b261ecSmrg			pDrawable->bitsPerPixel))
25905b261ecSmrg	    fbPadPixmap (pGC->tile.pixmap);
26005b261ecSmrg    }
26105b261ecSmrg    if (changes & GCStipple)
26205b261ecSmrg    {
26305b261ecSmrg	pPriv->evenStipple = FALSE;
26405b261ecSmrg
26505b261ecSmrg	if (pGC->stipple) {
26605b261ecSmrg
26705b261ecSmrg	    /* can we do an even stipple ?? */
26805b261ecSmrg	    if (FbEvenStip (pGC->stipple->drawable.width,
26905b261ecSmrg						pDrawable->bitsPerPixel) &&
27005b261ecSmrg	       (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel)))
27105b261ecSmrg	   	pPriv->evenStipple = TRUE;
27205b261ecSmrg
27305b261ecSmrg	    if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT)
27405b261ecSmrg		fbPadPixmap (pGC->stipple);
27505b261ecSmrg	}
27605b261ecSmrg    }
27705b261ecSmrg    /*
27805b261ecSmrg     * Recompute reduced rop values
27905b261ecSmrg     */
28005b261ecSmrg    if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction))
28105b261ecSmrg    {
28205b261ecSmrg	int	s;
28305b261ecSmrg	FbBits	depthMask;
28405b261ecSmrg
28505b261ecSmrg	mask = FbFullMask(pDrawable->bitsPerPixel);
28605b261ecSmrg	depthMask = FbFullMask(pDrawable->depth);
28705b261ecSmrg
28805b261ecSmrg	pPriv->fg = pGC->fgPixel & mask;
28905b261ecSmrg	pPriv->bg = pGC->bgPixel & mask;
29005b261ecSmrg
29105b261ecSmrg	if ((pGC->planemask & depthMask) == depthMask)
29205b261ecSmrg	    pPriv->pm = mask;
29305b261ecSmrg	else
29405b261ecSmrg	    pPriv->pm = pGC->planemask & mask;
29505b261ecSmrg
29605b261ecSmrg	s = pDrawable->bitsPerPixel;
29705b261ecSmrg	while (s < FB_UNIT)
29805b261ecSmrg	{
29905b261ecSmrg	    pPriv->fg |= pPriv->fg << s;
30005b261ecSmrg	    pPriv->bg |= pPriv->bg << s;
30105b261ecSmrg	    pPriv->pm |= pPriv->pm << s;
30205b261ecSmrg	    s <<= 1;
30305b261ecSmrg	}
30405b261ecSmrg	pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm);
30505b261ecSmrg	pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm);
30605b261ecSmrg	pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm);
30705b261ecSmrg	pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm);
30805b261ecSmrg    }
30905b261ecSmrg    if (changes & GCDashList)
31005b261ecSmrg    {
31105b261ecSmrg	unsigned short	n = pGC->numInDashList;
31205b261ecSmrg	unsigned char	*dash = pGC->dash;
31305b261ecSmrg	unsigned int	dashLength = 0;
31405b261ecSmrg
31505b261ecSmrg	while (n--)
31605b261ecSmrg	    dashLength += (unsigned int ) *dash++;
31705b261ecSmrg	pPriv->dashLength = dashLength;
31805b261ecSmrg    }
31905b261ecSmrg}
320