gc.c revision 9ace9065
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
531    /* use the default font and stipple */
532    pGC->font = defaultFont;
533    defaultFont->refcnt++;
534    pGC->stipple = pGC->pScreen->PixmapPerDepth[0];
535    pGC->stipple->refcnt++;
536
537    /* this is not a scratch GC */
538    pGC->scratch_inuse = FALSE;
539
540    /* security creation/labeling check */
541    *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
542			RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess);
543    if (*pStatus != Success)
544	goto out;
545
546    pGC->stateChanges = GCAllBits;
547    if (!(*pGC->pScreen->CreateGC)(pGC))
548	*pStatus = BadAlloc;
549    else if (mask)
550        *pStatus = ChangeGCXIDs(client, pGC, mask, pval);
551    else
552	*pStatus = Success;
553
554out:
555    if (*pStatus != Success)
556    {
557	if (!pGC->tileIsPixel && !pGC->tile.pixmap)
558	    pGC->tileIsPixel = TRUE; /* undo special case */
559	FreeGC(pGC, (XID)0);
560	pGC = (GCPtr)NULL;
561    }
562
563    return pGC;
564}
565
566static Bool
567CreateDefaultTile (GCPtr pGC)
568{
569    ChangeGCVal	tmpval[3];
570    PixmapPtr 	pTile;
571    GCPtr	pgcScratch;
572    xRectangle	rect;
573    CARD16	w, h;
574
575    w = 1;
576    h = 1;
577    (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen);
578    pTile = (PixmapPtr)
579	    (*pGC->pScreen->CreatePixmap)(pGC->pScreen,
580					  w, h, pGC->depth, 0);
581    pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
582    if (!pTile || !pgcScratch)
583    {
584	if (pTile)
585	    (*pTile->drawable.pScreen->DestroyPixmap)(pTile);
586	if (pgcScratch)
587	    FreeScratchGC(pgcScratch);
588	return FALSE;
589    }
590    tmpval[0].val = GXcopy;
591    tmpval[1].val = pGC->tile.pixel;
592    tmpval[2].val = FillSolid;
593    (void)ChangeGC(NullClient, pgcScratch, GCFunction | GCForeground | GCFillStyle, tmpval);
594    ValidateGC((DrawablePtr)pTile, pgcScratch);
595    rect.x = 0;
596    rect.y = 0;
597    rect.width = w;
598    rect.height = h;
599    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect);
600    /* Always remember to free the scratch graphics context after use. */
601    FreeScratchGC(pgcScratch);
602
603    pGC->tileIsPixel = FALSE;
604    pGC->tile.pixmap = pTile;
605    return TRUE;
606}
607
608int
609CopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask)
610{
611    BITS32	index2;
612    BITS32	maskQ;
613    int 	error = 0;
614
615    if (pgcSrc == pgcDst)
616	return Success;
617    pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
618    pgcDst->stateChanges |= mask;
619    maskQ = mask;
620    while (mask)
621    {
622	index2 = (BITS32) lowbit (mask);
623	mask &= ~index2;
624	switch (index2)
625	{
626	    case GCFunction:
627		pgcDst->alu = pgcSrc->alu;
628		break;
629	    case GCPlaneMask:
630		pgcDst->planemask = pgcSrc->planemask;
631		break;
632	    case GCForeground:
633		pgcDst->fgPixel = pgcSrc->fgPixel;
634		break;
635	    case GCBackground:
636		pgcDst->bgPixel = pgcSrc->bgPixel;
637		break;
638	    case GCLineWidth:
639		pgcDst->lineWidth = pgcSrc->lineWidth;
640		break;
641	    case GCLineStyle:
642		pgcDst->lineStyle = pgcSrc->lineStyle;
643		break;
644	    case GCCapStyle:
645		pgcDst->capStyle = pgcSrc->capStyle;
646		break;
647	    case GCJoinStyle:
648		pgcDst->joinStyle = pgcSrc->joinStyle;
649		break;
650	    case GCFillStyle:
651		pgcDst->fillStyle = pgcSrc->fillStyle;
652		break;
653	    case GCFillRule:
654		pgcDst->fillRule = pgcSrc->fillRule;
655		break;
656	    case GCTile:
657		{
658		    if (EqualPixUnion(pgcDst->tileIsPixel,
659				      pgcDst->tile,
660				      pgcSrc->tileIsPixel,
661				      pgcSrc->tile))
662		    {
663			break;
664		    }
665		    if (!pgcDst->tileIsPixel)
666			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap);
667		    pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
668		    pgcDst->tile = pgcSrc->tile;
669		    if (!pgcDst->tileIsPixel)
670		       pgcDst->tile.pixmap->refcnt++;
671		    break;
672		}
673	    case GCStipple:
674		{
675		    if (pgcDst->stipple == pgcSrc->stipple)
676			break;
677		    if (pgcDst->stipple)
678			(* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple);
679		    pgcDst->stipple = pgcSrc->stipple;
680		    if (pgcDst->stipple)
681			pgcDst->stipple->refcnt ++;
682		    break;
683		}
684	    case GCTileStipXOrigin:
685		pgcDst->patOrg.x = pgcSrc->patOrg.x;
686		break;
687	    case GCTileStipYOrigin:
688		pgcDst->patOrg.y = pgcSrc->patOrg.y;
689		break;
690	    case GCFont:
691		if (pgcDst->font == pgcSrc->font)
692		    break;
693		if (pgcDst->font)
694		    CloseFont(pgcDst->font, (Font)0);
695		if ((pgcDst->font = pgcSrc->font) != NullFont)
696		    (pgcDst->font)->refcnt++;
697		break;
698	    case GCSubwindowMode:
699		pgcDst->subWindowMode = pgcSrc->subWindowMode;
700		break;
701	    case GCGraphicsExposures:
702		pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
703		break;
704	    case GCClipXOrigin:
705		pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
706		break;
707	    case GCClipYOrigin:
708		pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
709		break;
710	    case GCClipMask:
711		(* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc);
712		break;
713	    case GCDashOffset:
714		pgcDst->dashOffset = pgcSrc->dashOffset;
715		break;
716	    case GCDashList:
717		if (pgcSrc->dash == DefaultDash)
718		{
719		    if (pgcDst->dash != DefaultDash)
720		    {
721			free(pgcDst->dash);
722			pgcDst->numInDashList = pgcSrc->numInDashList;
723			pgcDst->dash = pgcSrc->dash;
724		    }
725		}
726		else
727		{
728		    unsigned char *dash;
729		    unsigned int i;
730
731		    dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char));
732		    if (dash)
733		    {
734			if (pgcDst->dash != DefaultDash)
735			    free(pgcDst->dash);
736			pgcDst->numInDashList = pgcSrc->numInDashList;
737			pgcDst->dash = dash;
738			for (i=0; i<pgcSrc->numInDashList; i++)
739			    dash[i] = pgcSrc->dash[i];
740		    }
741		    else
742			error = BadAlloc;
743		}
744		break;
745	    case GCArcMode:
746		pgcDst->arcMode = pgcSrc->arcMode;
747		break;
748	    default:
749		FatalError ("CopyGC: Unhandled mask!\n");
750	}
751    }
752    if (pgcDst->fillStyle == FillTiled && pgcDst->tileIsPixel)
753    {
754	if (!CreateDefaultTile (pgcDst))
755	{
756	    pgcDst->fillStyle = FillSolid;
757	    error = BadAlloc;
758	}
759    }
760    (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
761    return error;
762}
763
764/**
765 * does the diX part of freeing the characteristics in the GC.
766 *
767 *  \param value  must conform to DeleteType
768 */
769int
770FreeGC(pointer value, XID gid)
771{
772    GCPtr pGC = (GCPtr)value;
773
774    CloseFont(pGC->font, (Font)0);
775    (* pGC->funcs->DestroyClip)(pGC);
776
777    if (!pGC->tileIsPixel)
778	(* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap);
779    if (pGC->stipple)
780	(* pGC->pScreen->DestroyPixmap)(pGC->stipple);
781
782    (*pGC->funcs->DestroyGC) (pGC);
783    if (pGC->dash != DefaultDash)
784	free(pGC->dash);
785    dixFreeObjectWithPrivates(pGC, PRIVATE_GC);
786    return Success;
787}
788
789/* CreateScratchGC(pScreen, depth)
790    like CreateGC, but doesn't do the default tile or stipple,
791since we can't create them without already having a GC.  any code
792using the tile or stipple has to set them explicitly anyway,
793since the state of the scratch gc is unknown.  This is OK
794because ChangeGC() has to be able to deal with NULL tiles and
795stipples anyway (in case the CreateGC() call has provided a
796value for them -- we can't set the default tile until the
797client-supplied attributes are installed, since the fgPixel
798is what fills the default tile.  (maybe this comment should
799go with CreateGC() or ChangeGC().)
800*/
801
802static GCPtr
803CreateScratchGC(ScreenPtr pScreen, unsigned depth)
804{
805    GCPtr pGC;
806
807    pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC);
808    if (!pGC)
809	return (GCPtr)NULL;
810
811    pGC->pScreen = pScreen;
812    pGC->depth = depth;
813    pGC->alu = GXcopy; /* dst <- src */
814    pGC->planemask = ~0;
815    pGC->serialNumber = 0;
816    pGC->fgPixel = 0;
817    pGC->bgPixel = 1;
818    pGC->lineWidth = 0;
819    pGC->lineStyle = LineSolid;
820    pGC->capStyle = CapButt;
821    pGC->joinStyle = JoinMiter;
822    pGC->fillStyle = FillSolid;
823    pGC->fillRule = EvenOddRule;
824    pGC->arcMode = ArcPieSlice;
825    pGC->font = defaultFont;
826    if ( pGC->font)  /* necessary, because open of default font could fail */
827	pGC->font->refcnt++;
828    pGC->tileIsPixel = TRUE;
829    pGC->tile.pixel = 0;
830    pGC->tile.pixmap = NullPixmap;
831    pGC->stipple = NullPixmap;
832    pGC->patOrg.x = 0;
833    pGC->patOrg.y = 0;
834    pGC->subWindowMode = ClipByChildren;
835    pGC->graphicsExposures = TRUE;
836    pGC->clipOrg.x = 0;
837    pGC->clipOrg.y = 0;
838    pGC->clientClipType = CT_NONE;
839    pGC->dashOffset = 0;
840    pGC->numInDashList = 2;
841    pGC->dash = DefaultDash;
842
843    /* scratch GCs in the GCperDepth pool start off unused */
844    pGC->scratch_inuse = FALSE;
845
846    pGC->stateChanges = GCAllBits;
847    if (!(*pScreen->CreateGC)(pGC))
848    {
849	FreeGC(pGC, (XID)0);
850	pGC = (GCPtr)NULL;
851    }
852    return pGC;
853}
854
855void
856FreeGCperDepth(int screenNum)
857{
858    int i;
859    ScreenPtr pScreen;
860    GCPtr *ppGC;
861
862    pScreen = screenInfo.screens[screenNum];
863    ppGC = pScreen->GCperDepth;
864
865    for (i = 0; i <= pScreen->numDepths; i++)
866    {
867	(void)FreeGC(ppGC[i], (XID)0);
868	ppGC[i] = NULL;
869    }
870}
871
872
873Bool
874CreateGCperDepth(int screenNum)
875{
876    int i;
877    ScreenPtr pScreen;
878    DepthPtr pDepth;
879    GCPtr *ppGC;
880
881    pScreen = screenInfo.screens[screenNum];
882    ppGC = pScreen->GCperDepth;
883    /* do depth 1 separately because it's not included in list */
884    if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
885	return FALSE;
886    ppGC[0]->graphicsExposures = FALSE;
887    /* Make sure we don't overflow GCperDepth[] */
888    if( pScreen->numDepths > MAXFORMATS )
889	    return FALSE;
890
891    pDepth = pScreen->allowedDepths;
892    for (i=0; i<pScreen->numDepths; i++, pDepth++)
893    {
894	if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth)))
895	{
896	    for (; i >= 0; i--)
897		(void)FreeGC(ppGC[i], (XID)0);
898	    return FALSE;
899	}
900	ppGC[i+1]->graphicsExposures = FALSE;
901    }
902    return TRUE;
903}
904
905Bool
906CreateDefaultStipple(int screenNum)
907{
908    ScreenPtr pScreen;
909    ChangeGCVal tmpval[3];
910    xRectangle rect;
911    CARD16 w, h;
912    GCPtr pgcScratch;
913
914    pScreen = screenInfo.screens[screenNum];
915
916    w = 16;
917    h = 16;
918    (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen);
919    if (!(pScreen->PixmapPerDepth[0] =
920			(*pScreen->CreatePixmap)(pScreen, w, h, 1, 0)))
921	return FALSE;
922    /* fill stipple with 1 */
923    tmpval[0].val = GXcopy;
924    tmpval[1].val = 1;
925    tmpval[2].val = FillSolid;
926    pgcScratch = GetScratchGC(1, pScreen);
927    if (!pgcScratch)
928    {
929	(*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
930	return FALSE;
931    }
932    (void)ChangeGC(NullClient, pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval);
933    ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch);
934    rect.x = 0;
935    rect.y = 0;
936    rect.width = w;
937    rect.height = h;
938    (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0],
939				     pgcScratch, 1, &rect);
940    FreeScratchGC(pgcScratch);
941    return TRUE;
942}
943
944void
945FreeDefaultStipple(int screenNum)
946{
947    ScreenPtr pScreen = screenInfo.screens[screenNum];
948    (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]);
949}
950
951int
952SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
953{
954    long i;
955    unsigned char *p, *indash;
956    BITS32 maskQ = 0;
957
958    i = ndash;
959    p = pdash;
960    while (i--)
961    {
962	if (!*p++)
963	{
964	    /* dash segment must be > 0 */
965	    return BadValue;
966	}
967    }
968
969    if (ndash & 1)
970	p = malloc(2 * ndash * sizeof(unsigned char));
971    else
972	p = malloc(ndash * sizeof(unsigned char));
973    if (!p)
974	return BadAlloc;
975
976    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
977    if (offset != pGC->dashOffset)
978    {
979	pGC->dashOffset = offset;
980	pGC->stateChanges |= GCDashOffset;
981	maskQ |= GCDashOffset;
982    }
983
984    if (pGC->dash != DefaultDash)
985	free(pGC->dash);
986    pGC->numInDashList = ndash;
987    pGC->dash = p;
988    if (ndash & 1)
989    {
990	pGC->numInDashList += ndash;
991	indash = pdash;
992	i = ndash;
993	while (i--)
994	    *p++ = *indash++;
995    }
996    while(ndash--)
997	*p++ = *pdash++;
998    pGC->stateChanges |= GCDashList;
999    maskQ |= GCDashList;
1000
1001    if (pGC->funcs->ChangeGC)
1002	(*pGC->funcs->ChangeGC) (pGC, maskQ);
1003    return Success;
1004}
1005
1006int
1007VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
1008{
1009    xRectangle	*prectP, *prectN;
1010    int	i;
1011
1012    switch(ordering)
1013    {
1014      case Unsorted:
1015	  return CT_UNSORTED;
1016      case YSorted:
1017	  if(nrects > 1)
1018	  {
1019	      for(i = 1, prectP = prects, prectN = prects + 1;
1020		  i < nrects;
1021		  i++, prectP++, prectN++)
1022		  if(prectN->y < prectP->y)
1023		      return -1;
1024	  }
1025	  return CT_YSORTED;
1026      case YXSorted:
1027	  if(nrects > 1)
1028	  {
1029	      for(i = 1, prectP = prects, prectN = prects + 1;
1030		  i < nrects;
1031		  i++, prectP++, prectN++)
1032		  if((prectN->y < prectP->y) ||
1033		      ( (prectN->y == prectP->y) &&
1034		        (prectN->x < prectP->x) ) )
1035		      return -1;
1036	  }
1037	  return CT_YXSORTED;
1038      case YXBanded:
1039	  if(nrects > 1)
1040	  {
1041	      for(i = 1, prectP = prects, prectN = prects + 1;
1042		  i < nrects;
1043		  i++, prectP++, prectN++)
1044		  if((prectN->y != prectP->y &&
1045 		      prectN->y < prectP->y + (int) prectP->height) ||
1046		     ((prectN->y == prectP->y) &&
1047		      (prectN->height != prectP->height ||
1048		       prectN->x < prectP->x + (int) prectP->width)))
1049		      return -1;
1050	  }
1051	  return CT_YXBANDED;
1052    }
1053    return -1;
1054}
1055
1056int
1057SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
1058             xRectangle *prects, int ordering)
1059{
1060    int			newct, size;
1061    xRectangle 		*prectsNew;
1062
1063    newct = VerifyRectOrder(nrects, prects, ordering);
1064    if (newct < 0)
1065	return BadMatch;
1066    size = nrects * sizeof(xRectangle);
1067    prectsNew = malloc(size);
1068    if (!prectsNew && size)
1069	return BadAlloc;
1070
1071    pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1072    pGC->clipOrg.x = xOrigin;
1073    pGC->stateChanges |= GCClipXOrigin;
1074
1075    pGC->clipOrg.y = yOrigin;
1076    pGC->stateChanges |= GCClipYOrigin;
1077
1078    if (size)
1079	memmove((char *)prectsNew, (char *)prects, size);
1080    (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects);
1081    if (pGC->funcs->ChangeGC)
1082	(*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask);
1083    return Success;
1084}
1085
1086
1087/*
1088   sets reasonable defaults
1089   if we can get a pre-allocated one, use it and mark it as used.
1090   if we can't, create one out of whole cloth (The Velveteen GC -- if
1091   you use it often enough it will become real.)
1092*/
1093GCPtr
1094GetScratchGC(unsigned depth, ScreenPtr pScreen)
1095{
1096    int i;
1097    GCPtr pGC;
1098
1099    for (i=0; i<=pScreen->numDepths; i++)
1100    {
1101	pGC = pScreen->GCperDepth[i];
1102	if (pGC && pGC->depth == depth && !pGC->scratch_inuse)
1103	{
1104	    pGC->scratch_inuse = TRUE;
1105
1106	    pGC->alu = GXcopy;
1107	    pGC->planemask = ~0;
1108	    pGC->serialNumber = 0;
1109	    pGC->fgPixel = 0;
1110	    pGC->bgPixel = 1;
1111	    pGC->lineWidth = 0;
1112	    pGC->lineStyle = LineSolid;
1113	    pGC->capStyle = CapButt;
1114	    pGC->joinStyle = JoinMiter;
1115	    pGC->fillStyle = FillSolid;
1116	    pGC->fillRule = EvenOddRule;
1117	    pGC->arcMode = ArcChord;
1118	    pGC->patOrg.x = 0;
1119	    pGC->patOrg.y = 0;
1120	    pGC->subWindowMode = ClipByChildren;
1121	    pGC->graphicsExposures = FALSE;
1122	    pGC->clipOrg.x = 0;
1123	    pGC->clipOrg.y = 0;
1124	    if (pGC->clientClipType != CT_NONE)
1125		(*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1126	    pGC->stateChanges = GCAllBits;
1127	    return pGC;
1128	}
1129    }
1130    /* if we make it this far, need to roll our own */
1131    pGC = CreateScratchGC(pScreen, depth);
1132    if (pGC)
1133	pGC->graphicsExposures = FALSE;
1134    return pGC;
1135}
1136
1137/*
1138   if the gc to free is in the table of pre-existing ones,
1139mark it as available.
1140   if not, free it for real
1141*/
1142void
1143FreeScratchGC(GCPtr pGC)
1144{
1145    if (pGC->scratch_inuse)
1146	pGC->scratch_inuse = FALSE;
1147    else
1148	FreeGC(pGC, (GContext)0);
1149}
1150