TinyX/fb/fbgc.c

322 lines
8.3 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->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 _X_UNUSED, yOff _X_UNUSED;
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 = *bits & mask;
w = width;
while (w < FB_UNIT) {
b = b | FbScrRight(b, w);
w <<= 1;
}
*bits = b;
bits += stride;
}
}
/*
* 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 (*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 _X_UNUSED, stipYoff _X_UNUSED;
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))
return FALSE;
bits += stride;
}
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;
}
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;
}
}