297 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
			
		
		
	
	
			297 lines
		
	
	
		
			8.1 KiB
		
	
	
	
		
			C
		
	
	
	
| /*
 | |
|  * 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->ops = (GCOps *) &fbGCOps;
 | |
|     pGC->funcs = (GCFuncs *) &fbGCFuncs;
 | |
| 
 | |
|     /* fb wants to translate before scan conversion */
 | |
|     pGC->miTranslate = 1;
 | |
|     pGC->fExpose = 1;
 | |
| 
 | |
|     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;
 | |
|     _X_UNUSED 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;
 | |
|     _X_UNUSED 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;
 | |
| 
 | |
|     /*
 | |
|      * 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);
 | |
|     }
 | |
| 
 | |
|     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;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     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;
 | |
|     }
 | |
| }
 |