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;
|
|
}
|
|
}
|