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