/* * Copyright © 1998 Keith Packard * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation, and that the name of Keith Packard not be used in * advertising or publicity pertaining to distribution of the software without * specific, written prior permission. Keith Packard makes no * representations about the suitability of this software for any purpose. It * is provided "as is" without express or implied warranty. * * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ #ifdef HAVE_DIX_CONFIG_H #include <dix-config.h> #endif #include <stdlib.h> #include "fb.h" const GCFuncs fbGCFuncs = { fbValidateGC, miChangeGC, miCopyGC, miDestroyGC, miChangeClip, miDestroyClip, miCopyClip, }; const GCOps fbGCOps = { fbFillSpans, fbSetSpans, fbPutImage, fbCopyArea, fbCopyPlane, fbPolyPoint, fbPolyLine, fbPolySegment, fbPolyRectangle, fbPolyArc, miFillPolygon, fbPolyFillRect, fbPolyFillArc, miPolyText8, miPolyText16, miImageText8, miImageText16, fbImageGlyphBlt, fbPolyGlyphBlt, fbPushPixels }; Bool fbCreateGC(GCPtr pGC) { pGC->clientClip = NULL; pGC->clientClipType = CT_NONE; pGC->ops = (GCOps *) &fbGCOps; pGC->funcs = (GCFuncs *) &fbGCFuncs; /* fb wants to translate before scan conversion */ pGC->miTranslate = 1; fbGetRotatedPixmap(pGC) = 0; fbGetExpose(pGC) = 1; fbGetFreeCompClip(pGC) = 0; fbGetCompositeClip(pGC) = 0; fbGetGCPrivate(pGC)->bpp = BitsPerPixel (pGC->depth); return TRUE; } /* * Pad pixmap to FB_UNIT bits wide */ void fbPadPixmap (PixmapPtr pPixmap) { int width; FbBits *bits; FbBits b; FbBits mask; int height; int w; int stride; int bpp; int xOff, yOff; fbGetDrawable (&pPixmap->drawable, bits, stride, bpp, xOff, yOff); width = pPixmap->drawable.width * pPixmap->drawable.bitsPerPixel; height = pPixmap->drawable.height; mask = FbBitsMask (0, width); while (height--) { b = READ(bits) & mask; w = width; while (w < FB_UNIT) { b = b | FbScrRight(b, w); w <<= 1; } WRITE(bits, b); bits += stride; } fbFinishAccess (&pPixmap->drawable); } /* * Verify that 'bits' repeats every 'len' bits */ static Bool fbBitsRepeat (FbBits bits, int len, int width) { FbBits mask = FbBitsMask(0, len); FbBits orig = bits & mask; int i; if (width > FB_UNIT) width = FB_UNIT; for (i = 0; i < width / len; i++) { if ((bits & mask) != orig) return FALSE; bits = FbScrLeft(bits,len); } return TRUE; } /* * Check whether an entire bitmap line is a repetition of * the first 'len' bits */ static Bool fbLineRepeat (FbBits *bits, int len, int width) { FbBits first = bits[0]; if (!fbBitsRepeat (first, len, width)) return FALSE; width = (width + FB_UNIT-1) >> FB_SHIFT; bits++; while (--width) if (READ(bits) != first) return FALSE; return TRUE; } /* * The even stipple code wants the first FB_UNIT/bpp bits on * each scanline to represent the entire stipple */ static Bool fbCanEvenStipple (PixmapPtr pStipple, int bpp) { int len = FB_UNIT / bpp; FbBits *bits; int stride; int stip_bpp; int stipXoff, stipYoff; int h; /* can't even stipple 24bpp drawables */ if ((bpp & (bpp-1)) != 0) return FALSE; /* make sure the stipple width is a multiple of the even stipple width */ if (pStipple->drawable.width % len != 0) return FALSE; fbGetDrawable (&pStipple->drawable, bits, stride, stip_bpp, stipXoff, stipYoff); h = pStipple->drawable.height; /* check to see that the stipple repeats horizontally */ while (h--) { if (!fbLineRepeat (bits, len, pStipple->drawable.width)) { fbFinishAccess (&pStipple->drawable); return FALSE; } bits += stride; } fbFinishAccess (&pStipple->drawable); return TRUE; } void fbValidateGC(GCPtr pGC, unsigned long changes, DrawablePtr pDrawable) { FbGCPrivPtr pPriv = fbGetGCPrivate(pGC); FbBits mask; pGC->lastWinOrg.x = pDrawable->x; pGC->lastWinOrg.y = pDrawable->y; /* * if the client clip is different or moved OR the subwindowMode has * changed OR the window's clip has changed since the last validation * we need to recompute the composite clip */ if ((changes & (GCClipXOrigin|GCClipYOrigin|GCClipMask|GCSubwindowMode)) || (pDrawable->serialNumber != (pGC->serialNumber & DRAWABLE_SERIAL_BITS)) ) { miComputeCompositeClip (pGC, pDrawable); pPriv->oneRect = REGION_NUM_RECTS(fbGetCompositeClip(pGC)) == 1; } #ifdef FB_24_32BIT if (pPriv->bpp != pDrawable->bitsPerPixel) { changes |= GCStipple|GCForeground|GCBackground|GCPlaneMask; pPriv->bpp = pDrawable->bitsPerPixel; } if ((changes & GCTile) && fbGetRotatedPixmap(pGC)) { (*pGC->pScreen->DestroyPixmap) (fbGetRotatedPixmap(pGC)); fbGetRotatedPixmap(pGC) = 0; } if (pGC->fillStyle == FillTiled) { PixmapPtr pOldTile, pNewTile; pOldTile = pGC->tile.pixmap; if (pOldTile->drawable.bitsPerPixel != pDrawable->bitsPerPixel) { pNewTile = fbGetRotatedPixmap(pGC); if (!pNewTile || pNewTile ->drawable.bitsPerPixel != pDrawable->bitsPerPixel) { if (pNewTile) (*pGC->pScreen->DestroyPixmap) (pNewTile); pNewTile = fb24_32ReformatTile (pOldTile, pDrawable->bitsPerPixel); } if (pNewTile) { fbGetRotatedPixmap(pGC) = pOldTile; pGC->tile.pixmap = pNewTile; changes |= GCTile; } } } #endif if (changes & GCTile) { if (!pGC->tileIsPixel && FbEvenTile (pGC->tile.pixmap->drawable.width * pDrawable->bitsPerPixel)) fbPadPixmap (pGC->tile.pixmap); } if (changes & GCStipple) { pPriv->evenStipple = FALSE; if (pGC->stipple) { /* can we do an even stipple ?? */ if (FbEvenStip (pGC->stipple->drawable.width, pDrawable->bitsPerPixel) && (fbCanEvenStipple (pGC->stipple, pDrawable->bitsPerPixel))) pPriv->evenStipple = TRUE; if (pGC->stipple->drawable.width * pDrawable->bitsPerPixel < FB_UNIT) fbPadPixmap (pGC->stipple); } } /* * Recompute reduced rop values */ if (changes & (GCForeground|GCBackground|GCPlaneMask|GCFunction)) { int s; FbBits depthMask; mask = FbFullMask(pDrawable->bitsPerPixel); depthMask = FbFullMask(pDrawable->depth); pPriv->fg = pGC->fgPixel & mask; pPriv->bg = pGC->bgPixel & mask; if ((pGC->planemask & depthMask) == depthMask) pPriv->pm = mask; else pPriv->pm = pGC->planemask & mask; s = pDrawable->bitsPerPixel; while (s < FB_UNIT) { pPriv->fg |= pPriv->fg << s; pPriv->bg |= pPriv->bg << s; pPriv->pm |= pPriv->pm << s; s <<= 1; } pPriv->and = fbAnd(pGC->alu, pPriv->fg, pPriv->pm); pPriv->xor = fbXor(pGC->alu, pPriv->fg, pPriv->pm); pPriv->bgand = fbAnd(pGC->alu, pPriv->bg, pPriv->pm); pPriv->bgxor = fbXor(pGC->alu, pPriv->bg, pPriv->pm); } if (changes & GCDashList) { unsigned short n = pGC->numInDashList; unsigned char *dash = pGC->dash; unsigned int dashLength = 0; while (n--) dashLength += (unsigned int ) *dash++; pPriv->dashLength = dashLength; } }