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