1/***********************************************************
2
3Copyright 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45******************************************************************/
46
47#ifdef HAVE_DIX_CONFIG_H
48#include <dix-config.h>
49#endif
50
51#include <X11/X.h>
52#include <X11/Xmd.h>
53#include <X11/Xproto.h>
54#include "misc.h"
55#include "resource.h"
56#include "gcstruct.h"
57#include "pixmapstr.h"
58#include "dixfontstr.h"
59#include "scrnintstr.h"
60#include "region.h"
61#include "dixstruct.h"
62
63#include "privates.h"
64#include "dix.h"
65#include "xace.h"
66#include <assert.h>
67
68extern FontPtr defaultFont;
69
70static Bool CreateDefaultTile(GCPtr pGC);
71
72static unsigned char DefaultDash[2] = { 4, 4 };
73
74void
75ValidateGC(DrawablePtr pDraw, GC * pGC)
76{
77    (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
78    pGC->stateChanges = 0;
79    pGC->serialNumber = pDraw->serialNumber;
80}
81
82/*
83 * ChangeGC/ChangeGCXIDs:
84 *
85 * The client performing the gc change must be passed so that access
86 * checks can be performed on any tiles, stipples, or fonts that are
87 * specified.  ddxen can call this too; they should normally pass
88 * NullClient for the client since any access checking should have
89 * already been done at a higher level.
90 *
91 * If you have any XIDs, you must use ChangeGCXIDs:
92 *
93 *     CARD32 v[2];
94 *     v[0] = FillTiled;
95 *     v[1] = pid;
96 *     ChangeGCXIDs(client, pGC, GCFillStyle|GCTile, v);
97 *
98 * However, if you need to pass a pointer to a pixmap or font, you must
99 * use ChangeGC:
100 *
101 *     ChangeGCVal v[2];
102 *     v[0].val = FillTiled;
103 *     v[1].ptr = pPixmap;
104 *     ChangeGC(client, pGC, GCFillStyle|GCTile, v);
105 *
106 * If you have neither XIDs nor pointers, you can use either function,
107 * but ChangeGC will do less work.
108 *
109 *     ChangeGCVal v[2];
110 *     v[0].val = foreground;
111 *     v[1].val = background;
112 *     ChangeGC(client, pGC, GCForeground|GCBackground, v);
113 */
114
115#define NEXTVAL(_type, _var) { \
116	_var = (_type)(pUnion->val); pUnion++; \
117    }
118
119#define NEXT_PTR(_type, _var) { \
120    _var = (_type)pUnion->ptr; pUnion++; }
121
122int
123ChangeGC(ClientPtr client, GC * pGC, BITS32 mask, ChangeGCValPtr pUnion)
124{
125    BITS32 index2;
126    int error = 0;
127    PixmapPtr pPixmap;
128    BITS32 maskQ;
129
130    assert(pUnion);
131    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
132
133    maskQ = mask;               /* save these for when we walk the GCque */
134    while (mask && !error) {
135        index2 = (BITS32) lowbit(mask);
136        mask &= ~index2;
137        pGC->stateChanges |= index2;
138        switch (index2) {
139        case GCFunction:
140        {
141            CARD8 newalu;
142            NEXTVAL(CARD8, newalu);
143
144            if (newalu <= GXset)
145                pGC->alu = newalu;
146            else {
147                if (client)
148                    client->errorValue = newalu;
149                error = BadValue;
150            }
151            break;
152        }
153        case GCPlaneMask:
154            NEXTVAL(unsigned long, pGC->planemask);
155
156            break;
157        case GCForeground:
158            NEXTVAL(unsigned long, pGC->fgPixel);
159
160            /*
161             * this is for CreateGC
162             */
163            if (!pGC->tileIsPixel && !pGC->tile.pixmap) {
164                pGC->tileIsPixel = TRUE;
165                pGC->tile.pixel = pGC->fgPixel;
166            }
167            break;
168        case GCBackground:
169            NEXTVAL(unsigned long, pGC->bgPixel);
170
171            break;
172        case GCLineWidth:      /* ??? line width is a CARD16 */
173            NEXTVAL(CARD16, pGC->lineWidth);
174
175            break;
176        case GCLineStyle:
177        {
178            unsigned int newlinestyle;
179            NEXTVAL(unsigned int, newlinestyle);
180
181            if (newlinestyle <= LineDoubleDash)
182                pGC->lineStyle = newlinestyle;
183            else {
184                if (client)
185                    client->errorValue = newlinestyle;
186                error = BadValue;
187            }
188            break;
189        }
190        case GCCapStyle:
191        {
192            unsigned int newcapstyle;
193            NEXTVAL(unsigned int, newcapstyle);
194
195            if (newcapstyle <= CapProjecting)
196                pGC->capStyle = newcapstyle;
197            else {
198                if (client)
199                    client->errorValue = newcapstyle;
200                error = BadValue;
201            }
202            break;
203        }
204        case GCJoinStyle:
205        {
206            unsigned int newjoinstyle;
207            NEXTVAL(unsigned int, newjoinstyle);
208
209            if (newjoinstyle <= JoinBevel)
210                pGC->joinStyle = newjoinstyle;
211            else {
212                if (client)
213                    client->errorValue = newjoinstyle;
214                error = BadValue;
215            }
216            break;
217        }
218        case GCFillStyle:
219        {
220            unsigned int newfillstyle;
221            NEXTVAL(unsigned int, newfillstyle);
222
223            if (newfillstyle <= FillOpaqueStippled)
224                pGC->fillStyle = newfillstyle;
225            else {
226                if (client)
227                    client->errorValue = newfillstyle;
228                error = BadValue;
229            }
230            break;
231        }
232        case GCFillRule:
233        {
234            unsigned int newfillrule;
235            NEXTVAL(unsigned int, newfillrule);
236
237            if (newfillrule <= WindingRule)
238                pGC->fillRule = newfillrule;
239            else {
240                if (client)
241                    client->errorValue = newfillrule;
242                error = BadValue;
243            }
244            break;
245        }
246        case GCTile:
247            NEXT_PTR(PixmapPtr, pPixmap);
248
249            if ((pPixmap->drawable.depth != pGC->depth) ||
250                (pPixmap->drawable.pScreen != pGC->pScreen)) {
251                error = BadMatch;
252            }
253            else {
254                pPixmap->refcnt++;
255                if (!pGC->tileIsPixel)
256                    (*pGC->pScreen->DestroyPixmap) (pGC->tile.pixmap);
257                pGC->tileIsPixel = FALSE;
258                pGC->tile.pixmap = pPixmap;
259            }
260            break;
261        case GCStipple:
262            NEXT_PTR(PixmapPtr, pPixmap);
263
264            if (pPixmap && ((pPixmap->drawable.depth != 1) ||
265                            (pPixmap->drawable.pScreen != pGC->pScreen)))
266            {
267                error = BadMatch;
268            }
269            else {
270                if (pPixmap)
271                    pPixmap->refcnt++;
272                if (pGC->stipple)
273                    (*pGC->pScreen->DestroyPixmap) (pGC->stipple);
274                pGC->stipple = pPixmap;
275            }
276            break;
277        case GCTileStipXOrigin:
278            NEXTVAL(INT16, pGC->patOrg.x);
279
280            break;
281        case GCTileStipYOrigin:
282            NEXTVAL(INT16, pGC->patOrg.y);
283
284            break;
285        case GCFont:
286        {
287            FontPtr pFont;
288            NEXT_PTR(FontPtr, pFont);
289
290            pFont->refcnt++;
291            if (pGC->font)
292                CloseFont(pGC->font, (Font) 0);
293            pGC->font = pFont;
294            break;
295        }
296        case GCSubwindowMode:
297        {
298            unsigned int newclipmode;
299            NEXTVAL(unsigned int, newclipmode);
300
301            if (newclipmode <= IncludeInferiors)
302                pGC->subWindowMode = newclipmode;
303            else {
304                if (client)
305                    client->errorValue = newclipmode;
306                error = BadValue;
307            }
308            break;
309        }
310        case GCGraphicsExposures:
311        {
312            unsigned int newge;
313            NEXTVAL(unsigned int, newge);
314
315            if (newge <= xTrue)
316                pGC->graphicsExposures = newge;
317            else {
318                if (client)
319                    client->errorValue = newge;
320                error = BadValue;
321            }
322            break;
323        }
324        case GCClipXOrigin:
325            NEXTVAL(INT16, pGC->clipOrg.x);
326
327            break;
328        case GCClipYOrigin:
329            NEXTVAL(INT16, pGC->clipOrg.y);
330
331            break;
332        case GCClipMask:
333            NEXT_PTR(PixmapPtr, pPixmap);
334
335            if (pPixmap) {
336                if ((pPixmap->drawable.depth != 1) ||
337                    (pPixmap->drawable.pScreen != pGC->pScreen)) {
338                    error = BadMatch;
339                    break;
340                }
341                pPixmap->refcnt++;
342            }
343            (*pGC->funcs->ChangeClip) (pGC, pPixmap ? CT_PIXMAP : CT_NONE,
344                                       (void *) pPixmap, 0);
345            break;
346        case GCDashOffset:
347            NEXTVAL(INT16, pGC->dashOffset);
348
349            break;
350        case GCDashList:
351        {
352            CARD8 newdash;
353            NEXTVAL(CARD8, newdash);
354
355            if (newdash == 4) {
356                if (pGC->dash != DefaultDash) {
357                    free(pGC->dash);
358                    pGC->numInDashList = 2;
359                    pGC->dash = DefaultDash;
360                }
361            }
362            else if (newdash != 0) {
363                unsigned char *dash;
364
365                dash = malloc(2 * sizeof(unsigned char));
366                if (dash) {
367                    if (pGC->dash != DefaultDash)
368                        free(pGC->dash);
369                    pGC->numInDashList = 2;
370                    pGC->dash = dash;
371                    dash[0] = newdash;
372                    dash[1] = newdash;
373                }
374                else
375                    error = BadAlloc;
376            }
377            else {
378                if (client)
379                    client->errorValue = newdash;
380                error = BadValue;
381            }
382            break;
383        }
384        case GCArcMode:
385        {
386            unsigned int newarcmode;
387            NEXTVAL(unsigned int, newarcmode);
388
389            if (newarcmode <= ArcPieSlice)
390                pGC->arcMode = newarcmode;
391            else {
392                if (client)
393                    client->errorValue = newarcmode;
394                error = BadValue;
395            }
396            break;
397        }
398        default:
399            if (client)
400                client->errorValue = maskQ;
401            error = BadValue;
402            break;
403        }
404    }                           /* end while mask && !error */
405
406    if (pGC->fillStyle == FillTiled && pGC->tileIsPixel) {
407        if (!CreateDefaultTile(pGC)) {
408            pGC->fillStyle = FillSolid;
409            error = BadAlloc;
410        }
411    }
412    (*pGC->funcs->ChangeGC) (pGC, maskQ);
413    return error;
414}
415
416#undef NEXTVAL
417#undef NEXT_PTR
418
419static const struct {
420    BITS32 mask;
421    RESTYPE type;
422    Mask access_mode;
423} xidfields[] = {
424    {GCTile, RT_PIXMAP, DixReadAccess},
425    {GCStipple, RT_PIXMAP, DixReadAccess},
426    {GCFont, RT_FONT, DixUseAccess},
427    {GCClipMask, RT_PIXMAP, DixReadAccess},
428};
429
430int
431ChangeGCXIDs(ClientPtr client, GC * pGC, BITS32 mask, CARD32 *pC32)
432{
433    ChangeGCVal vals[GCLastBit + 1];
434    int i;
435
436    if (mask & ~GCAllBits) {
437        client->errorValue = mask;
438        return BadValue;
439    }
440    for (i = Ones(mask); i--;)
441        vals[i].val = pC32[i];
442    for (i = 0; i < ARRAY_SIZE(xidfields); ++i) {
443        int offset, rc;
444
445        if (!(mask & xidfields[i].mask))
446            continue;
447        offset = Ones(mask & (xidfields[i].mask - 1));
448        if (xidfields[i].mask == GCClipMask && vals[offset].val == None) {
449            vals[offset].ptr = NullPixmap;
450            continue;
451        }
452        rc = dixLookupResourceByType(&vals[offset].ptr, vals[offset].val,
453                                     xidfields[i].type, client,
454                                     xidfields[i].access_mode);
455        if (rc != Success) {
456            client->errorValue = vals[offset].val;
457            return rc;
458        }
459    }
460    return ChangeGC(client, pGC, mask, vals);
461}
462
463static GCPtr
464NewGCObject(ScreenPtr pScreen, int depth)
465{
466    GCPtr pGC;
467
468    pGC = dixAllocateScreenObjectWithPrivates(pScreen, GC, PRIVATE_GC);
469    if (!pGC) {
470        return (GCPtr) NULL;
471    }
472
473    pGC->pScreen = pScreen;
474    pGC->depth = depth;
475    pGC->alu = GXcopy;          /* dst <- src */
476    pGC->planemask = ~0;
477    pGC->serialNumber = 0;
478    pGC->funcs = 0;
479    pGC->fgPixel = 0;
480    pGC->bgPixel = 1;
481    pGC->lineWidth = 0;
482    pGC->lineStyle = LineSolid;
483    pGC->capStyle = CapButt;
484    pGC->joinStyle = JoinMiter;
485    pGC->fillStyle = FillSolid;
486    pGC->fillRule = EvenOddRule;
487    pGC->arcMode = ArcPieSlice;
488    pGC->tile.pixel = 0;
489    pGC->tile.pixmap = NullPixmap;
490
491    pGC->tileIsPixel = TRUE;
492    pGC->patOrg.x = 0;
493    pGC->patOrg.y = 0;
494    pGC->subWindowMode = ClipByChildren;
495    pGC->graphicsExposures = TRUE;
496    pGC->clipOrg.x = 0;
497    pGC->clipOrg.y = 0;
498    pGC->clientClip = (void *) NULL;
499    pGC->numInDashList = 2;
500    pGC->dash = DefaultDash;
501    pGC->dashOffset = 0;
502
503    /* use the default font and stipple */
504    pGC->font = defaultFont;
505    if (pGC->font)              /* necessary, because open of default font could fail */
506        pGC->font->refcnt++;
507    pGC->stipple = pGC->pScreen->defaultStipple;
508    if (pGC->stipple)
509        pGC->stipple->refcnt++;
510
511    /* this is not a scratch GC */
512    pGC->scratch_inuse = FALSE;
513    return pGC;
514}
515
516/* CreateGC(pDrawable, mask, pval, pStatus)
517   creates a default GC for the given drawable, using mask to fill
518   in any non-default values.
519   Returns a pointer to the new GC on success, NULL otherwise.
520   returns status of non-default fields in pStatus
521BUG:
522   should check for failure to create default tile
523
524*/
525GCPtr
526CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus,
527         XID gcid, ClientPtr client)
528{
529    GCPtr pGC;
530
531    pGC = NewGCObject(pDrawable->pScreen, pDrawable->depth);
532    if (!pGC) {
533        *pStatus = BadAlloc;
534        return (GCPtr) NULL;
535    }
536
537    pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
538    if (mask & GCForeground) {
539        /*
540         * magic special case -- ChangeGC checks for this condition
541         * and snags the Foreground value to create a pseudo default-tile
542         */
543        pGC->tileIsPixel = FALSE;
544    }
545    else {
546        pGC->tileIsPixel = TRUE;
547    }
548
549    /* security creation/labeling check */
550    *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
551                        RT_NONE, NULL, DixCreateAccess | DixSetAttrAccess);
552    if (*pStatus != Success)
553        goto out;
554
555    pGC->stateChanges = GCAllBits;
556    if (!(*pGC->pScreen->CreateGC) (pGC))
557        *pStatus = BadAlloc;
558    else if (mask)
559        *pStatus = ChangeGCXIDs(client, pGC, mask, pval);
560    else
561        *pStatus = Success;
562
563 out:
564    if (*pStatus != Success) {
565        if (!pGC->tileIsPixel && !pGC->tile.pixmap)
566            pGC->tileIsPixel = TRUE;    /* undo special case */
567        FreeGC(pGC, (XID) 0);
568        pGC = (GCPtr) NULL;
569    }
570
571    return pGC;
572}
573
574static Bool
575CreateDefaultTile(GCPtr pGC)
576{
577    ChangeGCVal tmpval[3];
578    PixmapPtr pTile;
579    GCPtr pgcScratch;
580    xRectangle rect;
581    CARD16 w, h;
582
583    w = 1;
584    h = 1;
585    (*pGC->pScreen->QueryBestSize) (TileShape, &w, &h, pGC->pScreen);
586    pTile = (PixmapPtr)
587        (*pGC->pScreen->CreatePixmap) (pGC->pScreen, w, h, pGC->depth, 0);
588    pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
589    if (!pTile || !pgcScratch) {
590        if (pTile)
591            (*pTile->drawable.pScreen->DestroyPixmap) (pTile);
592        if (pgcScratch)
593            FreeScratchGC(pgcScratch);
594        return FALSE;
595    }
596    tmpval[0].val = GXcopy;
597    tmpval[1].val = pGC->tile.pixel;
598    tmpval[2].val = FillSolid;
599    (void) ChangeGC(NullClient, pgcScratch,
600                    GCFunction | GCForeground | GCFillStyle, tmpval);
601    ValidateGC((DrawablePtr) pTile, pgcScratch);
602    rect.x = 0;
603    rect.y = 0;
604    rect.width = w;
605    rect.height = h;
606    (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pTile, pgcScratch, 1,
607                                      &rect);
608    /* Always remember to free the scratch graphics context after use. */
609    FreeScratchGC(pgcScratch);
610
611    pGC->tileIsPixel = FALSE;
612    pGC->tile.pixmap = pTile;
613    return TRUE;
614}
615
616int
617CopyGC(GC * pgcSrc, GC * pgcDst, BITS32 mask)
618{
619    BITS32 index2;
620    BITS32 maskQ;
621    int error = 0;
622
623    if (pgcSrc == pgcDst)
624        return Success;
625    pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
626    pgcDst->stateChanges |= mask;
627    maskQ = mask;
628    while (mask) {
629        index2 = (BITS32) lowbit(mask);
630        mask &= ~index2;
631        switch (index2) {
632        case GCFunction:
633            pgcDst->alu = pgcSrc->alu;
634            break;
635        case GCPlaneMask:
636            pgcDst->planemask = pgcSrc->planemask;
637            break;
638        case GCForeground:
639            pgcDst->fgPixel = pgcSrc->fgPixel;
640            break;
641        case GCBackground:
642            pgcDst->bgPixel = pgcSrc->bgPixel;
643            break;
644        case GCLineWidth:
645            pgcDst->lineWidth = pgcSrc->lineWidth;
646            break;
647        case GCLineStyle:
648            pgcDst->lineStyle = pgcSrc->lineStyle;
649            break;
650        case GCCapStyle:
651            pgcDst->capStyle = pgcSrc->capStyle;
652            break;
653        case GCJoinStyle:
654            pgcDst->joinStyle = pgcSrc->joinStyle;
655            break;
656        case GCFillStyle:
657            pgcDst->fillStyle = pgcSrc->fillStyle;
658            break;
659        case GCFillRule:
660            pgcDst->fillRule = pgcSrc->fillRule;
661            break;
662        case GCTile:
663        {
664            if (EqualPixUnion(pgcDst->tileIsPixel,
665                              pgcDst->tile,
666                              pgcSrc->tileIsPixel, pgcSrc->tile)) {
667                break;
668            }
669            if (!pgcDst->tileIsPixel)
670                (*pgcDst->pScreen->DestroyPixmap) (pgcDst->tile.pixmap);
671            pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
672            pgcDst->tile = pgcSrc->tile;
673            if (!pgcDst->tileIsPixel)
674                pgcDst->tile.pixmap->refcnt++;
675            break;
676        }
677        case GCStipple:
678        {
679            if (pgcDst->stipple == pgcSrc->stipple)
680                break;
681            if (pgcDst->stipple)
682                (*pgcDst->pScreen->DestroyPixmap) (pgcDst->stipple);
683            pgcDst->stipple = pgcSrc->stipple;
684            if (pgcDst->stipple)
685                pgcDst->stipple->refcnt++;
686            break;
687        }
688        case GCTileStipXOrigin:
689            pgcDst->patOrg.x = pgcSrc->patOrg.x;
690            break;
691        case GCTileStipYOrigin:
692            pgcDst->patOrg.y = pgcSrc->patOrg.y;
693            break;
694        case GCFont:
695            if (pgcDst->font == pgcSrc->font)
696                break;
697            if (pgcDst->font)
698                CloseFont(pgcDst->font, (Font) 0);
699            if ((pgcDst->font = pgcSrc->font) != NullFont)
700                (pgcDst->font)->refcnt++;
701            break;
702        case GCSubwindowMode:
703            pgcDst->subWindowMode = pgcSrc->subWindowMode;
704            break;
705        case GCGraphicsExposures:
706            pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
707            break;
708        case GCClipXOrigin:
709            pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
710            break;
711        case GCClipYOrigin:
712            pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
713            break;
714        case GCClipMask:
715            (*pgcDst->funcs->CopyClip) (pgcDst, pgcSrc);
716            break;
717        case GCDashOffset:
718            pgcDst->dashOffset = pgcSrc->dashOffset;
719            break;
720        case GCDashList:
721            if (pgcSrc->dash == DefaultDash) {
722                if (pgcDst->dash != DefaultDash) {
723                    free(pgcDst->dash);
724                    pgcDst->numInDashList = pgcSrc->numInDashList;
725                    pgcDst->dash = pgcSrc->dash;
726                }
727            }
728            else {
729                unsigned char *dash;
730                unsigned int i;
731
732                dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char));
733                if (dash) {
734                    if (pgcDst->dash != DefaultDash)
735                        free(pgcDst->dash);
736                    pgcDst->numInDashList = pgcSrc->numInDashList;
737                    pgcDst->dash = dash;
738                    for (i = 0; i < pgcSrc->numInDashList; i++)
739                        dash[i] = pgcSrc->dash[i];
740                }
741                else
742                    error = BadAlloc;
743            }
744            break;
745        case GCArcMode:
746            pgcDst->arcMode = pgcSrc->arcMode;
747            break;
748        default:
749            FatalError("CopyGC: Unhandled mask!\n");
750        }
751    }
752    if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel) {
753        if (!CreateDefaultTile(pgcDst)) {
754            pgcDst->fillStyle = FillSolid;
755            error = BadAlloc;
756        }
757    }
758    (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
759    return error;
760}
761
762/**
763 * does the diX part of freeing the characteristics in the GC.
764 *
765 *  \param value  must conform to DeleteType
766 */
767int
768FreeGC(void *value, XID gid)
769{
770    GCPtr pGC = (GCPtr) value;
771
772    CloseFont(pGC->font, (Font) 0);
773    (*pGC->funcs->DestroyClip) (pGC);
774
775    if (!pGC->tileIsPixel)
776        (*pGC->pScreen->DestroyPixmap) (pGC->tile.pixmap);
777    if (pGC->stipple)
778        (*pGC->pScreen->DestroyPixmap) (pGC->stipple);
779
780    (*pGC->funcs->DestroyGC) (pGC);
781    if (pGC->dash != DefaultDash)
782        free(pGC->dash);
783    dixFreeObjectWithPrivates(pGC, PRIVATE_GC);
784    return Success;
785}
786
787/* CreateScratchGC(pScreen, depth)
788    like CreateGC, but doesn't do the default tile or stipple,
789since we can't create them without already having a GC.  any code
790using the tile or stipple has to set them explicitly anyway,
791since the state of the scratch gc is unknown.  This is OK
792because ChangeGC() has to be able to deal with NULL tiles and
793stipples anyway (in case the CreateGC() call has provided a
794value for them -- we can't set the default tile until the
795client-supplied attributes are installed, since the fgPixel
796is what fills the default tile.  (maybe this comment should
797go with CreateGC() or ChangeGC().)
798*/
799
800static GCPtr
801CreateScratchGC(ScreenPtr pScreen, unsigned depth)
802{
803    GCPtr pGC;
804
805    pGC = NewGCObject(pScreen, depth);
806    if (!pGC)
807        return (GCPtr) NULL;
808
809    pGC->stateChanges = GCAllBits;
810    if (!(*pScreen->CreateGC) (pGC)) {
811        FreeGC(pGC, (XID) 0);
812        pGC = (GCPtr) NULL;
813    }
814    else
815        pGC->graphicsExposures = FALSE;
816    return pGC;
817}
818
819void
820FreeGCperDepth(int screenNum)
821{
822    int i;
823    ScreenPtr pScreen;
824    GCPtr *ppGC;
825
826    pScreen = screenInfo.screens[screenNum];
827    ppGC = pScreen->GCperDepth;
828
829    for (i = 0; i <= pScreen->numDepths; i++) {
830        (void) FreeGC(ppGC[i], (XID) 0);
831        ppGC[i] = NULL;
832    }
833}
834
835Bool
836CreateGCperDepth(int screenNum)
837{
838    int i;
839    ScreenPtr pScreen;
840    DepthPtr pDepth;
841    GCPtr *ppGC;
842
843    pScreen = screenInfo.screens[screenNum];
844    ppGC = pScreen->GCperDepth;
845    /* do depth 1 separately because it's not included in list */
846    if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
847        return FALSE;
848    /* Make sure we don't overflow GCperDepth[] */
849    if (pScreen->numDepths > MAXFORMATS)
850        return FALSE;
851
852    pDepth = pScreen->allowedDepths;
853    for (i = 0; i < pScreen->numDepths; i++, pDepth++) {
854        if (!(ppGC[i + 1] = CreateScratchGC(pScreen, pDepth->depth))) {
855            for (; i >= 0; i--)
856                (void) FreeGC(ppGC[i], (XID) 0);
857            return FALSE;
858        }
859    }
860    return TRUE;
861}
862
863Bool
864CreateDefaultStipple(int screenNum)
865{
866    ScreenPtr pScreen;
867    ChangeGCVal tmpval[3];
868    xRectangle rect;
869    CARD16 w, h;
870    GCPtr pgcScratch;
871
872    pScreen = screenInfo.screens[screenNum];
873
874    w = 16;
875    h = 16;
876    (*pScreen->QueryBestSize) (StippleShape, &w, &h, pScreen);
877    if (!(pScreen->defaultStipple = pScreen->CreatePixmap(pScreen, w, h, 1, 0)))
878        return FALSE;
879    /* fill stipple with 1 */
880    tmpval[0].val = GXcopy;
881    tmpval[1].val = 1;
882    tmpval[2].val = FillSolid;
883    pgcScratch = GetScratchGC(1, pScreen);
884    if (!pgcScratch) {
885        (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
886        return FALSE;
887    }
888    (void) ChangeGC(NullClient, pgcScratch,
889                    GCFunction | GCForeground | GCFillStyle, tmpval);
890    ValidateGC((DrawablePtr) pScreen->defaultStipple, pgcScratch);
891    rect.x = 0;
892    rect.y = 0;
893    rect.width = w;
894    rect.height = h;
895    (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pScreen->defaultStipple,
896                                      pgcScratch, 1, &rect);
897    FreeScratchGC(pgcScratch);
898    return TRUE;
899}
900
901void
902FreeDefaultStipple(int screenNum)
903{
904    ScreenPtr pScreen = screenInfo.screens[screenNum];
905
906    (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
907}
908
909int
910SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
911{
912    long i;
913    unsigned char *p, *indash;
914    BITS32 maskQ = 0;
915
916    i = ndash;
917    p = pdash;
918    while (i--) {
919        if (!*p++) {
920            /* dash segment must be > 0 */
921            return BadValue;
922        }
923    }
924
925    if (ndash & 1)
926        p = malloc(2 * ndash * sizeof(unsigned char));
927    else
928        p = malloc(ndash * sizeof(unsigned char));
929    if (!p)
930        return BadAlloc;
931
932    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
933    if (offset != pGC->dashOffset) {
934        pGC->dashOffset = offset;
935        pGC->stateChanges |= GCDashOffset;
936        maskQ |= GCDashOffset;
937    }
938
939    if (pGC->dash != DefaultDash)
940        free(pGC->dash);
941    pGC->numInDashList = ndash;
942    pGC->dash = p;
943    if (ndash & 1) {
944        pGC->numInDashList += ndash;
945        indash = pdash;
946        i = ndash;
947        while (i--)
948            *p++ = *indash++;
949    }
950    while (ndash--)
951        *p++ = *pdash++;
952    pGC->stateChanges |= GCDashList;
953    maskQ |= GCDashList;
954
955    if (pGC->funcs->ChangeGC)
956        (*pGC->funcs->ChangeGC) (pGC, maskQ);
957    return Success;
958}
959
960int
961VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
962{
963    xRectangle *prectP, *prectN;
964    int i;
965
966    switch (ordering) {
967    case Unsorted:
968        return CT_UNSORTED;
969    case YSorted:
970        if (nrects > 1) {
971            for (i = 1, prectP = prects, prectN = prects + 1;
972                 i < nrects; i++, prectP++, prectN++)
973                if (prectN->y < prectP->y)
974                    return -1;
975        }
976        return CT_YSORTED;
977    case YXSorted:
978        if (nrects > 1) {
979            for (i = 1, prectP = prects, prectN = prects + 1;
980                 i < nrects; i++, prectP++, prectN++)
981                if ((prectN->y < prectP->y) ||
982                    ((prectN->y == prectP->y) && (prectN->x < prectP->x)))
983                    return -1;
984        }
985        return CT_YXSORTED;
986    case YXBanded:
987        if (nrects > 1) {
988            for (i = 1, prectP = prects, prectN = prects + 1;
989                 i < nrects; i++, prectP++, prectN++)
990                if ((prectN->y != prectP->y &&
991                     prectN->y < prectP->y + (int) prectP->height) ||
992                    ((prectN->y == prectP->y) &&
993                     (prectN->height != prectP->height ||
994                      prectN->x < prectP->x + (int) prectP->width)))
995                    return -1;
996        }
997        return CT_YXBANDED;
998    }
999    return -1;
1000}
1001
1002int
1003SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
1004             xRectangle *prects, int ordering)
1005{
1006    int newct, size;
1007    xRectangle *prectsNew;
1008
1009    newct = VerifyRectOrder(nrects, prects, ordering);
1010    if (newct < 0)
1011        return BadMatch;
1012    size = nrects * sizeof(xRectangle);
1013    prectsNew = malloc(size);
1014    if (!prectsNew && size)
1015        return BadAlloc;
1016
1017    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1018    pGC->clipOrg.x = xOrigin;
1019    pGC->stateChanges |= GCClipXOrigin;
1020
1021    pGC->clipOrg.y = yOrigin;
1022    pGC->stateChanges |= GCClipYOrigin;
1023
1024    if (size)
1025        memmove((char *) prectsNew, (char *) prects, size);
1026    (*pGC->funcs->ChangeClip) (pGC, newct, (void *) prectsNew, nrects);
1027    if (pGC->funcs->ChangeGC)
1028        (*pGC->funcs->ChangeGC) (pGC,
1029                                 GCClipXOrigin | GCClipYOrigin | GCClipMask);
1030    return Success;
1031}
1032
1033/*
1034   sets reasonable defaults
1035   if we can get a pre-allocated one, use it and mark it as used.
1036   if we can't, create one out of whole cloth (The Velveteen GC -- if
1037   you use it often enough it will become real.)
1038*/
1039GCPtr
1040GetScratchGC(unsigned depth, ScreenPtr pScreen)
1041{
1042    int i;
1043    GCPtr pGC;
1044
1045    for (i = 0; i <= pScreen->numDepths; i++) {
1046        pGC = pScreen->GCperDepth[i];
1047        if (pGC && pGC->depth == depth && !pGC->scratch_inuse) {
1048            pGC->scratch_inuse = TRUE;
1049
1050            pGC->alu = GXcopy;
1051            pGC->planemask = ~0;
1052            pGC->serialNumber = 0;
1053            pGC->fgPixel = 0;
1054            pGC->bgPixel = 1;
1055            pGC->lineWidth = 0;
1056            pGC->lineStyle = LineSolid;
1057            pGC->capStyle = CapButt;
1058            pGC->joinStyle = JoinMiter;
1059            pGC->fillStyle = FillSolid;
1060            pGC->fillRule = EvenOddRule;
1061            pGC->arcMode = ArcChord;
1062            pGC->patOrg.x = 0;
1063            pGC->patOrg.y = 0;
1064            pGC->subWindowMode = ClipByChildren;
1065            pGC->graphicsExposures = FALSE;
1066            pGC->clipOrg.x = 0;
1067            pGC->clipOrg.y = 0;
1068            if (pGC->clientClip)
1069                (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1070            pGC->stateChanges = GCAllBits;
1071            return pGC;
1072        }
1073    }
1074    /* if we make it this far, need to roll our own */
1075    return CreateScratchGC(pScreen, depth);
1076}
1077
1078/*
1079   if the gc to free is in the table of pre-existing ones,
1080mark it as available.
1081   if not, free it for real
1082*/
1083void
1084FreeScratchGC(GCPtr pGC)
1085{
1086    if (pGC->scratch_inuse)
1087        pGC->scratch_inuse = FALSE;
1088    else
1089        FreeGC(pGC, (GContext) 0);
1090}
1091