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
2505b261ecSmrgCopyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
2605b261ecSmrg
2705b261ecSmrg                        All Rights Reserved
2805b261ecSmrg
2935c4bbdfSmrgPermission to use, copy, modify, and distribute this software and its
3035c4bbdfSmrgdocumentation for any purpose and without fee is hereby granted,
3105b261ecSmrgprovided that the above copyright notice appear in all copies and that
3235c4bbdfSmrgboth that copyright notice and this permission notice appear in
3305b261ecSmrgsupporting documentation, and that the name of Digital not be
3405b261ecSmrgused in advertising or publicity pertaining to distribution of the
3535c4bbdfSmrgsoftware without specific, written prior permission.
3605b261ecSmrg
3705b261ecSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
3805b261ecSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
3905b261ecSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
4005b261ecSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
4105b261ecSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
4205b261ecSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
4305b261ecSmrgSOFTWARE.
4405b261ecSmrg
4505b261ecSmrg******************************************************************/
4605b261ecSmrg
4705b261ecSmrg#ifdef HAVE_DIX_CONFIG_H
4805b261ecSmrg#include <dix-config.h>
4905b261ecSmrg#endif
5005b261ecSmrg
5105b261ecSmrg#include <X11/X.h>
5205b261ecSmrg#include <X11/Xmd.h>
5305b261ecSmrg#include <X11/Xproto.h>
5405b261ecSmrg#include "misc.h"
5505b261ecSmrg#include "resource.h"
5605b261ecSmrg#include "gcstruct.h"
5705b261ecSmrg#include "pixmapstr.h"
5805b261ecSmrg#include "dixfontstr.h"
5905b261ecSmrg#include "scrnintstr.h"
6005b261ecSmrg#include "region.h"
616747b715Smrg#include "dixstruct.h"
6205b261ecSmrg
634642e01fSmrg#include "privates.h"
6405b261ecSmrg#include "dix.h"
654642e01fSmrg#include "xace.h"
6605b261ecSmrg#include <assert.h>
6705b261ecSmrg
6805b261ecSmrgextern FontPtr defaultFont;
6905b261ecSmrg
7005b261ecSmrgstatic Bool CreateDefaultTile(GCPtr pGC);
7105b261ecSmrg
7235c4bbdfSmrgstatic unsigned char DefaultDash[2] = { 4, 4 };
7305b261ecSmrg
746747b715Smrgvoid
7535c4bbdfSmrgValidateGC(DrawablePtr pDraw, GC * pGC)
7605b261ecSmrg{
7705b261ecSmrg    (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
7805b261ecSmrg    pGC->stateChanges = 0;
7905b261ecSmrg    pGC->serialNumber = pDraw->serialNumber;
8005b261ecSmrg}
8105b261ecSmrg
826747b715Smrg/*
836747b715Smrg * ChangeGC/ChangeGCXIDs:
846747b715Smrg *
856747b715Smrg * The client performing the gc change must be passed so that access
866747b715Smrg * checks can be performed on any tiles, stipples, or fonts that are
876747b715Smrg * specified.  ddxen can call this too; they should normally pass
886747b715Smrg * NullClient for the client since any access checking should have
8905b261ecSmrg * already been done at a higher level.
9035c4bbdfSmrg *
916747b715Smrg * If you have any XIDs, you must use ChangeGCXIDs:
9235c4bbdfSmrg *
9305b261ecSmrg *     CARD32 v[2];
946747b715Smrg *     v[0] = FillTiled;
956747b715Smrg *     v[1] = pid;
966747b715Smrg *     ChangeGCXIDs(client, pGC, GCFillStyle|GCTile, v);
9735c4bbdfSmrg *
986747b715Smrg * However, if you need to pass a pointer to a pixmap or font, you must
996747b715Smrg * use ChangeGC:
10035c4bbdfSmrg *
10105b261ecSmrg *     ChangeGCVal v[2];
10205b261ecSmrg *     v[0].val = FillTiled;
10305b261ecSmrg *     v[1].ptr = pPixmap;
1046747b715Smrg *     ChangeGC(client, pGC, GCFillStyle|GCTile, v);
10535c4bbdfSmrg *
1066747b715Smrg * If you have neither XIDs nor pointers, you can use either function,
1076747b715Smrg * but ChangeGC will do less work.
1086747b715Smrg *
1096747b715Smrg *     ChangeGCVal v[2];
1106747b715Smrg *     v[0].val = foreground;
1116747b715Smrg *     v[1].val = background;
1126747b715Smrg *     ChangeGC(client, pGC, GCForeground|GCBackground, v);
11305b261ecSmrg */
11405b261ecSmrg
11505b261ecSmrg#define NEXTVAL(_type, _var) { \
11605b261ecSmrg	_var = (_type)(pUnion->val); pUnion++; \
11705b261ecSmrg    }
11805b261ecSmrg
11905b261ecSmrg#define NEXT_PTR(_type, _var) { \
1206747b715Smrg    _var = (_type)pUnion->ptr; pUnion++; }
12105b261ecSmrg
1226747b715Smrgint
12335c4bbdfSmrgChangeGC(ClientPtr client, GC * pGC, BITS32 mask, ChangeGCValPtr pUnion)
12405b261ecSmrg{
12535c4bbdfSmrg    BITS32 index2;
12635c4bbdfSmrg    int error = 0;
12735c4bbdfSmrg    PixmapPtr pPixmap;
12835c4bbdfSmrg    BITS32 maskQ;
12905b261ecSmrg
1306747b715Smrg    assert(pUnion);
13105b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
13205b261ecSmrg
13335c4bbdfSmrg    maskQ = mask;               /* save these for when we walk the GCque */
13435c4bbdfSmrg    while (mask && !error) {
13535c4bbdfSmrg        index2 = (BITS32) lowbit(mask);
13635c4bbdfSmrg        mask &= ~index2;
13735c4bbdfSmrg        pGC->stateChanges |= index2;
13835c4bbdfSmrg        switch (index2) {
13935c4bbdfSmrg        case GCFunction:
14035c4bbdfSmrg        {
14135c4bbdfSmrg            CARD8 newalu;
14235c4bbdfSmrg            NEXTVAL(CARD8, newalu);
14335c4bbdfSmrg
14435c4bbdfSmrg            if (newalu <= GXset)
14535c4bbdfSmrg                pGC->alu = newalu;
14635c4bbdfSmrg            else {
14735c4bbdfSmrg                if (client)
14835c4bbdfSmrg                    client->errorValue = newalu;
14935c4bbdfSmrg                error = BadValue;
15035c4bbdfSmrg            }
15135c4bbdfSmrg            break;
15235c4bbdfSmrg        }
15335c4bbdfSmrg        case GCPlaneMask:
15435c4bbdfSmrg            NEXTVAL(unsigned long, pGC->planemask);
15535c4bbdfSmrg
15635c4bbdfSmrg            break;
15735c4bbdfSmrg        case GCForeground:
15835c4bbdfSmrg            NEXTVAL(unsigned long, pGC->fgPixel);
15935c4bbdfSmrg
16035c4bbdfSmrg            /*
16135c4bbdfSmrg             * this is for CreateGC
16235c4bbdfSmrg             */
16335c4bbdfSmrg            if (!pGC->tileIsPixel && !pGC->tile.pixmap) {
16435c4bbdfSmrg                pGC->tileIsPixel = TRUE;
16535c4bbdfSmrg                pGC->tile.pixel = pGC->fgPixel;
16635c4bbdfSmrg            }
16735c4bbdfSmrg            break;
16835c4bbdfSmrg        case GCBackground:
16935c4bbdfSmrg            NEXTVAL(unsigned long, pGC->bgPixel);
17035c4bbdfSmrg
17135c4bbdfSmrg            break;
17235c4bbdfSmrg        case GCLineWidth:      /* ??? line width is a CARD16 */
17335c4bbdfSmrg            NEXTVAL(CARD16, pGC->lineWidth);
17435c4bbdfSmrg
17535c4bbdfSmrg            break;
17635c4bbdfSmrg        case GCLineStyle:
17735c4bbdfSmrg        {
17835c4bbdfSmrg            unsigned int newlinestyle;
17935c4bbdfSmrg            NEXTVAL(unsigned int, newlinestyle);
18035c4bbdfSmrg
18135c4bbdfSmrg            if (newlinestyle <= LineDoubleDash)
18235c4bbdfSmrg                pGC->lineStyle = newlinestyle;
18335c4bbdfSmrg            else {
18435c4bbdfSmrg                if (client)
18535c4bbdfSmrg                    client->errorValue = newlinestyle;
18635c4bbdfSmrg                error = BadValue;
18735c4bbdfSmrg            }
18835c4bbdfSmrg            break;
18935c4bbdfSmrg        }
19035c4bbdfSmrg        case GCCapStyle:
19135c4bbdfSmrg        {
19235c4bbdfSmrg            unsigned int newcapstyle;
19335c4bbdfSmrg            NEXTVAL(unsigned int, newcapstyle);
19435c4bbdfSmrg
19535c4bbdfSmrg            if (newcapstyle <= CapProjecting)
19635c4bbdfSmrg                pGC->capStyle = newcapstyle;
19735c4bbdfSmrg            else {
19835c4bbdfSmrg                if (client)
19935c4bbdfSmrg                    client->errorValue = newcapstyle;
20035c4bbdfSmrg                error = BadValue;
20135c4bbdfSmrg            }
20235c4bbdfSmrg            break;
20335c4bbdfSmrg        }
20435c4bbdfSmrg        case GCJoinStyle:
20535c4bbdfSmrg        {
20635c4bbdfSmrg            unsigned int newjoinstyle;
20735c4bbdfSmrg            NEXTVAL(unsigned int, newjoinstyle);
20835c4bbdfSmrg
20935c4bbdfSmrg            if (newjoinstyle <= JoinBevel)
21035c4bbdfSmrg                pGC->joinStyle = newjoinstyle;
21135c4bbdfSmrg            else {
21235c4bbdfSmrg                if (client)
21335c4bbdfSmrg                    client->errorValue = newjoinstyle;
21435c4bbdfSmrg                error = BadValue;
21535c4bbdfSmrg            }
21635c4bbdfSmrg            break;
21735c4bbdfSmrg        }
21835c4bbdfSmrg        case GCFillStyle:
21935c4bbdfSmrg        {
22035c4bbdfSmrg            unsigned int newfillstyle;
22135c4bbdfSmrg            NEXTVAL(unsigned int, newfillstyle);
22235c4bbdfSmrg
22335c4bbdfSmrg            if (newfillstyle <= FillOpaqueStippled)
22435c4bbdfSmrg                pGC->fillStyle = newfillstyle;
22535c4bbdfSmrg            else {
22635c4bbdfSmrg                if (client)
22735c4bbdfSmrg                    client->errorValue = newfillstyle;
22835c4bbdfSmrg                error = BadValue;
22935c4bbdfSmrg            }
23035c4bbdfSmrg            break;
23135c4bbdfSmrg        }
23235c4bbdfSmrg        case GCFillRule:
23335c4bbdfSmrg        {
23435c4bbdfSmrg            unsigned int newfillrule;
23535c4bbdfSmrg            NEXTVAL(unsigned int, newfillrule);
23635c4bbdfSmrg
23735c4bbdfSmrg            if (newfillrule <= WindingRule)
23835c4bbdfSmrg                pGC->fillRule = newfillrule;
23935c4bbdfSmrg            else {
24035c4bbdfSmrg                if (client)
24135c4bbdfSmrg                    client->errorValue = newfillrule;
24235c4bbdfSmrg                error = BadValue;
24335c4bbdfSmrg            }
24435c4bbdfSmrg            break;
24535c4bbdfSmrg        }
24635c4bbdfSmrg        case GCTile:
24735c4bbdfSmrg            NEXT_PTR(PixmapPtr, pPixmap);
24835c4bbdfSmrg
24935c4bbdfSmrg            if ((pPixmap->drawable.depth != pGC->depth) ||
25035c4bbdfSmrg                (pPixmap->drawable.pScreen != pGC->pScreen)) {
25135c4bbdfSmrg                error = BadMatch;
25235c4bbdfSmrg            }
25335c4bbdfSmrg            else {
25435c4bbdfSmrg                pPixmap->refcnt++;
25535c4bbdfSmrg                if (!pGC->tileIsPixel)
25635c4bbdfSmrg                    (*pGC->pScreen->DestroyPixmap) (pGC->tile.pixmap);
25735c4bbdfSmrg                pGC->tileIsPixel = FALSE;
25835c4bbdfSmrg                pGC->tile.pixmap = pPixmap;
25935c4bbdfSmrg            }
26035c4bbdfSmrg            break;
26135c4bbdfSmrg        case GCStipple:
26235c4bbdfSmrg            NEXT_PTR(PixmapPtr, pPixmap);
26335c4bbdfSmrg
26435c4bbdfSmrg            if (pPixmap && ((pPixmap->drawable.depth != 1) ||
26535c4bbdfSmrg                            (pPixmap->drawable.pScreen != pGC->pScreen)))
26635c4bbdfSmrg            {
26735c4bbdfSmrg                error = BadMatch;
26835c4bbdfSmrg            }
26935c4bbdfSmrg            else {
27035c4bbdfSmrg                if (pPixmap)
27135c4bbdfSmrg                    pPixmap->refcnt++;
27235c4bbdfSmrg                if (pGC->stipple)
27335c4bbdfSmrg                    (*pGC->pScreen->DestroyPixmap) (pGC->stipple);
27435c4bbdfSmrg                pGC->stipple = pPixmap;
27535c4bbdfSmrg            }
27635c4bbdfSmrg            break;
27735c4bbdfSmrg        case GCTileStipXOrigin:
27835c4bbdfSmrg            NEXTVAL(INT16, pGC->patOrg.x);
27935c4bbdfSmrg
28035c4bbdfSmrg            break;
28135c4bbdfSmrg        case GCTileStipYOrigin:
28235c4bbdfSmrg            NEXTVAL(INT16, pGC->patOrg.y);
28335c4bbdfSmrg
28435c4bbdfSmrg            break;
28535c4bbdfSmrg        case GCFont:
28635c4bbdfSmrg        {
28735c4bbdfSmrg            FontPtr pFont;
28835c4bbdfSmrg            NEXT_PTR(FontPtr, pFont);
28935c4bbdfSmrg
29035c4bbdfSmrg            pFont->refcnt++;
29135c4bbdfSmrg            if (pGC->font)
29235c4bbdfSmrg                CloseFont(pGC->font, (Font) 0);
29335c4bbdfSmrg            pGC->font = pFont;
29435c4bbdfSmrg            break;
29535c4bbdfSmrg        }
29635c4bbdfSmrg        case GCSubwindowMode:
29735c4bbdfSmrg        {
29835c4bbdfSmrg            unsigned int newclipmode;
29935c4bbdfSmrg            NEXTVAL(unsigned int, newclipmode);
30035c4bbdfSmrg
30135c4bbdfSmrg            if (newclipmode <= IncludeInferiors)
30235c4bbdfSmrg                pGC->subWindowMode = newclipmode;
30335c4bbdfSmrg            else {
30435c4bbdfSmrg                if (client)
30535c4bbdfSmrg                    client->errorValue = newclipmode;
30635c4bbdfSmrg                error = BadValue;
30735c4bbdfSmrg            }
30835c4bbdfSmrg            break;
30935c4bbdfSmrg        }
31035c4bbdfSmrg        case GCGraphicsExposures:
31135c4bbdfSmrg        {
31235c4bbdfSmrg            unsigned int newge;
31335c4bbdfSmrg            NEXTVAL(unsigned int, newge);
31435c4bbdfSmrg
31535c4bbdfSmrg            if (newge <= xTrue)
31635c4bbdfSmrg                pGC->graphicsExposures = newge;
31735c4bbdfSmrg            else {
31835c4bbdfSmrg                if (client)
31935c4bbdfSmrg                    client->errorValue = newge;
32035c4bbdfSmrg                error = BadValue;
32135c4bbdfSmrg            }
32235c4bbdfSmrg            break;
32335c4bbdfSmrg        }
32435c4bbdfSmrg        case GCClipXOrigin:
32535c4bbdfSmrg            NEXTVAL(INT16, pGC->clipOrg.x);
32635c4bbdfSmrg
32735c4bbdfSmrg            break;
32835c4bbdfSmrg        case GCClipYOrigin:
32935c4bbdfSmrg            NEXTVAL(INT16, pGC->clipOrg.y);
33035c4bbdfSmrg
33135c4bbdfSmrg            break;
33235c4bbdfSmrg        case GCClipMask:
33335c4bbdfSmrg            NEXT_PTR(PixmapPtr, pPixmap);
33435c4bbdfSmrg
33535c4bbdfSmrg            if (pPixmap) {
33635c4bbdfSmrg                if ((pPixmap->drawable.depth != 1) ||
33735c4bbdfSmrg                    (pPixmap->drawable.pScreen != pGC->pScreen)) {
33835c4bbdfSmrg                    error = BadMatch;
33935c4bbdfSmrg                    break;
34035c4bbdfSmrg                }
34135c4bbdfSmrg                pPixmap->refcnt++;
34235c4bbdfSmrg            }
34335c4bbdfSmrg            (*pGC->funcs->ChangeClip) (pGC, pPixmap ? CT_PIXMAP : CT_NONE,
34435c4bbdfSmrg                                       (void *) pPixmap, 0);
34535c4bbdfSmrg            break;
34635c4bbdfSmrg        case GCDashOffset:
34735c4bbdfSmrg            NEXTVAL(INT16, pGC->dashOffset);
34835c4bbdfSmrg
34935c4bbdfSmrg            break;
35035c4bbdfSmrg        case GCDashList:
35135c4bbdfSmrg        {
35235c4bbdfSmrg            CARD8 newdash;
35335c4bbdfSmrg            NEXTVAL(CARD8, newdash);
35435c4bbdfSmrg
35535c4bbdfSmrg            if (newdash == 4) {
35635c4bbdfSmrg                if (pGC->dash != DefaultDash) {
35735c4bbdfSmrg                    free(pGC->dash);
35835c4bbdfSmrg                    pGC->numInDashList = 2;
35935c4bbdfSmrg                    pGC->dash = DefaultDash;
36035c4bbdfSmrg                }
36135c4bbdfSmrg            }
36235c4bbdfSmrg            else if (newdash != 0) {
36335c4bbdfSmrg                unsigned char *dash;
36435c4bbdfSmrg
36535c4bbdfSmrg                dash = malloc(2 * sizeof(unsigned char));
36635c4bbdfSmrg                if (dash) {
36735c4bbdfSmrg                    if (pGC->dash != DefaultDash)
36835c4bbdfSmrg                        free(pGC->dash);
36935c4bbdfSmrg                    pGC->numInDashList = 2;
37035c4bbdfSmrg                    pGC->dash = dash;
37135c4bbdfSmrg                    dash[0] = newdash;
37235c4bbdfSmrg                    dash[1] = newdash;
37335c4bbdfSmrg                }
37435c4bbdfSmrg                else
37535c4bbdfSmrg                    error = BadAlloc;
37635c4bbdfSmrg            }
37735c4bbdfSmrg            else {
37835c4bbdfSmrg                if (client)
37935c4bbdfSmrg                    client->errorValue = newdash;
38035c4bbdfSmrg                error = BadValue;
38135c4bbdfSmrg            }
38235c4bbdfSmrg            break;
38335c4bbdfSmrg        }
38435c4bbdfSmrg        case GCArcMode:
38535c4bbdfSmrg        {
38635c4bbdfSmrg            unsigned int newarcmode;
38735c4bbdfSmrg            NEXTVAL(unsigned int, newarcmode);
38835c4bbdfSmrg
38935c4bbdfSmrg            if (newarcmode <= ArcPieSlice)
39035c4bbdfSmrg                pGC->arcMode = newarcmode;
39135c4bbdfSmrg            else {
39235c4bbdfSmrg                if (client)
39335c4bbdfSmrg                    client->errorValue = newarcmode;
39435c4bbdfSmrg                error = BadValue;
39535c4bbdfSmrg            }
39635c4bbdfSmrg            break;
39735c4bbdfSmrg        }
39835c4bbdfSmrg        default:
39935c4bbdfSmrg            if (client)
40035c4bbdfSmrg                client->errorValue = maskQ;
40135c4bbdfSmrg            error = BadValue;
40235c4bbdfSmrg            break;
40335c4bbdfSmrg        }
40435c4bbdfSmrg    }                           /* end while mask && !error */
40535c4bbdfSmrg
40635c4bbdfSmrg    if (pGC->fillStyle == FillTiled && pGC->tileIsPixel) {
40735c4bbdfSmrg        if (!CreateDefaultTile(pGC)) {
40835c4bbdfSmrg            pGC->fillStyle = FillSolid;
40935c4bbdfSmrg            error = BadAlloc;
41035c4bbdfSmrg        }
41105b261ecSmrg    }
41235c4bbdfSmrg    (*pGC->funcs->ChangeGC) (pGC, maskQ);
41305b261ecSmrg    return error;
41405b261ecSmrg}
41505b261ecSmrg
41605b261ecSmrg#undef NEXTVAL
41705b261ecSmrg#undef NEXT_PTR
41805b261ecSmrg
4196747b715Smrgstatic const struct {
4206747b715Smrg    BITS32 mask;
4216747b715Smrg    RESTYPE type;
4226747b715Smrg    Mask access_mode;
4236747b715Smrg} xidfields[] = {
42435c4bbdfSmrg    {GCTile, RT_PIXMAP, DixReadAccess},
42535c4bbdfSmrg    {GCStipple, RT_PIXMAP, DixReadAccess},
42635c4bbdfSmrg    {GCFont, RT_FONT, DixUseAccess},
42735c4bbdfSmrg    {GCClipMask, RT_PIXMAP, DixReadAccess},
4286747b715Smrg};
42905b261ecSmrg
4306747b715Smrgint
43135c4bbdfSmrgChangeGCXIDs(ClientPtr client, GC * pGC, BITS32 mask, CARD32 *pC32)
43205b261ecSmrg{
4336747b715Smrg    ChangeGCVal vals[GCLastBit + 1];
4346747b715Smrg    int i;
43535c4bbdfSmrg
43635c4bbdfSmrg    if (mask & ~GCAllBits) {
43735c4bbdfSmrg        client->errorValue = mask;
43835c4bbdfSmrg        return BadValue;
4396747b715Smrg    }
44035c4bbdfSmrg    for (i = Ones(mask); i--;)
44135c4bbdfSmrg        vals[i].val = pC32[i];
4421b5d61b8Smrg    for (i = 0; i < ARRAY_SIZE(xidfields); ++i) {
44335c4bbdfSmrg        int offset, rc;
44435c4bbdfSmrg
44535c4bbdfSmrg        if (!(mask & xidfields[i].mask))
44635c4bbdfSmrg            continue;
44735c4bbdfSmrg        offset = Ones(mask & (xidfields[i].mask - 1));
44835c4bbdfSmrg        if (xidfields[i].mask == GCClipMask && vals[offset].val == None) {
44935c4bbdfSmrg            vals[offset].ptr = NullPixmap;
45035c4bbdfSmrg            continue;
45135c4bbdfSmrg        }
45235c4bbdfSmrg        rc = dixLookupResourceByType(&vals[offset].ptr, vals[offset].val,
45335c4bbdfSmrg                                     xidfields[i].type, client,
45435c4bbdfSmrg                                     xidfields[i].access_mode);
45535c4bbdfSmrg        if (rc != Success) {
45635c4bbdfSmrg            client->errorValue = vals[offset].val;
45735c4bbdfSmrg            return rc;
45835c4bbdfSmrg        }
4596747b715Smrg    }
4606747b715Smrg    return ChangeGC(client, pGC, mask, vals);
46105b261ecSmrg}
46205b261ecSmrg
46335c4bbdfSmrgstatic GCPtr
46435c4bbdfSmrgNewGCObject(ScreenPtr pScreen, int depth)
46505b261ecSmrg{
46605b261ecSmrg    GCPtr pGC;
46705b261ecSmrg
46835c4bbdfSmrg    pGC = dixAllocateScreenObjectWithPrivates(pScreen, GC, PRIVATE_GC);
46935c4bbdfSmrg    if (!pGC) {
47035c4bbdfSmrg        return (GCPtr) NULL;
47105b261ecSmrg    }
47205b261ecSmrg
47335c4bbdfSmrg    pGC->pScreen = pScreen;
47435c4bbdfSmrg    pGC->depth = depth;
47535c4bbdfSmrg    pGC->alu = GXcopy;          /* dst <- src */
47605b261ecSmrg    pGC->planemask = ~0;
47735c4bbdfSmrg    pGC->serialNumber = 0;
47805b261ecSmrg    pGC->funcs = 0;
47905b261ecSmrg    pGC->fgPixel = 0;
48005b261ecSmrg    pGC->bgPixel = 1;
48105b261ecSmrg    pGC->lineWidth = 0;
48205b261ecSmrg    pGC->lineStyle = LineSolid;
48305b261ecSmrg    pGC->capStyle = CapButt;
48405b261ecSmrg    pGC->joinStyle = JoinMiter;
48505b261ecSmrg    pGC->fillStyle = FillSolid;
48605b261ecSmrg    pGC->fillRule = EvenOddRule;
48705b261ecSmrg    pGC->arcMode = ArcPieSlice;
4886747b715Smrg    pGC->tile.pixel = 0;
4896747b715Smrg    pGC->tile.pixmap = NullPixmap;
49005b261ecSmrg
49135c4bbdfSmrg    pGC->tileIsPixel = TRUE;
49205b261ecSmrg    pGC->patOrg.x = 0;
49305b261ecSmrg    pGC->patOrg.y = 0;
49405b261ecSmrg    pGC->subWindowMode = ClipByChildren;
49505b261ecSmrg    pGC->graphicsExposures = TRUE;
49605b261ecSmrg    pGC->clipOrg.x = 0;
49705b261ecSmrg    pGC->clipOrg.y = 0;
49835c4bbdfSmrg    pGC->clientClip = (void *) NULL;
49905b261ecSmrg    pGC->numInDashList = 2;
50005b261ecSmrg    pGC->dash = DefaultDash;
50105b261ecSmrg    pGC->dashOffset = 0;
50205b261ecSmrg
50305b261ecSmrg    /* use the default font and stipple */
50405b261ecSmrg    pGC->font = defaultFont;
50535c4bbdfSmrg    if (pGC->font)              /* necessary, because open of default font could fail */
50635c4bbdfSmrg        pGC->font->refcnt++;
5071b5d61b8Smrg    pGC->stipple = pGC->pScreen->defaultStipple;
50835c4bbdfSmrg    if (pGC->stipple)
50935c4bbdfSmrg        pGC->stipple->refcnt++;
51005b261ecSmrg
5116747b715Smrg    /* this is not a scratch GC */
5126747b715Smrg    pGC->scratch_inuse = FALSE;
51335c4bbdfSmrg    return pGC;
51435c4bbdfSmrg}
51535c4bbdfSmrg
51635c4bbdfSmrg/* CreateGC(pDrawable, mask, pval, pStatus)
51735c4bbdfSmrg   creates a default GC for the given drawable, using mask to fill
51835c4bbdfSmrg   in any non-default values.
51935c4bbdfSmrg   Returns a pointer to the new GC on success, NULL otherwise.
52035c4bbdfSmrg   returns status of non-default fields in pStatus
52135c4bbdfSmrgBUG:
52235c4bbdfSmrg   should check for failure to create default tile
52335c4bbdfSmrg
52435c4bbdfSmrg*/
52535c4bbdfSmrgGCPtr
52635c4bbdfSmrgCreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus,
52735c4bbdfSmrg         XID gcid, ClientPtr client)
52835c4bbdfSmrg{
52935c4bbdfSmrg    GCPtr pGC;
53035c4bbdfSmrg
53135c4bbdfSmrg    pGC = NewGCObject(pDrawable->pScreen, pDrawable->depth);
53235c4bbdfSmrg    if (!pGC) {
53335c4bbdfSmrg        *pStatus = BadAlloc;
53435c4bbdfSmrg        return (GCPtr) NULL;
53535c4bbdfSmrg    }
53635c4bbdfSmrg
53735c4bbdfSmrg    pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
53835c4bbdfSmrg    if (mask & GCForeground) {
53935c4bbdfSmrg        /*
54035c4bbdfSmrg         * magic special case -- ChangeGC checks for this condition
54135c4bbdfSmrg         * and snags the Foreground value to create a pseudo default-tile
54235c4bbdfSmrg         */
54335c4bbdfSmrg        pGC->tileIsPixel = FALSE;
54435c4bbdfSmrg    }
54535c4bbdfSmrg    else {
54635c4bbdfSmrg        pGC->tileIsPixel = TRUE;
54735c4bbdfSmrg    }
5486747b715Smrg
5494642e01fSmrg    /* security creation/labeling check */
5504642e01fSmrg    *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
55135c4bbdfSmrg                        RT_NONE, NULL, DixCreateAccess | DixSetAttrAccess);
5524642e01fSmrg    if (*pStatus != Success)
55335c4bbdfSmrg        goto out;
5544642e01fSmrg
5556747b715Smrg    pGC->stateChanges = GCAllBits;
55635c4bbdfSmrg    if (!(*pGC->pScreen->CreateGC) (pGC))
55735c4bbdfSmrg        *pStatus = BadAlloc;
55805b261ecSmrg    else if (mask)
5596747b715Smrg        *pStatus = ChangeGCXIDs(client, pGC, mask, pval);
56005b261ecSmrg    else
56135c4bbdfSmrg        *pStatus = Success;
56235c4bbdfSmrg
56335c4bbdfSmrg out:
56435c4bbdfSmrg    if (*pStatus != Success) {
56535c4bbdfSmrg        if (!pGC->tileIsPixel && !pGC->tile.pixmap)
56635c4bbdfSmrg            pGC->tileIsPixel = TRUE;    /* undo special case */
56735c4bbdfSmrg        FreeGC(pGC, (XID) 0);
56835c4bbdfSmrg        pGC = (GCPtr) NULL;
56905b261ecSmrg    }
57005b261ecSmrg
5716747b715Smrg    return pGC;
57205b261ecSmrg}
57305b261ecSmrg
57405b261ecSmrgstatic Bool
57535c4bbdfSmrgCreateDefaultTile(GCPtr pGC)
57605b261ecSmrg{
57735c4bbdfSmrg    ChangeGCVal tmpval[3];
57835c4bbdfSmrg    PixmapPtr pTile;
57935c4bbdfSmrg    GCPtr pgcScratch;
58035c4bbdfSmrg    xRectangle rect;
58135c4bbdfSmrg    CARD16 w, h;
58205b261ecSmrg
58305b261ecSmrg    w = 1;
58405b261ecSmrg    h = 1;
58535c4bbdfSmrg    (*pGC->pScreen->QueryBestSize) (TileShape, &w, &h, pGC->pScreen);
58605b261ecSmrg    pTile = (PixmapPtr)
58735c4bbdfSmrg        (*pGC->pScreen->CreatePixmap) (pGC->pScreen, w, h, pGC->depth, 0);
58805b261ecSmrg    pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
58935c4bbdfSmrg    if (!pTile || !pgcScratch) {
59035c4bbdfSmrg        if (pTile)
59135c4bbdfSmrg            (*pTile->drawable.pScreen->DestroyPixmap) (pTile);
59235c4bbdfSmrg        if (pgcScratch)
59335c4bbdfSmrg            FreeScratchGC(pgcScratch);
59435c4bbdfSmrg        return FALSE;
59505b261ecSmrg    }
5966747b715Smrg    tmpval[0].val = GXcopy;
5976747b715Smrg    tmpval[1].val = pGC->tile.pixel;
5986747b715Smrg    tmpval[2].val = FillSolid;
59935c4bbdfSmrg    (void) ChangeGC(NullClient, pgcScratch,
60035c4bbdfSmrg                    GCFunction | GCForeground | GCFillStyle, tmpval);
60135c4bbdfSmrg    ValidateGC((DrawablePtr) pTile, pgcScratch);
60205b261ecSmrg    rect.x = 0;
60305b261ecSmrg    rect.y = 0;
60405b261ecSmrg    rect.width = w;
60505b261ecSmrg    rect.height = h;
60635c4bbdfSmrg    (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pTile, pgcScratch, 1,
60735c4bbdfSmrg                                      &rect);
60805b261ecSmrg    /* Always remember to free the scratch graphics context after use. */
60905b261ecSmrg    FreeScratchGC(pgcScratch);
61005b261ecSmrg
61105b261ecSmrg    pGC->tileIsPixel = FALSE;
61205b261ecSmrg    pGC->tile.pixmap = pTile;
61305b261ecSmrg    return TRUE;
61405b261ecSmrg}
61505b261ecSmrg
6166747b715Smrgint
61735c4bbdfSmrgCopyGC(GC * pgcSrc, GC * pgcDst, BITS32 mask)
61805b261ecSmrg{
61935c4bbdfSmrg    BITS32 index2;
62035c4bbdfSmrg    BITS32 maskQ;
62135c4bbdfSmrg    int error = 0;
62205b261ecSmrg
62305b261ecSmrg    if (pgcSrc == pgcDst)
62435c4bbdfSmrg        return Success;
62505b261ecSmrg    pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
62605b261ecSmrg    pgcDst->stateChanges |= mask;
62705b261ecSmrg    maskQ = mask;
62835c4bbdfSmrg    while (mask) {
62935c4bbdfSmrg        index2 = (BITS32) lowbit(mask);
63035c4bbdfSmrg        mask &= ~index2;
63135c4bbdfSmrg        switch (index2) {
63235c4bbdfSmrg        case GCFunction:
63335c4bbdfSmrg            pgcDst->alu = pgcSrc->alu;
63435c4bbdfSmrg            break;
63535c4bbdfSmrg        case GCPlaneMask:
63635c4bbdfSmrg            pgcDst->planemask = pgcSrc->planemask;
63735c4bbdfSmrg            break;
63835c4bbdfSmrg        case GCForeground:
63935c4bbdfSmrg            pgcDst->fgPixel = pgcSrc->fgPixel;
64035c4bbdfSmrg            break;
64135c4bbdfSmrg        case GCBackground:
64235c4bbdfSmrg            pgcDst->bgPixel = pgcSrc->bgPixel;
64335c4bbdfSmrg            break;
64435c4bbdfSmrg        case GCLineWidth:
64535c4bbdfSmrg            pgcDst->lineWidth = pgcSrc->lineWidth;
64635c4bbdfSmrg            break;
64735c4bbdfSmrg        case GCLineStyle:
64835c4bbdfSmrg            pgcDst->lineStyle = pgcSrc->lineStyle;
64935c4bbdfSmrg            break;
65035c4bbdfSmrg        case GCCapStyle:
65135c4bbdfSmrg            pgcDst->capStyle = pgcSrc->capStyle;
65235c4bbdfSmrg            break;
65335c4bbdfSmrg        case GCJoinStyle:
65435c4bbdfSmrg            pgcDst->joinStyle = pgcSrc->joinStyle;
65535c4bbdfSmrg            break;
65635c4bbdfSmrg        case GCFillStyle:
65735c4bbdfSmrg            pgcDst->fillStyle = pgcSrc->fillStyle;
65835c4bbdfSmrg            break;
65935c4bbdfSmrg        case GCFillRule:
66035c4bbdfSmrg            pgcDst->fillRule = pgcSrc->fillRule;
66135c4bbdfSmrg            break;
66235c4bbdfSmrg        case GCTile:
66335c4bbdfSmrg        {
66435c4bbdfSmrg            if (EqualPixUnion(pgcDst->tileIsPixel,
66535c4bbdfSmrg                              pgcDst->tile,
66635c4bbdfSmrg                              pgcSrc->tileIsPixel, pgcSrc->tile)) {
66735c4bbdfSmrg                break;
66835c4bbdfSmrg            }
66935c4bbdfSmrg            if (!pgcDst->tileIsPixel)
67035c4bbdfSmrg                (*pgcDst->pScreen->DestroyPixmap) (pgcDst->tile.pixmap);
67135c4bbdfSmrg            pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
67235c4bbdfSmrg            pgcDst->tile = pgcSrc->tile;
67335c4bbdfSmrg            if (!pgcDst->tileIsPixel)
67435c4bbdfSmrg                pgcDst->tile.pixmap->refcnt++;
67535c4bbdfSmrg            break;
67635c4bbdfSmrg        }
67735c4bbdfSmrg        case GCStipple:
67835c4bbdfSmrg        {
67935c4bbdfSmrg            if (pgcDst->stipple == pgcSrc->stipple)
68035c4bbdfSmrg                break;
68135c4bbdfSmrg            if (pgcDst->stipple)
68235c4bbdfSmrg                (*pgcDst->pScreen->DestroyPixmap) (pgcDst->stipple);
68335c4bbdfSmrg            pgcDst->stipple = pgcSrc->stipple;
68435c4bbdfSmrg            if (pgcDst->stipple)
68535c4bbdfSmrg                pgcDst->stipple->refcnt++;
68635c4bbdfSmrg            break;
68735c4bbdfSmrg        }
68835c4bbdfSmrg        case GCTileStipXOrigin:
68935c4bbdfSmrg            pgcDst->patOrg.x = pgcSrc->patOrg.x;
69035c4bbdfSmrg            break;
69135c4bbdfSmrg        case GCTileStipYOrigin:
69235c4bbdfSmrg            pgcDst->patOrg.y = pgcSrc->patOrg.y;
69335c4bbdfSmrg            break;
69435c4bbdfSmrg        case GCFont:
69535c4bbdfSmrg            if (pgcDst->font == pgcSrc->font)
69635c4bbdfSmrg                break;
69735c4bbdfSmrg            if (pgcDst->font)
69835c4bbdfSmrg                CloseFont(pgcDst->font, (Font) 0);
69935c4bbdfSmrg            if ((pgcDst->font = pgcSrc->font) != NullFont)
70035c4bbdfSmrg                (pgcDst->font)->refcnt++;
70135c4bbdfSmrg            break;
70235c4bbdfSmrg        case GCSubwindowMode:
70335c4bbdfSmrg            pgcDst->subWindowMode = pgcSrc->subWindowMode;
70435c4bbdfSmrg            break;
70535c4bbdfSmrg        case GCGraphicsExposures:
70635c4bbdfSmrg            pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
70735c4bbdfSmrg            break;
70835c4bbdfSmrg        case GCClipXOrigin:
70935c4bbdfSmrg            pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
71035c4bbdfSmrg            break;
71135c4bbdfSmrg        case GCClipYOrigin:
71235c4bbdfSmrg            pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
71335c4bbdfSmrg            break;
71435c4bbdfSmrg        case GCClipMask:
71535c4bbdfSmrg            (*pgcDst->funcs->CopyClip) (pgcDst, pgcSrc);
71635c4bbdfSmrg            break;
71735c4bbdfSmrg        case GCDashOffset:
71835c4bbdfSmrg            pgcDst->dashOffset = pgcSrc->dashOffset;
71935c4bbdfSmrg            break;
72035c4bbdfSmrg        case GCDashList:
72135c4bbdfSmrg            if (pgcSrc->dash == DefaultDash) {
72235c4bbdfSmrg                if (pgcDst->dash != DefaultDash) {
72335c4bbdfSmrg                    free(pgcDst->dash);
72435c4bbdfSmrg                    pgcDst->numInDashList = pgcSrc->numInDashList;
72535c4bbdfSmrg                    pgcDst->dash = pgcSrc->dash;
72635c4bbdfSmrg                }
72735c4bbdfSmrg            }
72835c4bbdfSmrg            else {
72935c4bbdfSmrg                unsigned char *dash;
73035c4bbdfSmrg                unsigned int i;
73135c4bbdfSmrg
73235c4bbdfSmrg                dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char));
73335c4bbdfSmrg                if (dash) {
73435c4bbdfSmrg                    if (pgcDst->dash != DefaultDash)
73535c4bbdfSmrg                        free(pgcDst->dash);
73635c4bbdfSmrg                    pgcDst->numInDashList = pgcSrc->numInDashList;
73735c4bbdfSmrg                    pgcDst->dash = dash;
73835c4bbdfSmrg                    for (i = 0; i < pgcSrc->numInDashList; i++)
73935c4bbdfSmrg                        dash[i] = pgcSrc->dash[i];
74035c4bbdfSmrg                }
74135c4bbdfSmrg                else
74235c4bbdfSmrg                    error = BadAlloc;
74335c4bbdfSmrg            }
74435c4bbdfSmrg            break;
74535c4bbdfSmrg        case GCArcMode:
74635c4bbdfSmrg            pgcDst->arcMode = pgcSrc->arcMode;
74735c4bbdfSmrg            break;
74835c4bbdfSmrg        default:
74935c4bbdfSmrg            FatalError("CopyGC: Unhandled mask!\n");
75035c4bbdfSmrg        }
75105b261ecSmrg    }
75235c4bbdfSmrg    if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel) {
75335c4bbdfSmrg        if (!CreateDefaultTile(pgcDst)) {
75435c4bbdfSmrg            pgcDst->fillStyle = FillSolid;
75535c4bbdfSmrg            error = BadAlloc;
75635c4bbdfSmrg        }
75705b261ecSmrg    }
75805b261ecSmrg    (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
75905b261ecSmrg    return error;
76005b261ecSmrg}
76105b261ecSmrg
76205b261ecSmrg/**
76305b261ecSmrg * does the diX part of freeing the characteristics in the GC.
76405b261ecSmrg *
76505b261ecSmrg *  \param value  must conform to DeleteType
76605b261ecSmrg */
7676747b715Smrgint
76835c4bbdfSmrgFreeGC(void *value, XID gid)
76905b261ecSmrg{
77035c4bbdfSmrg    GCPtr pGC = (GCPtr) value;
77105b261ecSmrg
77235c4bbdfSmrg    CloseFont(pGC->font, (Font) 0);
77335c4bbdfSmrg    (*pGC->funcs->DestroyClip) (pGC);
77405b261ecSmrg
77505b261ecSmrg    if (!pGC->tileIsPixel)
77635c4bbdfSmrg        (*pGC->pScreen->DestroyPixmap) (pGC->tile.pixmap);
77705b261ecSmrg    if (pGC->stipple)
77835c4bbdfSmrg        (*pGC->pScreen->DestroyPixmap) (pGC->stipple);
77905b261ecSmrg
78005b261ecSmrg    (*pGC->funcs->DestroyGC) (pGC);
78105b261ecSmrg    if (pGC->dash != DefaultDash)
78235c4bbdfSmrg        free(pGC->dash);
7836747b715Smrg    dixFreeObjectWithPrivates(pGC, PRIVATE_GC);
7846747b715Smrg    return Success;
78505b261ecSmrg}
78605b261ecSmrg
78705b261ecSmrg/* CreateScratchGC(pScreen, depth)
78805b261ecSmrg    like CreateGC, but doesn't do the default tile or stipple,
78905b261ecSmrgsince we can't create them without already having a GC.  any code
79005b261ecSmrgusing the tile or stipple has to set them explicitly anyway,
79105b261ecSmrgsince the state of the scratch gc is unknown.  This is OK
79205b261ecSmrgbecause ChangeGC() has to be able to deal with NULL tiles and
79335c4bbdfSmrgstipples anyway (in case the CreateGC() call has provided a
79405b261ecSmrgvalue for them -- we can't set the default tile until the
79505b261ecSmrgclient-supplied attributes are installed, since the fgPixel
79605b261ecSmrgis what fills the default tile.  (maybe this comment should
79705b261ecSmrggo with CreateGC() or ChangeGC().)
79805b261ecSmrg*/
79905b261ecSmrg
8009ace9065Smrgstatic GCPtr
80105b261ecSmrgCreateScratchGC(ScreenPtr pScreen, unsigned depth)
80205b261ecSmrg{
80305b261ecSmrg    GCPtr pGC;
80405b261ecSmrg
80535c4bbdfSmrg    pGC = NewGCObject(pScreen, depth);
80605b261ecSmrg    if (!pGC)
80735c4bbdfSmrg        return (GCPtr) NULL;
8086747b715Smrg
8096747b715Smrg    pGC->stateChanges = GCAllBits;
81035c4bbdfSmrg    if (!(*pScreen->CreateGC) (pGC)) {
81135c4bbdfSmrg        FreeGC(pGC, (XID) 0);
81235c4bbdfSmrg        pGC = (GCPtr) NULL;
81305b261ecSmrg    }
81458cf2af7Smrg    else
81558cf2af7Smrg        pGC->graphicsExposures = FALSE;
81605b261ecSmrg    return pGC;
81705b261ecSmrg}
81805b261ecSmrg
81905b261ecSmrgvoid
82005b261ecSmrgFreeGCperDepth(int screenNum)
82105b261ecSmrg{
82205b261ecSmrg    int i;
82305b261ecSmrg    ScreenPtr pScreen;
82405b261ecSmrg    GCPtr *ppGC;
82505b261ecSmrg
82605b261ecSmrg    pScreen = screenInfo.screens[screenNum];
82705b261ecSmrg    ppGC = pScreen->GCperDepth;
82805b261ecSmrg
82935c4bbdfSmrg    for (i = 0; i <= pScreen->numDepths; i++) {
83035c4bbdfSmrg        (void) FreeGC(ppGC[i], (XID) 0);
83135c4bbdfSmrg        ppGC[i] = NULL;
8326747b715Smrg    }
83305b261ecSmrg}
83405b261ecSmrg
83505b261ecSmrgBool
83605b261ecSmrgCreateGCperDepth(int screenNum)
83705b261ecSmrg{
83805b261ecSmrg    int i;
83905b261ecSmrg    ScreenPtr pScreen;
84005b261ecSmrg    DepthPtr pDepth;
84105b261ecSmrg    GCPtr *ppGC;
84205b261ecSmrg
84305b261ecSmrg    pScreen = screenInfo.screens[screenNum];
84405b261ecSmrg    ppGC = pScreen->GCperDepth;
84505b261ecSmrg    /* do depth 1 separately because it's not included in list */
84605b261ecSmrg    if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
84735c4bbdfSmrg        return FALSE;
84805b261ecSmrg    /* Make sure we don't overflow GCperDepth[] */
84935c4bbdfSmrg    if (pScreen->numDepths > MAXFORMATS)
85035c4bbdfSmrg        return FALSE;
85105b261ecSmrg
85205b261ecSmrg    pDepth = pScreen->allowedDepths;
85335c4bbdfSmrg    for (i = 0; i < pScreen->numDepths; i++, pDepth++) {
85435c4bbdfSmrg        if (!(ppGC[i + 1] = CreateScratchGC(pScreen, pDepth->depth))) {
85535c4bbdfSmrg            for (; i >= 0; i--)
85635c4bbdfSmrg                (void) FreeGC(ppGC[i], (XID) 0);
85735c4bbdfSmrg            return FALSE;
85835c4bbdfSmrg        }
85905b261ecSmrg    }
86005b261ecSmrg    return TRUE;
86105b261ecSmrg}
86205b261ecSmrg
86305b261ecSmrgBool
86405b261ecSmrgCreateDefaultStipple(int screenNum)
86505b261ecSmrg{
86605b261ecSmrg    ScreenPtr pScreen;
8676747b715Smrg    ChangeGCVal tmpval[3];
86805b261ecSmrg    xRectangle rect;
86905b261ecSmrg    CARD16 w, h;
87005b261ecSmrg    GCPtr pgcScratch;
87105b261ecSmrg
87205b261ecSmrg    pScreen = screenInfo.screens[screenNum];
87305b261ecSmrg
87405b261ecSmrg    w = 16;
87505b261ecSmrg    h = 16;
87635c4bbdfSmrg    (*pScreen->QueryBestSize) (StippleShape, &w, &h, pScreen);
8771b5d61b8Smrg    if (!(pScreen->defaultStipple = pScreen->CreatePixmap(pScreen, w, h, 1, 0)))
87835c4bbdfSmrg        return FALSE;
87905b261ecSmrg    /* fill stipple with 1 */
8806747b715Smrg    tmpval[0].val = GXcopy;
8816747b715Smrg    tmpval[1].val = 1;
8826747b715Smrg    tmpval[2].val = FillSolid;
88305b261ecSmrg    pgcScratch = GetScratchGC(1, pScreen);
88435c4bbdfSmrg    if (!pgcScratch) {
8851b5d61b8Smrg        (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
88635c4bbdfSmrg        return FALSE;
88705b261ecSmrg    }
88835c4bbdfSmrg    (void) ChangeGC(NullClient, pgcScratch,
88935c4bbdfSmrg                    GCFunction | GCForeground | GCFillStyle, tmpval);
8901b5d61b8Smrg    ValidateGC((DrawablePtr) pScreen->defaultStipple, pgcScratch);
89105b261ecSmrg    rect.x = 0;
89205b261ecSmrg    rect.y = 0;
89305b261ecSmrg    rect.width = w;
89405b261ecSmrg    rect.height = h;
8951b5d61b8Smrg    (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pScreen->defaultStipple,
89635c4bbdfSmrg                                      pgcScratch, 1, &rect);
89705b261ecSmrg    FreeScratchGC(pgcScratch);
89805b261ecSmrg    return TRUE;
89905b261ecSmrg}
90005b261ecSmrg
90105b261ecSmrgvoid
90205b261ecSmrgFreeDefaultStipple(int screenNum)
90305b261ecSmrg{
90405b261ecSmrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
90535c4bbdfSmrg
9061b5d61b8Smrg    (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
90705b261ecSmrg}
90805b261ecSmrg
9094642e01fSmrgint
91005b261ecSmrgSetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
91105b261ecSmrg{
91205b261ecSmrg    long i;
91305b261ecSmrg    unsigned char *p, *indash;
91405b261ecSmrg    BITS32 maskQ = 0;
91505b261ecSmrg
91605b261ecSmrg    i = ndash;
91705b261ecSmrg    p = pdash;
91835c4bbdfSmrg    while (i--) {
91935c4bbdfSmrg        if (!*p++) {
92035c4bbdfSmrg            /* dash segment must be > 0 */
92135c4bbdfSmrg            return BadValue;
92235c4bbdfSmrg        }
92305b261ecSmrg    }
92405b261ecSmrg
92505b261ecSmrg    if (ndash & 1)
92635c4bbdfSmrg        p = malloc(2 * ndash * sizeof(unsigned char));
92705b261ecSmrg    else
92835c4bbdfSmrg        p = malloc(ndash * sizeof(unsigned char));
92905b261ecSmrg    if (!p)
93035c4bbdfSmrg        return BadAlloc;
93105b261ecSmrg
93205b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
93335c4bbdfSmrg    if (offset != pGC->dashOffset) {
93435c4bbdfSmrg        pGC->dashOffset = offset;
93535c4bbdfSmrg        pGC->stateChanges |= GCDashOffset;
93635c4bbdfSmrg        maskQ |= GCDashOffset;
93705b261ecSmrg    }
93805b261ecSmrg
93905b261ecSmrg    if (pGC->dash != DefaultDash)
94035c4bbdfSmrg        free(pGC->dash);
94105b261ecSmrg    pGC->numInDashList = ndash;
94205b261ecSmrg    pGC->dash = p;
94335c4bbdfSmrg    if (ndash & 1) {
94435c4bbdfSmrg        pGC->numInDashList += ndash;
94535c4bbdfSmrg        indash = pdash;
94635c4bbdfSmrg        i = ndash;
94735c4bbdfSmrg        while (i--)
94835c4bbdfSmrg            *p++ = *indash++;
94905b261ecSmrg    }
95035c4bbdfSmrg    while (ndash--)
95135c4bbdfSmrg        *p++ = *pdash++;
95205b261ecSmrg    pGC->stateChanges |= GCDashList;
95305b261ecSmrg    maskQ |= GCDashList;
95405b261ecSmrg
95505b261ecSmrg    if (pGC->funcs->ChangeGC)
95635c4bbdfSmrg        (*pGC->funcs->ChangeGC) (pGC, maskQ);
95705b261ecSmrg    return Success;
95805b261ecSmrg}
95905b261ecSmrg
9606747b715Smrgint
96105b261ecSmrgVerifyRectOrder(int nrects, xRectangle *prects, int ordering)
96205b261ecSmrg{
96335c4bbdfSmrg    xRectangle *prectP, *prectN;
96435c4bbdfSmrg    int i;
96535c4bbdfSmrg
96635c4bbdfSmrg    switch (ordering) {
96735c4bbdfSmrg    case Unsorted:
96835c4bbdfSmrg        return CT_UNSORTED;
96935c4bbdfSmrg    case YSorted:
97035c4bbdfSmrg        if (nrects > 1) {
97135c4bbdfSmrg            for (i = 1, prectP = prects, prectN = prects + 1;
97235c4bbdfSmrg                 i < nrects; i++, prectP++, prectN++)
97335c4bbdfSmrg                if (prectN->y < prectP->y)
97435c4bbdfSmrg                    return -1;
97535c4bbdfSmrg        }
97635c4bbdfSmrg        return CT_YSORTED;
97735c4bbdfSmrg    case YXSorted:
97835c4bbdfSmrg        if (nrects > 1) {
97935c4bbdfSmrg            for (i = 1, prectP = prects, prectN = prects + 1;
98035c4bbdfSmrg                 i < nrects; i++, prectP++, prectN++)
98135c4bbdfSmrg                if ((prectN->y < prectP->y) ||
98235c4bbdfSmrg                    ((prectN->y == prectP->y) && (prectN->x < prectP->x)))
98335c4bbdfSmrg                    return -1;
98435c4bbdfSmrg        }
98535c4bbdfSmrg        return CT_YXSORTED;
98635c4bbdfSmrg    case YXBanded:
98735c4bbdfSmrg        if (nrects > 1) {
98835c4bbdfSmrg            for (i = 1, prectP = prects, prectN = prects + 1;
98935c4bbdfSmrg                 i < nrects; i++, prectP++, prectN++)
99035c4bbdfSmrg                if ((prectN->y != prectP->y &&
99135c4bbdfSmrg                     prectN->y < prectP->y + (int) prectP->height) ||
99235c4bbdfSmrg                    ((prectN->y == prectP->y) &&
99335c4bbdfSmrg                     (prectN->height != prectP->height ||
99435c4bbdfSmrg                      prectN->x < prectP->x + (int) prectP->width)))
99535c4bbdfSmrg                    return -1;
99635c4bbdfSmrg        }
99735c4bbdfSmrg        return CT_YXBANDED;
99805b261ecSmrg    }
99905b261ecSmrg    return -1;
100005b261ecSmrg}
100105b261ecSmrg
10024642e01fSmrgint
100335c4bbdfSmrgSetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
100405b261ecSmrg             xRectangle *prects, int ordering)
100505b261ecSmrg{
100635c4bbdfSmrg    int newct, size;
100735c4bbdfSmrg    xRectangle *prectsNew;
100805b261ecSmrg
100905b261ecSmrg    newct = VerifyRectOrder(nrects, prects, ordering);
101005b261ecSmrg    if (newct < 0)
101135c4bbdfSmrg        return BadMatch;
101205b261ecSmrg    size = nrects * sizeof(xRectangle);
10136747b715Smrg    prectsNew = malloc(size);
101405b261ecSmrg    if (!prectsNew && size)
101535c4bbdfSmrg        return BadAlloc;
101605b261ecSmrg
101705b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
101805b261ecSmrg    pGC->clipOrg.x = xOrigin;
101905b261ecSmrg    pGC->stateChanges |= GCClipXOrigin;
102035c4bbdfSmrg
102105b261ecSmrg    pGC->clipOrg.y = yOrigin;
102205b261ecSmrg    pGC->stateChanges |= GCClipYOrigin;
102305b261ecSmrg
102405b261ecSmrg    if (size)
102535c4bbdfSmrg        memmove((char *) prectsNew, (char *) prects, size);
102635c4bbdfSmrg    (*pGC->funcs->ChangeClip) (pGC, newct, (void *) prectsNew, nrects);
102705b261ecSmrg    if (pGC->funcs->ChangeGC)
102835c4bbdfSmrg        (*pGC->funcs->ChangeGC) (pGC,
102935c4bbdfSmrg                                 GCClipXOrigin | GCClipYOrigin | GCClipMask);
103005b261ecSmrg    return Success;
103105b261ecSmrg}
103205b261ecSmrg
103305b261ecSmrg/*
103435c4bbdfSmrg   sets reasonable defaults
103505b261ecSmrg   if we can get a pre-allocated one, use it and mark it as used.
103605b261ecSmrg   if we can't, create one out of whole cloth (The Velveteen GC -- if
103705b261ecSmrg   you use it often enough it will become real.)
103805b261ecSmrg*/
10396747b715SmrgGCPtr
104005b261ecSmrgGetScratchGC(unsigned depth, ScreenPtr pScreen)
104105b261ecSmrg{
104205b261ecSmrg    int i;
104305b261ecSmrg    GCPtr pGC;
104405b261ecSmrg
104535c4bbdfSmrg    for (i = 0; i <= pScreen->numDepths; i++) {
104635c4bbdfSmrg        pGC = pScreen->GCperDepth[i];
104735c4bbdfSmrg        if (pGC && pGC->depth == depth && !pGC->scratch_inuse) {
104835c4bbdfSmrg            pGC->scratch_inuse = TRUE;
104935c4bbdfSmrg
105035c4bbdfSmrg            pGC->alu = GXcopy;
105135c4bbdfSmrg            pGC->planemask = ~0;
105235c4bbdfSmrg            pGC->serialNumber = 0;
105335c4bbdfSmrg            pGC->fgPixel = 0;
105435c4bbdfSmrg            pGC->bgPixel = 1;
105535c4bbdfSmrg            pGC->lineWidth = 0;
105635c4bbdfSmrg            pGC->lineStyle = LineSolid;
105735c4bbdfSmrg            pGC->capStyle = CapButt;
105835c4bbdfSmrg            pGC->joinStyle = JoinMiter;
105935c4bbdfSmrg            pGC->fillStyle = FillSolid;
106035c4bbdfSmrg            pGC->fillRule = EvenOddRule;
106135c4bbdfSmrg            pGC->arcMode = ArcChord;
106235c4bbdfSmrg            pGC->patOrg.x = 0;
106335c4bbdfSmrg            pGC->patOrg.y = 0;
106435c4bbdfSmrg            pGC->subWindowMode = ClipByChildren;
106535c4bbdfSmrg            pGC->graphicsExposures = FALSE;
106635c4bbdfSmrg            pGC->clipOrg.x = 0;
106735c4bbdfSmrg            pGC->clipOrg.y = 0;
106835c4bbdfSmrg            if (pGC->clientClip)
106935c4bbdfSmrg                (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
107035c4bbdfSmrg            pGC->stateChanges = GCAllBits;
107135c4bbdfSmrg            return pGC;
107235c4bbdfSmrg        }
10736747b715Smrg    }
107405b261ecSmrg    /* if we make it this far, need to roll our own */
10751b5d61b8Smrg    return CreateScratchGC(pScreen, depth);
107605b261ecSmrg}
107705b261ecSmrg
107805b261ecSmrg/*
107905b261ecSmrg   if the gc to free is in the table of pre-existing ones,
108005b261ecSmrgmark it as available.
108105b261ecSmrg   if not, free it for real
108205b261ecSmrg*/
10836747b715Smrgvoid
108405b261ecSmrgFreeScratchGC(GCPtr pGC)
108505b261ecSmrg{
10866747b715Smrg    if (pGC->scratch_inuse)
108735c4bbdfSmrg        pGC->scratch_inuse = FALSE;
10886747b715Smrg    else
108935c4bbdfSmrg        FreeGC(pGC, (GContext) 0);
109005b261ecSmrg}
1091