fbgc.c revision 05b261ec
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->clientClip = NULL;
68    pGC->clientClipType = CT_NONE;
69
70    pGC->ops = (GCOps *) &fbGCOps;
71    pGC->funcs = (GCFuncs *) &fbGCFuncs;
72
73    /* fb wants to translate before scan conversion */
74    pGC->miTranslate = 1;
75
76    fbGetRotatedPixmap(pGC) = 0;
77    fbGetExpose(pGC) = 1;
78    fbGetFreeCompClip(pGC) = 0;
79    fbGetCompositeClip(pGC) = 0;
80    fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth);
81    return TRUE;
82}
83
84/*
85 * Pad pixmap to FB_UNIT bits wide
86 */
87void
88fbPadPixmap (PixmapPtr pPixmap)
89{
90    int	    width;
91    FbBits  *bits;
92    FbBits  b;
93    FbBits  mask;
94    int	    height;
95    int	    w;
96    int     stride;
97    int     bpp;
98    int     xOff, yOff;
99
100    fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff);
101
102    width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel;
103    height = pPixmap->drawable.height;
104    mask = FbBitsMask (0, width);
105    while (height--)
106    {
107	b = READ(bits) & mask;
108	w = width;
109	while (w < FB_UNIT)
110	{
111	    b = b | FbScrRight(b, w);
112	    w <<= 1;
113	}
114	WRITE(bits, b);
115	bits += stride;
116    }
117
118    fbFinishAccess (&pPixmap->drawable);
119}
120
121/*
122 * Verify that 'bits' repeats every 'len' bits
123 */
124static Bool
125fbBitsRepeat (FbBits bits, int len, int width)
126{
127    FbBits  mask = FbBitsMask(0, len);
128    FbBits  orig = bits & mask;
129    int	    i;
130
131    if (width > FB_UNIT)
132	width = FB_UNIT;
133    for (i = 0; i < width / len; i++)
134    {
135	if ((bits & mask) != orig)
136	    return FALSE;
137	bits = FbScrLeft(bits,len);
138    }
139    return TRUE;
140}
141
142/*
143 * Check whether an entire bitmap line is a repetition of
144 * the first 'len' bits
145 */
146static Bool
147fbLineRepeat (FbBits *bits, int len, int width)
148{
149    FbBits  first = bits[0];
150
151    if (!fbBitsRepeat (first, len, width))
152	return FALSE;
153    width = (width + FB_UNIT-1) >> FB_SHIFT;
154    bits++;
155    while (--width)
156	if (READ(bits) != first)
157	    return FALSE;
158    return TRUE;
159}
160
161/*
162 * The even stipple code wants the first FB_UNIT/bpp bits on
163 * each scanline to represent the entire stipple
164 */
165static Bool
166fbCanEvenStipple (PixmapPtr pStipple, int bpp)
167{
168    int	    len = FB_UNIT / bpp;
169    FbBits  *bits;
170    int	    stride;
171    int	    stip_bpp;
172    int	    stipXoff, stipYoff;
173    int	    h;
174
175    /* can't even stipple 24bpp drawables */
176    if ((bpp & (bpp-1)) != 0)
177	return FALSE;
178    /* make sure the stipple width is a multiple of the even stipple width */
179    if (pStipple->drawable.width % len != 0)
180	return FALSE;
181    fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff);
182    h = pStipple->drawable.height;
183    /* check to see that the stipple repeats horizontally */
184    while (h--)
185    {
186	if (!fbLineRepeat (bits, len, pStipple->drawable.width)) {
187	    fbFinishAccess (&pStipple->drawable);
188	    return FALSE;
189	}
190	bits += stride;
191    }
192    fbFinishAccess (&pStipple->drawable);
193    return TRUE;
194}
195
196void
197fbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
198{
199    FbGCPrivPtr	pPriv = fbGetGCPrivate(pGC);
200    FbBits	mask;
201
202    pGC->lastWinOrg.x = pDrawable->x;
203    pGC->lastWinOrg.y = pDrawable->y;
204
205    /*
206     * if the client clip is different or moved OR the subwindowMode has
207     * changed OR the window's clip has changed since the last validation
208     * we need to recompute the composite clip
209     */
210
211    if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) ||
212	(pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
213	)
214    {
215	miComputeCompositeClip (pGC, pDrawable);
216	pPriv->oneRect = REGION_NUM_RECTS(fbGetCompositeClip(pGC)) == 1;
217    }
218
219#ifdef FB_24_32BIT
220    if (pPriv->bpp != pDrawable->bitsPerPixel)
221    {
222	changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask;
223	pPriv->bpp = pDrawable->bitsPerPixel;
224    }
225    if ((changes & GCTile) && fbGetRotatedPixmap(pGC))
226    {
227	(*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
228	fbGetRotatedPixmap(pGC) = 0;
229    }
230
231    if (pGC->fillStyle == FillTiled)
232    {
233	PixmapPtr	pOldTile, pNewTile;
234
235	pOldTile = pGC->tile.pixmap;
236	if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
237	{
238	    pNewTile = fbGetRotatedPixmap(pGC);
239	    if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel)
240	    {
241		if (pNewTile)
242		    (*pGC->pScreen->DestroyPixmap) (pNewTile);
243		pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel);
244	    }
245	    if (pNewTile)
246	    {
247		fbGetRotatedPixmap(pGC) = pOldTile;
248		pGC->tile.pixmap = pNewTile;
249		changes |= GCTile;
250	    }
251	}
252    }
253#endif
254    if (changes & GCTile)
255    {
256	if (!pGC->tileIsPixel &&
257	    FbEvenTile (pGC->tile.pixmap->drawable.width *
258			pDrawable->bitsPerPixel))
259	    fbPadPixmap (pGC->tile.pixmap);
260    }
261    if (changes & GCStipple)
262    {
263	pPriv->evenStipple = FALSE;
264
265	if (pGC->stipple) {
266
267	    /* can we do an even stipple ?? */
268	    if (FbEvenStip (pGC->stipple->drawable.width,
269						pDrawable->bitsPerPixel) &&
270	       (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel)))
271	   	pPriv->evenStipple = TRUE;
272
273	    if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT)
274		fbPadPixmap (pGC->stipple);
275	}
276    }
277    /*
278     * Recompute reduced rop values
279     */
280    if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction))
281    {
282	int	s;
283	FbBits	depthMask;
284
285	mask = FbFullMask(pDrawable->bitsPerPixel);
286	depthMask = FbFullMask(pDrawable->depth);
287
288	pPriv->fg = pGC->fgPixel & mask;
289	pPriv->bg = pGC->bgPixel & mask;
290
291	if ((pGC->planemask & depthMask) == depthMask)
292	    pPriv->pm = mask;
293	else
294	    pPriv->pm = pGC->planemask & mask;
295
296	s = pDrawable->bitsPerPixel;
297	while (s < FB_UNIT)
298	{
299	    pPriv->fg |= pPriv->fg << s;
300	    pPriv->bg |= pPriv->bg << s;
301	    pPriv->pm |= pPriv->pm << s;
302	    s <<= 1;
303	}
304	pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm);
305	pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm);
306	pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm);
307	pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm);
308    }
309    if (changes & GCDashList)
310    {
311	unsigned short	n = pGC->numInDashList;
312	unsigned char	*dash = pGC->dash;
313	unsigned int	dashLength = 0;
314
315	while (n--)
316	    dashLength += (unsigned int ) *dash++;
317	pPriv->dashLength = dashLength;
318    }
319}
320