gc.c revision 6747b715
105b261ecSmrg/***********************************************************
205b261ecSmrg
305b261ecSmrgCopyright 1987, 1998  The Open Group
405b261ecSmrg
505b261ecSmrgPermission to use, copy, modify, distribute, and sell this software and its
605b261ecSmrgdocumentation for any purpose is hereby granted without fee, provided that
705b261ecSmrgthe above copyright notice appear in all copies and that both that
805b261ecSmrgcopyright notice and this permission notice appear in supporting
905b261ecSmrgdocumentation.
1005b261ecSmrg
1105b261ecSmrgThe above copyright notice and this permission notice shall be included in
1205b261ecSmrgall copies or substantial portions of the Software.
1305b261ecSmrg
1405b261ecSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1505b261ecSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
1605b261ecSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
1705b261ecSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
1805b261ecSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
1905b261ecSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2005b261ecSmrg
2105b261ecSmrgExcept as contained in this notice, the name of The Open Group shall not be
2205b261ecSmrgused in advertising or otherwise to promote the sale, use or other dealings
2305b261ecSmrgin this Software without prior written authorization from The Open Group.
2405b261ecSmrg
2505b261ecSmrg
2605b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2705b261ecSmrg
2805b261ecSmrg                        All Rights Reserved
2905b261ecSmrg
3005b261ecSmrgPermission to use, copy, modify, and distribute this software and its
3105b261ecSmrgdocumentation for any purpose and without fee is hereby granted,
3205b261ecSmrgprovided that the above copyright notice appear in all copies and that
3305b261ecSmrgboth that copyright notice and this permission notice appear in
3405b261ecSmrgsupporting documentation, and that the name of Digital not be
3505b261ecSmrgused in advertising or publicity pertaining to distribution of the
3605b261ecSmrgsoftware without specific, written prior permission.
3705b261ecSmrg
3805b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3905b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
4005b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4105b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4205b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4305b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4405b261ecSmrgSOFTWARE.
4505b261ecSmrg
4605b261ecSmrg******************************************************************/
4705b261ecSmrg
4805b261ecSmrg
4905b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
5005b261ecSmrg#include <dix-config.h>
5105b261ecSmrg#endif
5205b261ecSmrg
5305b261ecSmrg#include <X11/X.h>
5405b261ecSmrg#include <X11/Xmd.h>
5505b261ecSmrg#include <X11/Xproto.h>
5605b261ecSmrg#include "misc.h"
5705b261ecSmrg#include "resource.h"
5805b261ecSmrg#include "gcstruct.h"
5905b261ecSmrg#include "pixmapstr.h"
6005b261ecSmrg#include "dixfontstr.h"
6105b261ecSmrg#include "scrnintstr.h"
6205b261ecSmrg#include "region.h"
636747b715Smrg#include "dixstruct.h"
6405b261ecSmrg
654642e01fSmrg#include "privates.h"
6605b261ecSmrg#include "dix.h"
674642e01fSmrg#include "xace.h"
6805b261ecSmrg#include <assert.h>
6905b261ecSmrg
7005b261ecSmrgextern FontPtr defaultFont;
7105b261ecSmrg
7205b261ecSmrgstatic Bool CreateDefaultTile(GCPtr pGC);
7305b261ecSmrg
7405b261ecSmrgstatic unsigned char DefaultDash[2] = {4, 4};
7505b261ecSmrg
766747b715Smrgvoid
7705b261ecSmrgValidateGC(DrawablePtr pDraw, GC *pGC)
7805b261ecSmrg{
7905b261ecSmrg    (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
8005b261ecSmrg    pGC->stateChanges = 0;
8105b261ecSmrg    pGC->serialNumber = pDraw->serialNumber;
8205b261ecSmrg}
8305b261ecSmrg
8405b261ecSmrg
856747b715Smrg/*
866747b715Smrg * ChangeGC/ChangeGCXIDs:
876747b715Smrg *
886747b715Smrg * The client performing the gc change must be passed so that access
896747b715Smrg * checks can be performed on any tiles, stipples, or fonts that are
906747b715Smrg * specified.  ddxen can call this too; they should normally pass
916747b715Smrg * NullClient for the client since any access checking should have
9205b261ecSmrg * already been done at a higher level.
9305b261ecSmrg *
946747b715Smrg * If you have any XIDs, you must use ChangeGCXIDs:
9505b261ecSmrg *
9605b261ecSmrg *     CARD32 v[2];
976747b715Smrg *     v[0] = FillTiled;
986747b715Smrg *     v[1] = pid;
996747b715Smrg *     ChangeGCXIDs(client, pGC, GCFillStyle|GCTile, v);
10005b261ecSmrg *
1016747b715Smrg * However, if you need to pass a pointer to a pixmap or font, you must
1026747b715Smrg * use ChangeGC:
10305b261ecSmrg *
10405b261ecSmrg *     ChangeGCVal v[2];
10505b261ecSmrg *     v[0].val = FillTiled;
10605b261ecSmrg *     v[1].ptr = pPixmap;
1076747b715Smrg *     ChangeGC(client, pGC, GCFillStyle|GCTile, v);
10805b261ecSmrg *
1096747b715Smrg * If you have neither XIDs nor pointers, you can use either function,
1106747b715Smrg * but ChangeGC will do less work.
1116747b715Smrg *
1126747b715Smrg *     ChangeGCVal v[2];
1136747b715Smrg *     v[0].val = foreground;
1146747b715Smrg *     v[1].val = background;
1156747b715Smrg *     ChangeGC(client, pGC, GCForeground|GCBackground, v);
11605b261ecSmrg */
11705b261ecSmrg
11805b261ecSmrg#define NEXTVAL(_type, _var) { \
11905b261ecSmrg	_var = (_type)(pUnion->val); pUnion++; \
12005b261ecSmrg    }
12105b261ecSmrg
12205b261ecSmrg#define NEXT_PTR(_type, _var) { \
1236747b715Smrg    _var = (_type)pUnion->ptr; pUnion++; }
12405b261ecSmrg
1256747b715Smrgint
1266747b715SmrgChangeGC(ClientPtr client, GC *pGC, BITS32 mask, ChangeGCValPtr pUnion)
12705b261ecSmrg{
12805b261ecSmrg    BITS32 	index2;
1296747b715Smrg    int 	error = 0;
13005b261ecSmrg    PixmapPtr 	pPixmap;
13105b261ecSmrg    BITS32	maskQ;
13205b261ecSmrg
1336747b715Smrg    assert(pUnion);
13405b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
13505b261ecSmrg
13605b261ecSmrg    maskQ = mask;	/* save these for when we walk the GCque */
13705b261ecSmrg    while (mask && !error)
13805b261ecSmrg    {
13905b261ecSmrg	index2 = (BITS32) lowbit (mask);
14005b261ecSmrg	mask &= ~index2;
14105b261ecSmrg	pGC->stateChanges |= index2;
14205b261ecSmrg	switch (index2)
14305b261ecSmrg	{
14405b261ecSmrg	    case GCFunction:
14505b261ecSmrg	    {
14605b261ecSmrg		CARD8 newalu;
14705b261ecSmrg		NEXTVAL(CARD8, newalu);
14805b261ecSmrg		if (newalu <= GXset)
14905b261ecSmrg		    pGC->alu = newalu;
15005b261ecSmrg		else
15105b261ecSmrg		{
1526747b715Smrg		    if (client)
1536747b715Smrg			client->errorValue = newalu;
15405b261ecSmrg		    error = BadValue;
15505b261ecSmrg		}
15605b261ecSmrg		break;
15705b261ecSmrg	    }
15805b261ecSmrg	    case GCPlaneMask:
15905b261ecSmrg		NEXTVAL(unsigned long, pGC->planemask);
16005b261ecSmrg		break;
16105b261ecSmrg	    case GCForeground:
16205b261ecSmrg		NEXTVAL(unsigned long, pGC->fgPixel);
16305b261ecSmrg		/*
16405b261ecSmrg		 * this is for CreateGC
16505b261ecSmrg		 */
16605b261ecSmrg		if (!pGC->tileIsPixel && !pGC->tile.pixmap)
16705b261ecSmrg		{
16805b261ecSmrg		    pGC->tileIsPixel = TRUE;
16905b261ecSmrg		    pGC->tile.pixel = pGC->fgPixel;
17005b261ecSmrg		}
17105b261ecSmrg		break;
17205b261ecSmrg	    case GCBackground:
17305b261ecSmrg		NEXTVAL(unsigned long, pGC->bgPixel);
17405b261ecSmrg		break;
17505b261ecSmrg	    case GCLineWidth:		/* ??? line width is a CARD16 */
17605b261ecSmrg		 NEXTVAL(CARD16, pGC->lineWidth);
17705b261ecSmrg		break;
17805b261ecSmrg	    case GCLineStyle:
17905b261ecSmrg	    {
18005b261ecSmrg		unsigned int newlinestyle;
18105b261ecSmrg		NEXTVAL(unsigned int, newlinestyle);
18205b261ecSmrg		if (newlinestyle <= LineDoubleDash)
18305b261ecSmrg		    pGC->lineStyle = newlinestyle;
18405b261ecSmrg		else
18505b261ecSmrg		{
1866747b715Smrg		    if (client)
1876747b715Smrg			client->errorValue = newlinestyle;
18805b261ecSmrg		    error = BadValue;
18905b261ecSmrg		}
19005b261ecSmrg		break;
19105b261ecSmrg	    }
19205b261ecSmrg	    case GCCapStyle:
19305b261ecSmrg	    {
19405b261ecSmrg		unsigned int newcapstyle;
19505b261ecSmrg		NEXTVAL(unsigned int, newcapstyle);
19605b261ecSmrg		if (newcapstyle <= CapProjecting)
19705b261ecSmrg		    pGC->capStyle = newcapstyle;
19805b261ecSmrg		else
19905b261ecSmrg		{
2006747b715Smrg		    if (client)
2016747b715Smrg			client->errorValue = newcapstyle;
20205b261ecSmrg		    error = BadValue;
20305b261ecSmrg		}
20405b261ecSmrg		break;
20505b261ecSmrg	    }
20605b261ecSmrg	    case GCJoinStyle:
20705b261ecSmrg	    {
20805b261ecSmrg		unsigned int newjoinstyle;
20905b261ecSmrg		NEXTVAL(unsigned int, newjoinstyle);
21005b261ecSmrg		if (newjoinstyle <= JoinBevel)
21105b261ecSmrg		    pGC->joinStyle = newjoinstyle;
21205b261ecSmrg		else
21305b261ecSmrg		{
2146747b715Smrg		    if (client)
2156747b715Smrg			client->errorValue = newjoinstyle;
21605b261ecSmrg		    error = BadValue;
21705b261ecSmrg		}
21805b261ecSmrg		break;
21905b261ecSmrg	    }
22005b261ecSmrg	    case GCFillStyle:
22105b261ecSmrg	    {
22205b261ecSmrg		unsigned int newfillstyle;
22305b261ecSmrg		NEXTVAL(unsigned int, newfillstyle);
22405b261ecSmrg		if (newfillstyle <= FillOpaqueStippled)
22505b261ecSmrg		    pGC->fillStyle = newfillstyle;
22605b261ecSmrg		else
22705b261ecSmrg		{
2286747b715Smrg		    if (client)
2296747b715Smrg			client->errorValue = newfillstyle;
23005b261ecSmrg		    error = BadValue;
23105b261ecSmrg		}
23205b261ecSmrg		break;
23305b261ecSmrg	    }
23405b261ecSmrg	    case GCFillRule:
23505b261ecSmrg	    {
23605b261ecSmrg		unsigned int newfillrule;
23705b261ecSmrg		NEXTVAL(unsigned int, newfillrule);
23805b261ecSmrg		if (newfillrule <= WindingRule)
23905b261ecSmrg		    pGC->fillRule = newfillrule;
24005b261ecSmrg		else
24105b261ecSmrg		{
2426747b715Smrg		    if (client)
2436747b715Smrg			client->errorValue = newfillrule;
24405b261ecSmrg		    error = BadValue;
24505b261ecSmrg		}
24605b261ecSmrg		break;
24705b261ecSmrg	    }
24805b261ecSmrg	    case GCTile:
2496747b715Smrg		NEXT_PTR(PixmapPtr, pPixmap);
2506747b715Smrg		if ((pPixmap->drawable.depth != pGC->depth) ||
2516747b715Smrg		    (pPixmap->drawable.pScreen != pGC->pScreen))
25205b261ecSmrg		{
2536747b715Smrg		    error = BadMatch;
25405b261ecSmrg		}
25505b261ecSmrg		else
25605b261ecSmrg		{
2576747b715Smrg		    pPixmap->refcnt++;
2586747b715Smrg		    if (!pGC->tileIsPixel)
2596747b715Smrg			(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
2606747b715Smrg		    pGC->tileIsPixel = FALSE;
2616747b715Smrg		    pGC->tile.pixmap = pPixmap;
26205b261ecSmrg		}
26305b261ecSmrg		break;
26405b261ecSmrg	    case GCStipple:
2656747b715Smrg		NEXT_PTR(PixmapPtr, pPixmap);
2666747b715Smrg		if ((pPixmap->drawable.depth != 1) ||
2676747b715Smrg		    (pPixmap->drawable.pScreen != pGC->pScreen))
26805b261ecSmrg		{
2696747b715Smrg		    error = BadMatch;
27005b261ecSmrg		}
27105b261ecSmrg		else
27205b261ecSmrg		{
2736747b715Smrg		    pPixmap->refcnt++;
2746747b715Smrg		    if (pGC->stipple)
2756747b715Smrg			(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
2766747b715Smrg		    pGC->stipple = pPixmap;
27705b261ecSmrg		}
27805b261ecSmrg		break;
27905b261ecSmrg	    case GCTileStipXOrigin:
28005b261ecSmrg		NEXTVAL(INT16, pGC->patOrg.x);
28105b261ecSmrg		break;
28205b261ecSmrg	    case GCTileStipYOrigin:
28305b261ecSmrg		NEXTVAL(INT16, pGC->patOrg.y);
28405b261ecSmrg		break;
28505b261ecSmrg	    case GCFont:
28605b261ecSmrg    	    {
28705b261ecSmrg		FontPtr	pFont;
2886747b715Smrg		NEXT_PTR(FontPtr, pFont);
2896747b715Smrg		pFont->refcnt++;
2906747b715Smrg		if (pGC->font)
2916747b715Smrg		    CloseFont(pGC->font, (Font)0);
2926747b715Smrg		pGC->font = pFont;
29305b261ecSmrg		break;
29405b261ecSmrg	    }
29505b261ecSmrg	    case GCSubwindowMode:
29605b261ecSmrg	    {
29705b261ecSmrg		unsigned int newclipmode;
29805b261ecSmrg		NEXTVAL(unsigned int, newclipmode);
29905b261ecSmrg		if (newclipmode <= IncludeInferiors)
30005b261ecSmrg		    pGC->subWindowMode = newclipmode;
30105b261ecSmrg		else
30205b261ecSmrg		{
3036747b715Smrg		    if (client)
3046747b715Smrg			client->errorValue = newclipmode;
30505b261ecSmrg		    error = BadValue;
30605b261ecSmrg		}
30705b261ecSmrg		break;
30805b261ecSmrg	    }
30905b261ecSmrg	    case GCGraphicsExposures:
31005b261ecSmrg    	    {
31105b261ecSmrg		unsigned int newge;
31205b261ecSmrg		NEXTVAL(unsigned int, newge);
31305b261ecSmrg		if (newge <= xTrue)
31405b261ecSmrg		    pGC->graphicsExposures = newge;
31505b261ecSmrg		else
31605b261ecSmrg		{
3176747b715Smrg		    if (client)
3186747b715Smrg			client->errorValue = newge;
31905b261ecSmrg		    error = BadValue;
32005b261ecSmrg		}
32105b261ecSmrg		break;
32205b261ecSmrg	    }
32305b261ecSmrg	    case GCClipXOrigin:
32405b261ecSmrg		NEXTVAL(INT16, pGC->clipOrg.x);
32505b261ecSmrg		break;
32605b261ecSmrg	    case GCClipYOrigin:
32705b261ecSmrg		NEXTVAL(INT16, pGC->clipOrg.y);
32805b261ecSmrg		break;
32905b261ecSmrg	    case GCClipMask:
3306747b715Smrg		NEXT_PTR(PixmapPtr, pPixmap);
33105b261ecSmrg		if (pPixmap)
33205b261ecSmrg		{
33305b261ecSmrg		    if ((pPixmap->drawable.depth != 1) ||
33405b261ecSmrg			(pPixmap->drawable.pScreen != pGC->pScreen))
33505b261ecSmrg		    {
33605b261ecSmrg			error = BadMatch;
3376747b715Smrg			break;
33805b261ecSmrg		    }
3396747b715Smrg		    pPixmap->refcnt++;
34005b261ecSmrg		}
3416747b715Smrg		(*pGC->funcs->ChangeClip)(pGC, pPixmap ? CT_PIXMAP : CT_NONE,
3426747b715Smrg					  (pointer)pPixmap, 0);
34305b261ecSmrg		break;
34405b261ecSmrg	    case GCDashOffset:
34505b261ecSmrg		NEXTVAL(INT16, pGC->dashOffset);
34605b261ecSmrg		break;
34705b261ecSmrg	    case GCDashList:
34805b261ecSmrg	    {
34905b261ecSmrg		CARD8 newdash;
35005b261ecSmrg		NEXTVAL(CARD8, newdash);
35105b261ecSmrg		if (newdash == 4)
35205b261ecSmrg		{
35305b261ecSmrg		    if (pGC->dash != DefaultDash)
35405b261ecSmrg		    {
3556747b715Smrg			free(pGC->dash);
35605b261ecSmrg			pGC->numInDashList = 2;
35705b261ecSmrg			pGC->dash = DefaultDash;
35805b261ecSmrg		    }
35905b261ecSmrg		}
36005b261ecSmrg		else if (newdash != 0)
36105b261ecSmrg 		{
36205b261ecSmrg		    unsigned char *dash;
36305b261ecSmrg
3646747b715Smrg		    dash = malloc(2 * sizeof(unsigned char));
36505b261ecSmrg		    if (dash)
36605b261ecSmrg		    {
36705b261ecSmrg			if (pGC->dash != DefaultDash)
3686747b715Smrg			    free(pGC->dash);
36905b261ecSmrg			pGC->numInDashList = 2;
37005b261ecSmrg			pGC->dash = dash;
37105b261ecSmrg			dash[0] = newdash;
37205b261ecSmrg			dash[1] = newdash;
37305b261ecSmrg		    }
37405b261ecSmrg		    else
37505b261ecSmrg			error = BadAlloc;
37605b261ecSmrg		}
37705b261ecSmrg 		else
37805b261ecSmrg		{
3796747b715Smrg		   if (client)
3806747b715Smrg			client->errorValue = newdash;
38105b261ecSmrg		   error = BadValue;
38205b261ecSmrg		}
38305b261ecSmrg		break;
38405b261ecSmrg	    }
38505b261ecSmrg	    case GCArcMode:
38605b261ecSmrg	    {
38705b261ecSmrg		unsigned int newarcmode;
38805b261ecSmrg		NEXTVAL(unsigned int, newarcmode);
38905b261ecSmrg		if (newarcmode <= ArcPieSlice)
39005b261ecSmrg		    pGC->arcMode = newarcmode;
39105b261ecSmrg		else
39205b261ecSmrg		{
3936747b715Smrg		    if (client)
3946747b715Smrg			client->errorValue = newarcmode;
39505b261ecSmrg		    error = BadValue;
39605b261ecSmrg		}
39705b261ecSmrg		break;
39805b261ecSmrg	    }
39905b261ecSmrg	    default:
4006747b715Smrg		if (client)
4016747b715Smrg		    client->errorValue = maskQ;
40205b261ecSmrg		error = BadValue;
40305b261ecSmrg		break;
40405b261ecSmrg	}
40505b261ecSmrg    } /* end while mask && !error */
40605b261ecSmrg
40705b261ecSmrg    if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
40805b261ecSmrg    {
40905b261ecSmrg	if (!CreateDefaultTile (pGC))
41005b261ecSmrg	{
41105b261ecSmrg	    pGC->fillStyle = FillSolid;
41205b261ecSmrg	    error = BadAlloc;
41305b261ecSmrg	}
41405b261ecSmrg    }
41505b261ecSmrg    (*pGC->funcs->ChangeGC)(pGC, maskQ);
41605b261ecSmrg    return error;
41705b261ecSmrg}
41805b261ecSmrg
41905b261ecSmrg#undef NEXTVAL
42005b261ecSmrg#undef NEXT_PTR
42105b261ecSmrg
4226747b715Smrgstatic const struct {
4236747b715Smrg    BITS32 mask;
4246747b715Smrg    RESTYPE type;
4256747b715Smrg    Mask access_mode;
4266747b715Smrg} xidfields[] = {
4276747b715Smrg    { GCTile, RT_PIXMAP, DixReadAccess },
4286747b715Smrg    { GCStipple, RT_PIXMAP, DixReadAccess },
4296747b715Smrg    { GCFont, RT_FONT, DixUseAccess },
4306747b715Smrg    { GCClipMask, RT_PIXMAP, DixReadAccess },
4316747b715Smrg};
43205b261ecSmrg
4336747b715Smrgint
4346747b715SmrgChangeGCXIDs(ClientPtr client, GC *pGC, BITS32 mask, CARD32 *pC32)
43505b261ecSmrg{
4366747b715Smrg    ChangeGCVal vals[GCLastBit + 1];
4376747b715Smrg    int i;
4386747b715Smrg    if (mask & ~GCAllBits)
4396747b715Smrg    {
4406747b715Smrg	client->errorValue = mask;
4416747b715Smrg	return BadValue;
4426747b715Smrg    }
4436747b715Smrg    for (i = Ones(mask); i--; )
4446747b715Smrg	vals[i].val = pC32[i];
4456747b715Smrg    for (i = 0; i < sizeof(xidfields) / sizeof(*xidfields); ++i)
4466747b715Smrg    {
4476747b715Smrg	int offset, rc;
4486747b715Smrg	if (!(mask & xidfields[i].mask))
4496747b715Smrg	    continue;
4506747b715Smrg	offset = Ones(mask & (xidfields[i].mask - 1));
4516747b715Smrg	if (xidfields[i].mask == GCClipMask && vals[offset].val == None)
4526747b715Smrg	{
4536747b715Smrg	    vals[offset].ptr = NullPixmap;
4546747b715Smrg	    continue;
4556747b715Smrg	}
4566747b715Smrg	rc = dixLookupResourceByType(&vals[offset].ptr, vals[offset].val,
4576747b715Smrg		xidfields[i].type, client, xidfields[i].access_mode);
4586747b715Smrg	if (rc != Success)
4596747b715Smrg	{
4606747b715Smrg	    client->errorValue = vals[offset].val;
4616747b715Smrg	    return rc;
4626747b715Smrg	}
4636747b715Smrg    }
4646747b715Smrg    return ChangeGC(client, pGC, mask, vals);
46505b261ecSmrg}
46605b261ecSmrg
46705b261ecSmrg/* CreateGC(pDrawable, mask, pval, pStatus)
46805b261ecSmrg   creates a default GC for the given drawable, using mask to fill
46905b261ecSmrg   in any non-default values.
47005b261ecSmrg   Returns a pointer to the new GC on success, NULL otherwise.
47105b261ecSmrg   returns status of non-default fields in pStatus
47205b261ecSmrgBUG:
47305b261ecSmrg   should check for failure to create default tile
47405b261ecSmrg
47505b261ecSmrg*/
4766747b715SmrgGCPtr
4774642e01fSmrgCreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus,
4784642e01fSmrg	 XID gcid, ClientPtr client)
47905b261ecSmrg{
48005b261ecSmrg    GCPtr pGC;
48105b261ecSmrg
4826747b715Smrg    pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC);
48305b261ecSmrg    if (!pGC)
48405b261ecSmrg    {
48505b261ecSmrg	*pStatus = BadAlloc;
48605b261ecSmrg	return (GCPtr)NULL;
48705b261ecSmrg    }
48805b261ecSmrg
48905b261ecSmrg    pGC->pScreen = pDrawable->pScreen;
49005b261ecSmrg    pGC->depth = pDrawable->depth;
49105b261ecSmrg    pGC->alu = GXcopy; /* dst <- src */
49205b261ecSmrg    pGC->planemask = ~0;
49305b261ecSmrg    pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
49405b261ecSmrg    pGC->funcs = 0;
49505b261ecSmrg    pGC->fgPixel = 0;
49605b261ecSmrg    pGC->bgPixel = 1;
49705b261ecSmrg    pGC->lineWidth = 0;
49805b261ecSmrg    pGC->lineStyle = LineSolid;
49905b261ecSmrg    pGC->capStyle = CapButt;
50005b261ecSmrg    pGC->joinStyle = JoinMiter;
50105b261ecSmrg    pGC->fillStyle = FillSolid;
50205b261ecSmrg    pGC->fillRule = EvenOddRule;
50305b261ecSmrg    pGC->arcMode = ArcPieSlice;
5046747b715Smrg    pGC->tile.pixel = 0;
5056747b715Smrg    pGC->tile.pixmap = NullPixmap;
50605b261ecSmrg    if (mask & GCForeground)
50705b261ecSmrg    {
50805b261ecSmrg	/*
50905b261ecSmrg	 * magic special case -- ChangeGC checks for this condition
51005b261ecSmrg	 * and snags the Foreground value to create a pseudo default-tile
51105b261ecSmrg	 */
51205b261ecSmrg	pGC->tileIsPixel = FALSE;
51305b261ecSmrg    }
51405b261ecSmrg    else
51505b261ecSmrg    {
51605b261ecSmrg	pGC->tileIsPixel = TRUE;
51705b261ecSmrg    }
51805b261ecSmrg
51905b261ecSmrg    pGC->patOrg.x = 0;
52005b261ecSmrg    pGC->patOrg.y = 0;
52105b261ecSmrg    pGC->subWindowMode = ClipByChildren;
52205b261ecSmrg    pGC->graphicsExposures = TRUE;
52305b261ecSmrg    pGC->clipOrg.x = 0;
52405b261ecSmrg    pGC->clipOrg.y = 0;
52505b261ecSmrg    pGC->clientClipType = CT_NONE;
52605b261ecSmrg    pGC->clientClip = (pointer)NULL;
52705b261ecSmrg    pGC->numInDashList = 2;
52805b261ecSmrg    pGC->dash = DefaultDash;
52905b261ecSmrg    pGC->dashOffset = 0;
53005b261ecSmrg    pGC->lastWinOrg.x = 0;
53105b261ecSmrg    pGC->lastWinOrg.y = 0;
53205b261ecSmrg
53305b261ecSmrg    /* use the default font and stipple */
53405b261ecSmrg    pGC->font = defaultFont;
53505b261ecSmrg    defaultFont->refcnt++;
53605b261ecSmrg    pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
53705b261ecSmrg    pGC->stipple->refcnt++;
53805b261ecSmrg
5396747b715Smrg    /* this is not a scratch GC */
5406747b715Smrg    pGC->scratch_inuse = FALSE;
5416747b715Smrg
5424642e01fSmrg    /* security creation/labeling check */
5434642e01fSmrg    *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
5444642e01fSmrg			RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess);
5454642e01fSmrg    if (*pStatus != Success)
5464642e01fSmrg	goto out;
5474642e01fSmrg
5486747b715Smrg    pGC->stateChanges = GCAllBits;
54905b261ecSmrg    if (!(*pGC->pScreen->CreateGC)(pGC))
55005b261ecSmrg	*pStatus = BadAlloc;
55105b261ecSmrg    else if (mask)
5526747b715Smrg        *pStatus = ChangeGCXIDs(client, pGC, mask, pval);
55305b261ecSmrg    else
55405b261ecSmrg	*pStatus = Success;
5554642e01fSmrg
5564642e01fSmrgout:
55705b261ecSmrg    if (*pStatus != Success)
55805b261ecSmrg    {
55905b261ecSmrg	if (!pGC->tileIsPixel && !pGC->tile.pixmap)
56005b261ecSmrg	    pGC->tileIsPixel = TRUE; /* undo special case */
56105b261ecSmrg	FreeGC(pGC, (XID)0);
56205b261ecSmrg	pGC = (GCPtr)NULL;
56305b261ecSmrg    }
56405b261ecSmrg
5656747b715Smrg    return pGC;
56605b261ecSmrg}
56705b261ecSmrg
56805b261ecSmrgstatic Bool
56905b261ecSmrgCreateDefaultTile (GCPtr pGC)
57005b261ecSmrg{
5716747b715Smrg    ChangeGCVal	tmpval[3];
57205b261ecSmrg    PixmapPtr 	pTile;
57305b261ecSmrg    GCPtr	pgcScratch;
57405b261ecSmrg    xRectangle	rect;
57505b261ecSmrg    CARD16	w, h;
57605b261ecSmrg
57705b261ecSmrg    w = 1;
57805b261ecSmrg    h = 1;
57905b261ecSmrg    (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
58005b261ecSmrg    pTile = (PixmapPtr)
58105b261ecSmrg	    (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
5824642e01fSmrg					  w, h, pGC->depth, 0);
58305b261ecSmrg    pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
58405b261ecSmrg    if (!pTile || !pgcScratch)
58505b261ecSmrg    {
58605b261ecSmrg	if (pTile)
58705b261ecSmrg	    (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
58805b261ecSmrg	if (pgcScratch)
58905b261ecSmrg	    FreeScratchGC(pgcScratch);
59005b261ecSmrg	return FALSE;
59105b261ecSmrg    }
5926747b715Smrg    tmpval[0].val = GXcopy;
5936747b715Smrg    tmpval[1].val = pGC->tile.pixel;
5946747b715Smrg    tmpval[2].val = FillSolid;
5956747b715Smrg    (void)ChangeGC(NullClient, pgcScratch, GCFunction | GCForeground | GCFillStyle, tmpval);
59605b261ecSmrg    ValidateGC((DrawablePtr)pTile, pgcScratch);
59705b261ecSmrg    rect.x = 0;
59805b261ecSmrg    rect.y = 0;
59905b261ecSmrg    rect.width = w;
60005b261ecSmrg    rect.height = h;
60105b261ecSmrg    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
60205b261ecSmrg    /* Always remember to free the scratch graphics context after use. */
60305b261ecSmrg    FreeScratchGC(pgcScratch);
60405b261ecSmrg
60505b261ecSmrg    pGC->tileIsPixel = FALSE;
60605b261ecSmrg    pGC->tile.pixmap = pTile;
60705b261ecSmrg    return TRUE;
60805b261ecSmrg}
60905b261ecSmrg
6106747b715Smrgint
61105b261ecSmrgCopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
61205b261ecSmrg{
61305b261ecSmrg    BITS32	index2;
61405b261ecSmrg    BITS32	maskQ;
61505b261ecSmrg    int 	error = 0;
61605b261ecSmrg
61705b261ecSmrg    if (pgcSrc == pgcDst)
61805b261ecSmrg	return Success;
61905b261ecSmrg    pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
62005b261ecSmrg    pgcDst->stateChanges |= mask;
62105b261ecSmrg    maskQ = mask;
62205b261ecSmrg    while (mask)
62305b261ecSmrg    {
62405b261ecSmrg	index2 = (BITS32) lowbit (mask);
62505b261ecSmrg	mask &= ~index2;
62605b261ecSmrg	switch (index2)
62705b261ecSmrg	{
62805b261ecSmrg	    case GCFunction:
62905b261ecSmrg		pgcDst->alu = pgcSrc->alu;
63005b261ecSmrg		break;
63105b261ecSmrg	    case GCPlaneMask:
63205b261ecSmrg		pgcDst->planemask = pgcSrc->planemask;
63305b261ecSmrg		break;
63405b261ecSmrg	    case GCForeground:
63505b261ecSmrg		pgcDst->fgPixel = pgcSrc->fgPixel;
63605b261ecSmrg		break;
63705b261ecSmrg	    case GCBackground:
63805b261ecSmrg		pgcDst->bgPixel = pgcSrc->bgPixel;
63905b261ecSmrg		break;
64005b261ecSmrg	    case GCLineWidth:
64105b261ecSmrg		pgcDst->lineWidth = pgcSrc->lineWidth;
64205b261ecSmrg		break;
64305b261ecSmrg	    case GCLineStyle:
64405b261ecSmrg		pgcDst->lineStyle = pgcSrc->lineStyle;
64505b261ecSmrg		break;
64605b261ecSmrg	    case GCCapStyle:
64705b261ecSmrg		pgcDst->capStyle = pgcSrc->capStyle;
64805b261ecSmrg		break;
64905b261ecSmrg	    case GCJoinStyle:
65005b261ecSmrg		pgcDst->joinStyle = pgcSrc->joinStyle;
65105b261ecSmrg		break;
65205b261ecSmrg	    case GCFillStyle:
65305b261ecSmrg		pgcDst->fillStyle = pgcSrc->fillStyle;
65405b261ecSmrg		break;
65505b261ecSmrg	    case GCFillRule:
65605b261ecSmrg		pgcDst->fillRule = pgcSrc->fillRule;
65705b261ecSmrg		break;
65805b261ecSmrg	    case GCTile:
65905b261ecSmrg		{
66005b261ecSmrg		    if (EqualPixUnion(pgcDst->tileIsPixel,
66105b261ecSmrg				      pgcDst->tile,
66205b261ecSmrg				      pgcSrc->tileIsPixel,
66305b261ecSmrg				      pgcSrc->tile))
66405b261ecSmrg		    {
66505b261ecSmrg			break;
66605b261ecSmrg		    }
66705b261ecSmrg		    if (!pgcDst->tileIsPixel)
66805b261ecSmrg			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
66905b261ecSmrg		    pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
67005b261ecSmrg		    pgcDst->tile = pgcSrc->tile;
67105b261ecSmrg		    if (!pgcDst->tileIsPixel)
67205b261ecSmrg		       pgcDst->tile.pixmap->refcnt++;
67305b261ecSmrg		    break;
67405b261ecSmrg		}
67505b261ecSmrg	    case GCStipple:
67605b261ecSmrg		{
67705b261ecSmrg		    if (pgcDst->stipple == pgcSrc->stipple)
67805b261ecSmrg			break;
67905b261ecSmrg		    if (pgcDst->stipple)
68005b261ecSmrg			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
68105b261ecSmrg		    pgcDst->stipple = pgcSrc->stipple;
68205b261ecSmrg		    if (pgcDst->stipple)
68305b261ecSmrg			pgcDst->stipple->refcnt ++;
68405b261ecSmrg		    break;
68505b261ecSmrg		}
68605b261ecSmrg	    case GCTileStipXOrigin:
68705b261ecSmrg		pgcDst->patOrg.x = pgcSrc->patOrg.x;
68805b261ecSmrg		break;
68905b261ecSmrg	    case GCTileStipYOrigin:
69005b261ecSmrg		pgcDst->patOrg.y = pgcSrc->patOrg.y;
69105b261ecSmrg		break;
69205b261ecSmrg	    case GCFont:
69305b261ecSmrg		if (pgcDst->font == pgcSrc->font)
69405b261ecSmrg		    break;
69505b261ecSmrg		if (pgcDst->font)
69605b261ecSmrg		    CloseFont(pgcDst->font, (Font)0);
69705b261ecSmrg		if ((pgcDst->font = pgcSrc->font) != NullFont)
69805b261ecSmrg		    (pgcDst->font)->refcnt++;
69905b261ecSmrg		break;
70005b261ecSmrg	    case GCSubwindowMode:
70105b261ecSmrg		pgcDst->subWindowMode = pgcSrc->subWindowMode;
70205b261ecSmrg		break;
70305b261ecSmrg	    case GCGraphicsExposures:
70405b261ecSmrg		pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
70505b261ecSmrg		break;
70605b261ecSmrg	    case GCClipXOrigin:
70705b261ecSmrg		pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
70805b261ecSmrg		break;
70905b261ecSmrg	    case GCClipYOrigin:
71005b261ecSmrg		pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
71105b261ecSmrg		break;
71205b261ecSmrg	    case GCClipMask:
71305b261ecSmrg		(* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
71405b261ecSmrg		break;
71505b261ecSmrg	    case GCDashOffset:
71605b261ecSmrg		pgcDst->dashOffset = pgcSrc->dashOffset;
71705b261ecSmrg		break;
71805b261ecSmrg	    case GCDashList:
71905b261ecSmrg		if (pgcSrc->dash == DefaultDash)
72005b261ecSmrg		{
72105b261ecSmrg		    if (pgcDst->dash != DefaultDash)
72205b261ecSmrg		    {
7236747b715Smrg			free(pgcDst->dash);
72405b261ecSmrg			pgcDst->numInDashList = pgcSrc->numInDashList;
72505b261ecSmrg			pgcDst->dash = pgcSrc->dash;
72605b261ecSmrg		    }
72705b261ecSmrg		}
72805b261ecSmrg		else
72905b261ecSmrg		{
73005b261ecSmrg		    unsigned char *dash;
73105b261ecSmrg		    unsigned int i;
73205b261ecSmrg
7336747b715Smrg		    dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char));
73405b261ecSmrg		    if (dash)
73505b261ecSmrg		    {
73605b261ecSmrg			if (pgcDst->dash != DefaultDash)
7376747b715Smrg			    free(pgcDst->dash);
73805b261ecSmrg			pgcDst->numInDashList = pgcSrc->numInDashList;
73905b261ecSmrg			pgcDst->dash = dash;
74005b261ecSmrg			for (i=0; i<pgcSrc->numInDashList; i++)
74105b261ecSmrg			    dash[i] = pgcSrc->dash[i];
74205b261ecSmrg		    }
74305b261ecSmrg		    else
74405b261ecSmrg			error = BadAlloc;
74505b261ecSmrg		}
74605b261ecSmrg		break;
74705b261ecSmrg	    case GCArcMode:
74805b261ecSmrg		pgcDst->arcMode = pgcSrc->arcMode;
74905b261ecSmrg		break;
75005b261ecSmrg	    default:
7516747b715Smrg		FatalError ("CopyGC: Unhandled mask!\n");
75205b261ecSmrg	}
75305b261ecSmrg    }
75405b261ecSmrg    if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
75505b261ecSmrg    {
75605b261ecSmrg	if (!CreateDefaultTile (pgcDst))
75705b261ecSmrg	{
75805b261ecSmrg	    pgcDst->fillStyle = FillSolid;
75905b261ecSmrg	    error = BadAlloc;
76005b261ecSmrg	}
76105b261ecSmrg    }
76205b261ecSmrg    (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
76305b261ecSmrg    return error;
76405b261ecSmrg}
76505b261ecSmrg
76605b261ecSmrg/**
76705b261ecSmrg * does the diX part of freeing the characteristics in the GC.
76805b261ecSmrg *
76905b261ecSmrg *  \param value  must conform to DeleteType
77005b261ecSmrg */
7716747b715Smrgint
77205b261ecSmrgFreeGC(pointer value, XID gid)
77305b261ecSmrg{
77405b261ecSmrg    GCPtr pGC = (GCPtr)value;
77505b261ecSmrg
77605b261ecSmrg    CloseFont(pGC->font, (Font)0);
77705b261ecSmrg    (* pGC->funcs->DestroyClip)(pGC);
77805b261ecSmrg
77905b261ecSmrg    if (!pGC->tileIsPixel)
78005b261ecSmrg	(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
78105b261ecSmrg    if (pGC->stipple)
78205b261ecSmrg	(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
78305b261ecSmrg
78405b261ecSmrg    (*pGC->funcs->DestroyGC) (pGC);
78505b261ecSmrg    if (pGC->dash != DefaultDash)
7866747b715Smrg	free(pGC->dash);
7876747b715Smrg    dixFreeObjectWithPrivates(pGC, PRIVATE_GC);
7886747b715Smrg    return Success;
78905b261ecSmrg}
79005b261ecSmrg
79105b261ecSmrg/* CreateScratchGC(pScreen, depth)
79205b261ecSmrg    like CreateGC, but doesn't do the default tile or stipple,
79305b261ecSmrgsince we can't create them without already having a GC.  any code
79405b261ecSmrgusing the tile or stipple has to set them explicitly anyway,
79505b261ecSmrgsince the state of the scratch gc is unknown.  This is OK
79605b261ecSmrgbecause ChangeGC() has to be able to deal with NULL tiles and
79705b261ecSmrgstipples anyway (in case the CreateGC() call has provided a
79805b261ecSmrgvalue for them -- we can't set the default tile until the
79905b261ecSmrgclient-supplied attributes are installed, since the fgPixel
80005b261ecSmrgis what fills the default tile.  (maybe this comment should
80105b261ecSmrggo with CreateGC() or ChangeGC().)
80205b261ecSmrg*/
80305b261ecSmrg
8046747b715SmrgGCPtr
80505b261ecSmrgCreateScratchGC(ScreenPtr pScreen, unsigned depth)
80605b261ecSmrg{
80705b261ecSmrg    GCPtr pGC;
80805b261ecSmrg
8096747b715Smrg    pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC);
81005b261ecSmrg    if (!pGC)
81105b261ecSmrg	return (GCPtr)NULL;
81205b261ecSmrg
81305b261ecSmrg    pGC->pScreen = pScreen;
81405b261ecSmrg    pGC->depth = depth;
81505b261ecSmrg    pGC->alu = GXcopy; /* dst <- src */
81605b261ecSmrg    pGC->planemask = ~0;
81705b261ecSmrg    pGC->serialNumber = 0;
81805b261ecSmrg    pGC->fgPixel = 0;
81905b261ecSmrg    pGC->bgPixel = 1;
82005b261ecSmrg    pGC->lineWidth = 0;
82105b261ecSmrg    pGC->lineStyle = LineSolid;
82205b261ecSmrg    pGC->capStyle = CapButt;
82305b261ecSmrg    pGC->joinStyle = JoinMiter;
82405b261ecSmrg    pGC->fillStyle = FillSolid;
82505b261ecSmrg    pGC->fillRule = EvenOddRule;
82605b261ecSmrg    pGC->arcMode = ArcPieSlice;
82705b261ecSmrg    pGC->font = defaultFont;
82805b261ecSmrg    if ( pGC->font)  /* necessary, because open of default font could fail */
82905b261ecSmrg	pGC->font->refcnt++;
83005b261ecSmrg    pGC->tileIsPixel = TRUE;
83105b261ecSmrg    pGC->tile.pixel = 0;
8326747b715Smrg    pGC->tile.pixmap = NullPixmap;
83305b261ecSmrg    pGC->stipple = NullPixmap;
83405b261ecSmrg    pGC->patOrg.x = 0;
83505b261ecSmrg    pGC->patOrg.y = 0;
83605b261ecSmrg    pGC->subWindowMode = ClipByChildren;
83705b261ecSmrg    pGC->graphicsExposures = TRUE;
83805b261ecSmrg    pGC->clipOrg.x = 0;
83905b261ecSmrg    pGC->clipOrg.y = 0;
84005b261ecSmrg    pGC->clientClipType = CT_NONE;
84105b261ecSmrg    pGC->dashOffset = 0;
84205b261ecSmrg    pGC->numInDashList = 2;
84305b261ecSmrg    pGC->dash = DefaultDash;
84405b261ecSmrg    pGC->lastWinOrg.x = 0;
84505b261ecSmrg    pGC->lastWinOrg.y = 0;
84605b261ecSmrg
8476747b715Smrg    /* scratch GCs in the GCperDepth pool start off unused */
8486747b715Smrg    pGC->scratch_inuse = FALSE;
8496747b715Smrg
8506747b715Smrg    pGC->stateChanges = GCAllBits;
85105b261ecSmrg    if (!(*pScreen->CreateGC)(pGC))
85205b261ecSmrg    {
85305b261ecSmrg	FreeGC(pGC, (XID)0);
85405b261ecSmrg	pGC = (GCPtr)NULL;
85505b261ecSmrg    }
85605b261ecSmrg    return pGC;
85705b261ecSmrg}
85805b261ecSmrg
85905b261ecSmrgvoid
86005b261ecSmrgFreeGCperDepth(int screenNum)
86105b261ecSmrg{
86205b261ecSmrg    int i;
86305b261ecSmrg    ScreenPtr pScreen;
86405b261ecSmrg    GCPtr *ppGC;
86505b261ecSmrg
86605b261ecSmrg    pScreen = screenInfo.screens[screenNum];
86705b261ecSmrg    ppGC = pScreen->GCperDepth;
86805b261ecSmrg
86905b261ecSmrg    for (i = 0; i <= pScreen->numDepths; i++)
8706747b715Smrg    {
87105b261ecSmrg	(void)FreeGC(ppGC[i], (XID)0);
8726747b715Smrg	ppGC[i] = NULL;
8736747b715Smrg    }
87405b261ecSmrg}
87505b261ecSmrg
87605b261ecSmrg
87705b261ecSmrgBool
87805b261ecSmrgCreateGCperDepth(int screenNum)
87905b261ecSmrg{
88005b261ecSmrg    int i;
88105b261ecSmrg    ScreenPtr pScreen;
88205b261ecSmrg    DepthPtr pDepth;
88305b261ecSmrg    GCPtr *ppGC;
88405b261ecSmrg
88505b261ecSmrg    pScreen = screenInfo.screens[screenNum];
88605b261ecSmrg    ppGC = pScreen->GCperDepth;
88705b261ecSmrg    /* do depth 1 separately because it's not included in list */
88805b261ecSmrg    if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
88905b261ecSmrg	return FALSE;
89005b261ecSmrg    ppGC[0]->graphicsExposures = FALSE;
89105b261ecSmrg    /* Make sure we don't overflow GCperDepth[] */
89205b261ecSmrg    if( pScreen->numDepths > MAXFORMATS )
89305b261ecSmrg	    return FALSE;
89405b261ecSmrg
89505b261ecSmrg    pDepth = pScreen->allowedDepths;
89605b261ecSmrg    for (i=0; i<pScreen->numDepths; i++, pDepth++)
89705b261ecSmrg    {
89805b261ecSmrg	if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
89905b261ecSmrg	{
90005b261ecSmrg	    for (; i >= 0; i--)
90105b261ecSmrg		(void)FreeGC(ppGC[i], (XID)0);
90205b261ecSmrg	    return FALSE;
90305b261ecSmrg	}
90405b261ecSmrg	ppGC[i+1]->graphicsExposures = FALSE;
90505b261ecSmrg    }
90605b261ecSmrg    return TRUE;
90705b261ecSmrg}
90805b261ecSmrg
90905b261ecSmrgBool
91005b261ecSmrgCreateDefaultStipple(int screenNum)
91105b261ecSmrg{
91205b261ecSmrg    ScreenPtr pScreen;
9136747b715Smrg    ChangeGCVal tmpval[3];
91405b261ecSmrg    xRectangle rect;
91505b261ecSmrg    CARD16 w, h;
91605b261ecSmrg    GCPtr pgcScratch;
91705b261ecSmrg
91805b261ecSmrg    pScreen = screenInfo.screens[screenNum];
91905b261ecSmrg
92005b261ecSmrg    w = 16;
92105b261ecSmrg    h = 16;
92205b261ecSmrg    (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
92305b261ecSmrg    if (!(pScreen->PixmapPerDepth[0] =
9244642e01fSmrg			(*pScreen->CreatePixmap)(pScreen, w, h, 1, 0)))
92505b261ecSmrg	return FALSE;
92605b261ecSmrg    /* fill stipple with 1 */
9276747b715Smrg    tmpval[0].val = GXcopy;
9286747b715Smrg    tmpval[1].val = 1;
9296747b715Smrg    tmpval[2].val = FillSolid;
93005b261ecSmrg    pgcScratch = GetScratchGC(1, pScreen);
93105b261ecSmrg    if (!pgcScratch)
93205b261ecSmrg    {
93305b261ecSmrg	(*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
93405b261ecSmrg	return FALSE;
93505b261ecSmrg    }
9366747b715Smrg    (void)ChangeGC(NullClient, pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
93705b261ecSmrg    ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
93805b261ecSmrg    rect.x = 0;
93905b261ecSmrg    rect.y = 0;
94005b261ecSmrg    rect.width = w;
94105b261ecSmrg    rect.height = h;
94205b261ecSmrg    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
94305b261ecSmrg				     pgcScratch, 1, &rect);
94405b261ecSmrg    FreeScratchGC(pgcScratch);
94505b261ecSmrg    return TRUE;
94605b261ecSmrg}
94705b261ecSmrg
94805b261ecSmrgvoid
94905b261ecSmrgFreeDefaultStipple(int screenNum)
95005b261ecSmrg{
95105b261ecSmrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
95205b261ecSmrg    (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
95305b261ecSmrg}
95405b261ecSmrg
9554642e01fSmrgint
95605b261ecSmrgSetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
95705b261ecSmrg{
95805b261ecSmrg    long i;
95905b261ecSmrg    unsigned char *p, *indash;
96005b261ecSmrg    BITS32 maskQ = 0;
96105b261ecSmrg
96205b261ecSmrg    i = ndash;
96305b261ecSmrg    p = pdash;
96405b261ecSmrg    while (i--)
96505b261ecSmrg    {
96605b261ecSmrg	if (!*p++)
96705b261ecSmrg	{
96805b261ecSmrg	    /* dash segment must be > 0 */
96905b261ecSmrg	    return BadValue;
97005b261ecSmrg	}
97105b261ecSmrg    }
97205b261ecSmrg
97305b261ecSmrg    if (ndash & 1)
9746747b715Smrg	p = malloc(2 * ndash * sizeof(unsigned char));
97505b261ecSmrg    else
9766747b715Smrg	p = malloc(ndash * sizeof(unsigned char));
97705b261ecSmrg    if (!p)
97805b261ecSmrg	return BadAlloc;
97905b261ecSmrg
98005b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
98105b261ecSmrg    if (offset != pGC->dashOffset)
98205b261ecSmrg    {
98305b261ecSmrg	pGC->dashOffset = offset;
98405b261ecSmrg	pGC->stateChanges |= GCDashOffset;
98505b261ecSmrg	maskQ |= GCDashOffset;
98605b261ecSmrg    }
98705b261ecSmrg
98805b261ecSmrg    if (pGC->dash != DefaultDash)
9896747b715Smrg	free(pGC->dash);
99005b261ecSmrg    pGC->numInDashList = ndash;
99105b261ecSmrg    pGC->dash = p;
99205b261ecSmrg    if (ndash & 1)
99305b261ecSmrg    {
99405b261ecSmrg	pGC->numInDashList += ndash;
99505b261ecSmrg	indash = pdash;
99605b261ecSmrg	i = ndash;
99705b261ecSmrg	while (i--)
99805b261ecSmrg	    *p++ = *indash++;
99905b261ecSmrg    }
100005b261ecSmrg    while(ndash--)
100105b261ecSmrg	*p++ = *pdash++;
100205b261ecSmrg    pGC->stateChanges |= GCDashList;
100305b261ecSmrg    maskQ |= GCDashList;
100405b261ecSmrg
100505b261ecSmrg    if (pGC->funcs->ChangeGC)
100605b261ecSmrg	(*pGC->funcs->ChangeGC) (pGC, maskQ);
100705b261ecSmrg    return Success;
100805b261ecSmrg}
100905b261ecSmrg
10106747b715Smrgint
101105b261ecSmrgVerifyRectOrder(int nrects, xRectangle *prects, int ordering)
101205b261ecSmrg{
101305b261ecSmrg    xRectangle	*prectP, *prectN;
101405b261ecSmrg    int	i;
101505b261ecSmrg
101605b261ecSmrg    switch(ordering)
101705b261ecSmrg    {
101805b261ecSmrg      case Unsorted:
101905b261ecSmrg	  return CT_UNSORTED;
102005b261ecSmrg      case YSorted:
102105b261ecSmrg	  if(nrects > 1)
102205b261ecSmrg	  {
102305b261ecSmrg	      for(i = 1, prectP = prects, prectN = prects + 1;
102405b261ecSmrg		  i < nrects;
102505b261ecSmrg		  i++, prectP++, prectN++)
102605b261ecSmrg		  if(prectN->y < prectP->y)
102705b261ecSmrg		      return -1;
102805b261ecSmrg	  }
102905b261ecSmrg	  return CT_YSORTED;
103005b261ecSmrg      case YXSorted:
103105b261ecSmrg	  if(nrects > 1)
103205b261ecSmrg	  {
103305b261ecSmrg	      for(i = 1, prectP = prects, prectN = prects + 1;
103405b261ecSmrg		  i < nrects;
103505b261ecSmrg		  i++, prectP++, prectN++)
103605b261ecSmrg		  if((prectN->y < prectP->y) ||
103705b261ecSmrg		      ( (prectN->y == prectP->y) &&
103805b261ecSmrg		        (prectN->x < prectP->x) ) )
103905b261ecSmrg		      return -1;
104005b261ecSmrg	  }
104105b261ecSmrg	  return CT_YXSORTED;
104205b261ecSmrg      case YXBanded:
104305b261ecSmrg	  if(nrects > 1)
104405b261ecSmrg	  {
104505b261ecSmrg	      for(i = 1, prectP = prects, prectN = prects + 1;
104605b261ecSmrg		  i < nrects;
104705b261ecSmrg		  i++, prectP++, prectN++)
104805b261ecSmrg		  if((prectN->y != prectP->y &&
104905b261ecSmrg 		      prectN->y < prectP->y + (int) prectP->height) ||
105005b261ecSmrg		     ((prectN->y == prectP->y) &&
105105b261ecSmrg		      (prectN->height != prectP->height ||
105205b261ecSmrg		       prectN->x < prectP->x + (int) prectP->width)))
105305b261ecSmrg		      return -1;
105405b261ecSmrg	  }
105505b261ecSmrg	  return CT_YXBANDED;
105605b261ecSmrg    }
105705b261ecSmrg    return -1;
105805b261ecSmrg}
105905b261ecSmrg
10604642e01fSmrgint
106105b261ecSmrgSetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
106205b261ecSmrg             xRectangle *prects, int ordering)
106305b261ecSmrg{
106405b261ecSmrg    int			newct, size;
106505b261ecSmrg    xRectangle 		*prectsNew;
106605b261ecSmrg
106705b261ecSmrg    newct = VerifyRectOrder(nrects, prects, ordering);
106805b261ecSmrg    if (newct < 0)
10696747b715Smrg	return BadMatch;
107005b261ecSmrg    size = nrects * sizeof(xRectangle);
10716747b715Smrg    prectsNew = malloc(size);
107205b261ecSmrg    if (!prectsNew && size)
107305b261ecSmrg	return BadAlloc;
107405b261ecSmrg
107505b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
107605b261ecSmrg    pGC->clipOrg.x = xOrigin;
107705b261ecSmrg    pGC->stateChanges |= GCClipXOrigin;
107805b261ecSmrg
107905b261ecSmrg    pGC->clipOrg.y = yOrigin;
108005b261ecSmrg    pGC->stateChanges |= GCClipYOrigin;
108105b261ecSmrg
108205b261ecSmrg    if (size)
108305b261ecSmrg	memmove((char *)prectsNew, (char *)prects, size);
108405b261ecSmrg    (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
108505b261ecSmrg    if (pGC->funcs->ChangeGC)
108605b261ecSmrg	(*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
108705b261ecSmrg    return Success;
108805b261ecSmrg}
108905b261ecSmrg
109005b261ecSmrg
109105b261ecSmrg/*
109205b261ecSmrg   sets reasonable defaults
109305b261ecSmrg   if we can get a pre-allocated one, use it and mark it as used.
109405b261ecSmrg   if we can't, create one out of whole cloth (The Velveteen GC -- if
109505b261ecSmrg   you use it often enough it will become real.)
109605b261ecSmrg*/
10976747b715SmrgGCPtr
109805b261ecSmrgGetScratchGC(unsigned depth, ScreenPtr pScreen)
109905b261ecSmrg{
110005b261ecSmrg    int i;
110105b261ecSmrg    GCPtr pGC;
110205b261ecSmrg
110305b261ecSmrg    for (i=0; i<=pScreen->numDepths; i++)
11046747b715Smrg    {
11056747b715Smrg	pGC = pScreen->GCperDepth[i];
11066747b715Smrg	if (pGC && pGC->depth == depth && !pGC->scratch_inuse)
110705b261ecSmrg	{
11086747b715Smrg	    pGC->scratch_inuse = TRUE;
110905b261ecSmrg
111005b261ecSmrg	    pGC->alu = GXcopy;
111105b261ecSmrg	    pGC->planemask = ~0;
111205b261ecSmrg	    pGC->serialNumber = 0;
111305b261ecSmrg	    pGC->fgPixel = 0;
111405b261ecSmrg	    pGC->bgPixel = 1;
111505b261ecSmrg	    pGC->lineWidth = 0;
111605b261ecSmrg	    pGC->lineStyle = LineSolid;
111705b261ecSmrg	    pGC->capStyle = CapButt;
111805b261ecSmrg	    pGC->joinStyle = JoinMiter;
111905b261ecSmrg	    pGC->fillStyle = FillSolid;
112005b261ecSmrg	    pGC->fillRule = EvenOddRule;
112105b261ecSmrg	    pGC->arcMode = ArcChord;
112205b261ecSmrg	    pGC->patOrg.x = 0;
112305b261ecSmrg	    pGC->patOrg.y = 0;
112405b261ecSmrg	    pGC->subWindowMode = ClipByChildren;
112505b261ecSmrg	    pGC->graphicsExposures = FALSE;
112605b261ecSmrg	    pGC->clipOrg.x = 0;
112705b261ecSmrg	    pGC->clipOrg.y = 0;
112805b261ecSmrg	    if (pGC->clientClipType != CT_NONE)
112905b261ecSmrg		(*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
11306747b715Smrg	    pGC->stateChanges = GCAllBits;
113105b261ecSmrg	    return pGC;
113205b261ecSmrg	}
11336747b715Smrg    }
113405b261ecSmrg    /* if we make it this far, need to roll our own */
113505b261ecSmrg    pGC = CreateScratchGC(pScreen, depth);
113605b261ecSmrg    if (pGC)
113705b261ecSmrg	pGC->graphicsExposures = FALSE;
113805b261ecSmrg    return pGC;
113905b261ecSmrg}
114005b261ecSmrg
114105b261ecSmrg/*
114205b261ecSmrg   if the gc to free is in the table of pre-existing ones,
114305b261ecSmrgmark it as available.
114405b261ecSmrg   if not, free it for real
114505b261ecSmrg*/
11466747b715Smrgvoid
114705b261ecSmrgFreeScratchGC(GCPtr pGC)
114805b261ecSmrg{
11496747b715Smrg    if (pGC->scratch_inuse)
11506747b715Smrg	pGC->scratch_inuse = FALSE;
11516747b715Smrg    else
11526747b715Smrg	FreeGC(pGC, (GContext)0);
115305b261ecSmrg}
1154