Imported Upstream version 1.15.1
[deb_xorg-server.git] / fb / fbgc.c
CommitLineData
a09e091a
JB
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 _X_UNUSED 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 b = READ(bits) & mask;
101 w = width;
102 while (w < FB_UNIT) {
103 b = b | FbScrRight(b, w);
104 w <<= 1;
105 }
106 WRITE(bits, b);
107 bits += stride;
108 }
109
110 fbFinishAccess(&pPixmap->drawable);
111}
112
113/*
114 * Verify that 'bits' repeats every 'len' bits
115 */
116static Bool
117fbBitsRepeat(FbBits bits, int len, int width)
118{
119 FbBits mask = FbBitsMask(0, len);
120 FbBits orig = bits & mask;
121 int i;
122
123 if (width > FB_UNIT)
124 width = FB_UNIT;
125 for (i = 0; i < width / len; i++) {
126 if ((bits & mask) != orig)
127 return FALSE;
128 bits = FbScrLeft(bits, len);
129 }
130 return TRUE;
131}
132
133/*
134 * Check whether an entire bitmap line is a repetition of
135 * the first 'len' bits
136 */
137static Bool
138fbLineRepeat(FbBits * bits, int len, int width)
139{
140 FbBits first = bits[0];
141
142 if (!fbBitsRepeat(first, len, width))
143 return FALSE;
144 width = (width + FB_UNIT - 1) >> FB_SHIFT;
145 bits++;
146 while (--width)
147 if (READ(bits) != first)
148 return FALSE;
149 return TRUE;
150}
151
152/*
153 * The even stipple code wants the first FB_UNIT/bpp bits on
154 * each scanline to represent the entire stipple
155 */
156static Bool
157fbCanEvenStipple(PixmapPtr pStipple, int bpp)
158{
159 int len = FB_UNIT / bpp;
160 FbBits *bits;
161 int stride;
162 int stip_bpp;
163 _X_UNUSED int stipXoff, stipYoff;
164 int h;
165
166 /* can't even stipple 24bpp drawables */
167 if ((bpp & (bpp - 1)) != 0)
168 return FALSE;
169 /* make sure the stipple width is a multiple of the even stipple width */
170 if (pStipple->drawable.width % len != 0)
171 return FALSE;
172 fbGetDrawable(&pStipple->drawable, bits, stride, stip_bpp, stipXoff,
173 stipYoff);
174 h = pStipple->drawable.height;
175 /* check to see that the stipple repeats horizontally */
176 while (h--) {
177 if (!fbLineRepeat(bits, len, pStipple->drawable.width)) {
178 fbFinishAccess(&pStipple->drawable);
179 return FALSE;
180 }
181 bits += stride;
182 }
183 fbFinishAccess(&pStipple->drawable);
184 return TRUE;
185}
186
187void
188fbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable)
189{
190 FbGCPrivPtr pPriv = fbGetGCPrivate(pGC);
191 FbBits mask;
192
193 /*
194 * if the client clip is different or moved OR the subwindowMode has
195 * changed OR the window's clip has changed since the last validation
196 * we need to recompute the composite clip
197 */
198
199 if ((changes &
200 (GCClipXOrigin | GCClipYOrigin | GCClipMask | GCSubwindowMode)) ||
201 (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS))
202 ) {
203 miComputeCompositeClip(pGC, pDrawable);
204 }
205
206 if (pPriv->bpp != pDrawable->bitsPerPixel) {
207 changes |= GCStipple | GCForeground | GCBackground | GCPlaneMask;
208 pPriv->bpp = pDrawable->bitsPerPixel;
209 }
210 if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) {
211 (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC));
212 fbGetRotatedPixmap(pGC) = 0;
213 }
214
215 if (pGC->fillStyle == FillTiled) {
216 PixmapPtr pOldTile, pNewTile;
217
218 pOldTile = pGC->tile.pixmap;
219 if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) {
220 pNewTile = fbGetRotatedPixmap(pGC);
221 if (!pNewTile ||
222 pNewTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) {
223 if (pNewTile)
224 (*pGC->pScreen->DestroyPixmap) (pNewTile);
225 pNewTile =
226 fb24_32ReformatTile(pOldTile, pDrawable->bitsPerPixel);
227 }
228 if (pNewTile) {
229 fbGetRotatedPixmap(pGC) = pOldTile;
230 pGC->tile.pixmap = pNewTile;
231 changes |= GCTile;
232 }
233 }
234 }
235 if (changes & GCTile) {
236 if (!pGC->tileIsPixel &&
237 FbEvenTile(pGC->tile.pixmap->drawable.width *
238 pDrawable->bitsPerPixel))
239 fbPadPixmap(pGC->tile.pixmap);
240 }
241 if (changes & GCStipple) {
242 pPriv->evenStipple = FALSE;
243
244 if (pGC->stipple) {
245
246 /* can we do an even stipple ?? */
247 if (FbEvenStip(pGC->stipple->drawable.width,
248 pDrawable->bitsPerPixel) &&
249 (fbCanEvenStipple(pGC->stipple, pDrawable->bitsPerPixel)))
250 pPriv->evenStipple = TRUE;
251
252 if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel <
253 FB_UNIT)
254 fbPadPixmap(pGC->stipple);
255 }
256 }
257 /*
258 * Recompute reduced rop values
259 */
260 if (changes & (GCForeground | GCBackground | GCPlaneMask | GCFunction)) {
261 int s;
262 FbBits depthMask;
263
264 mask = FbFullMask(pDrawable->bitsPerPixel);
265 depthMask = FbFullMask(pDrawable->depth);
266
267 pPriv->fg = pGC->fgPixel & mask;
268 pPriv->bg = pGC->bgPixel & mask;
269
270 if ((pGC->planemask & depthMask) == depthMask)
271 pPriv->pm = mask;
272 else
273 pPriv->pm = pGC->planemask & mask;
274
275 s = pDrawable->bitsPerPixel;
276 while (s < FB_UNIT) {
277 pPriv->fg |= pPriv->fg << s;
278 pPriv->bg |= pPriv->bg << s;
279 pPriv->pm |= pPriv->pm << s;
280 s <<= 1;
281 }
282 pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm);
283 pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm);
284 pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm);
285 pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm);
286 }
287 if (changes & GCDashList) {
288 unsigned short n = pGC->numInDashList;
289 unsigned char *dash = pGC->dash;
290 unsigned int dashLength = 0;
291
292 while (n--)
293 dashLength += (unsigned int) *dash++;
294 pPriv->dashLength = dashLength;
295 }
296}