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