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