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