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