#ifdef HAVE_DIX_CONFIG_H
#include <dix-config.h>
#endif
#include <X11/X.h>
#include <X11/Xmd.h>
#include <X11/Xproto.h>
#include "misc.h"
#include "resource.h"
#include "gcstruct.h"
#include "pixmapstr.h"
#include "dixfontstr.h"
#include "scrnintstr.h"
#include "region.h"
#include "dix.h"
#include <assert.h>
extern XID clientErrorValue;
extern FontPtr defaultFont;
static Bool CreateDefaultTile(GCPtr pGC);
unsigned char DefaultDash[2] = {4, 4};
_X_EXPORT void
ValidateGC(DrawablePtr pDraw, GC *pGC)
{
(*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
pGC->stateChanges = 0;
pGC->serialNumber = pDraw->serialNumber;
}
#define NEXTVAL(_type, _var) { \
if (pC32) _var = (_type)*pC32++; \
else { \
_var = (_type)(pUnion->val); pUnion++; \
} \
}
#define NEXT_PTR(_type, _var) { \
assert(pUnion); _var = (_type)pUnion->ptr; pUnion++; }
_X_EXPORT int
dixChangeGC(ClientPtr client, register GC *pGC, register BITS32 mask, CARD32 *pC32, ChangeGCValPtr pUnion)
{
register BITS32 index2;
register int error = 0;
PixmapPtr pPixmap;
BITS32 maskQ;
assert( (pC32 && !pUnion) || (!pC32 && pUnion) );
pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
maskQ = mask;
while (mask && !error)
{
index2 = (BITS32) lowbit (mask);
mask &= ~index2;
pGC->stateChanges |= index2;
switch (index2)
{
case GCFunction:
{
CARD8 newalu;
NEXTVAL(CARD8, newalu);
if (newalu <= GXset)
pGC->alu = newalu;
else
{
clientErrorValue = newalu;
error = BadValue;
}
break;
}
case GCPlaneMask:
NEXTVAL(unsigned long, pGC->planemask);
break;
case GCForeground:
NEXTVAL(unsigned long, pGC->fgPixel);
if (!pGC->tileIsPixel && !pGC->tile.pixmap)
{
pGC->tileIsPixel = TRUE;
pGC->tile.pixel = pGC->fgPixel;
}
break;
case GCBackground:
NEXTVAL(unsigned long, pGC->bgPixel);
break;
case GCLineWidth:
NEXTVAL(CARD16, pGC->lineWidth);
break;
case GCLineStyle:
{
unsigned int newlinestyle;
NEXTVAL(unsigned int, newlinestyle);
if (newlinestyle <= LineDoubleDash)
pGC->lineStyle = newlinestyle;
else
{
clientErrorValue = newlinestyle;
error = BadValue;
}
break;
}
case GCCapStyle:
{
unsigned int newcapstyle;
NEXTVAL(unsigned int, newcapstyle);
if (newcapstyle <= CapProjecting)
pGC->capStyle = newcapstyle;
else
{
clientErrorValue = newcapstyle;
error = BadValue;
}
break;
}
case GCJoinStyle:
{
unsigned int newjoinstyle;
NEXTVAL(unsigned int, newjoinstyle);
if (newjoinstyle <= JoinBevel)
pGC->joinStyle = newjoinstyle;
else
{
clientErrorValue = newjoinstyle;
error = BadValue;
}
break;
}
case GCFillStyle:
{
unsigned int newfillstyle;
NEXTVAL(unsigned int, newfillstyle);
if (newfillstyle <= FillOpaqueStippled)
pGC->fillStyle = newfillstyle;
else
{
clientErrorValue = newfillstyle;
error = BadValue;
}
break;
}
case GCFillRule:
{
unsigned int newfillrule;
NEXTVAL(unsigned int, newfillrule);
if (newfillrule <= WindingRule)
pGC->fillRule = newfillrule;
else
{
clientErrorValue = newfillrule;
error = BadValue;
}
break;
}
case GCTile:
{
XID newpix = 0;
if (pUnion)
{
NEXT_PTR(PixmapPtr, pPixmap);
}
else
{
NEXTVAL(XID, newpix);
pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
newpix, RT_PIXMAP, SecurityReadAccess);
}
if (pPixmap)
{
if ((pPixmap->drawable.depth != pGC->depth) ||
(pPixmap->drawable.pScreen != pGC->pScreen))
{
error = BadMatch;
}
else
{
pPixmap->refcnt++;
if (!pGC->tileIsPixel)
(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
pGC->tileIsPixel = FALSE;
pGC->tile.pixmap = pPixmap;
}
}
else
{
clientErrorValue = newpix;
error = BadPixmap;
}
break;
}
case GCStipple:
{
XID newstipple = 0;
if (pUnion)
{
NEXT_PTR(PixmapPtr, pPixmap);
}
else
{
NEXTVAL(XID, newstipple)
pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
newstipple, RT_PIXMAP, SecurityReadAccess);
}
if (pPixmap)
{
if ((pPixmap->drawable.depth != 1) ||
(pPixmap->drawable.pScreen != pGC->pScreen))
{
error = BadMatch;
}
else
{
pPixmap->refcnt++;
if (pGC->stipple)
(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
pGC->stipple = pPixmap;
}
}
else
{
clientErrorValue = newstipple;
error = BadPixmap;
}
break;
}
case GCTileStipXOrigin:
NEXTVAL(INT16, pGC->patOrg.x);
break;
case GCTileStipYOrigin:
NEXTVAL(INT16, pGC->patOrg.y);
break;
case GCFont:
{
FontPtr pFont;
XID newfont = 0;
if (pUnion)
{
NEXT_PTR(FontPtr, pFont);
}
else
{
NEXTVAL(XID, newfont)
pFont = (FontPtr)SecurityLookupIDByType(client, newfont,
RT_FONT, SecurityReadAccess);
}
if (pFont)
{
pFont->refcnt++;
if (pGC->font)
CloseFont(pGC->font, (Font)0);
pGC->font = pFont;
}
else
{
clientErrorValue = newfont;
error = BadFont;
}
break;
}
case GCSubwindowMode:
{
unsigned int newclipmode;
NEXTVAL(unsigned int, newclipmode);
if (newclipmode <= IncludeInferiors)
pGC->subWindowMode = newclipmode;
else
{
clientErrorValue = newclipmode;
error = BadValue;
}
break;
}
case GCGraphicsExposures:
{
unsigned int newge;
NEXTVAL(unsigned int, newge);
if (newge <= xTrue)
pGC->graphicsExposures = newge;
else
{
clientErrorValue = newge;
error = BadValue;
}
break;
}
case GCClipXOrigin:
NEXTVAL(INT16, pGC->clipOrg.x);
break;
case GCClipYOrigin:
NEXTVAL(INT16, pGC->clipOrg.y);
break;
case GCClipMask:
{
Pixmap pid = 0;
int clipType = 0;
if (pUnion)
{
NEXT_PTR(PixmapPtr, pPixmap);
}
else
{
NEXTVAL(Pixmap, pid)
if (pid == None)
{
clipType = CT_NONE;
pPixmap = NullPixmap;
}
else
pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
pid, RT_PIXMAP, SecurityReadAccess);
}
if (pPixmap)
{
if ((pPixmap->drawable.depth != 1) ||
(pPixmap->drawable.pScreen != pGC->pScreen))
{
error = BadMatch;
}
else
{
clipType = CT_PIXMAP;
pPixmap->refcnt++;
}
}
else if (!pUnion && (pid != None))
{
clientErrorValue = pid;
error = BadPixmap;
}
if(error == Success)
{
(*pGC->funcs->ChangeClip)(pGC, clipType,
(pointer)pPixmap, 0);
}
break;
}
case GCDashOffset:
NEXTVAL(INT16, pGC->dashOffset);
break;
case GCDashList:
{
CARD8 newdash;
NEXTVAL(CARD8, newdash);
if (newdash == 4)
{
if (pGC->dash != DefaultDash)
{
xfree(pGC->dash);
pGC->numInDashList = 2;
pGC->dash = DefaultDash;
}
}
else if (newdash != 0)
{
unsigned char *dash;
dash = (unsigned char *)xalloc(2 * sizeof(unsigned char));
if (dash)
{
if (pGC->dash != DefaultDash)
xfree(pGC->dash);
pGC->numInDashList = 2;
pGC->dash = dash;
dash[0] = newdash;
dash[1] = newdash;
}
else
error = BadAlloc;
}
else
{
clientErrorValue = newdash;
error = BadValue;
}
break;
}
case GCArcMode:
{
unsigned int newarcmode;
NEXTVAL(unsigned int, newarcmode);
if (newarcmode <= ArcPieSlice)
pGC->arcMode = newarcmode;
else
{
clientErrorValue = newarcmode;
error = BadValue;
}
break;
}
default:
clientErrorValue = maskQ;
error = BadValue;
break;
}
}
if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
{
if (!CreateDefaultTile (pGC))
{
pGC->fillStyle = FillSolid;
error = BadAlloc;
}
}
(*pGC->funcs->ChangeGC)(pGC, maskQ);
return error;
}
#undef NEXTVAL
#undef NEXT_PTR
_X_EXPORT int
ChangeGC(register GC *pGC, register BITS32 mask, XID *pval)
{
return (dixChangeGC(NullClient, pGC, mask, pval, NULL));
}
_X_EXPORT int
DoChangeGC(register GC *pGC, register BITS32 mask, XID *pval, int fPointer)
{
if (fPointer)
return dixChangeGC(NullClient, pGC, mask, NULL, (ChangeGCValPtr)pval);
else
return dixChangeGC(NullClient, pGC, mask, pval, NULL);
}
static GCPtr
AllocateGC(ScreenPtr pScreen)
{
GCPtr pGC;
register char *ptr;
register DevUnion *ppriv;
register unsigned *sizes;
register unsigned size;
register int i;
pGC = (GCPtr)xalloc(pScreen->totalGCSize);
if (pGC)
{
ppriv = (DevUnion *)(pGC + 1);
pGC->devPrivates = ppriv;
sizes = pScreen->GCPrivateSizes;
ptr = (char *)(ppriv + pScreen->GCPrivateLen);
for (i = pScreen->GCPrivateLen; --i >= 0; ppriv++, sizes++)
{
if ( (size = *sizes) )
{
ppriv->ptr = (pointer)ptr;
ptr += size;
}
else
ppriv->ptr = (pointer)NULL;
}
}
return pGC;
}
_X_EXPORT GCPtr
CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus)
{
register GCPtr pGC;
pGC = AllocateGC(pDrawable->pScreen);
if (!pGC)
{
*pStatus = BadAlloc;
return (GCPtr)NULL;
}
pGC->pScreen = pDrawable->pScreen;
pGC->depth = pDrawable->depth;
pGC->alu = GXcopy;
pGC->planemask = ~0;
pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
pGC->funcs = 0;
pGC->fgPixel = 0;
pGC->bgPixel = 1;
pGC->lineWidth = 0;
pGC->lineStyle = LineSolid;
pGC->capStyle = CapButt;
pGC->joinStyle = JoinMiter;
pGC->fillStyle = FillSolid;
pGC->fillRule = EvenOddRule;
pGC->arcMode = ArcPieSlice;
if (mask & GCForeground)
{
pGC->tileIsPixel = FALSE;
pGC->tile.pixmap = NullPixmap;
}
else
{
pGC->tileIsPixel = TRUE;
pGC->tile.pixel = 0;
}
pGC->patOrg.x = 0;
pGC->patOrg.y = 0;
pGC->subWindowMode = ClipByChildren;
pGC->graphicsExposures = TRUE;
pGC->clipOrg.x = 0;
pGC->clipOrg.y = 0;
pGC->clientClipType = CT_NONE;
pGC->clientClip = (pointer)NULL;
pGC->numInDashList = 2;
pGC->dash = DefaultDash;
pGC->dashOffset = 0;
pGC->lastWinOrg.x = 0;
pGC->lastWinOrg.y = 0;
pGC->font = defaultFont;
defaultFont->refcnt++;
pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
pGC->stipple->refcnt++;
pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
if (!(*pGC->pScreen->CreateGC)(pGC))
*pStatus = BadAlloc;
else if (mask)
*pStatus = ChangeGC(pGC, mask, pval);
else
*pStatus = Success;
if (*pStatus != Success)
{
if (!pGC->tileIsPixel && !pGC->tile.pixmap)
pGC->tileIsPixel = TRUE;
FreeGC(pGC, (XID)0);
pGC = (GCPtr)NULL;
}
return (pGC);
}
static Bool
CreateDefaultTile (GCPtr pGC)
{
XID tmpval[3];
PixmapPtr pTile;
GCPtr pgcScratch;
xRectangle rect;
CARD16 w, h;
w = 1;
h = 1;
(*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
pTile = (PixmapPtr)
(*pGC->pScreen->CreatePixmap)(pGC->pScreen,
w, h, pGC->depth);
pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
if (!pTile || !pgcScratch)
{
if (pTile)
(*pTile->drawable.pScreen->DestroyPixmap)(pTile);
if (pgcScratch)
FreeScratchGC(pgcScratch);
return FALSE;
}
tmpval[0] = GXcopy;
tmpval[1] = pGC->tile.pixel;
tmpval[2] = FillSolid;
(void)ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle,
tmpval);
ValidateGC((DrawablePtr)pTile, pgcScratch);
rect.x = 0;
rect.y = 0;
rect.width = w;
rect.height = h;
(*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
FreeScratchGC(pgcScratch);
pGC->tileIsPixel = FALSE;
pGC->tile.pixmap = pTile;
return TRUE;
}
_X_EXPORT int
CopyGC(register GC *pgcSrc, register GC *pgcDst, register BITS32 mask)
{
register BITS32 index2;
BITS32 maskQ;
int error = 0;
if (pgcSrc == pgcDst)
return Success;
pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
pgcDst->stateChanges |= mask;
maskQ = mask;
while (mask)
{
index2 = (BITS32) lowbit (mask);
mask &= ~index2;
switch (index2)
{
case GCFunction:
pgcDst->alu = pgcSrc->alu;
break;
case GCPlaneMask:
pgcDst->planemask = pgcSrc->planemask;
break;
case GCForeground:
pgcDst->fgPixel = pgcSrc->fgPixel;
break;
case GCBackground:
pgcDst->bgPixel = pgcSrc->bgPixel;
break;
case GCLineWidth:
pgcDst->lineWidth = pgcSrc->lineWidth;
break;
case GCLineStyle:
pgcDst->lineStyle = pgcSrc->lineStyle;
break;
case GCCapStyle:
pgcDst->capStyle = pgcSrc->capStyle;
break;
case GCJoinStyle:
pgcDst->joinStyle = pgcSrc->joinStyle;
break;
case GCFillStyle:
pgcDst->fillStyle = pgcSrc->fillStyle;
break;
case GCFillRule:
pgcDst->fillRule = pgcSrc->fillRule;
break;
case GCTile:
{
if (EqualPixUnion(pgcDst->tileIsPixel,
pgcDst->tile,
pgcSrc->tileIsPixel,
pgcSrc->tile))
{
break;
}
if (!pgcDst->tileIsPixel)
(* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
pgcDst->tile = pgcSrc->tile;
if (!pgcDst->tileIsPixel)
pgcDst->tile.pixmap->refcnt++;
break;
}
case GCStipple:
{
if (pgcDst->stipple == pgcSrc->stipple)
break;
if (pgcDst->stipple)
(* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
pgcDst->stipple = pgcSrc->stipple;
if (pgcDst->stipple)
pgcDst->stipple->refcnt ++;
break;
}
case GCTileStipXOrigin:
pgcDst->patOrg.x = pgcSrc->patOrg.x;
break;
case GCTileStipYOrigin:
pgcDst->patOrg.y = pgcSrc->patOrg.y;
break;
case GCFont:
if (pgcDst->font == pgcSrc->font)
break;
if (pgcDst->font)
CloseFont(pgcDst->font, (Font)0);
if ((pgcDst->font = pgcSrc->font) != NullFont)
(pgcDst->font)->refcnt++;
break;
case GCSubwindowMode:
pgcDst->subWindowMode = pgcSrc->subWindowMode;
break;
case GCGraphicsExposures:
pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
break;
case GCClipXOrigin:
pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
break;
case GCClipYOrigin:
pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
break;
case GCClipMask:
(* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
break;
case GCDashOffset:
pgcDst->dashOffset = pgcSrc->dashOffset;
break;
case GCDashList:
if (pgcSrc->dash == DefaultDash)
{
if (pgcDst->dash != DefaultDash)
{
xfree(pgcDst->dash);
pgcDst->numInDashList = pgcSrc->numInDashList;
pgcDst->dash = pgcSrc->dash;
}
}
else
{
unsigned char *dash;
unsigned int i;
dash = (unsigned char *)xalloc(pgcSrc->numInDashList *
sizeof(unsigned char));
if (dash)
{
if (pgcDst->dash != DefaultDash)
xfree(pgcDst->dash);
pgcDst->numInDashList = pgcSrc->numInDashList;
pgcDst->dash = dash;
for (i=0; i<pgcSrc->numInDashList; i++)
dash[i] = pgcSrc->dash[i];
}
else
error = BadAlloc;
}
break;
case GCArcMode:
pgcDst->arcMode = pgcSrc->arcMode;
break;
default:
clientErrorValue = maskQ;
error = BadValue;
break;
}
}
if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
{
if (!CreateDefaultTile (pgcDst))
{
pgcDst->fillStyle = FillSolid;
error = BadAlloc;
}
}
(*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
return error;
}
_X_EXPORT int
FreeGC(pointer value, XID gid)
{
GCPtr pGC = (GCPtr)value;
CloseFont(pGC->font, (Font)0);
(* pGC->funcs->DestroyClip)(pGC);
if (!pGC->tileIsPixel)
(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
if (pGC->stipple)
(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
(*pGC->funcs->DestroyGC) (pGC);
if (pGC->dash != DefaultDash)
xfree(pGC->dash);
xfree(pGC);
return(Success);
}
void
SetGCMask(GCPtr pGC, Mask selectMask, Mask newDataMask)
{
pGC->stateChanges = (~selectMask & pGC->stateChanges) |
(selectMask & newDataMask);
if (selectMask & newDataMask)
pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
}
_X_EXPORT GCPtr
CreateScratchGC(ScreenPtr pScreen, unsigned depth)
{
register GCPtr pGC;
pGC = AllocateGC(pScreen);
if (!pGC)
return (GCPtr)NULL;
pGC->pScreen = pScreen;
pGC->depth = depth;
pGC->alu = GXcopy;
pGC->planemask = ~0;
pGC->serialNumber = 0;
pGC->fgPixel = 0;
pGC->bgPixel = 1;
pGC->lineWidth = 0;
pGC->lineStyle = LineSolid;
pGC->capStyle = CapButt;
pGC->joinStyle = JoinMiter;
pGC->fillStyle = FillSolid;
pGC->fillRule = EvenOddRule;
pGC->arcMode = ArcPieSlice;
pGC->font = defaultFont;
if ( pGC->font)
pGC->font->refcnt++;
pGC->tileIsPixel = TRUE;
pGC->tile.pixel = 0;
pGC->stipple = NullPixmap;
pGC->patOrg.x = 0;
pGC->patOrg.y = 0;
pGC->subWindowMode = ClipByChildren;
pGC->graphicsExposures = TRUE;
pGC->clipOrg.x = 0;
pGC->clipOrg.y = 0;
pGC->clientClipType = CT_NONE;
pGC->dashOffset = 0;
pGC->numInDashList = 2;
pGC->dash = DefaultDash;
pGC->lastWinOrg.x = 0;
pGC->lastWinOrg.y = 0;
pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
if (!(*pScreen->CreateGC)(pGC))
{
FreeGC(pGC, (XID)0);
pGC = (GCPtr)NULL;
}
return pGC;
}
void
FreeGCperDepth(int screenNum)
{
register int i;
register ScreenPtr pScreen;
GCPtr *ppGC;
pScreen = screenInfo.screens[screenNum];
ppGC = pScreen->GCperDepth;
for (i = 0; i <= pScreen->numDepths; i++)
(void)FreeGC(ppGC[i], (XID)0);
pScreen->rgf = ~0L;
}
Bool
CreateGCperDepth(int screenNum)
{
register int i;
register ScreenPtr pScreen;
DepthPtr pDepth;
GCPtr *ppGC;
pScreen = screenInfo.screens[screenNum];
pScreen->rgf = 0;
ppGC = pScreen->GCperDepth;
if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
return FALSE;
ppGC[0]->graphicsExposures = FALSE;
if( pScreen->numDepths > MAXFORMATS )
return FALSE;
pDepth = pScreen->allowedDepths;
for (i=0; i<pScreen->numDepths; i++, pDepth++)
{
if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
{
for (; i >= 0; i--)
(void)FreeGC(ppGC[i], (XID)0);
return FALSE;
}
ppGC[i+1]->graphicsExposures = FALSE;
}
return TRUE;
}
Bool
CreateDefaultStipple(int screenNum)
{
register ScreenPtr pScreen;
XID tmpval[3];
xRectangle rect;
CARD16 w, h;
GCPtr pgcScratch;
pScreen = screenInfo.screens[screenNum];
w = 16;
h = 16;
(* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
if (!(pScreen->PixmapPerDepth[0] =
(*pScreen->CreatePixmap)(pScreen, w, h, 1)))
return FALSE;
tmpval[0] = GXcopy; tmpval[1] = 1; tmpval[2] = FillSolid;
pgcScratch = GetScratchGC(1, pScreen);
if (!pgcScratch)
{
(*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
return FALSE;
}
(void)ChangeGC(pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
rect.x = 0;
rect.y = 0;
rect.width = w;
rect.height = h;
(*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
pgcScratch, 1, &rect);
FreeScratchGC(pgcScratch);
return TRUE;
}
void
FreeDefaultStipple(int screenNum)
{
ScreenPtr pScreen = screenInfo.screens[screenNum];
(*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
}
_X_EXPORT int
SetDashes(register GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
{
register long i;
register unsigned char *p, *indash;
BITS32 maskQ = 0;
i = ndash;
p = pdash;
while (i--)
{
if (!*p++)
{
clientErrorValue = 0;
return BadValue;
}
}
if (ndash & 1)
p = (unsigned char *)xalloc(2 * ndash * sizeof(unsigned char));
else
p = (unsigned char *)xalloc(ndash * sizeof(unsigned char));
if (!p)
return BadAlloc;
pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
if (offset != pGC->dashOffset)
{
pGC->dashOffset = offset;
pGC->stateChanges |= GCDashOffset;
maskQ |= GCDashOffset;
}
if (pGC->dash != DefaultDash)
xfree(pGC->dash);
pGC->numInDashList = ndash;
pGC->dash = p;
if (ndash & 1)
{
pGC->numInDashList += ndash;
indash = pdash;
i = ndash;
while (i--)
*p++ = *indash++;
}
while(ndash--)
*p++ = *pdash++;
pGC->stateChanges |= GCDashList;
maskQ |= GCDashList;
if (pGC->funcs->ChangeGC)
(*pGC->funcs->ChangeGC) (pGC, maskQ);
return Success;
}
_X_EXPORT int
VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
{
register xRectangle *prectP, *prectN;
register int i;
switch(ordering)
{
case Unsorted:
return CT_UNSORTED;
case YSorted:
if(nrects > 1)
{
for(i = 1, prectP = prects, prectN = prects + 1;
i < nrects;
i++, prectP++, prectN++)
if(prectN->y < prectP->y)
return -1;
}
return CT_YSORTED;
case YXSorted:
if(nrects > 1)
{
for(i = 1, prectP = prects, prectN = prects + 1;
i < nrects;
i++, prectP++, prectN++)
if((prectN->y < prectP->y) ||
( (prectN->y == prectP->y) &&
(prectN->x < prectP->x) ) )
return -1;
}
return CT_YXSORTED;
case YXBanded:
if(nrects > 1)
{
for(i = 1, prectP = prects, prectN = prects + 1;
i < nrects;
i++, prectP++, prectN++)
if((prectN->y != prectP->y &&
prectN->y < prectP->y + (int) prectP->height) ||
((prectN->y == prectP->y) &&
(prectN->height != prectP->height ||
prectN->x < prectP->x + (int) prectP->width)))
return -1;
}
return CT_YXBANDED;
}
return -1;
}
_X_EXPORT int
SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
xRectangle *prects, int ordering)
{
int newct, size;
xRectangle *prectsNew;
newct = VerifyRectOrder(nrects, prects, ordering);
if (newct < 0)
return(BadMatch);
size = nrects * sizeof(xRectangle);
prectsNew = (xRectangle *) xalloc(size);
if (!prectsNew && size)
return BadAlloc;
pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
pGC->clipOrg.x = xOrigin;
pGC->stateChanges |= GCClipXOrigin;
pGC->clipOrg.y = yOrigin;
pGC->stateChanges |= GCClipYOrigin;
if (size)
memmove((char *)prectsNew, (char *)prects, size);
(*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
if (pGC->funcs->ChangeGC)
(*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
return Success;
}
_X_EXPORT GCPtr
GetScratchGC(register unsigned depth, register ScreenPtr pScreen)
{
register int i;
register GCPtr pGC;
for (i=0; i<=pScreen->numDepths; i++)
if ( pScreen->GCperDepth[i]->depth == depth &&
!(pScreen->rgf & (1L << (i+1)))
)
{
pScreen->rgf |= (1L << (i+1));
pGC = (pScreen->GCperDepth[i]);
pGC->alu = GXcopy;
pGC->planemask = ~0;
pGC->serialNumber = 0;
pGC->fgPixel = 0;
pGC->bgPixel = 1;
pGC->lineWidth = 0;
pGC->lineStyle = LineSolid;
pGC->capStyle = CapButt;
pGC->joinStyle = JoinMiter;
pGC->fillStyle = FillSolid;
pGC->fillRule = EvenOddRule;
pGC->arcMode = ArcChord;
pGC->patOrg.x = 0;
pGC->patOrg.y = 0;
pGC->subWindowMode = ClipByChildren;
pGC->graphicsExposures = FALSE;
pGC->clipOrg.x = 0;
pGC->clipOrg.y = 0;
if (pGC->clientClipType != CT_NONE)
(*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
return pGC;
}
pGC = CreateScratchGC(pScreen, depth);
if (pGC)
pGC->graphicsExposures = FALSE;
return pGC;
}
_X_EXPORT void
FreeScratchGC(register GCPtr pGC)
{
register ScreenPtr pScreen = pGC->pScreen;
register int i;
for (i=0; i<=pScreen->numDepths; i++)
{
if ( pScreen->GCperDepth[i] == pGC)
{
pScreen->rgf &= ~(1L << (i+1));
return;
}
}
(void)FreeGC(pGC, (GContext)0);
}