1706f2543Smrg/*
2706f2543Smrg * Copyright © 1998 Keith Packard
3706f2543Smrg *
4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its
5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that
6706f2543Smrg * the above copyright notice appear in all copies and that both that
7706f2543Smrg * copyright notice and this permission notice appear in supporting
8706f2543Smrg * documentation, and that the name of Keith Packard not be used in
9706f2543Smrg * advertising or publicity pertaining to distribution of the software without
10706f2543Smrg * specific, written prior permission.  Keith Packard makes no
11706f2543Smrg * representations about the suitability of this software for any purpose.  It
12706f2543Smrg * is provided "as is" without express or implied warranty.
13706f2543Smrg *
14706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE.
21706f2543Smrg */
22706f2543Smrg
23706f2543Smrg#ifdef HAVE_DIX_CONFIG_H
24706f2543Smrg#include <dix-config.h>
25706f2543Smrg#endif
26706f2543Smrg
27706f2543Smrg#include <stdlib.h>
28706f2543Smrg
29706f2543Smrg#include "fb.h"
30706f2543Smrg
31706f2543Smrgconst GCFuncs fbGCFuncs = {
32706f2543Smrg    fbValidateGC,
33706f2543Smrg    miChangeGC,
34706f2543Smrg    miCopyGC,
35706f2543Smrg    miDestroyGC,
36706f2543Smrg    miChangeClip,
37706f2543Smrg    miDestroyClip,
38706f2543Smrg    miCopyClip,
39706f2543Smrg};
40706f2543Smrg
41706f2543Smrgconst GCOps	fbGCOps = {
42706f2543Smrg    fbFillSpans,
43706f2543Smrg    fbSetSpans,
44706f2543Smrg    fbPutImage,
45706f2543Smrg    fbCopyArea,
46706f2543Smrg    fbCopyPlane,
47706f2543Smrg    fbPolyPoint,
48706f2543Smrg    fbPolyLine,
49706f2543Smrg    fbPolySegment,
50706f2543Smrg    fbPolyRectangle,
51706f2543Smrg    fbPolyArc,
52706f2543Smrg    miFillPolygon,
53706f2543Smrg    fbPolyFillRect,
54706f2543Smrg    fbPolyFillArc,
55706f2543Smrg    miPolyText8,
56706f2543Smrg    miPolyText16,
57706f2543Smrg    miImageText8,
58706f2543Smrg    miImageText16,
59706f2543Smrg    fbImageGlyphBlt,
60706f2543Smrg    fbPolyGlyphBlt,
61706f2543Smrg    fbPushPixels
62706f2543Smrg};
63706f2543Smrg
64706f2543SmrgBool
65706f2543SmrgfbCreateGC(GCPtr pGC)
66706f2543Smrg{
67706f2543Smrg    pGC->ops = (GCOps *) &fbGCOps;
68706f2543Smrg    pGC->funcs = (GCFuncs *) &fbGCFuncs;
69706f2543Smrg
70706f2543Smrg    /* fb wants to translate before scan conversion */
71706f2543Smrg    pGC->miTranslate = 1;
72706f2543Smrg    pGC->fExpose = 1;
73706f2543Smrg
74706f2543Smrg    fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth);
75706f2543Smrg    return TRUE;
76706f2543Smrg}
77706f2543Smrg
78706f2543Smrg/*
79706f2543Smrg * Pad pixmap to FB_UNIT bits wide
80706f2543Smrg */
81706f2543Smrgvoid
82706f2543SmrgfbPadPixmap (PixmapPtr pPixmap)
83706f2543Smrg{
84706f2543Smrg    int	    width;
85706f2543Smrg    FbBits  *bits;
86706f2543Smrg    FbBits  b;
87706f2543Smrg    FbBits  mask;
88706f2543Smrg    int	    height;
89706f2543Smrg    int	    w;
90706f2543Smrg    int     stride;
91706f2543Smrg    int     bpp;
92706f2543Smrg    int     xOff, yOff;
93706f2543Smrg
94706f2543Smrg    fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
95706f2543Smrg
96706f2543Smrg    width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
97706f2543Smrg    height = pPixmap->drawable.height;
98706f2543Smrg    mask = FbBitsMask (0, width);
99706f2543Smrg    while (height--)
100706f2543Smrg    {
101706f2543Smrg	b = READ(bits) & mask;
102706f2543Smrg	w = width;
103706f2543Smrg	while (w < FB_UNIT)
104706f2543Smrg	{
105706f2543Smrg	    b = b | FbScrRight(b, w);
106706f2543Smrg	    w <<= 1;
107706f2543Smrg	}
108706f2543Smrg	WRITE(bits, b);
109706f2543Smrg	bits += stride;
110706f2543Smrg    }
111706f2543Smrg
112706f2543Smrg    fbFinishAccess (&pPixmap->drawable);
113706f2543Smrg}
114706f2543Smrg
115706f2543Smrg/*
116706f2543Smrg * Verify that 'bits' repeats every 'len' bits
117706f2543Smrg */
118706f2543Smrgstatic Bool
119706f2543SmrgfbBitsRepeat (FbBits bits, int len, int width)
120706f2543Smrg{
121706f2543Smrg    FbBits  mask = FbBitsMask(0, len);
122706f2543Smrg    FbBits  orig = bits & mask;
123706f2543Smrg    int	    i;
124706f2543Smrg
125706f2543Smrg    if (width > FB_UNIT)
126706f2543Smrg	width = FB_UNIT;
127706f2543Smrg    for (i = 0; i < width / len; i++)
128706f2543Smrg    {
129706f2543Smrg	if ((bits & mask) != orig)
130706f2543Smrg	    return FALSE;
131706f2543Smrg	bits = FbScrLeft(bits,len);
132706f2543Smrg    }
133706f2543Smrg    return TRUE;
134706f2543Smrg}
135706f2543Smrg
136706f2543Smrg/*
137706f2543Smrg * Check whether an entire bitmap line is a repetition of
138706f2543Smrg * the first 'len' bits
139706f2543Smrg */
140706f2543Smrgstatic Bool
141706f2543SmrgfbLineRepeat (FbBits *bits, int len, int width)
142706f2543Smrg{
143706f2543Smrg    FbBits  first = bits[0];
144706f2543Smrg
145706f2543Smrg    if (!fbBitsRepeat (first, len, width))
146706f2543Smrg	return FALSE;
147706f2543Smrg    width = (width + FB_UNIT-1) >> FB_SHIFT;
148706f2543Smrg    bits++;
149706f2543Smrg    while (--width)
150706f2543Smrg	if (READ(bits) != first)
151706f2543Smrg	    return FALSE;
152706f2543Smrg    return TRUE;
153706f2543Smrg}
154706f2543Smrg
155706f2543Smrg/*
156706f2543Smrg * The even stipple code wants the first FB_UNIT/bpp bits on
157706f2543Smrg * each scanline to represent the entire stipple
158706f2543Smrg */
159706f2543Smrgstatic Bool
160706f2543SmrgfbCanEvenStipple (PixmapPtr pStipple, int bpp)
161706f2543Smrg{
162706f2543Smrg    int	    len = FB_UNIT / bpp;
163706f2543Smrg    FbBits  *bits;
164706f2543Smrg    int	    stride;
165706f2543Smrg    int	    stip_bpp;
166706f2543Smrg    int	    stipXoff, stipYoff;
167706f2543Smrg    int	    h;
168706f2543Smrg
169706f2543Smrg    /* can't even stipple 24bpp drawables */
170706f2543Smrg    if ((bpp & (bpp-1)) != 0)
171706f2543Smrg	return FALSE;
172706f2543Smrg    /* make sure the stipple width is a multiple of the even stipple width */
173706f2543Smrg    if (pStipple->drawable.width % len != 0)
174706f2543Smrg	return FALSE;
175706f2543Smrg    fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff);
176706f2543Smrg    h = pStipple->drawable.height;
177706f2543Smrg    /* check to see that the stipple repeats horizontally */
178706f2543Smrg    while (h--)
179706f2543Smrg    {
180706f2543Smrg	if (!fbLineRepeat (bits, len, pStipple->drawable.width)) {
181706f2543Smrg	    fbFinishAccess (&pStipple->drawable);
182706f2543Smrg	    return FALSE;
183706f2543Smrg	}
184706f2543Smrg	bits += stride;
185706f2543Smrg    }
186706f2543Smrg    fbFinishAccess (&pStipple->drawable);
187706f2543Smrg    return TRUE;
188706f2543Smrg}
189706f2543Smrg
190706f2543Smrgvoid
191706f2543SmrgfbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
192706f2543Smrg{
193706f2543Smrg    FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
194706f2543Smrg    FbBits	mask;
195706f2543Smrg
196706f2543Smrg    /*
197706f2543Smrg     * if the client clip is different or moved OR the subwindowMode has
198706f2543Smrg     * changed OR the window's clip has changed since the last validation
199706f2543Smrg     * we need to recompute the composite clip
200706f2543Smrg     */
201706f2543Smrg
202706f2543Smrg    if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
203706f2543Smrg	(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
204706f2543Smrg	)
205706f2543Smrg    {
206706f2543Smrg	miComputeCompositeClip (pGC, pDrawable);
207706f2543Smrg    }
208706f2543Smrg
209706f2543Smrg#ifdef FB_24_32BIT
210706f2543Smrg    if (pPriv->bpp != pDrawable->bitsPerPixel)
211706f2543Smrg    {
212706f2543Smrg	changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask;
213706f2543Smrg	pPriv->bpp = pDrawable->bitsPerPixel;
214706f2543Smrg    }
215706f2543Smrg    if ((changes & GCTile) && fbGetRotatedPixmap(pGC))
216706f2543Smrg    {
217706f2543Smrg	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
218706f2543Smrg	fbGetRotatedPixmap(pGC) = 0;
219706f2543Smrg    }
220706f2543Smrg
221706f2543Smrg    if (pGC->fillStyle == FillTiled)
222706f2543Smrg    {
223706f2543Smrg	PixmapPtr	pOldTile, pNewTile;
224706f2543Smrg
225706f2543Smrg	pOldTile = pGC->tile.pixmap;
226706f2543Smrg	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
227706f2543Smrg	{
228706f2543Smrg	    pNewTile = fbGetRotatedPixmap(pGC);
229706f2543Smrg	    if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
230706f2543Smrg	    {
231706f2543Smrg		if (pNewTile)
232706f2543Smrg		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
233706f2543Smrg		pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel);
234706f2543Smrg	    }
235706f2543Smrg	    if (pNewTile)
236706f2543Smrg	    {
237706f2543Smrg		fbGetRotatedPixmap(pGC) = pOldTile;
238706f2543Smrg		pGC->tile.pixmap = pNewTile;
239706f2543Smrg		changes |= GCTile;
240706f2543Smrg	    }
241706f2543Smrg	}
242706f2543Smrg    }
243706f2543Smrg#endif
244706f2543Smrg    if (changes & GCTile)
245706f2543Smrg    {
246706f2543Smrg	if (!pGC->tileIsPixel &&
247706f2543Smrg	    FbEvenTile (pGC->tile.pixmap->drawable.width *
248706f2543Smrg			pDrawable->bitsPerPixel))
249706f2543Smrg	    fbPadPixmap (pGC->tile.pixmap);
250706f2543Smrg    }
251706f2543Smrg    if (changes & GCStipple)
252706f2543Smrg    {
253706f2543Smrg	pPriv->evenStipple = FALSE;
254706f2543Smrg
255706f2543Smrg	if (pGC->stipple) {
256706f2543Smrg
257706f2543Smrg	    /* can we do an even stipple ?? */
258706f2543Smrg	    if (FbEvenStip (pGC->stipple->drawable.width,
259706f2543Smrg						pDrawable->bitsPerPixel) &&
260706f2543Smrg	       (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel)))
261706f2543Smrg	   	pPriv->evenStipple = TRUE;
262706f2543Smrg
263706f2543Smrg	    if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT)
264706f2543Smrg		fbPadPixmap (pGC->stipple);
265706f2543Smrg	}
266706f2543Smrg    }
267706f2543Smrg    /*
268706f2543Smrg     * Recompute reduced rop values
269706f2543Smrg     */
270706f2543Smrg    if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction))
271706f2543Smrg    {
272706f2543Smrg	int	s;
273706f2543Smrg	FbBits	depthMask;
274706f2543Smrg
275706f2543Smrg	mask = FbFullMask(pDrawable->bitsPerPixel);
276706f2543Smrg	depthMask = FbFullMask(pDrawable->depth);
277706f2543Smrg
278706f2543Smrg	pPriv->fg = pGC->fgPixel & mask;
279706f2543Smrg	pPriv->bg = pGC->bgPixel & mask;
280706f2543Smrg
281706f2543Smrg	if ((pGC->planemask & depthMask) == depthMask)
282706f2543Smrg	    pPriv->pm = mask;
283706f2543Smrg	else
284706f2543Smrg	    pPriv->pm = pGC->planemask & mask;
285706f2543Smrg
286706f2543Smrg	s = pDrawable->bitsPerPixel;
287706f2543Smrg	while (s < FB_UNIT)
288706f2543Smrg	{
289706f2543Smrg	    pPriv->fg |= pPriv->fg << s;
290706f2543Smrg	    pPriv->bg |= pPriv->bg << s;
291706f2543Smrg	    pPriv->pm |= pPriv->pm << s;
292706f2543Smrg	    s <<= 1;
293706f2543Smrg	}
294706f2543Smrg	pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm);
295706f2543Smrg	pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm);
296706f2543Smrg	pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm);
297706f2543Smrg	pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm);
298706f2543Smrg    }
299706f2543Smrg    if (changes & GCDashList)
300706f2543Smrg    {
301706f2543Smrg	unsigned short	n = pGC->numInDashList;
302706f2543Smrg	unsigned char	*dash = pGC->dash;
303706f2543Smrg	unsigned int	dashLength = 0;
304706f2543Smrg
305706f2543Smrg	while (n--)
306706f2543Smrg	    dashLength += (unsigned int ) *dash++;
307706f2543Smrg	pPriv->dashLength = dashLength;
308706f2543Smrg    }
309706f2543Smrg}
310