]> git.sesse.net Git - rdpsrv/blob - Xserver/programs/Xserver/dix/gc.c
Import X server from vnc-3.3.7.
[rdpsrv] / Xserver / programs / Xserver / dix / gc.c
1 /***********************************************************
2
3 Copyright (c) 1987  X Consortium
4
5 Permission is hereby granted, free of charge, to any person obtaining a copy
6 of this software and associated documentation files (the "Software"), to deal
7 in the Software without restriction, including without limitation the rights
8 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 copies of the Software, and to permit persons to whom the Software is
10 furnished to do so, subject to the following conditions:
11
12 The above copyright notice and this permission notice shall be included in
13 all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
18 X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
19 AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of the X Consortium shall not be
23 used in advertising or otherwise to promote the sale, use or other dealings
24 in this Software without prior written authorization from the X Consortium.
25
26
27 Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
28
29                         All Rights Reserved
30
31 Permission to use, copy, modify, and distribute this software and its 
32 documentation for any purpose and without fee is hereby granted, 
33 provided that the above copyright notice appear in all copies and that
34 both that copyright notice and this permission notice appear in 
35 supporting documentation, and that the name of Digital not be
36 used in advertising or publicity pertaining to distribution of the
37 software without specific, written prior permission.  
38
39 DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
40 ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
41 DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
42 ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
43 WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
44 ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
45 SOFTWARE.
46
47 ******************************************************************/
48
49 /* $XConsortium: gc.c /main/70 1996/08/01 19:21:09 dpw $ */
50 /* $XFree86: xc/programs/Xserver/dix/gc.c,v 3.4 1996/12/23 06:29:45 dawes Exp $ */
51
52 #include "X.h"
53 #include "Xmd.h"
54 #include "Xproto.h"
55 #include "misc.h"
56 #include "resource.h"
57 #include "gcstruct.h"
58 #include "pixmapstr.h"
59 #include "dixfontstr.h"
60 #include "scrnintstr.h"
61 #include "region.h"
62
63 #include "dix.h"
64 #include <assert.h>
65
66 extern XID clientErrorValue;
67 extern FontPtr defaultFont;
68
69 static Bool CreateDefaultTile(
70 #if NeedFunctionPrototypes
71     GCPtr /*pGC*/
72 #endif
73 );
74
75 unsigned char DefaultDash[2] = {4, 4};
76
77 void
78 ValidateGC(pDraw, pGC)
79     DrawablePtr pDraw;
80     GC          *pGC;
81 {
82     (*pGC->funcs->ValidateGC) (pGC, pGC->stateChanges, pDraw);
83     pGC->stateChanges = 0;
84     pGC->serialNumber = pDraw->serialNumber;
85 }
86
87
88 /* dixChangeGC(client, pGC, mask, pC32, pUnion)
89  * 
90  * This function was created as part of the Security extension
91  * implementation.  The client performing the gc change must be passed so
92  * that access checks can be performed on any tiles, stipples, or fonts
93  * that are specified.  ddxen can call this too; they should normally
94  * pass NullClient for the client since any access checking should have
95  * already been done at a higher level.
96  * 
97  * Since we had to create a new function anyway, we decided to change the
98  * way the list of gc values is passed to eliminate the compiler warnings
99  * caused by the DoChangeGC interface.  You can pass the values via pC32
100  * or pUnion, but not both; one of them must be NULL.  If you don't need
101  * to pass any pointers, you can use either one:
102  * 
103  *     /* example calling dixChangeGC using pC32 parameter
104  *     CARD32 v[2];
105  *     v[0] = foreground;
106  *     v[1] = background;
107  *     dixChangeGC(client, pGC, GCForeground|GCBackground, v, NULL);
108  * 
109  *     /* example calling dixChangeGC using pUnion parameter;
110  *     /* same effect as above
111  *     ChangeGCVal v[2];
112  *     v[0].val = foreground;
113  *     v[1].val = background;
114  *     dixChangeGC(client, pGC, GCForeground|GCBackground, NULL, v);
115  * 
116  * However, if you need to pass a pointer to a pixmap or font, you MUST
117  * use the pUnion parameter.
118  * 
119  *     /* example calling dixChangeGC passing pointers in the value list
120  *     ChangeGCVal v[2];
121  *     v[0].val = FillTiled;
122  *     v[1].ptr = pPixmap; /* pointer to a pixmap
123  *     dixChangeGC(client, pGC, GCFillStyle|GCTile, NULL, v);
124  * 
125  * Note: we could have gotten by with just the pUnion parameter, but on
126  * 64 bit machines that would have forced us to copy the value list that
127  * comes in the ChangeGC request.
128  * 
129  * Ideally, we'd change all the DoChangeGC calls to dixChangeGC, but this
130  * is far too many changes to consider at this time, so we've only
131  * changed the ones that caused compiler warnings.  New code should use
132  * dixChangeGC.
133  * 
134  * dpw
135  */
136
137 #define NEXTVAL(_type, _var) { \
138       if (pC32) _var = (_type)*pC32++; \
139       else { \
140         _var = (_type)(pUnion->val); pUnion++; \
141       } \
142     }
143
144 #define NEXT_PTR(_type, _var) { \
145     assert(pUnion); _var = (_type)pUnion->ptr; pUnion++; }
146
147 int
148 dixChangeGC(client, pGC, mask, pC32, pUnion)
149     ClientPtr client;
150     register GC         *pGC;
151     register BITS32     mask;
152     CARD32              *pC32;
153     ChangeGCValPtr      pUnion;
154 {
155     register BITS32     index2;
156     register int        error = 0;
157     PixmapPtr           pPixmap;
158     BITS32              maskQ;
159
160     assert( (pC32 && !pUnion) || (!pC32 && pUnion) );
161     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
162
163     maskQ = mask;       /* save these for when we walk the GCque */
164     while (mask && !error) 
165     {
166         index2 = (BITS32) lowbit (mask);
167         mask &= ~index2;
168         pGC->stateChanges |= index2;
169         switch (index2)
170         {
171             case GCFunction:
172             {
173                 CARD8 newalu;
174                 NEXTVAL(CARD8, newalu);
175                 if (newalu <= GXset)
176                     pGC->alu = newalu;
177                 else
178                 {
179                     clientErrorValue = newalu;
180                     error = BadValue;
181                 }
182                 break;
183             }
184             case GCPlaneMask:
185                 NEXTVAL(unsigned long, pGC->planemask);
186                 break;
187             case GCForeground:
188                 NEXTVAL(unsigned long, pGC->fgPixel);
189                 /*
190                  * this is for CreateGC
191                  */
192                 if (!pGC->tileIsPixel && !pGC->tile.pixmap)
193                 {
194                     pGC->tileIsPixel = TRUE;
195                     pGC->tile.pixel = pGC->fgPixel;
196                 }
197                 break;
198             case GCBackground:
199                 NEXTVAL(unsigned long, pGC->bgPixel);
200                 break;
201             case GCLineWidth:           /* ??? line width is a CARD16 */
202                  NEXTVAL(CARD16, pGC->lineWidth);
203                 break;
204             case GCLineStyle:
205             {
206                 unsigned int newlinestyle;
207                 NEXTVAL(unsigned int, newlinestyle);
208                 if (newlinestyle <= LineDoubleDash)
209                     pGC->lineStyle = newlinestyle;
210                 else
211                 {
212                     clientErrorValue = newlinestyle;
213                     error = BadValue;
214                 }
215                 break;
216             }
217             case GCCapStyle:
218             {
219                 unsigned int newcapstyle;
220                 NEXTVAL(unsigned int, newcapstyle);
221                 if (newcapstyle <= CapProjecting)
222                     pGC->capStyle = newcapstyle;
223                 else
224                 {
225                     clientErrorValue = newcapstyle;
226                     error = BadValue;
227                 }
228                 break;
229             }
230             case GCJoinStyle:
231             {
232                 unsigned int newjoinstyle;
233                 NEXTVAL(unsigned int, newjoinstyle);
234                 if (newjoinstyle <= JoinBevel)
235                     pGC->joinStyle = newjoinstyle;
236                 else
237                 {
238                     clientErrorValue = newjoinstyle;
239                     error = BadValue;
240                 }
241                 break;
242             }
243             case GCFillStyle:
244             {
245                 unsigned int newfillstyle;
246                 NEXTVAL(unsigned int, newfillstyle);
247                 if (newfillstyle <= FillOpaqueStippled)
248                     pGC->fillStyle = newfillstyle;
249                 else
250                 {
251                     clientErrorValue = newfillstyle;
252                     error = BadValue;
253                 }
254                 break;
255             }
256             case GCFillRule:
257             {
258                 unsigned int newfillrule;
259                 NEXTVAL(unsigned int, newfillrule);
260                 if (newfillrule <= WindingRule)
261                     pGC->fillRule = newfillrule;
262                 else
263                 {
264                     clientErrorValue = newfillrule;
265                     error = BadValue;
266                 }
267                 break;
268             }
269             case GCTile:
270             {
271                 XID newpix = 0;
272                 if (pUnion)
273                 {
274                     NEXT_PTR(PixmapPtr, pPixmap);
275                 }
276                 else
277                 {
278                     NEXTVAL(XID, newpix);
279                     pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
280                                         newpix, RT_PIXMAP, SecurityReadAccess);
281                 }
282                 if (pPixmap)
283                 {
284                     if ((pPixmap->drawable.depth != pGC->depth) ||
285                         (pPixmap->drawable.pScreen != pGC->pScreen))
286                     {
287                         error = BadMatch;
288                     }
289                     else
290                     {
291                         pPixmap->refcnt++;
292                         if (!pGC->tileIsPixel)
293                             (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
294                         pGC->tileIsPixel = FALSE;
295                         pGC->tile.pixmap = pPixmap;
296                     }
297                 }
298                 else
299                 {
300                     clientErrorValue = newpix;
301                     error = BadPixmap;
302                 }
303                 break;
304             }
305             case GCStipple:
306             {
307                 XID newstipple = 0;
308                 if (pUnion)
309                 {
310                     NEXT_PTR(PixmapPtr, pPixmap);
311                 }
312                 else
313                 {
314                     NEXTVAL(XID, newstipple)
315                     pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
316                                 newstipple, RT_PIXMAP, SecurityReadAccess);
317                 }
318                 if (pPixmap)
319                 {
320                     if ((pPixmap->drawable.depth != 1) ||
321                         (pPixmap->drawable.pScreen != pGC->pScreen))
322                     {
323                         error = BadMatch;
324                     }
325                     else
326                     {
327                         pPixmap->refcnt++;
328                         if (pGC->stipple)
329                             (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
330                         pGC->stipple = pPixmap;
331                     }
332                 }
333                 else
334                 {
335                     clientErrorValue = newstipple;
336                     error = BadPixmap;
337                 }
338                 break;
339             }
340             case GCTileStipXOrigin:
341                 NEXTVAL(INT16, pGC->patOrg.x);
342                 break;
343             case GCTileStipYOrigin:
344                 NEXTVAL(INT16, pGC->patOrg.y);
345                 break;
346             case GCFont:
347             {
348                 FontPtr pFont;
349                 XID newfont = 0;
350                 if (pUnion)
351                 {
352                     NEXT_PTR(FontPtr, pFont);
353                 }
354                 else
355                 {
356                     NEXTVAL(XID, newfont)
357                     pFont = (FontPtr)SecurityLookupIDByType(client, newfont,
358                                                 RT_FONT, SecurityReadAccess);
359                 }
360                 if (pFont)
361                 {
362                     pFont->refcnt++;
363                     if (pGC->font)
364                         CloseFont(pGC->font, (Font)0);
365                     pGC->font = pFont;
366                  }
367                 else
368                 {
369                     clientErrorValue = newfont;
370                     error = BadFont;
371                 }
372                 break;
373             }
374             case GCSubwindowMode:
375             {
376                 unsigned int newclipmode;
377                 NEXTVAL(unsigned int, newclipmode);
378                 if (newclipmode <= IncludeInferiors)
379                     pGC->subWindowMode = newclipmode;
380                 else
381                 {
382                     clientErrorValue = newclipmode;
383                     error = BadValue;
384                 }
385                 break;
386             }
387             case GCGraphicsExposures:
388             {
389                 unsigned int newge;
390                 NEXTVAL(unsigned int, newge);
391                 if (newge <= xTrue)
392                     pGC->graphicsExposures = newge;
393                 else
394                 {
395                     clientErrorValue = newge;
396                     error = BadValue;
397                 }
398                 break;
399             }
400             case GCClipXOrigin:
401                 NEXTVAL(INT16, pGC->clipOrg.x);
402                 break;
403             case GCClipYOrigin:
404                 NEXTVAL(INT16, pGC->clipOrg.y);
405                 break;
406             case GCClipMask:
407             {
408                 Pixmap pid;
409                 int    clipType;
410
411                 if (pUnion)
412                 {
413                     NEXT_PTR(PixmapPtr, pPixmap);
414                 }
415                 else
416                 {
417                     NEXTVAL(Pixmap, pid)
418                     if (pid == None)
419                     {
420                         clipType = CT_NONE;
421                         pPixmap = NullPixmap;
422                     }
423                     else
424                         pPixmap = (PixmapPtr)SecurityLookupIDByType(client,
425                                         pid, RT_PIXMAP, SecurityReadAccess);
426                 }
427
428                 if (pPixmap)
429                 {
430                     if ((pPixmap->drawable.depth != 1) ||
431                         (pPixmap->drawable.pScreen != pGC->pScreen))
432                     {
433                         error = BadMatch;
434                     }
435                     else
436                     {
437                         clipType = CT_PIXMAP;
438                         pPixmap->refcnt++;
439                     }
440                 }
441                 else if (!pUnion && (pid != None))
442                 {
443                     clientErrorValue = pid;
444                     error = BadPixmap;
445                 }
446                 if(error == Success)
447                 {
448                     (*pGC->funcs->ChangeClip)(pGC, clipType,
449                                               (pointer)pPixmap, 0);
450                 }
451                 break;
452             }
453             case GCDashOffset:
454                 NEXTVAL(INT16, pGC->dashOffset);
455                 break;
456             case GCDashList:
457             {
458                 CARD8 newdash;
459                 NEXTVAL(CARD8, newdash);
460                 if (newdash == 4)
461                 {
462                     if (pGC->dash != DefaultDash)
463                     {
464                         xfree(pGC->dash);
465                         pGC->numInDashList = 2;
466                         pGC->dash = DefaultDash;
467                     }
468                 }
469                 else if (newdash != 0)
470                 {
471                     unsigned char *dash;
472
473                     dash = (unsigned char *)xalloc(2 * sizeof(unsigned char));
474                     if (dash)
475                     {
476                         if (pGC->dash != DefaultDash)
477                             xfree(pGC->dash);
478                         pGC->numInDashList = 2;
479                         pGC->dash = dash;
480                         dash[0] = newdash;
481                         dash[1] = newdash;
482                     }
483                     else
484                         error = BadAlloc;
485                 }
486                 else
487                 {
488                    clientErrorValue = newdash;
489                    error = BadValue;
490                 }
491                 break;
492             }
493             case GCArcMode:
494             {
495                 unsigned int newarcmode;
496                 NEXTVAL(unsigned int, newarcmode);
497                 if (newarcmode <= ArcPieSlice)
498                     pGC->arcMode = newarcmode;
499                 else
500                 {
501                     clientErrorValue = newarcmode;
502                     error = BadValue;
503                 }
504                 break;
505             }
506             default:
507                 clientErrorValue = maskQ;
508                 error = BadValue;
509                 break;
510         }
511     } /* end while mask && !error */
512
513     if (pGC->fillStyle == FillTiled && pGC->tileIsPixel)
514     {
515         if (!CreateDefaultTile (pGC))
516         {
517             pGC->fillStyle = FillSolid;
518             error = BadAlloc;
519         }
520     }
521     (*pGC->funcs->ChangeGC)(pGC, maskQ);
522     return error;
523 }
524
525 #undef NEXTVAL
526 #undef NEXT_PTR
527
528 /* Publically defined entry to ChangeGC.  Just calls dixChangeGC and tells
529  * it that all of the entries are constants or IDs */
530 int
531 ChangeGC(pGC, mask, pval)
532     register GC         *pGC;
533     register BITS32     mask;
534     XID                 *pval;
535 {
536     return (dixChangeGC(NullClient, pGC, mask, pval, NULL));
537 }
538
539 /* DoChangeGC(pGC, mask, pval, fPointer)
540    mask is a set of bits indicating which values to change.
541    pval contains an appropriate value for each mask.
542    fPointer is true if the values for tiles, stipples, fonts or clipmasks
543    are pointers instead of IDs.  Note: if you are passing pointers you
544    MUST declare the array of values as type pointer!  Other data types
545    may not be large enough to hold pointers on some machines.  Yes,
546    this means you have to cast to (XID *) when you pass the array to
547    DoChangeGC.  Similarly, if you are not passing pointers (fPointer = 0) you
548    MUST declare the array as type XID (not unsigned long!), or again the wrong
549    size data type may be used.  To avoid this cruftiness, use dixChangeGC
550    above.
551
552    if there is an error, the value is marked as changed 
553    anyway, which is probably wrong, but infrequent.
554
555 NOTE:
556         all values sent over the protocol for ChangeGC requests are
557 32 bits long
558 */
559 int
560 DoChangeGC(pGC, mask, pval, fPointer)
561     register GC         *pGC;
562     register BITS32     mask;
563     XID                 *pval;
564     int                 fPointer;
565 {
566     if (fPointer)
567     /* XXX might be a problem on 64 bit big-endian servers */
568         dixChangeGC(NullClient, pGC, mask, NULL, (ChangeGCValPtr)pval);
569     else
570         dixChangeGC(NullClient, pGC, mask, pval, NULL);
571 }
572
573
574 /* CreateGC(pDrawable, mask, pval, pStatus)
575    creates a default GC for the given drawable, using mask to fill
576    in any non-default values.
577    Returns a pointer to the new GC on success, NULL otherwise.
578    returns status of non-default fields in pStatus
579 BUG:
580    should check for failure to create default tile
581
582 */
583
584 static GCPtr
585 #if NeedFunctionPrototypes
586 AllocateGC(ScreenPtr pScreen)
587 #else
588 AllocateGC(pScreen)
589     ScreenPtr pScreen;
590 #endif
591 {
592     GCPtr pGC;
593     register char *ptr;
594     register DevUnion *ppriv;
595     register unsigned *sizes;
596     register unsigned size;
597     register int i;
598
599     pGC = (GCPtr)xalloc(pScreen->totalGCSize);
600     if (pGC)
601     {
602         ppriv = (DevUnion *)(pGC + 1);
603         pGC->devPrivates = ppriv;
604         sizes = pScreen->GCPrivateSizes;
605         ptr = (char *)(ppriv + pScreen->GCPrivateLen);
606         for (i = pScreen->GCPrivateLen; --i >= 0; ppriv++, sizes++)
607         {
608             if ( (size = *sizes) )
609             {
610                 ppriv->ptr = (pointer)ptr;
611                 ptr += size;
612             }
613             else
614                 ppriv->ptr = (pointer)NULL;
615         }
616     }
617     return pGC;
618 }
619
620 GCPtr
621 CreateGC(pDrawable, mask, pval, pStatus)
622     DrawablePtr pDrawable;
623     BITS32      mask;
624     XID         *pval;
625     int         *pStatus;
626 {
627     register GCPtr pGC;
628
629     pGC = AllocateGC(pDrawable->pScreen);
630     if (!pGC)
631     {
632         *pStatus = BadAlloc;
633         return (GCPtr)NULL;
634     }
635
636     pGC->pScreen = pDrawable->pScreen;
637     pGC->depth = pDrawable->depth;
638     pGC->alu = GXcopy; /* dst <- src */
639     pGC->planemask = ~0;
640     pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
641     pGC->funcs = 0;
642
643     pGC->fgPixel = 0;
644     pGC->bgPixel = 1;
645     pGC->lineWidth = 0;
646     pGC->lineStyle = LineSolid;
647     pGC->capStyle = CapButt;
648     pGC->joinStyle = JoinMiter;
649     pGC->fillStyle = FillSolid;
650     pGC->fillRule = EvenOddRule;
651     pGC->arcMode = ArcPieSlice;
652     if (mask & GCForeground)
653     {
654         /*
655          * magic special case -- ChangeGC checks for this condition
656          * and snags the Foreground value to create a pseudo default-tile
657          */
658         pGC->tileIsPixel = FALSE;
659         pGC->tile.pixmap = NullPixmap;
660     }
661     else
662     {
663         pGC->tileIsPixel = TRUE;
664         pGC->tile.pixel = 0;
665     }
666
667     pGC->patOrg.x = 0;
668     pGC->patOrg.y = 0;
669     pGC->subWindowMode = ClipByChildren;
670     pGC->graphicsExposures = TRUE;
671     pGC->clipOrg.x = 0;
672     pGC->clipOrg.y = 0;
673     pGC->clientClipType = CT_NONE;
674     pGC->clientClip = (pointer)NULL;
675     pGC->numInDashList = 2;
676     pGC->dash = DefaultDash;
677     pGC->dashOffset = 0;
678     pGC->lastWinOrg.x = 0;
679     pGC->lastWinOrg.y = 0;
680
681     /* use the default font and stipple */
682     pGC->font = defaultFont;
683     defaultFont->refcnt++;
684     pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
685     pGC->stipple->refcnt++;
686
687     pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
688     if (!(*pGC->pScreen->CreateGC)(pGC))
689         *pStatus = BadAlloc;
690     else if (mask)
691         *pStatus = ChangeGC(pGC, mask, pval);
692     else
693         *pStatus = Success;
694     if (*pStatus != Success)
695     {
696         if (!pGC->tileIsPixel && !pGC->tile.pixmap)
697             pGC->tileIsPixel = TRUE; /* undo special case */
698         FreeGC(pGC, (XID)0);
699         pGC = (GCPtr)NULL;
700     }
701
702     return (pGC);
703 }
704
705 static Bool
706 CreateDefaultTile (pGC)
707     GCPtr   pGC;
708 {
709     XID         tmpval[3];
710     PixmapPtr   pTile;
711     GCPtr       pgcScratch;
712     xRectangle  rect;
713     CARD16      w, h;
714
715     w = 1;
716     h = 1;
717     (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
718     pTile = (PixmapPtr)
719             (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
720                                           w, h, pGC->depth);
721     pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
722     if (!pTile || !pgcScratch)
723     {
724         if (pTile)
725             (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
726         if (pgcScratch)
727             FreeScratchGC(pgcScratch);
728         return FALSE;
729     }
730     tmpval[0] = GXcopy;
731     tmpval[1] = pGC->tile.pixel;
732     tmpval[2] = FillSolid;
733     (void)ChangeGC(pgcScratch, GCFunction | GCForeground | GCFillStyle, 
734                    tmpval);
735     ValidateGC((DrawablePtr)pTile, pgcScratch);
736     rect.x = 0;
737     rect.y = 0;
738     rect.width = w;
739     rect.height = h;
740     (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
741     /* Always remember to free the scratch graphics context after use. */
742     FreeScratchGC(pgcScratch);
743
744     pGC->tileIsPixel = FALSE;
745     pGC->tile.pixmap = pTile;
746     return TRUE;
747 }
748
749 int
750 CopyGC(pgcSrc, pgcDst, mask)
751     register GC         *pgcSrc;
752     register GC         *pgcDst;
753     register BITS32     mask;
754 {
755     register BITS32     index2;
756     BITS32              maskQ;
757     int                 error = 0;
758
759     if (pgcSrc == pgcDst)
760         return Success;
761     pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
762     pgcDst->stateChanges |= mask;
763     maskQ = mask;
764     while (mask)
765     {
766         index2 = (BITS32) lowbit (mask);
767         mask &= ~index2;
768         switch (index2)
769         {
770             case GCFunction:
771                 pgcDst->alu = pgcSrc->alu;
772                 break;
773             case GCPlaneMask:
774                 pgcDst->planemask = pgcSrc->planemask;
775                 break;
776             case GCForeground:
777                 pgcDst->fgPixel = pgcSrc->fgPixel;
778                 break;
779             case GCBackground:
780                 pgcDst->bgPixel = pgcSrc->bgPixel;
781                 break;
782             case GCLineWidth:
783                 pgcDst->lineWidth = pgcSrc->lineWidth;
784                 break;
785             case GCLineStyle:
786                 pgcDst->lineStyle = pgcSrc->lineStyle;
787                 break;
788             case GCCapStyle:
789                 pgcDst->capStyle = pgcSrc->capStyle;
790                 break;
791             case GCJoinStyle:
792                 pgcDst->joinStyle = pgcSrc->joinStyle;
793                 break;
794             case GCFillStyle:
795                 pgcDst->fillStyle = pgcSrc->fillStyle;
796                 break;
797             case GCFillRule:
798                 pgcDst->fillRule = pgcSrc->fillRule;
799                 break;
800             case GCTile:
801                 {
802                     if (EqualPixUnion(pgcDst->tileIsPixel,
803                                       pgcDst->tile,
804                                       pgcSrc->tileIsPixel,
805                                       pgcSrc->tile))
806                     {
807                         break;
808                     }
809                     if (!pgcDst->tileIsPixel)
810                         (* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
811                     pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
812                     pgcDst->tile = pgcSrc->tile;
813                     if (!pgcDst->tileIsPixel)
814                        pgcDst->tile.pixmap->refcnt++;
815                     break;
816                 }
817             case GCStipple:
818                 {
819                     if (pgcDst->stipple == pgcSrc->stipple)
820                         break;
821                     if (pgcDst->stipple)
822                         (* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
823                     pgcDst->stipple = pgcSrc->stipple;
824                     if (pgcDst->stipple)
825                         pgcDst->stipple->refcnt ++;
826                     break;
827                 }
828             case GCTileStipXOrigin:
829                 pgcDst->patOrg.x = pgcSrc->patOrg.x;
830                 break;
831             case GCTileStipYOrigin:
832                 pgcDst->patOrg.y = pgcSrc->patOrg.y;
833                 break;
834             case GCFont:
835                 if (pgcDst->font == pgcSrc->font)
836                     break;
837                 if (pgcDst->font)
838                     CloseFont(pgcDst->font, (Font)0);
839                 if ((pgcDst->font = pgcSrc->font) != NullFont)
840                     (pgcDst->font)->refcnt++;
841                 break;
842             case GCSubwindowMode:
843                 pgcDst->subWindowMode = pgcSrc->subWindowMode;
844                 break;
845             case GCGraphicsExposures:
846                 pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
847                 break;
848             case GCClipXOrigin:
849                 pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
850                 break;
851             case GCClipYOrigin:
852                 pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
853                 break;
854             case GCClipMask:
855                 (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
856                 break;
857             case GCDashOffset:
858                 pgcDst->dashOffset = pgcSrc->dashOffset;
859                 break;
860             case GCDashList:
861                 if (pgcSrc->dash == DefaultDash)
862                 {
863                     if (pgcDst->dash != DefaultDash)
864                     {
865                         xfree(pgcDst->dash);
866                         pgcDst->numInDashList = pgcSrc->numInDashList;
867                         pgcDst->dash = pgcSrc->dash;
868                     }
869                 }
870                 else
871                 {
872                     unsigned char *dash;
873                     unsigned int i;
874
875                     dash = (unsigned char *)xalloc(pgcSrc->numInDashList *
876                                                    sizeof(unsigned char));
877                     if (dash)
878                     {
879                         if (pgcDst->dash != DefaultDash)
880                             xfree(pgcDst->dash);
881                         pgcDst->numInDashList = pgcSrc->numInDashList;
882                         pgcDst->dash = dash;
883                         for (i=0; i<pgcSrc->numInDashList; i++)
884                             dash[i] = pgcSrc->dash[i];
885                     }
886                     else
887                         error = BadAlloc;
888                 }
889                 break;
890             case GCArcMode:
891                 pgcDst->arcMode = pgcSrc->arcMode;
892                 break;
893             default:
894                 clientErrorValue = maskQ;
895                 error = BadValue;
896                 break;
897         }
898     }
899     if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
900     {
901         if (!CreateDefaultTile (pgcDst))
902         {
903             pgcDst->fillStyle = FillSolid;
904             error = BadAlloc;
905         }
906     }
907     (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
908     return error;
909 }
910
911 /*****************
912  * FreeGC 
913  *   does the diX part of freeing the characteristics in the GC 
914  ***************/
915
916 /*ARGSUSED*/
917 int
918 FreeGC(value, gid)
919     pointer value; /* must conform to DeleteType */
920     XID gid;
921 {
922     GCPtr pGC = (GCPtr)value;
923
924     CloseFont(pGC->font, (Font)0);
925     (* pGC->funcs->DestroyClip)(pGC);
926
927     if (!pGC->tileIsPixel)
928         (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
929     if (pGC->stipple)
930         (* pGC->pScreen->DestroyPixmap)(pGC->stipple);
931
932     (*pGC->funcs->DestroyGC) (pGC);
933     if (pGC->dash != DefaultDash)
934         xfree(pGC->dash);
935     xfree(pGC);
936     return(Success);
937 }
938
939 void
940 SetGCMask(pGC, selectMask, newDataMask)
941     GCPtr pGC;
942     Mask selectMask;
943     Mask newDataMask;
944 {
945     pGC->stateChanges = (~selectMask & pGC->stateChanges) |
946                         (selectMask & newDataMask);
947     if (selectMask & newDataMask)
948         pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;        
949 }
950
951
952
953 /* CreateScratchGC(pScreen, depth)
954     like CreateGC, but doesn't do the default tile or stipple,
955 since we can't create them without already having a GC.  any code
956 using the tile or stipple has to set them explicitly anyway,
957 since the state of the scratch gc is unknown.  This is OK
958 because ChangeGC() has to be able to deal with NULL tiles and
959 stipples anyway (in case the CreateGC() call has provided a 
960 value for them -- we can't set the default tile until the
961 client-supplied attributes are installed, since the fgPixel
962 is what fills the default tile.  (maybe this comment should
963 go with CreateGC() or ChangeGC().)
964 */
965
966 GCPtr
967 CreateScratchGC(pScreen, depth)
968     ScreenPtr pScreen;
969     unsigned depth;
970 {
971     register GCPtr pGC;
972
973     pGC = AllocateGC(pScreen);
974     if (!pGC)
975         return (GCPtr)NULL;
976
977     pGC->pScreen = pScreen;
978     pGC->depth = depth;
979     pGC->alu = GXcopy; /* dst <- src */
980     pGC->planemask = ~0;
981     pGC->serialNumber = 0;
982
983     pGC->fgPixel = 0;
984     pGC->bgPixel = 1;
985     pGC->lineWidth = 0;
986     pGC->lineStyle = LineSolid;
987     pGC->capStyle = CapButt;
988     pGC->joinStyle = JoinMiter;
989     pGC->fillStyle = FillSolid;
990     pGC->fillRule = EvenOddRule;
991     pGC->arcMode = ArcPieSlice;
992     pGC->font = defaultFont;
993     if ( pGC->font)  /* necessary, because open of default font could fail */
994         pGC->font->refcnt++;
995     pGC->tileIsPixel = TRUE;
996     pGC->tile.pixel = 0;
997     pGC->stipple = NullPixmap;
998     pGC->patOrg.x = 0;
999     pGC->patOrg.y = 0;
1000     pGC->subWindowMode = ClipByChildren;
1001     pGC->graphicsExposures = TRUE;
1002     pGC->clipOrg.x = 0;
1003     pGC->clipOrg.y = 0;
1004     pGC->clientClipType = CT_NONE;
1005     pGC->dashOffset = 0;
1006     pGC->numInDashList = 2;
1007     pGC->dash = DefaultDash;
1008     pGC->lastWinOrg.x = 0;
1009     pGC->lastWinOrg.y = 0;
1010
1011     pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
1012     if (!(*pScreen->CreateGC)(pGC))
1013     {
1014         FreeGC(pGC, (XID)0);
1015         pGC = (GCPtr)NULL;
1016     }
1017     return pGC;
1018 }
1019
1020 void
1021 FreeGCperDepth(screenNum)
1022     int screenNum;
1023 {
1024     register int i;
1025     register ScreenPtr pScreen;
1026     GCPtr *ppGC;
1027
1028     pScreen = screenInfo.screens[screenNum];
1029     ppGC = pScreen->GCperDepth;
1030
1031     for (i = 0; i <= pScreen->numDepths; i++)
1032         (void)FreeGC(ppGC[i], (XID)0);
1033     pScreen->rgf = ~0L;
1034 }
1035
1036
1037 Bool
1038 CreateGCperDepth(screenNum)
1039     int screenNum;
1040 {
1041     register int i;
1042     register ScreenPtr pScreen;
1043     DepthPtr pDepth;
1044     GCPtr *ppGC;
1045
1046     pScreen = screenInfo.screens[screenNum];
1047     pScreen->rgf = 0;
1048     ppGC = pScreen->GCperDepth;
1049     /* do depth 1 separately because it's not included in list */
1050     if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
1051         return FALSE;
1052     ppGC[0]->graphicsExposures = FALSE;
1053
1054     pDepth = pScreen->allowedDepths;
1055     for (i=0; i<pScreen->numDepths; i++, pDepth++)
1056     {
1057         if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
1058         {
1059             for (; i >= 0; i--)
1060                 (void)FreeGC(ppGC[i], (XID)0);
1061             return FALSE;
1062         }
1063         ppGC[i+1]->graphicsExposures = FALSE;
1064     }
1065     return TRUE;
1066 }
1067
1068 Bool
1069 CreateDefaultStipple(screenNum)
1070     int screenNum;
1071 {
1072     register ScreenPtr pScreen;
1073     XID tmpval[3];
1074     xRectangle rect;
1075     CARD16 w, h;
1076     GCPtr pgcScratch;
1077
1078     pScreen = screenInfo.screens[screenNum];
1079
1080     w = 16;
1081     h = 16;
1082     (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
1083     if (!(pScreen->PixmapPerDepth[0] =
1084                         (*pScreen->CreatePixmap)(pScreen, w, h, 1)))
1085         return FALSE;
1086     /* fill stipple with 1 */
1087     tmpval[0] = GXcopy; tmpval[1] = 1; tmpval[2] = FillSolid;
1088     pgcScratch = GetScratchGC(1, pScreen);
1089     if (!pgcScratch)
1090     {
1091         (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
1092         return FALSE;
1093     }
1094     (void)ChangeGC(pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
1095     ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
1096     rect.x = 0;
1097     rect.y = 0;
1098     rect.width = w;
1099     rect.height = h;
1100     (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0], 
1101                                      pgcScratch, 1, &rect);
1102     FreeScratchGC(pgcScratch);
1103     return TRUE;
1104 }
1105
1106 void
1107 FreeDefaultStipple(screenNum)
1108     int screenNum;
1109 {
1110     ScreenPtr pScreen = screenInfo.screens[screenNum];
1111     (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
1112 }
1113
1114 int
1115 SetDashes(pGC, offset, ndash, pdash)
1116 register GCPtr pGC;
1117 unsigned offset;
1118 register unsigned ndash;
1119 register unsigned char *pdash;
1120 {
1121     register long i;
1122     register unsigned char *p, *indash;
1123     BITS32 maskQ = 0;
1124
1125     i = ndash;
1126     p = pdash;
1127     while (i--)
1128     {
1129         if (!*p++)
1130         {
1131             /* dash segment must be > 0 */
1132             clientErrorValue = 0;
1133             return BadValue;
1134         }
1135     }
1136
1137     if (ndash & 1)
1138         p = (unsigned char *)xalloc(2 * ndash * sizeof(unsigned char));
1139     else
1140         p = (unsigned char *)xalloc(ndash * sizeof(unsigned char));
1141     if (!p)
1142         return BadAlloc;
1143
1144     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1145     if (offset != pGC->dashOffset)
1146     {
1147         pGC->dashOffset = offset;
1148         pGC->stateChanges |= GCDashOffset;
1149         maskQ |= GCDashOffset;
1150     }
1151
1152     if (pGC->dash != DefaultDash)
1153         xfree(pGC->dash);
1154     pGC->numInDashList = ndash;
1155     pGC->dash = p;
1156     if (ndash & 1)
1157     {
1158         pGC->numInDashList += ndash;
1159         indash = pdash;
1160         i = ndash;
1161         while (i--)
1162             *p++ = *indash++;
1163     }
1164     while(ndash--)
1165         *p++ = *pdash++;
1166     pGC->stateChanges |= GCDashList;
1167     maskQ |= GCDashList;
1168
1169     if (pGC->funcs->ChangeGC)
1170         (*pGC->funcs->ChangeGC) (pGC, maskQ);
1171     return Success;
1172 }
1173
1174 int
1175 VerifyRectOrder(nrects, prects, ordering)
1176     int                 nrects;
1177     xRectangle          *prects;
1178     int                 ordering;
1179 {
1180     register xRectangle *prectP, *prectN;
1181     register int        i;
1182
1183     switch(ordering)
1184     {
1185       case Unsorted:
1186           return CT_UNSORTED;
1187       case YSorted:
1188           if(nrects > 1)
1189           {
1190               for(i = 1, prectP = prects, prectN = prects + 1;
1191                   i < nrects;
1192                   i++, prectP++, prectN++)
1193                   if(prectN->y < prectP->y)
1194                       return -1;
1195           }
1196           return CT_YSORTED;
1197       case YXSorted:
1198           if(nrects > 1)
1199           {
1200               for(i = 1, prectP = prects, prectN = prects + 1;
1201                   i < nrects;
1202                   i++, prectP++, prectN++)
1203                   if((prectN->y < prectP->y) ||
1204                       ( (prectN->y == prectP->y) &&
1205                         (prectN->x < prectP->x) ) )
1206                       return -1;
1207           }
1208           return CT_YXSORTED;
1209       case YXBanded:
1210           if(nrects > 1)
1211           {
1212               for(i = 1, prectP = prects, prectN = prects + 1;
1213                   i < nrects;
1214                   i++, prectP++, prectN++)
1215                   if((prectN->y != prectP->y &&
1216                       prectN->y < prectP->y + (int) prectP->height) ||
1217                      ((prectN->y == prectP->y) &&
1218                       (prectN->height != prectP->height ||
1219                        prectN->x < prectP->x + (int) prectP->width)))
1220                       return -1;
1221           }
1222           return CT_YXBANDED;
1223     }
1224     return -1;
1225 }
1226
1227 int
1228 SetClipRects(pGC, xOrigin, yOrigin, nrects, prects, ordering)
1229     GCPtr               pGC;
1230     int                 xOrigin, yOrigin;
1231     int                 nrects;
1232     xRectangle          *prects;
1233     int                 ordering;
1234 {
1235     int                 newct, size;
1236     xRectangle          *prectsNew;
1237
1238     newct = VerifyRectOrder(nrects, prects, ordering);
1239     if (newct < 0)
1240         return(BadMatch);
1241     size = nrects * sizeof(xRectangle);
1242     prectsNew = (xRectangle *) xalloc(size);
1243     if (!prectsNew && size)
1244         return BadAlloc;
1245
1246     pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1247     pGC->clipOrg.x = xOrigin;
1248     pGC->stateChanges |= GCClipXOrigin;
1249                  
1250     pGC->clipOrg.y = yOrigin;
1251     pGC->stateChanges |= GCClipYOrigin;
1252
1253     if (size)
1254         memmove((char *)prectsNew, (char *)prects, size);
1255     (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
1256     if (pGC->funcs->ChangeGC)
1257         (*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
1258     return Success;
1259 }
1260
1261
1262 /*
1263    sets reasonable defaults 
1264    if we can get a pre-allocated one, use it and mark it as used.
1265    if we can't, create one out of whole cloth (The Velveteen GC -- if
1266    you use it often enough it will become real.)
1267 */
1268 GCPtr
1269 GetScratchGC(depth, pScreen)
1270     register unsigned depth;
1271     register ScreenPtr pScreen;
1272 {
1273     register int i;
1274     register GCPtr pGC;
1275
1276     for (i=0; i<=pScreen->numDepths; i++)
1277         if ( pScreen->GCperDepth[i]->depth == depth &&
1278              !(pScreen->rgf & (1L << (i+1)))
1279            )
1280         {
1281             pScreen->rgf |= (1L << (i+1));
1282             pGC = (pScreen->GCperDepth[i]);
1283
1284             pGC->alu = GXcopy;
1285             pGC->planemask = ~0;
1286             pGC->serialNumber = 0;
1287             pGC->fgPixel = 0;
1288             pGC->bgPixel = 1;
1289             pGC->lineWidth = 0;
1290             pGC->lineStyle = LineSolid;
1291             pGC->capStyle = CapButt;
1292             pGC->joinStyle = JoinMiter;
1293             pGC->fillStyle = FillSolid;
1294             pGC->fillRule = EvenOddRule;
1295             pGC->arcMode = ArcChord;
1296             pGC->patOrg.x = 0;
1297             pGC->patOrg.y = 0;
1298             pGC->subWindowMode = ClipByChildren;
1299             pGC->graphicsExposures = FALSE;
1300             pGC->clipOrg.x = 0;
1301             pGC->clipOrg.y = 0;
1302             if (pGC->clientClipType != CT_NONE)
1303                 (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1304             pGC->stateChanges = (1 << (GCLastBit+1)) - 1;
1305             return pGC;
1306         }
1307     /* if we make it this far, need to roll our own */
1308     pGC = CreateScratchGC(pScreen, depth);
1309     if (pGC)
1310         pGC->graphicsExposures = FALSE;
1311     return pGC;
1312 }
1313
1314 /*
1315    if the gc to free is in the table of pre-existing ones,
1316 mark it as available.
1317    if not, free it for real
1318 */
1319 void
1320 FreeScratchGC(pGC)
1321     register GCPtr pGC;
1322 {
1323     register ScreenPtr pScreen = pGC->pScreen;
1324     register int i;
1325
1326     for (i=0; i<=pScreen->numDepths; i++)
1327     {
1328         if ( pScreen->GCperDepth[i] == pGC)
1329         {
1330             pScreen->rgf &= ~(1L << (i+1));
1331             return;
1332         }
1333     }
1334     (void)FreeGC(pGC, (GContext)0);
1335 }