1 /***********************************************************
2 
3 Copyright 1987, 1998  The Open Group
4 
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10 
11 The above copyright notice and this permission notice shall be included in
12 all copies or substantial portions of the Software.
13 
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17 OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20 
21 Except as contained in this notice, the name of The Open Group shall not be
22 used in advertising or otherwise to promote the sale, use or other dealings
23 in this Software without prior written authorization from The Open Group.
24 
25 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26 
27                         All Rights Reserved
28 
29 Permission to use, copy, modify, and distribute this software and its
30 documentation for any purpose and without fee is hereby granted,
31 provided that the above copyright notice appear in all copies and that
32 both that copyright notice and this permission notice appear in
33 supporting documentation, and that the name of Digital not be
34 used in advertising or publicity pertaining to distribution of the
35 software without specific, written prior permission.
36 
37 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43 SOFTWARE.
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 
68 extern FontPtr defaultFont;
69 
70 static Bool CreateDefaultTile(GCPtr pGC);
71 
72 static unsigned char DefaultDash[2] = { 4, 4 };
73 
74 void
ValidateGC(DrawablePtr pDraw,GC * pGC)75 ValidateGC(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 
122 int
ChangeGC(ClientPtr client,GC * pGC,BITS32 mask,ChangeGCValPtr pUnion)123 ChangeGC(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 
419 static 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 
430 int
ChangeGCXIDs(ClientPtr client,GC * pGC,BITS32 mask,CARD32 * pC32)431 ChangeGCXIDs(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 
463 static GCPtr
NewGCObject(ScreenPtr pScreen,int depth)464 NewGCObject(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
521 BUG:
522    should check for failure to create default tile
523 
524 */
525 GCPtr
CreateGC(DrawablePtr pDrawable,BITS32 mask,XID * pval,int * pStatus,XID gcid,ClientPtr client)526 CreateGC(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 
574 static Bool
CreateDefaultTile(GCPtr pGC)575 CreateDefaultTile(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 
616 int
CopyGC(GC * pgcSrc,GC * pgcDst,BITS32 mask)617 CopyGC(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  */
767 int
FreeGC(void * value,XID gid)768 FreeGC(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,
789 since we can't create them without already having a GC.  any code
790 using the tile or stipple has to set them explicitly anyway,
791 since the state of the scratch gc is unknown.  This is OK
792 because ChangeGC() has to be able to deal with NULL tiles and
793 stipples anyway (in case the CreateGC() call has provided a
794 value for them -- we can't set the default tile until the
795 client-supplied attributes are installed, since the fgPixel
796 is what fills the default tile.  (maybe this comment should
797 go with CreateGC() or ChangeGC().)
798 */
799 
800 static GCPtr
CreateScratchGC(ScreenPtr pScreen,unsigned depth)801 CreateScratchGC(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     pGC->graphicsExposures = FALSE;
815     return pGC;
816 }
817 
818 void
FreeGCperDepth(int screenNum)819 FreeGCperDepth(int screenNum)
820 {
821     int i;
822     ScreenPtr pScreen;
823     GCPtr *ppGC;
824 
825     pScreen = screenInfo.screens[screenNum];
826     ppGC = pScreen->GCperDepth;
827 
828     for (i = 0; i <= pScreen->numDepths; i++) {
829         (void) FreeGC(ppGC[i], (XID) 0);
830         ppGC[i] = NULL;
831     }
832 }
833 
834 Bool
CreateGCperDepth(int screenNum)835 CreateGCperDepth(int screenNum)
836 {
837     int i;
838     ScreenPtr pScreen;
839     DepthPtr pDepth;
840     GCPtr *ppGC;
841 
842     pScreen = screenInfo.screens[screenNum];
843     ppGC = pScreen->GCperDepth;
844     /* do depth 1 separately because it's not included in list */
845     if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
846         return FALSE;
847     /* Make sure we don't overflow GCperDepth[] */
848     if (pScreen->numDepths > MAXFORMATS)
849         return FALSE;
850 
851     pDepth = pScreen->allowedDepths;
852     for (i = 0; i < pScreen->numDepths; i++, pDepth++) {
853         if (!(ppGC[i + 1] = CreateScratchGC(pScreen, pDepth->depth))) {
854             for (; i >= 0; i--)
855                 (void) FreeGC(ppGC[i], (XID) 0);
856             return FALSE;
857         }
858     }
859     return TRUE;
860 }
861 
862 Bool
CreateDefaultStipple(int screenNum)863 CreateDefaultStipple(int screenNum)
864 {
865     ScreenPtr pScreen;
866     ChangeGCVal tmpval[3];
867     xRectangle rect;
868     CARD16 w, h;
869     GCPtr pgcScratch;
870 
871     pScreen = screenInfo.screens[screenNum];
872 
873     w = 16;
874     h = 16;
875     (*pScreen->QueryBestSize) (StippleShape, &w, &h, pScreen);
876     if (!(pScreen->defaultStipple = pScreen->CreatePixmap(pScreen, w, h, 1, 0)))
877         return FALSE;
878     /* fill stipple with 1 */
879     tmpval[0].val = GXcopy;
880     tmpval[1].val = 1;
881     tmpval[2].val = FillSolid;
882     pgcScratch = GetScratchGC(1, pScreen);
883     if (!pgcScratch) {
884         (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
885         return FALSE;
886     }
887     (void) ChangeGC(NullClient, pgcScratch,
888                     GCFunction | GCForeground | GCFillStyle, tmpval);
889     ValidateGC((DrawablePtr) pScreen->defaultStipple, pgcScratch);
890     rect.x = 0;
891     rect.y = 0;
892     rect.width = w;
893     rect.height = h;
894     (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pScreen->defaultStipple,
895                                       pgcScratch, 1, &rect);
896     FreeScratchGC(pgcScratch);
897     return TRUE;
898 }
899 
900 void
FreeDefaultStipple(int screenNum)901 FreeDefaultStipple(int screenNum)
902 {
903     ScreenPtr pScreen = screenInfo.screens[screenNum];
904 
905     (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
906 }
907 
908 int
SetDashes(GCPtr pGC,unsigned offset,unsigned ndash,unsigned char * pdash)909 SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
910 {
911     long i;
912     unsigned char *p, *indash;
913     BITS32 maskQ = 0;
914 
915     i = ndash;
916     p = pdash;
917     while (i--) {
918         if (!*p++) {
919             /* dash segment must be > 0 */
920             return BadValue;
921         }
922     }
923 
924     if (ndash & 1)
925         p = malloc(2 * ndash * sizeof(unsigned char));
926     else
927         p = malloc(ndash * sizeof(unsigned char));
928     if (!p)
929         return BadAlloc;
930 
931     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
932     if (offset != pGC->dashOffset) {
933         pGC->dashOffset = offset;
934         pGC->stateChanges |= GCDashOffset;
935         maskQ |= GCDashOffset;
936     }
937 
938     if (pGC->dash != DefaultDash)
939         free(pGC->dash);
940     pGC->numInDashList = ndash;
941     pGC->dash = p;
942     if (ndash & 1) {
943         pGC->numInDashList += ndash;
944         indash = pdash;
945         i = ndash;
946         while (i--)
947             *p++ = *indash++;
948     }
949     while (ndash--)
950         *p++ = *pdash++;
951     pGC->stateChanges |= GCDashList;
952     maskQ |= GCDashList;
953 
954     if (pGC->funcs->ChangeGC)
955         (*pGC->funcs->ChangeGC) (pGC, maskQ);
956     return Success;
957 }
958 
959 int
VerifyRectOrder(int nrects,xRectangle * prects,int ordering)960 VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
961 {
962     xRectangle *prectP, *prectN;
963     int i;
964 
965     switch (ordering) {
966     case Unsorted:
967         return CT_UNSORTED;
968     case YSorted:
969         if (nrects > 1) {
970             for (i = 1, prectP = prects, prectN = prects + 1;
971                  i < nrects; i++, prectP++, prectN++)
972                 if (prectN->y < prectP->y)
973                     return -1;
974         }
975         return CT_YSORTED;
976     case YXSorted:
977         if (nrects > 1) {
978             for (i = 1, prectP = prects, prectN = prects + 1;
979                  i < nrects; i++, prectP++, prectN++)
980                 if ((prectN->y < prectP->y) ||
981                     ((prectN->y == prectP->y) && (prectN->x < prectP->x)))
982                     return -1;
983         }
984         return CT_YXSORTED;
985     case YXBanded:
986         if (nrects > 1) {
987             for (i = 1, prectP = prects, prectN = prects + 1;
988                  i < nrects; i++, prectP++, prectN++)
989                 if ((prectN->y != prectP->y &&
990                      prectN->y < prectP->y + (int) prectP->height) ||
991                     ((prectN->y == prectP->y) &&
992                      (prectN->height != prectP->height ||
993                       prectN->x < prectP->x + (int) prectP->width)))
994                     return -1;
995         }
996         return CT_YXBANDED;
997     }
998     return -1;
999 }
1000 
1001 int
SetClipRects(GCPtr pGC,int xOrigin,int yOrigin,int nrects,xRectangle * prects,int ordering)1002 SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
1003              xRectangle *prects, int ordering)
1004 {
1005     int newct, size;
1006     xRectangle *prectsNew;
1007 
1008     newct = VerifyRectOrder(nrects, prects, ordering);
1009     if (newct < 0)
1010         return BadMatch;
1011     size = nrects * sizeof(xRectangle);
1012     prectsNew = malloc(size);
1013     if (!prectsNew && size)
1014         return BadAlloc;
1015 
1016     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1017     pGC->clipOrg.x = xOrigin;
1018     pGC->stateChanges |= GCClipXOrigin;
1019 
1020     pGC->clipOrg.y = yOrigin;
1021     pGC->stateChanges |= GCClipYOrigin;
1022 
1023     if (size)
1024         memmove((char *) prectsNew, (char *) prects, size);
1025     (*pGC->funcs->ChangeClip) (pGC, newct, (void *) prectsNew, nrects);
1026     if (pGC->funcs->ChangeGC)
1027         (*pGC->funcs->ChangeGC) (pGC,
1028                                  GCClipXOrigin | GCClipYOrigin | GCClipMask);
1029     return Success;
1030 }
1031 
1032 /*
1033    sets reasonable defaults
1034    if we can get a pre-allocated one, use it and mark it as used.
1035    if we can't, create one out of whole cloth (The Velveteen GC -- if
1036    you use it often enough it will become real.)
1037 */
1038 GCPtr
GetScratchGC(unsigned depth,ScreenPtr pScreen)1039 GetScratchGC(unsigned depth, ScreenPtr pScreen)
1040 {
1041     int i;
1042     GCPtr pGC;
1043 
1044     for (i = 0; i <= pScreen->numDepths; i++) {
1045         pGC = pScreen->GCperDepth[i];
1046         if (pGC && pGC->depth == depth && !pGC->scratch_inuse) {
1047             pGC->scratch_inuse = TRUE;
1048 
1049             pGC->alu = GXcopy;
1050             pGC->planemask = ~0;
1051             pGC->serialNumber = 0;
1052             pGC->fgPixel = 0;
1053             pGC->bgPixel = 1;
1054             pGC->lineWidth = 0;
1055             pGC->lineStyle = LineSolid;
1056             pGC->capStyle = CapButt;
1057             pGC->joinStyle = JoinMiter;
1058             pGC->fillStyle = FillSolid;
1059             pGC->fillRule = EvenOddRule;
1060             pGC->arcMode = ArcChord;
1061             pGC->patOrg.x = 0;
1062             pGC->patOrg.y = 0;
1063             pGC->subWindowMode = ClipByChildren;
1064             pGC->graphicsExposures = FALSE;
1065             pGC->clipOrg.x = 0;
1066             pGC->clipOrg.y = 0;
1067             if (pGC->clientClip)
1068                 (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1069             pGC->stateChanges = GCAllBits;
1070             return pGC;
1071         }
1072     }
1073     /* if we make it this far, need to roll our own */
1074     return CreateScratchGC(pScreen, depth);
1075 }
1076 
1077 /*
1078    if the gc to free is in the table of pre-existing ones,
1079 mark it as available.
1080    if not, free it for real
1081 */
1082 void
FreeScratchGC(GCPtr pGC)1083 FreeScratchGC(GCPtr pGC)
1084 {
1085     if (pGC->scratch_inuse)
1086         pGC->scratch_inuse = FALSE;
1087     else
1088         FreeGC(pGC, (GContext) 0);
1089 }
1090