1706f2543Smrg/* 2706f2543Smrg * Copyright © 1998 Keith Packard 3706f2543Smrg * 4706f2543Smrg * Permission to use, copy, modify, distribute, and sell this software and its 5706f2543Smrg * documentation for any purpose is hereby granted without fee, provided that 6706f2543Smrg * the above copyright notice appear in all copies and that both that 7706f2543Smrg * copyright notice and this permission notice appear in supporting 8706f2543Smrg * documentation, and that the name of Keith Packard not be used in 9706f2543Smrg * advertising or publicity pertaining to distribution of the software without 10706f2543Smrg * specific, written prior permission. Keith Packard makes no 11706f2543Smrg * representations about the suitability of this software for any purpose. It 12706f2543Smrg * is provided "as is" without express or implied warranty. 13706f2543Smrg * 14706f2543Smrg * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15706f2543Smrg * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16706f2543Smrg * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17706f2543Smrg * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18706f2543Smrg * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19706f2543Smrg * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20706f2543Smrg * PERFORMANCE OF THIS SOFTWARE. 21706f2543Smrg */ 22706f2543Smrg 23706f2543Smrg#ifdef HAVE_DIX_CONFIG_H 24706f2543Smrg#include <dix-config.h> 25706f2543Smrg#endif 26706f2543Smrg 27706f2543Smrg#include <stdlib.h> 28706f2543Smrg 29706f2543Smrg#include "fb.h" 30706f2543Smrg 31706f2543Smrgconst GCFuncs fbGCFuncs = { 32706f2543Smrg fbValidateGC, 33706f2543Smrg miChangeGC, 34706f2543Smrg miCopyGC, 35706f2543Smrg miDestroyGC, 36706f2543Smrg miChangeClip, 37706f2543Smrg miDestroyClip, 38706f2543Smrg miCopyClip, 39706f2543Smrg}; 40706f2543Smrg 41706f2543Smrgconst GCOps fbGCOps = { 42706f2543Smrg fbFillSpans, 43706f2543Smrg fbSetSpans, 44706f2543Smrg fbPutImage, 45706f2543Smrg fbCopyArea, 46706f2543Smrg fbCopyPlane, 47706f2543Smrg fbPolyPoint, 48706f2543Smrg fbPolyLine, 49706f2543Smrg fbPolySegment, 50706f2543Smrg fbPolyRectangle, 51706f2543Smrg fbPolyArc, 52706f2543Smrg miFillPolygon, 53706f2543Smrg fbPolyFillRect, 54706f2543Smrg fbPolyFillArc, 55706f2543Smrg miPolyText8, 56706f2543Smrg miPolyText16, 57706f2543Smrg miImageText8, 58706f2543Smrg miImageText16, 59706f2543Smrg fbImageGlyphBlt, 60706f2543Smrg fbPolyGlyphBlt, 61706f2543Smrg fbPushPixels 62706f2543Smrg}; 63706f2543Smrg 64706f2543SmrgBool 65706f2543SmrgfbCreateGC(GCPtr pGC) 66706f2543Smrg{ 67706f2543Smrg pGC->ops = (GCOps *) &fbGCOps; 68706f2543Smrg pGC->funcs = (GCFuncs *) &fbGCFuncs; 69706f2543Smrg 70706f2543Smrg /* fb wants to translate before scan conversion */ 71706f2543Smrg pGC->miTranslate = 1; 72706f2543Smrg pGC->fExpose = 1; 73706f2543Smrg 74706f2543Smrg fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth); 75706f2543Smrg return TRUE; 76706f2543Smrg} 77706f2543Smrg 78706f2543Smrg/* 79706f2543Smrg * Pad pixmap to FB_UNIT bits wide 80706f2543Smrg */ 81706f2543Smrgvoid 82706f2543SmrgfbPadPixmap (PixmapPtr pPixmap) 83706f2543Smrg{ 84706f2543Smrg int width; 85706f2543Smrg FbBits *bits; 86706f2543Smrg FbBits b; 87706f2543Smrg FbBits mask; 88706f2543Smrg int height; 89706f2543Smrg int w; 90706f2543Smrg int stride; 91706f2543Smrg int bpp; 92706f2543Smrg int xOff, yOff; 93706f2543Smrg 94706f2543Smrg fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff); 95706f2543Smrg 96706f2543Smrg width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel; 97706f2543Smrg height = pPixmap->drawable.height; 98706f2543Smrg mask = FbBitsMask (0, width); 99706f2543Smrg while (height--) 100706f2543Smrg { 101706f2543Smrg b = READ(bits) & mask; 102706f2543Smrg w = width; 103706f2543Smrg while (w < FB_UNIT) 104706f2543Smrg { 105706f2543Smrg b = b | FbScrRight(b, w); 106706f2543Smrg w <<= 1; 107706f2543Smrg } 108706f2543Smrg WRITE(bits, b); 109706f2543Smrg bits += stride; 110706f2543Smrg } 111706f2543Smrg 112706f2543Smrg fbFinishAccess (&pPixmap->drawable); 113706f2543Smrg} 114706f2543Smrg 115706f2543Smrg/* 116706f2543Smrg * Verify that 'bits' repeats every 'len' bits 117706f2543Smrg */ 118706f2543Smrgstatic Bool 119706f2543SmrgfbBitsRepeat (FbBits bits, int len, int width) 120706f2543Smrg{ 121706f2543Smrg FbBits mask = FbBitsMask(0, len); 122706f2543Smrg FbBits orig = bits & mask; 123706f2543Smrg int i; 124706f2543Smrg 125706f2543Smrg if (width > FB_UNIT) 126706f2543Smrg width = FB_UNIT; 127706f2543Smrg for (i = 0; i < width / len; i++) 128706f2543Smrg { 129706f2543Smrg if ((bits & mask) != orig) 130706f2543Smrg return FALSE; 131706f2543Smrg bits = FbScrLeft(bits,len); 132706f2543Smrg } 133706f2543Smrg return TRUE; 134706f2543Smrg} 135706f2543Smrg 136706f2543Smrg/* 137706f2543Smrg * Check whether an entire bitmap line is a repetition of 138706f2543Smrg * the first 'len' bits 139706f2543Smrg */ 140706f2543Smrgstatic Bool 141706f2543SmrgfbLineRepeat (FbBits *bits, int len, int width) 142706f2543Smrg{ 143706f2543Smrg FbBits first = bits[0]; 144706f2543Smrg 145706f2543Smrg if (!fbBitsRepeat (first, len, width)) 146706f2543Smrg return FALSE; 147706f2543Smrg width = (width + FB_UNIT-1) >> FB_SHIFT; 148706f2543Smrg bits++; 149706f2543Smrg while (--width) 150706f2543Smrg if (READ(bits) != first) 151706f2543Smrg return FALSE; 152706f2543Smrg return TRUE; 153706f2543Smrg} 154706f2543Smrg 155706f2543Smrg/* 156706f2543Smrg * The even stipple code wants the first FB_UNIT/bpp bits on 157706f2543Smrg * each scanline to represent the entire stipple 158706f2543Smrg */ 159706f2543Smrgstatic Bool 160706f2543SmrgfbCanEvenStipple (PixmapPtr pStipple, int bpp) 161706f2543Smrg{ 162706f2543Smrg int len = FB_UNIT / bpp; 163706f2543Smrg FbBits *bits; 164706f2543Smrg int stride; 165706f2543Smrg int stip_bpp; 166706f2543Smrg int stipXoff, stipYoff; 167706f2543Smrg int h; 168706f2543Smrg 169706f2543Smrg /* can't even stipple 24bpp drawables */ 170706f2543Smrg if ((bpp & (bpp-1)) != 0) 171706f2543Smrg return FALSE; 172706f2543Smrg /* make sure the stipple width is a multiple of the even stipple width */ 173706f2543Smrg if (pStipple->drawable.width % len != 0) 174706f2543Smrg return FALSE; 175706f2543Smrg fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff); 176706f2543Smrg h = pStipple->drawable.height; 177706f2543Smrg /* check to see that the stipple repeats horizontally */ 178706f2543Smrg while (h--) 179706f2543Smrg { 180706f2543Smrg if (!fbLineRepeat (bits, len, pStipple->drawable.width)) { 181706f2543Smrg fbFinishAccess (&pStipple->drawable); 182706f2543Smrg return FALSE; 183706f2543Smrg } 184706f2543Smrg bits += stride; 185706f2543Smrg } 186706f2543Smrg fbFinishAccess (&pStipple->drawable); 187706f2543Smrg return TRUE; 188706f2543Smrg} 189706f2543Smrg 190706f2543Smrgvoid 191706f2543SmrgfbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) 192706f2543Smrg{ 193706f2543Smrg FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); 194706f2543Smrg FbBits mask; 195706f2543Smrg 196706f2543Smrg /* 197706f2543Smrg * if the client clip is different or moved OR the subwindowMode has 198706f2543Smrg * changed OR the window's clip has changed since the last validation 199706f2543Smrg * we need to recompute the composite clip 200706f2543Smrg */ 201706f2543Smrg 202706f2543Smrg if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) || 203706f2543Smrg (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)) 204706f2543Smrg ) 205706f2543Smrg { 206706f2543Smrg miComputeCompositeClip (pGC, pDrawable); 207706f2543Smrg } 208706f2543Smrg 209706f2543Smrg#ifdef FB_24_32BIT 210706f2543Smrg if (pPriv->bpp != pDrawable->bitsPerPixel) 211706f2543Smrg { 212706f2543Smrg changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask; 213706f2543Smrg pPriv->bpp = pDrawable->bitsPerPixel; 214706f2543Smrg } 215706f2543Smrg if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) 216706f2543Smrg { 217706f2543Smrg (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC)); 218706f2543Smrg fbGetRotatedPixmap(pGC) = 0; 219706f2543Smrg } 220706f2543Smrg 221706f2543Smrg if (pGC->fillStyle == FillTiled) 222706f2543Smrg { 223706f2543Smrg PixmapPtr pOldTile, pNewTile; 224706f2543Smrg 225706f2543Smrg pOldTile = pGC->tile.pixmap; 226706f2543Smrg if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) 227706f2543Smrg { 228706f2543Smrg pNewTile = fbGetRotatedPixmap(pGC); 229706f2543Smrg if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel) 230706f2543Smrg { 231706f2543Smrg if (pNewTile) 232706f2543Smrg (*pGC->pScreen->DestroyPixmap) (pNewTile); 233706f2543Smrg pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel); 234706f2543Smrg } 235706f2543Smrg if (pNewTile) 236706f2543Smrg { 237706f2543Smrg fbGetRotatedPixmap(pGC) = pOldTile; 238706f2543Smrg pGC->tile.pixmap = pNewTile; 239706f2543Smrg changes |= GCTile; 240706f2543Smrg } 241706f2543Smrg } 242706f2543Smrg } 243706f2543Smrg#endif 244706f2543Smrg if (changes & GCTile) 245706f2543Smrg { 246706f2543Smrg if (!pGC->tileIsPixel && 247706f2543Smrg FbEvenTile (pGC->tile.pixmap->drawable.width * 248706f2543Smrg pDrawable->bitsPerPixel)) 249706f2543Smrg fbPadPixmap (pGC->tile.pixmap); 250706f2543Smrg } 251706f2543Smrg if (changes & GCStipple) 252706f2543Smrg { 253706f2543Smrg pPriv->evenStipple = FALSE; 254706f2543Smrg 255706f2543Smrg if (pGC->stipple) { 256706f2543Smrg 257706f2543Smrg /* can we do an even stipple ?? */ 258706f2543Smrg if (FbEvenStip (pGC->stipple->drawable.width, 259706f2543Smrg pDrawable->bitsPerPixel) && 260706f2543Smrg (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel))) 261706f2543Smrg pPriv->evenStipple = TRUE; 262706f2543Smrg 263706f2543Smrg if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT) 264706f2543Smrg fbPadPixmap (pGC->stipple); 265706f2543Smrg } 266706f2543Smrg } 267706f2543Smrg /* 268706f2543Smrg * Recompute reduced rop values 269706f2543Smrg */ 270706f2543Smrg if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction)) 271706f2543Smrg { 272706f2543Smrg int s; 273706f2543Smrg FbBits depthMask; 274706f2543Smrg 275706f2543Smrg mask = FbFullMask(pDrawable->bitsPerPixel); 276706f2543Smrg depthMask = FbFullMask(pDrawable->depth); 277706f2543Smrg 278706f2543Smrg pPriv->fg = pGC->fgPixel & mask; 279706f2543Smrg pPriv->bg = pGC->bgPixel & mask; 280706f2543Smrg 281706f2543Smrg if ((pGC->planemask & depthMask) == depthMask) 282706f2543Smrg pPriv->pm = mask; 283706f2543Smrg else 284706f2543Smrg pPriv->pm = pGC->planemask & mask; 285706f2543Smrg 286706f2543Smrg s = pDrawable->bitsPerPixel; 287706f2543Smrg while (s < FB_UNIT) 288706f2543Smrg { 289706f2543Smrg pPriv->fg |= pPriv->fg << s; 290706f2543Smrg pPriv->bg |= pPriv->bg << s; 291706f2543Smrg pPriv->pm |= pPriv->pm << s; 292706f2543Smrg s <<= 1; 293706f2543Smrg } 294706f2543Smrg pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm); 295706f2543Smrg pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm); 296706f2543Smrg pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm); 297706f2543Smrg pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm); 298706f2543Smrg } 299706f2543Smrg if (changes & GCDashList) 300706f2543Smrg { 301706f2543Smrg unsigned short n = pGC->numInDashList; 302706f2543Smrg unsigned char *dash = pGC->dash; 303706f2543Smrg unsigned int dashLength = 0; 304706f2543Smrg 305706f2543Smrg while (n--) 306706f2543Smrg dashLength += (unsigned int ) *dash++; 307706f2543Smrg pPriv->dashLength = dashLength; 308706f2543Smrg } 309706f2543Smrg} 310