gc.c revision 35c4bbdf
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];
44235c4bbdfSmrg    for (i = 0; i < sizeof(xidfields) / sizeof(*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++;
50705b261ecSmrg    pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
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    }
81405b261ecSmrg    return pGC;
81505b261ecSmrg}
81605b261ecSmrg
81705b261ecSmrgvoid
81805b261ecSmrgFreeGCperDepth(int screenNum)
81905b261ecSmrg{
82005b261ecSmrg    int i;
82105b261ecSmrg    ScreenPtr pScreen;
82205b261ecSmrg    GCPtr *ppGC;
82305b261ecSmrg
82405b261ecSmrg    pScreen = screenInfo.screens[screenNum];
82505b261ecSmrg    ppGC = pScreen->GCperDepth;
82605b261ecSmrg
82735c4bbdfSmrg    for (i = 0; i <= pScreen->numDepths; i++) {
82835c4bbdfSmrg        (void) FreeGC(ppGC[i], (XID) 0);
82935c4bbdfSmrg        ppGC[i] = NULL;
8306747b715Smrg    }
83105b261ecSmrg}
83205b261ecSmrg
83305b261ecSmrgBool
83405b261ecSmrgCreateGCperDepth(int screenNum)
83505b261ecSmrg{
83605b261ecSmrg    int i;
83705b261ecSmrg    ScreenPtr pScreen;
83805b261ecSmrg    DepthPtr pDepth;
83905b261ecSmrg    GCPtr *ppGC;
84005b261ecSmrg
84105b261ecSmrg    pScreen = screenInfo.screens[screenNum];
84205b261ecSmrg    ppGC = pScreen->GCperDepth;
84305b261ecSmrg    /* do depth 1 separately because it's not included in list */
84405b261ecSmrg    if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
84535c4bbdfSmrg        return FALSE;
84605b261ecSmrg    ppGC[0]->graphicsExposures = FALSE;
84705b261ecSmrg    /* Make sure we don't overflow GCperDepth[] */
84835c4bbdfSmrg    if (pScreen->numDepths > MAXFORMATS)
84935c4bbdfSmrg        return FALSE;
85005b261ecSmrg
85105b261ecSmrg    pDepth = pScreen->allowedDepths;
85235c4bbdfSmrg    for (i = 0; i < pScreen->numDepths; i++, pDepth++) {
85335c4bbdfSmrg        if (!(ppGC[i + 1] = CreateScratchGC(pScreen, pDepth->depth))) {
85435c4bbdfSmrg            for (; i >= 0; i--)
85535c4bbdfSmrg                (void) FreeGC(ppGC[i], (XID) 0);
85635c4bbdfSmrg            return FALSE;
85735c4bbdfSmrg        }
85835c4bbdfSmrg        ppGC[i + 1]->graphicsExposures = FALSE;
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);
87705b261ecSmrg    if (!(pScreen->PixmapPerDepth[0] =
87835c4bbdfSmrg          (*pScreen->CreatePixmap) (pScreen, w, h, 1, 0)))
87935c4bbdfSmrg        return FALSE;
88005b261ecSmrg    /* fill stipple with 1 */
8816747b715Smrg    tmpval[0].val = GXcopy;
8826747b715Smrg    tmpval[1].val = 1;
8836747b715Smrg    tmpval[2].val = FillSolid;
88405b261ecSmrg    pgcScratch = GetScratchGC(1, pScreen);
88535c4bbdfSmrg    if (!pgcScratch) {
88635c4bbdfSmrg        (*pScreen->DestroyPixmap) (pScreen->PixmapPerDepth[0]);
88735c4bbdfSmrg        return FALSE;
88805b261ecSmrg    }
88935c4bbdfSmrg    (void) ChangeGC(NullClient, pgcScratch,
89035c4bbdfSmrg                    GCFunction | GCForeground | GCFillStyle, tmpval);
89135c4bbdfSmrg    ValidateGC((DrawablePtr) pScreen->PixmapPerDepth[0], pgcScratch);
89205b261ecSmrg    rect.x = 0;
89305b261ecSmrg    rect.y = 0;
89405b261ecSmrg    rect.width = w;
89505b261ecSmrg    rect.height = h;
89635c4bbdfSmrg    (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pScreen->PixmapPerDepth[0],
89735c4bbdfSmrg                                      pgcScratch, 1, &rect);
89805b261ecSmrg    FreeScratchGC(pgcScratch);
89905b261ecSmrg    return TRUE;
90005b261ecSmrg}
90105b261ecSmrg
90205b261ecSmrgvoid
90305b261ecSmrgFreeDefaultStipple(int screenNum)
90405b261ecSmrg{
90505b261ecSmrg    ScreenPtr pScreen = screenInfo.screens[screenNum];
90635c4bbdfSmrg
90735c4bbdfSmrg    (*pScreen->DestroyPixmap) (pScreen->PixmapPerDepth[0]);
90805b261ecSmrg}
90905b261ecSmrg
9104642e01fSmrgint
91105b261ecSmrgSetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
91205b261ecSmrg{
91305b261ecSmrg    long i;
91405b261ecSmrg    unsigned char *p, *indash;
91505b261ecSmrg    BITS32 maskQ = 0;
91605b261ecSmrg
91705b261ecSmrg    i = ndash;
91805b261ecSmrg    p = pdash;
91935c4bbdfSmrg    while (i--) {
92035c4bbdfSmrg        if (!*p++) {
92135c4bbdfSmrg            /* dash segment must be > 0 */
92235c4bbdfSmrg            return BadValue;
92335c4bbdfSmrg        }
92405b261ecSmrg    }
92505b261ecSmrg
92605b261ecSmrg    if (ndash & 1)
92735c4bbdfSmrg        p = malloc(2 * ndash * sizeof(unsigned char));
92805b261ecSmrg    else
92935c4bbdfSmrg        p = malloc(ndash * sizeof(unsigned char));
93005b261ecSmrg    if (!p)
93135c4bbdfSmrg        return BadAlloc;
93205b261ecSmrg
93305b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
93435c4bbdfSmrg    if (offset != pGC->dashOffset) {
93535c4bbdfSmrg        pGC->dashOffset = offset;
93635c4bbdfSmrg        pGC->stateChanges |= GCDashOffset;
93735c4bbdfSmrg        maskQ |= GCDashOffset;
93805b261ecSmrg    }
93905b261ecSmrg
94005b261ecSmrg    if (pGC->dash != DefaultDash)
94135c4bbdfSmrg        free(pGC->dash);
94205b261ecSmrg    pGC->numInDashList = ndash;
94305b261ecSmrg    pGC->dash = p;
94435c4bbdfSmrg    if (ndash & 1) {
94535c4bbdfSmrg        pGC->numInDashList += ndash;
94635c4bbdfSmrg        indash = pdash;
94735c4bbdfSmrg        i = ndash;
94835c4bbdfSmrg        while (i--)
94935c4bbdfSmrg            *p++ = *indash++;
95005b261ecSmrg    }
95135c4bbdfSmrg    while (ndash--)
95235c4bbdfSmrg        *p++ = *pdash++;
95305b261ecSmrg    pGC->stateChanges |= GCDashList;
95405b261ecSmrg    maskQ |= GCDashList;
95505b261ecSmrg
95605b261ecSmrg    if (pGC->funcs->ChangeGC)
95735c4bbdfSmrg        (*pGC->funcs->ChangeGC) (pGC, maskQ);
95805b261ecSmrg    return Success;
95905b261ecSmrg}
96005b261ecSmrg
9616747b715Smrgint
96205b261ecSmrgVerifyRectOrder(int nrects, xRectangle *prects, int ordering)
96305b261ecSmrg{
96435c4bbdfSmrg    xRectangle *prectP, *prectN;
96535c4bbdfSmrg    int i;
96635c4bbdfSmrg
96735c4bbdfSmrg    switch (ordering) {
96835c4bbdfSmrg    case Unsorted:
96935c4bbdfSmrg        return CT_UNSORTED;
97035c4bbdfSmrg    case YSorted:
97135c4bbdfSmrg        if (nrects > 1) {
97235c4bbdfSmrg            for (i = 1, prectP = prects, prectN = prects + 1;
97335c4bbdfSmrg                 i < nrects; i++, prectP++, prectN++)
97435c4bbdfSmrg                if (prectN->y < prectP->y)
97535c4bbdfSmrg                    return -1;
97635c4bbdfSmrg        }
97735c4bbdfSmrg        return CT_YSORTED;
97835c4bbdfSmrg    case YXSorted:
97935c4bbdfSmrg        if (nrects > 1) {
98035c4bbdfSmrg            for (i = 1, prectP = prects, prectN = prects + 1;
98135c4bbdfSmrg                 i < nrects; i++, prectP++, prectN++)
98235c4bbdfSmrg                if ((prectN->y < prectP->y) ||
98335c4bbdfSmrg                    ((prectN->y == prectP->y) && (prectN->x < prectP->x)))
98435c4bbdfSmrg                    return -1;
98535c4bbdfSmrg        }
98635c4bbdfSmrg        return CT_YXSORTED;
98735c4bbdfSmrg    case YXBanded:
98835c4bbdfSmrg        if (nrects > 1) {
98935c4bbdfSmrg            for (i = 1, prectP = prects, prectN = prects + 1;
99035c4bbdfSmrg                 i < nrects; i++, prectP++, prectN++)
99135c4bbdfSmrg                if ((prectN->y != prectP->y &&
99235c4bbdfSmrg                     prectN->y < prectP->y + (int) prectP->height) ||
99335c4bbdfSmrg                    ((prectN->y == prectP->y) &&
99435c4bbdfSmrg                     (prectN->height != prectP->height ||
99535c4bbdfSmrg                      prectN->x < prectP->x + (int) prectP->width)))
99635c4bbdfSmrg                    return -1;
99735c4bbdfSmrg        }
99835c4bbdfSmrg        return CT_YXBANDED;
99905b261ecSmrg    }
100005b261ecSmrg    return -1;
100105b261ecSmrg}
100205b261ecSmrg
10034642e01fSmrgint
100435c4bbdfSmrgSetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
100505b261ecSmrg             xRectangle *prects, int ordering)
100605b261ecSmrg{
100735c4bbdfSmrg    int newct, size;
100835c4bbdfSmrg    xRectangle *prectsNew;
100905b261ecSmrg
101005b261ecSmrg    newct = VerifyRectOrder(nrects, prects, ordering);
101105b261ecSmrg    if (newct < 0)
101235c4bbdfSmrg        return BadMatch;
101305b261ecSmrg    size = nrects * sizeof(xRectangle);
10146747b715Smrg    prectsNew = malloc(size);
101505b261ecSmrg    if (!prectsNew && size)
101635c4bbdfSmrg        return BadAlloc;
101705b261ecSmrg
101805b261ecSmrg    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
101905b261ecSmrg    pGC->clipOrg.x = xOrigin;
102005b261ecSmrg    pGC->stateChanges |= GCClipXOrigin;
102135c4bbdfSmrg
102205b261ecSmrg    pGC->clipOrg.y = yOrigin;
102305b261ecSmrg    pGC->stateChanges |= GCClipYOrigin;
102405b261ecSmrg
102505b261ecSmrg    if (size)
102635c4bbdfSmrg        memmove((char *) prectsNew, (char *) prects, size);
102735c4bbdfSmrg    (*pGC->funcs->ChangeClip) (pGC, newct, (void *) prectsNew, nrects);
102805b261ecSmrg    if (pGC->funcs->ChangeGC)
102935c4bbdfSmrg        (*pGC->funcs->ChangeGC) (pGC,
103035c4bbdfSmrg                                 GCClipXOrigin | GCClipYOrigin | GCClipMask);
103105b261ecSmrg    return Success;
103205b261ecSmrg}
103305b261ecSmrg
103405b261ecSmrg/*
103535c4bbdfSmrg   sets reasonable defaults
103605b261ecSmrg   if we can get a pre-allocated one, use it and mark it as used.
103705b261ecSmrg   if we can't, create one out of whole cloth (The Velveteen GC -- if
103805b261ecSmrg   you use it often enough it will become real.)
103905b261ecSmrg*/
10406747b715SmrgGCPtr
104105b261ecSmrgGetScratchGC(unsigned depth, ScreenPtr pScreen)
104205b261ecSmrg{
104305b261ecSmrg    int i;
104405b261ecSmrg    GCPtr pGC;
104505b261ecSmrg
104635c4bbdfSmrg    for (i = 0; i <= pScreen->numDepths; i++) {
104735c4bbdfSmrg        pGC = pScreen->GCperDepth[i];
104835c4bbdfSmrg        if (pGC && pGC->depth == depth && !pGC->scratch_inuse) {
104935c4bbdfSmrg            pGC->scratch_inuse = TRUE;
105035c4bbdfSmrg
105135c4bbdfSmrg            pGC->alu = GXcopy;
105235c4bbdfSmrg            pGC->planemask = ~0;
105335c4bbdfSmrg            pGC->serialNumber = 0;
105435c4bbdfSmrg            pGC->fgPixel = 0;
105535c4bbdfSmrg            pGC->bgPixel = 1;
105635c4bbdfSmrg            pGC->lineWidth = 0;
105735c4bbdfSmrg            pGC->lineStyle = LineSolid;
105835c4bbdfSmrg            pGC->capStyle = CapButt;
105935c4bbdfSmrg            pGC->joinStyle = JoinMiter;
106035c4bbdfSmrg            pGC->fillStyle = FillSolid;
106135c4bbdfSmrg            pGC->fillRule = EvenOddRule;
106235c4bbdfSmrg            pGC->arcMode = ArcChord;
106335c4bbdfSmrg            pGC->patOrg.x = 0;
106435c4bbdfSmrg            pGC->patOrg.y = 0;
106535c4bbdfSmrg            pGC->subWindowMode = ClipByChildren;
106635c4bbdfSmrg            pGC->graphicsExposures = FALSE;
106735c4bbdfSmrg            pGC->clipOrg.x = 0;
106835c4bbdfSmrg            pGC->clipOrg.y = 0;
106935c4bbdfSmrg            if (pGC->clientClip)
107035c4bbdfSmrg                (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
107135c4bbdfSmrg            pGC->stateChanges = GCAllBits;
107235c4bbdfSmrg            return pGC;
107335c4bbdfSmrg        }
10746747b715Smrg    }
107505b261ecSmrg    /* if we make it this far, need to roll our own */
107605b261ecSmrg    pGC = CreateScratchGC(pScreen, depth);
107705b261ecSmrg    if (pGC)
107835c4bbdfSmrg        pGC->graphicsExposures = FALSE;
107905b261ecSmrg    return pGC;
108005b261ecSmrg}
108105b261ecSmrg
108205b261ecSmrg/*
108305b261ecSmrg   if the gc to free is in the table of pre-existing ones,
108405b261ecSmrgmark it as available.
108505b261ecSmrg   if not, free it for real
108605b261ecSmrg*/
10876747b715Smrgvoid
108805b261ecSmrgFreeScratchGC(GCPtr pGC)
108905b261ecSmrg{
10906747b715Smrg    if (pGC->scratch_inuse)
109135c4bbdfSmrg        pGC->scratch_inuse = FALSE;
10926747b715Smrg    else
109335c4bbdfSmrg        FreeGC(pGC, (GContext) 0);
109405b261ecSmrg}
1095