1119 lines
24 KiB
C
1119 lines
24 KiB
C
/***********************************************************
|
|
|
|
Copyright 1987, 1998 The Open Group
|
|
|
|
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.
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
|
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
|
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
|
|
Except as contained in this notice, the name of The Open Group shall not be
|
|
used in advertising or otherwise to promote the sale, use or other dealings
|
|
in this Software without prior written authorization from The Open Group.
|
|
|
|
|
|
Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
|
|
|
|
All Rights Reserved
|
|
|
|
Permission to use, copy, modify, and distribute this software and its
|
|
documentation for any purpose and without fee is hereby granted,
|
|
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 Digital not be
|
|
used in advertising or publicity pertaining to distribution of the
|
|
software without specific, written prior permission.
|
|
|
|
DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
|
|
ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
|
|
DIGITAL 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 <X11/X.h>
|
|
#include <X11/Xmd.h>
|
|
#include <X11/Xproto.h>
|
|
#include "mfb.h"
|
|
#include "dixfontstr.h"
|
|
#include <X11/fonts/fontstruct.h>
|
|
#include "gcstruct.h"
|
|
#include "windowstr.h"
|
|
#include "pixmapstr.h"
|
|
#include "scrnintstr.h"
|
|
#include "region.h"
|
|
|
|
#include "mistruct.h"
|
|
#include "migc.h"
|
|
|
|
#include "maskbits.h"
|
|
|
|
static GCFuncs mfbFuncs = {
|
|
mfbValidateGC,
|
|
miChangeGC,
|
|
miCopyGC,
|
|
miDestroyGC,
|
|
miChangeClip,
|
|
miDestroyClip,
|
|
miCopyClip
|
|
};
|
|
|
|
|
|
static GCOps whiteTECopyOps = {
|
|
mfbWhiteSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
mfbZeroPolyArcSS,
|
|
mfbFillPolyWhite,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbTEGlyphBltWhite,
|
|
mfbPolyGlyphBltWhite,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps blackTECopyOps = {
|
|
mfbBlackSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
mfbZeroPolyArcSS,
|
|
mfbFillPolyBlack,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbTEGlyphBltBlack,
|
|
mfbPolyGlyphBltBlack,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps whiteTEInvertOps = {
|
|
mfbInvertSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
miCopyArea,
|
|
miCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
miZeroPolyArc,
|
|
mfbFillPolyInvert,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbTEGlyphBltWhite,
|
|
mfbPolyGlyphBltInvert,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps blackTEInvertOps = {
|
|
mfbInvertSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
miZeroPolyArc,
|
|
mfbFillPolyInvert,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbTEGlyphBltBlack,
|
|
mfbPolyGlyphBltInvert,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps whiteCopyOps = {
|
|
mfbWhiteSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
mfbZeroPolyArcSS,
|
|
mfbFillPolyWhite,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbImageGlyphBltWhite,
|
|
mfbPolyGlyphBltWhite,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps blackCopyOps = {
|
|
mfbBlackSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
mfbZeroPolyArcSS,
|
|
mfbFillPolyBlack,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbImageGlyphBltBlack,
|
|
mfbPolyGlyphBltBlack,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps whiteInvertOps = {
|
|
mfbInvertSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
miZeroPolyArc,
|
|
mfbFillPolyInvert,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbImageGlyphBltWhite,
|
|
mfbPolyGlyphBltInvert,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps blackInvertOps = {
|
|
mfbInvertSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
miZeroPolyArc,
|
|
mfbFillPolyInvert,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
mfbImageGlyphBltBlack,
|
|
mfbPolyGlyphBltInvert,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps whiteWhiteCopyOps = {
|
|
mfbWhiteSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
mfbZeroPolyArcSS,
|
|
mfbFillPolyWhite,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
miImageGlyphBlt,
|
|
mfbPolyGlyphBltWhite,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps blackBlackCopyOps = {
|
|
mfbBlackSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
mfbZeroPolyArcSS,
|
|
mfbFillPolyBlack,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
miImageGlyphBlt,
|
|
mfbPolyGlyphBltBlack,
|
|
mfbSolidPP
|
|
};
|
|
|
|
static GCOps fgEqBgInvertOps = {
|
|
mfbInvertSolidFS,
|
|
mfbSetSpans,
|
|
mfbPutImage,
|
|
mfbCopyArea,
|
|
mfbCopyPlane,
|
|
mfbPolyPoint,
|
|
mfbLineSS,
|
|
mfbSegmentSS,
|
|
miPolyRectangle,
|
|
miZeroPolyArc,
|
|
mfbFillPolyInvert,
|
|
mfbPolyFillRect,
|
|
mfbPolyFillArcSolid,
|
|
miPolyText8,
|
|
miPolyText16,
|
|
miImageText8,
|
|
miImageText16,
|
|
miImageGlyphBlt,
|
|
mfbPolyGlyphBltInvert,
|
|
mfbSolidPP
|
|
};
|
|
|
|
|
|
struct commonOps {
|
|
int fg, bg;
|
|
int rrop;
|
|
int terminalFont;
|
|
GCOps *ops;
|
|
void (*fillArea)(
|
|
DrawablePtr /*pDraw*/,
|
|
int /*nbox*/,
|
|
BoxPtr /*pbox*/,
|
|
int /*alu*/,
|
|
PixmapPtr /*nop*/);
|
|
};
|
|
|
|
static struct commonOps mfbCommonOps[] = {
|
|
{ 1, 0, RROP_WHITE, 1, &whiteTECopyOps, mfbSolidWhiteArea },
|
|
{ 0, 1, RROP_BLACK, 1, &blackTECopyOps, mfbSolidBlackArea },
|
|
{ 1, 0, RROP_INVERT, 1, &whiteTEInvertOps, mfbSolidInvertArea },
|
|
{ 0, 1, RROP_INVERT, 1, &blackTEInvertOps, mfbSolidInvertArea },
|
|
{ 1, 0, RROP_WHITE, 0, &whiteCopyOps, mfbSolidWhiteArea },
|
|
{ 0, 1, RROP_BLACK, 0, &blackCopyOps, mfbSolidBlackArea },
|
|
{ 1, 0, RROP_INVERT, 0, &whiteInvertOps, mfbSolidInvertArea },
|
|
{ 0, 1, RROP_INVERT, 0, &blackInvertOps, mfbSolidInvertArea },
|
|
{ 1, 1, RROP_WHITE, 0, &whiteWhiteCopyOps, mfbSolidWhiteArea },
|
|
{ 0, 0, RROP_BLACK, 0, &blackBlackCopyOps, mfbSolidBlackArea },
|
|
{ 1, 1, RROP_INVERT, 0, &fgEqBgInvertOps, mfbSolidInvertArea },
|
|
{ 0, 0, RROP_INVERT, 0, &fgEqBgInvertOps, mfbSolidInvertArea },
|
|
};
|
|
|
|
#define numberCommonOps (sizeof (mfbCommonOps) / sizeof (mfbCommonOps[0]))
|
|
|
|
static GCOps *
|
|
matchCommon (
|
|
GCPtr pGC)
|
|
{
|
|
int i;
|
|
struct commonOps *cop;
|
|
mfbPrivGC *priv;
|
|
|
|
if (pGC->lineWidth != 0)
|
|
return 0;
|
|
if (pGC->lineStyle != LineSolid)
|
|
return 0;
|
|
if (pGC->fillStyle != FillSolid)
|
|
return 0;
|
|
if (!pGC->font ||
|
|
FONTMAXBOUNDS(pGC->font,rightSideBearing) -
|
|
FONTMINBOUNDS(pGC->font,leftSideBearing) > 32 ||
|
|
FONTMINBOUNDS(pGC->font,characterWidth) < 0)
|
|
return 0;
|
|
priv = (mfbPrivGC *) pGC->devPrivates[mfbGCPrivateIndex].ptr;
|
|
for (i = 0; i < numberCommonOps; i++) {
|
|
cop = &mfbCommonOps[i];
|
|
if ((pGC->fgPixel & 1) != cop->fg)
|
|
continue;
|
|
if ((pGC->bgPixel & 1) != cop->bg)
|
|
continue;
|
|
if (priv->rop != cop->rrop)
|
|
continue;
|
|
if (cop->terminalFont && !TERMINALFONT(pGC->font))
|
|
continue;
|
|
priv->FillArea = cop->fillArea;
|
|
return cop->ops;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
Bool
|
|
mfbCreateGC(pGC)
|
|
register GCPtr pGC;
|
|
{
|
|
mfbPrivGC *pPriv;
|
|
|
|
pGC->clientClip = NULL;
|
|
pGC->clientClipType = CT_NONE;
|
|
|
|
/* some of the output primitives aren't really necessary, since
|
|
they will be filled in ValidateGC because of dix/CreateGC()
|
|
setting all the change bits. Others are necessary because although
|
|
they depend on being a monochrome frame buffer, they don't change
|
|
*/
|
|
|
|
pGC->ops = &whiteCopyOps;
|
|
pGC->funcs = &mfbFuncs;
|
|
|
|
/* mfb wants to translate before scan convesion */
|
|
pGC->miTranslate = 1;
|
|
|
|
pPriv = (mfbPrivGC *)(pGC->devPrivates[mfbGCPrivateIndex].ptr);
|
|
pPriv->rop = mfbReduceRop(pGC->alu, pGC->fgPixel);
|
|
pGC->fExpose = TRUE;
|
|
pGC->pRotatedPixmap = NullPixmap;
|
|
pGC->freeCompClip = FALSE;
|
|
pPriv->FillArea = mfbSolidInvertArea;
|
|
return TRUE;
|
|
}
|
|
|
|
/* some noop functions */
|
|
static void
|
|
mfbPolyGlyphBltNoop(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int x,
|
|
int y,
|
|
unsigned int nglyph,
|
|
CharInfoPtr * ppci,
|
|
pointer pglyphBase)
|
|
{
|
|
/* this is a no-op function */
|
|
}
|
|
|
|
static void
|
|
mfbNoopFS(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int nInit,
|
|
DDXPointPtr pptInit,
|
|
int * pwidthInit,
|
|
int fSorted)
|
|
{
|
|
/* this is a no-op function */
|
|
}
|
|
|
|
static void
|
|
mfbFillPolyNoop(
|
|
DrawablePtr pDrawable,
|
|
GCPtr pGC,
|
|
int shape,
|
|
int mode,
|
|
int count,
|
|
DDXPointPtr ptsIn)
|
|
{
|
|
/* this is a no-op function */
|
|
}
|
|
|
|
|
|
/* Clipping conventions
|
|
if the drawable is a window
|
|
CT_REGION ==> pCompositeClip really is the composite
|
|
CT_other ==> pCompositeClip is the window clip region
|
|
if the drawable is a pixmap
|
|
CT_REGION ==> pCompositeClip is the translated client region
|
|
clipped to the pixmap boundary
|
|
CT_other ==> pCompositeClip is the pixmap bounding box
|
|
*/
|
|
|
|
/*ARGSUSED*/
|
|
void
|
|
mfbValidateGC(pGC, changes, pDrawable)
|
|
register GCPtr pGC;
|
|
unsigned long changes;
|
|
DrawablePtr pDrawable;
|
|
{
|
|
register mfbPrivGCPtr devPriv;
|
|
int mask; /* stateChanges */
|
|
int index; /* used for stepping through bitfields */
|
|
int xrot, yrot; /* rotations for tile and stipple pattern */
|
|
int rrop; /* reduced rasterop */
|
|
/* flags for changing the proc vector
|
|
and updating things in devPriv
|
|
*/
|
|
int new_rotate, new_rrop, new_line, new_text, new_fill;
|
|
DDXPointRec oldOrg; /* origin of thing GC was last used with */
|
|
|
|
oldOrg = pGC->lastWinOrg;
|
|
|
|
pGC->lastWinOrg.x = pDrawable->x;
|
|
pGC->lastWinOrg.y = pDrawable->y;
|
|
|
|
/* we need to re-rotate the tile if the previous window/pixmap
|
|
origin (oldOrg) differs from the new window/pixmap origin
|
|
(pGC->lastWinOrg)
|
|
*/
|
|
new_rotate = (oldOrg.x != pGC->lastWinOrg.x) ||
|
|
(oldOrg.y != pGC->lastWinOrg.y);
|
|
|
|
devPriv = ((mfbPrivGCPtr) (pGC->devPrivates[mfbGCPrivateIndex].ptr));
|
|
|
|
/*
|
|
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);
|
|
}
|
|
|
|
new_rrop = FALSE;
|
|
new_line = FALSE;
|
|
new_text = FALSE;
|
|
new_fill = FALSE;
|
|
|
|
mask = changes;
|
|
while (mask)
|
|
{
|
|
index = lowbit (mask);
|
|
mask &= ~index;
|
|
|
|
/* this switch acculmulates a list of which procedures
|
|
might have to change due to changes in the GC. in
|
|
some cases (e.g. changing one 16 bit tile for another)
|
|
we might not really need a change, but the code is
|
|
being paranoid.
|
|
this sort of batching wins if, for example, the alu
|
|
and the font have been changed, or any other pair
|
|
of items that both change the same thing.
|
|
*/
|
|
switch (index)
|
|
{
|
|
case GCFunction:
|
|
case GCForeground:
|
|
new_rrop = TRUE;
|
|
break;
|
|
case GCPlaneMask:
|
|
break;
|
|
case GCBackground:
|
|
new_rrop = TRUE; /* for opaque stipples */
|
|
break;
|
|
case GCLineStyle:
|
|
case GCLineWidth:
|
|
case GCJoinStyle:
|
|
new_line = TRUE;
|
|
break;
|
|
case GCCapStyle:
|
|
break;
|
|
case GCFillStyle:
|
|
new_fill = TRUE;
|
|
break;
|
|
case GCFillRule:
|
|
break;
|
|
case GCTile:
|
|
if(pGC->tileIsPixel)
|
|
break;
|
|
new_rotate = TRUE;
|
|
new_fill = TRUE;
|
|
break;
|
|
|
|
case GCStipple:
|
|
if(pGC->stipple == (PixmapPtr)NULL)
|
|
break;
|
|
new_rotate = TRUE;
|
|
new_fill = TRUE;
|
|
break;
|
|
|
|
case GCTileStipXOrigin:
|
|
new_rotate = TRUE;
|
|
break;
|
|
|
|
case GCTileStipYOrigin:
|
|
new_rotate = TRUE;
|
|
break;
|
|
|
|
case GCFont:
|
|
new_text = TRUE;
|
|
break;
|
|
case GCSubwindowMode:
|
|
break;
|
|
case GCGraphicsExposures:
|
|
break;
|
|
case GCClipXOrigin:
|
|
break;
|
|
case GCClipYOrigin:
|
|
break;
|
|
case GCClipMask:
|
|
break;
|
|
case GCDashOffset:
|
|
break;
|
|
case GCDashList:
|
|
break;
|
|
case GCArcMode:
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* deal with the changes we've collected .
|
|
new_rrop must be done first because subsequent things
|
|
depend on it.
|
|
*/
|
|
|
|
if(new_rotate || new_fill)
|
|
{
|
|
Bool new_pix = FALSE;
|
|
|
|
/* figure out how much to rotate */
|
|
xrot = pGC->patOrg.x;
|
|
yrot = pGC->patOrg.y;
|
|
xrot += pDrawable->x;
|
|
yrot += pDrawable->y;
|
|
|
|
switch (pGC->fillStyle)
|
|
{
|
|
case FillTiled:
|
|
/* copy current tile and stipple */
|
|
if (!pGC->tileIsPixel && (pGC->tile.pixmap->drawable.width <= PPW) &&
|
|
!(pGC->tile.pixmap->drawable.width & (pGC->tile.pixmap->drawable.width - 1)))
|
|
{
|
|
mfbCopyRotatePixmap(pGC->tile.pixmap,
|
|
&pGC->pRotatedPixmap, xrot, yrot);
|
|
new_pix = TRUE;
|
|
}
|
|
break;
|
|
case FillStippled:
|
|
case FillOpaqueStippled:
|
|
if (pGC->stipple && (pGC->stipple->drawable.width <= PPW) &&
|
|
!(pGC->stipple->drawable.width & (pGC->stipple->drawable.width - 1)))
|
|
{
|
|
mfbCopyRotatePixmap(pGC->stipple,
|
|
&pGC->pRotatedPixmap, xrot, yrot);
|
|
new_pix = TRUE;
|
|
}
|
|
}
|
|
/* destroy any previously rotated tile or stipple */
|
|
if (!new_pix && pGC->pRotatedPixmap)
|
|
{
|
|
(*pDrawable->pScreen->DestroyPixmap)(pGC->pRotatedPixmap);
|
|
pGC->pRotatedPixmap = (PixmapPtr)NULL;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* duck out here when the GC is unchanged
|
|
*/
|
|
|
|
if (!changes)
|
|
return;
|
|
|
|
if (new_rrop || new_fill)
|
|
{
|
|
rrop = mfbReduceRop(pGC->alu, pGC->fgPixel);
|
|
devPriv->rop = rrop;
|
|
new_fill = TRUE;
|
|
/* FillArea raster op is GC's for tile filling,
|
|
and the reduced rop for solid and stipple
|
|
*/
|
|
if (pGC->fillStyle == FillTiled)
|
|
devPriv->ropFillArea = pGC->alu;
|
|
else
|
|
devPriv->ropFillArea = rrop;
|
|
|
|
/* opaque stipples:
|
|
fg bg ropOpStip fill style
|
|
1 0 alu tile
|
|
0 1 inverseAlu tile
|
|
1 1 rrop(fg, alu) solid
|
|
0 0 rrop(fg, alu) solid
|
|
Note that rrop(fg, alu) == mfbPrivGC.rop, so we don't really need to
|
|
compute it.
|
|
*/
|
|
if (pGC->fillStyle == FillOpaqueStippled)
|
|
{
|
|
if ((pGC->fgPixel & 1) != (pGC->bgPixel & 1))
|
|
{
|
|
if (pGC->fgPixel & 1)
|
|
devPriv->ropOpStip = pGC->alu;
|
|
else
|
|
devPriv->ropOpStip = InverseAlu[pGC->alu];
|
|
}
|
|
else
|
|
devPriv->ropOpStip = rrop;
|
|
devPriv->ropFillArea = devPriv->ropOpStip;
|
|
}
|
|
}
|
|
else
|
|
rrop = devPriv->rop;
|
|
|
|
if (new_line || new_fill || new_text)
|
|
{
|
|
GCOps *newops;
|
|
|
|
if ((newops = matchCommon (pGC)))
|
|
{
|
|
if (pGC->ops->devPrivate.val)
|
|
miDestroyGCOps (pGC->ops);
|
|
pGC->ops = newops;
|
|
new_line = new_fill = new_text = 0;
|
|
}
|
|
else
|
|
{
|
|
if (!pGC->ops->devPrivate.val)
|
|
{
|
|
pGC->ops = miCreateGCOps (pGC->ops);
|
|
pGC->ops->devPrivate.val = 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (new_line || new_fill)
|
|
{
|
|
if (pGC->lineWidth == 0)
|
|
{
|
|
if ((pGC->lineStyle == LineSolid) && (pGC->fillStyle == FillSolid)
|
|
&& ((rrop == RROP_WHITE) || (rrop == RROP_BLACK)))
|
|
pGC->ops->PolyArc = mfbZeroPolyArcSS;
|
|
else
|
|
pGC->ops->PolyArc = miZeroPolyArc;
|
|
}
|
|
else
|
|
pGC->ops->PolyArc = miPolyArc;
|
|
if (pGC->lineStyle == LineSolid)
|
|
{
|
|
if(pGC->lineWidth == 0)
|
|
{
|
|
if (pGC->fillStyle == FillSolid)
|
|
{
|
|
pGC->ops->PolySegment = mfbSegmentSS;
|
|
pGC->ops->Polylines = mfbLineSS;
|
|
}
|
|
else
|
|
{
|
|
pGC->ops->PolySegment = miPolySegment;
|
|
pGC->ops->Polylines = miZeroLine;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pGC->ops->PolySegment = miPolySegment;
|
|
pGC->ops->Polylines = miWideLine;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(pGC->lineWidth == 0 && pGC->fillStyle == FillSolid)
|
|
{
|
|
pGC->ops->Polylines = mfbLineSD;
|
|
pGC->ops->PolySegment = mfbSegmentSD;
|
|
}
|
|
else
|
|
{
|
|
pGC->ops->Polylines = miWideDash;
|
|
pGC->ops->PolySegment = miPolySegment;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (new_text || new_fill)
|
|
{
|
|
if ((pGC->font) &&
|
|
(FONTMAXBOUNDS(pGC->font,rightSideBearing) -
|
|
FONTMINBOUNDS(pGC->font,leftSideBearing) > 32 ||
|
|
FONTMINBOUNDS(pGC->font,characterWidth) < 0))
|
|
{
|
|
pGC->ops->PolyGlyphBlt = miPolyGlyphBlt;
|
|
pGC->ops->ImageGlyphBlt = miImageGlyphBlt;
|
|
}
|
|
else
|
|
{
|
|
/* special case ImageGlyphBlt for terminal emulator fonts */
|
|
|
|
|
|
if ((pGC->font) &&
|
|
TERMINALFONT(pGC->font) &&
|
|
((pGC->fgPixel & 1) != (pGC->bgPixel & 1)))
|
|
{
|
|
/* pcc bug makes this not compile...
|
|
pGC->ops->ImageGlyphBlt = (pGC->fgPixel & 1) ? mfbTEGlyphBltWhite :
|
|
mfbTEGlyphBltBlack;
|
|
*/
|
|
if (pGC->fgPixel & 1)
|
|
pGC->ops->ImageGlyphBlt = mfbTEGlyphBltWhite;
|
|
else
|
|
pGC->ops->ImageGlyphBlt = mfbTEGlyphBltBlack;
|
|
}
|
|
else
|
|
|
|
|
|
{
|
|
if (pGC->fgPixel & 1)
|
|
pGC->ops->ImageGlyphBlt = mfbImageGlyphBltWhite;
|
|
else
|
|
pGC->ops->ImageGlyphBlt = mfbImageGlyphBltBlack;
|
|
}
|
|
|
|
/* now do PolyGlyphBlt */
|
|
if (pGC->fillStyle == FillSolid ||
|
|
(pGC->fillStyle == FillOpaqueStippled &&
|
|
(pGC->fgPixel & 1) == (pGC->bgPixel & 1)
|
|
)
|
|
)
|
|
{
|
|
if (rrop == RROP_WHITE)
|
|
pGC->ops->PolyGlyphBlt = mfbPolyGlyphBltWhite;
|
|
else if (rrop == RROP_BLACK)
|
|
pGC->ops->PolyGlyphBlt = mfbPolyGlyphBltBlack;
|
|
else if (rrop == RROP_INVERT)
|
|
pGC->ops->PolyGlyphBlt = mfbPolyGlyphBltInvert;
|
|
else
|
|
pGC->ops->PolyGlyphBlt = mfbPolyGlyphBltNoop;
|
|
}
|
|
else
|
|
{
|
|
pGC->ops->PolyGlyphBlt = miPolyGlyphBlt;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (new_fill)
|
|
|
|
|
|
{
|
|
/* install a suitable fillspans and pushpixels */
|
|
pGC->ops->PushPixels = mfbPushPixels;
|
|
pGC->ops->FillPolygon = miFillPolygon;
|
|
if ((pGC->fillStyle == FillSolid) ||
|
|
((pGC->fillStyle == FillOpaqueStippled) &&
|
|
((pGC->fgPixel & 1) == (pGC->bgPixel & 1))))
|
|
{
|
|
pGC->ops->PushPixels = mfbSolidPP;
|
|
switch(devPriv->rop)
|
|
{
|
|
case RROP_WHITE:
|
|
pGC->ops->FillSpans = mfbWhiteSolidFS;
|
|
pGC->ops->FillPolygon = mfbFillPolyWhite;
|
|
break;
|
|
case RROP_BLACK:
|
|
pGC->ops->FillSpans = mfbBlackSolidFS;
|
|
pGC->ops->FillPolygon = mfbFillPolyBlack;
|
|
break;
|
|
case RROP_INVERT:
|
|
pGC->ops->FillSpans = mfbInvertSolidFS;
|
|
pGC->ops->FillPolygon = mfbFillPolyInvert;
|
|
break;
|
|
case RROP_NOP:
|
|
pGC->ops->FillSpans = mfbNoopFS;
|
|
pGC->ops->FillPolygon = mfbFillPolyNoop;
|
|
break;
|
|
}
|
|
}
|
|
/* beyond this point, opaqueStippled ==> fg != bg */
|
|
else if (((pGC->fillStyle == FillTiled) ||
|
|
(pGC->fillStyle == FillOpaqueStippled)) &&
|
|
!pGC->pRotatedPixmap)
|
|
{
|
|
pGC->ops->FillSpans = mfbUnnaturalTileFS;
|
|
}
|
|
else if ((pGC->fillStyle == FillStippled) && !pGC->pRotatedPixmap)
|
|
{
|
|
pGC->ops->FillSpans = mfbUnnaturalStippleFS;
|
|
}
|
|
else if (pGC->fillStyle == FillStippled)
|
|
{
|
|
switch(devPriv->rop)
|
|
{
|
|
case RROP_WHITE:
|
|
pGC->ops->FillSpans = mfbWhiteStippleFS;
|
|
break;
|
|
case RROP_BLACK:
|
|
pGC->ops->FillSpans = mfbBlackStippleFS;
|
|
break;
|
|
case RROP_INVERT:
|
|
pGC->ops->FillSpans = mfbInvertStippleFS;
|
|
break;
|
|
case RROP_NOP:
|
|
pGC->ops->FillSpans = mfbNoopFS;
|
|
break;
|
|
}
|
|
}
|
|
else /* overload tiles to do parti-colored opaque stipples */
|
|
{
|
|
pGC->ops->FillSpans = mfbTileFS;
|
|
}
|
|
if (pGC->fillStyle == FillSolid)
|
|
pGC->ops->PolyFillArc = mfbPolyFillArcSolid;
|
|
else
|
|
pGC->ops->PolyFillArc = miPolyFillArc;
|
|
/* the rectangle code doesn't deal with opaque stipples that
|
|
are two colors -- we can fool it for fg==bg, though
|
|
*/
|
|
if ((((pGC->fillStyle == FillTiled) ||
|
|
(pGC->fillStyle == FillStippled)) &&
|
|
!pGC->pRotatedPixmap) ||
|
|
((pGC->fillStyle == FillOpaqueStippled) &&
|
|
((pGC->fgPixel & 1) != (pGC->bgPixel & 1)))
|
|
)
|
|
{
|
|
pGC->ops->PolyFillRect = miPolyFillRect;
|
|
}
|
|
else /* deal with solids and natural stipples and tiles */
|
|
{
|
|
pGC->ops->PolyFillRect = mfbPolyFillRect;
|
|
|
|
if ((pGC->fillStyle == FillSolid) ||
|
|
((pGC->fillStyle == FillOpaqueStippled) &&
|
|
((pGC->fgPixel & 1) == (pGC->bgPixel & 1))))
|
|
{
|
|
switch(devPriv->rop)
|
|
{
|
|
case RROP_WHITE:
|
|
devPriv->FillArea = mfbSolidWhiteArea;
|
|
break;
|
|
case RROP_BLACK:
|
|
devPriv->FillArea = mfbSolidBlackArea;
|
|
break;
|
|
case RROP_INVERT:
|
|
devPriv->FillArea = mfbSolidInvertArea;
|
|
break;
|
|
case RROP_NOP:
|
|
devPriv->FillArea = (mfbFillAreaProcPtr)NoopDDA;
|
|
break;
|
|
}
|
|
}
|
|
else if (pGC->fillStyle == FillStippled)
|
|
{
|
|
switch(devPriv->rop)
|
|
{
|
|
case RROP_WHITE:
|
|
devPriv->FillArea = mfbStippleWhiteArea;
|
|
break;
|
|
case RROP_BLACK:
|
|
devPriv->FillArea = mfbStippleBlackArea;
|
|
break;
|
|
case RROP_INVERT:
|
|
devPriv->FillArea = mfbStippleInvertArea;
|
|
break;
|
|
case RROP_NOP:
|
|
devPriv->FillArea = (mfbFillAreaProcPtr)NoopDDA;
|
|
break;
|
|
}
|
|
}
|
|
else /* deal with tiles */
|
|
{
|
|
switch (pGC->alu)
|
|
{
|
|
case GXcopy:
|
|
devPriv->FillArea = mfbTileAreaPPWCopy;
|
|
break;
|
|
default:
|
|
devPriv->FillArea = mfbTileAreaPPWGeneral;
|
|
break;
|
|
}
|
|
}
|
|
} /* end of natural rectangles */
|
|
} /* end of new_fill */
|
|
|
|
|
|
}
|
|
|
|
/* table to map alu(src, dst) to alu(~src, dst) */
|
|
int InverseAlu[16] = {
|
|
GXclear,
|
|
GXandInverted,
|
|
GXnor,
|
|
GXcopyInverted,
|
|
GXand,
|
|
GXnoop,
|
|
GXequiv,
|
|
GXorInverted,
|
|
GXandReverse,
|
|
GXxor,
|
|
GXinvert,
|
|
GXnand,
|
|
GXcopy,
|
|
GXor,
|
|
GXorReverse,
|
|
GXset
|
|
};
|
|
|
|
int mfbGetInverseAlu(i)
|
|
int i;
|
|
{
|
|
return InverseAlu[i];
|
|
}
|
|
|
|
int
|
|
mfbReduceRop(alu, src)
|
|
register int alu;
|
|
register Pixel src;
|
|
{
|
|
int rop = 0;
|
|
if ((src & 1) == 0) /* src is black */
|
|
{
|
|
switch(alu)
|
|
{
|
|
case GXclear:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXand:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXandReverse:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXcopy:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXandInverted:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXnoop:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXxor:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXor:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXnor:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXequiv:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXinvert:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXorReverse:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXcopyInverted:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
case GXorInverted:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
case GXnand:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
case GXset:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
}
|
|
}
|
|
else /* src is white */
|
|
{
|
|
switch(alu)
|
|
{
|
|
case GXclear:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXand:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXandReverse:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXcopy:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
case GXandInverted:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXnoop:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXxor:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXor:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
case GXnor:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXequiv:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXinvert:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXorReverse:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
case GXcopyInverted:
|
|
rop = RROP_BLACK;
|
|
break;
|
|
case GXorInverted:
|
|
rop = RROP_NOP;
|
|
break;
|
|
case GXnand:
|
|
rop = RROP_INVERT;
|
|
break;
|
|
case GXset:
|
|
rop = RROP_WHITE;
|
|
break;
|
|
}
|
|
}
|
|
return rop;
|
|
}
|