1/*
2 * Copyright © 1998 Keith Packard
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that
7 * copyright notice and this permission notice appear in supporting
8 * documentation, and that the name of Keith Packard not be used in
9 * advertising or publicity pertaining to distribution of the software without
10 * specific, written prior permission.  Keith Packard makes no
11 * representations about the suitability of this software for any purpose.  It
12 * is provided "as is" without express or implied warranty.
13 *
14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
20 * PERFORMANCE OF THIS SOFTWARE.
21 */
22
23#ifdef HAVE_DIX_CONFIG_H
24#include <dix-config.h>
25#endif
26
27#include <stdlib.h>
28
29#include "fb.h"
30
31const GCFuncs fbGCFuncs = {
32    fbValidateGC,
33    miChangeGC,
34    miCopyGC,
35    miDestroyGC,
36    miChangeClip,
37    miDestroyClip,
38    miCopyClip,
39};
40
41const GCOps	fbGCOps = {
42    fbFillSpans,
43    fbSetSpans,
44    fbPutImage,
45    fbCopyArea,
46    fbCopyPlane,
47    fbPolyPoint,
48    fbPolyLine,
49    fbPolySegment,
50    fbPolyRectangle,
51    fbPolyArc,
52    miFillPolygon,
53    fbPolyFillRect,
54    fbPolyFillArc,
55    miPolyText8,
56    miPolyText16,
57    miImageText8,
58    miImageText16,
59    fbImageGlyphBlt,
60    fbPolyGlyphBlt,
61    fbPushPixels
62};
63
64Bool
65fbCreateGC(GCPtr pGC)
66{
67    pGC->ops = (GCOps *) &fbGCOps;
68    pGC->funcs = (GCFuncs *) &fbGCFuncs;
69
70    /* fb wants to translate before scan conversion */
71    pGC->miTranslate = 1;
72    pGC->fExpose = 1;
73
74    fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth);
75    return TRUE;
76}
77
78/*
79 * Pad pixmap to FB_UNIT bits wide
80 */
81void
82fbPadPixmap (PixmapPtr pPixmap)
83{
84    int	    width;
85    FbBits  *bits;
86    FbBits  b;
87    FbBits  mask;
88    int	    height;
89    int	    w;
90    int     stride;
91    int     bpp;
92    int     xOff, yOff;
93
94    fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
95
96    width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
97    height = pPixmap->drawable.height;
98    mask = FbBitsMask (0, width);
99    while (height--)
100    {
101	b = READ(bits) & mask;
102	w = width;
103	while (w < FB_UNIT)
104	{
105	    b = b | FbScrRight(b, w);
106	    w <<= 1;
107	}
108	WRITE(bits, b);
109	bits += stride;
110    }
111
112    fbFinishAccess (&pPixmap->drawable);
113}
114
115/*
116 * Verify that 'bits' repeats every 'len' bits
117 */
118static Bool
119fbBitsRepeat (FbBits bits, int len, int width)
120{
121    FbBits  mask = FbBitsMask(0, len);
122    FbBits  orig = bits & mask;
123    int	    i;
124
125    if (width > FB_UNIT)
126	width = FB_UNIT;
127    for (i = 0; i < width / len; i++)
128    {
129	if ((bits & mask) != orig)
130	    return FALSE;
131	bits = FbScrLeft(bits,len);
132    }
133    return TRUE;
134}
135
136/*
137 * Check whether an entire bitmap line is a repetition of
138 * the first 'len' bits
139 */
140static Bool
141fbLineRepeat (FbBits *bits, int len, int width)
142{
143    FbBits  first = bits[0];
144
145    if (!fbBitsRepeat (first, len, width))
146	return FALSE;
147    width = (width + FB_UNIT-1) >> FB_SHIFT;
148    bits++;
149    while (--width)
150	if (READ(bits) != first)
151	    return FALSE;
152    return TRUE;
153}
154
155/*
156 * The even stipple code wants the first FB_UNIT/bpp bits on
157 * each scanline to represent the entire stipple
158 */
159static Bool
160fbCanEvenStipple (PixmapPtr pStipple, int bpp)
161{
162    int	    len = FB_UNIT / bpp;
163    FbBits  *bits;
164    int	    stride;
165    int	    stip_bpp;
166    int	    stipXoff, stipYoff;
167    int	    h;
168
169    /* can't even stipple 24bpp drawables */
170    if ((bpp & (bpp-1)) != 0)
171	return FALSE;
172    /* make sure the stipple width is a multiple of the even stipple width */
173    if (pStipple->drawable.width % len != 0)
174	return FALSE;
175    fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff);
176    h = pStipple->drawable.height;
177    /* check to see that the stipple repeats horizontally */
178    while (h--)
179    {
180	if (!fbLineRepeat (bits, len, pStipple->drawable.width)) {
181	    fbFinishAccess (&pStipple->drawable);
182	    return FALSE;
183	}
184	bits += stride;
185    }
186    fbFinishAccess (&pStipple->drawable);
187    return TRUE;
188}
189
190void
191fbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
192{
193    FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
194    FbBits	mask;
195
196    /*
197     * if the client clip is different or moved OR the subwindowMode has
198     * changed OR the window's clip has changed since the last validation
199     * we need to recompute the composite clip
200     */
201
202    if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
203	(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
204	)
205    {
206	miComputeCompositeClip (pGC, pDrawable);
207    }
208
209#ifdef FB_24_32BIT
210    if (pPriv->bpp != pDrawable->bitsPerPixel)
211    {
212	changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask;
213	pPriv->bpp = pDrawable->bitsPerPixel;
214    }
215    if ((changes & GCTile) && fbGetRotatedPixmap(pGC))
216    {
217	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
218	fbGetRotatedPixmap(pGC) = 0;
219    }
220
221    if (pGC->fillStyle == FillTiled)
222    {
223	PixmapPtr	pOldTile, pNewTile;
224
225	pOldTile = pGC->tile.pixmap;
226	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
227	{
228	    pNewTile = fbGetRotatedPixmap(pGC);
229	    if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
230	    {
231		if (pNewTile)
232		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
233		pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel);
234	    }
235	    if (pNewTile)
236	    {
237		fbGetRotatedPixmap(pGC) = pOldTile;
238		pGC->tile.pixmap = pNewTile;
239		changes |= GCTile;
240	    }
241	}
242    }
243#endif
244    if (changes & GCTile)
245    {
246	if (!pGC->tileIsPixel &&
247	    FbEvenTile (pGC->tile.pixmap->drawable.width *
248			pDrawable->bitsPerPixel))
249	    fbPadPixmap (pGC->tile.pixmap);
250    }
251    if (changes & GCStipple)
252    {
253	pPriv->evenStipple = FALSE;
254
255	if (pGC->stipple) {
256
257	    /* can we do an even stipple ?? */
258	    if (FbEvenStip (pGC->stipple->drawable.width,
259						pDrawable->bitsPerPixel) &&
260	       (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel)))
261	   	pPriv->evenStipple = TRUE;
262
263	    if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT)
264		fbPadPixmap (pGC->stipple);
265	}
266    }
267    /*
268     * Recompute reduced rop values
269     */
270    if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction))
271    {
272	int	s;
273	FbBits	depthMask;
274
275	mask = FbFullMask(pDrawable->bitsPerPixel);
276	depthMask = FbFullMask(pDrawable->depth);
277
278	pPriv->fg = pGC->fgPixel & mask;
279	pPriv->bg = pGC->bgPixel & mask;
280
281	if ((pGC->planemask & depthMask) == depthMask)
282	    pPriv->pm = mask;
283	else
284	    pPriv->pm = pGC->planemask & mask;
285
286	s = pDrawable->bitsPerPixel;
287	while (s < FB_UNIT)
288	{
289	    pPriv->fg |= pPriv->fg << s;
290	    pPriv->bg |= pPriv->bg << s;
291	    pPriv->pm |= pPriv->pm << s;
292	    s <<= 1;
293	}
294	pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm);
295	pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm);
296	pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm);
297	pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm);
298    }
299    if (changes & GCDashList)
300    {
301	unsigned short	n = pGC->numInDashList;
302	unsigned char	*dash = pGC->dash;
303	unsigned int	dashLength = 0;
304
305	while (n--)
306	    dashLength += (unsigned int ) *dash++;
307	pPriv->dashLength = dashLength;
308    }
309}
310