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