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
ValidateGC(DrawablePtr pDraw,GC * pGC)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
ChangeGC(ClientPtr client,GC * pGC,BITS32 mask,ChangeGCValPtr pUnion)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 && ((pPixmap->drawable.depth != 1) ||
265 (pPixmap->drawable.pScreen != pGC->pScreen)))
266 {
267 error = BadMatch;
268 }
269 else {
270 if (pPixmap)
271 pPixmap->refcnt++;
272 if (pGC->stipple)
273 (*pGC->pScreen->DestroyPixmap) (pGC->stipple);
274 pGC->stipple = pPixmap;
275 }
276 break;
277 case GCTileStipXOrigin:
278 NEXTVAL(INT16, pGC->patOrg.x);
279
280 break;
281 case GCTileStipYOrigin:
282 NEXTVAL(INT16, pGC->patOrg.y);
283
284 break;
285 case GCFont:
286 {
287 FontPtr pFont;
288 NEXT_PTR(FontPtr, pFont);
289
290 pFont->refcnt++;
291 if (pGC->font)
292 CloseFont(pGC->font, (Font) 0);
293 pGC->font = pFont;
294 break;
295 }
296 case GCSubwindowMode:
297 {
298 unsigned int newclipmode;
299 NEXTVAL(unsigned int, newclipmode);
300
301 if (newclipmode <= IncludeInferiors)
302 pGC->subWindowMode = newclipmode;
303 else {
304 if (client)
305 client->errorValue = newclipmode;
306 error = BadValue;
307 }
308 break;
309 }
310 case GCGraphicsExposures:
311 {
312 unsigned int newge;
313 NEXTVAL(unsigned int, newge);
314
315 if (newge <= xTrue)
316 pGC->graphicsExposures = newge;
317 else {
318 if (client)
319 client->errorValue = newge;
320 error = BadValue;
321 }
322 break;
323 }
324 case GCClipXOrigin:
325 NEXTVAL(INT16, pGC->clipOrg.x);
326
327 break;
328 case GCClipYOrigin:
329 NEXTVAL(INT16, pGC->clipOrg.y);
330
331 break;
332 case GCClipMask:
333 NEXT_PTR(PixmapPtr, pPixmap);
334
335 if (pPixmap) {
336 if ((pPixmap->drawable.depth != 1) ||
337 (pPixmap->drawable.pScreen != pGC->pScreen)) {
338 error = BadMatch;
339 break;
340 }
341 pPixmap->refcnt++;
342 }
343 (*pGC->funcs->ChangeClip) (pGC, pPixmap ? CT_PIXMAP : CT_NONE,
344 (void *) pPixmap, 0);
345 break;
346 case GCDashOffset:
347 NEXTVAL(INT16, pGC->dashOffset);
348
349 break;
350 case GCDashList:
351 {
352 CARD8 newdash;
353 NEXTVAL(CARD8, newdash);
354
355 if (newdash == 4) {
356 if (pGC->dash != DefaultDash) {
357 free(pGC->dash);
358 pGC->numInDashList = 2;
359 pGC->dash = DefaultDash;
360 }
361 }
362 else if (newdash != 0) {
363 unsigned char *dash;
364
365 dash = malloc(2 * sizeof(unsigned char));
366 if (dash) {
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 if (client)
379 client->errorValue = newdash;
380 error = BadValue;
381 }
382 break;
383 }
384 case GCArcMode:
385 {
386 unsigned int newarcmode;
387 NEXTVAL(unsigned int, newarcmode);
388
389 if (newarcmode <= ArcPieSlice)
390 pGC->arcMode = newarcmode;
391 else {
392 if (client)
393 client->errorValue = newarcmode;
394 error = BadValue;
395 }
396 break;
397 }
398 default:
399 if (client)
400 client->errorValue = maskQ;
401 error = BadValue;
402 break;
403 }
404 } /* end while mask && !error */
405
406 if (pGC->fillStyle == FillTiled && pGC->tileIsPixel) {
407 if (!CreateDefaultTile(pGC)) {
408 pGC->fillStyle = FillSolid;
409 error = BadAlloc;
410 }
411 }
412 (*pGC->funcs->ChangeGC) (pGC, maskQ);
413 return error;
414 }
415
416 #undef NEXTVAL
417 #undef NEXT_PTR
418
419 static const struct {
420 BITS32 mask;
421 RESTYPE type;
422 Mask access_mode;
423 } xidfields[] = {
424 {GCTile, RT_PIXMAP, DixReadAccess},
425 {GCStipple, RT_PIXMAP, DixReadAccess},
426 {GCFont, RT_FONT, DixUseAccess},
427 {GCClipMask, RT_PIXMAP, DixReadAccess},
428 };
429
430 int
ChangeGCXIDs(ClientPtr client,GC * pGC,BITS32 mask,CARD32 * pC32)431 ChangeGCXIDs(ClientPtr client, GC * pGC, BITS32 mask, CARD32 *pC32)
432 {
433 ChangeGCVal vals[GCLastBit + 1];
434 int i;
435
436 if (mask & ~GCAllBits) {
437 client->errorValue = mask;
438 return BadValue;
439 }
440 for (i = Ones(mask); i--;)
441 vals[i].val = pC32[i];
442 for (i = 0; i < ARRAY_SIZE(xidfields); ++i) {
443 int offset, rc;
444
445 if (!(mask & xidfields[i].mask))
446 continue;
447 offset = Ones(mask & (xidfields[i].mask - 1));
448 if (xidfields[i].mask == GCClipMask && vals[offset].val == None) {
449 vals[offset].ptr = NullPixmap;
450 continue;
451 }
452 rc = dixLookupResourceByType(&vals[offset].ptr, vals[offset].val,
453 xidfields[i].type, client,
454 xidfields[i].access_mode);
455 if (rc != Success) {
456 client->errorValue = vals[offset].val;
457 return rc;
458 }
459 }
460 return ChangeGC(client, pGC, mask, vals);
461 }
462
463 static GCPtr
NewGCObject(ScreenPtr pScreen,int depth)464 NewGCObject(ScreenPtr pScreen, int depth)
465 {
466 GCPtr pGC;
467
468 pGC = dixAllocateScreenObjectWithPrivates(pScreen, GC, PRIVATE_GC);
469 if (!pGC) {
470 return (GCPtr) NULL;
471 }
472
473 pGC->pScreen = pScreen;
474 pGC->depth = depth;
475 pGC->alu = GXcopy; /* dst <- src */
476 pGC->planemask = ~0;
477 pGC->serialNumber = 0;
478 pGC->funcs = 0;
479 pGC->fgPixel = 0;
480 pGC->bgPixel = 1;
481 pGC->lineWidth = 0;
482 pGC->lineStyle = LineSolid;
483 pGC->capStyle = CapButt;
484 pGC->joinStyle = JoinMiter;
485 pGC->fillStyle = FillSolid;
486 pGC->fillRule = EvenOddRule;
487 pGC->arcMode = ArcPieSlice;
488 pGC->tile.pixel = 0;
489 pGC->tile.pixmap = NullPixmap;
490
491 pGC->tileIsPixel = TRUE;
492 pGC->patOrg.x = 0;
493 pGC->patOrg.y = 0;
494 pGC->subWindowMode = ClipByChildren;
495 pGC->graphicsExposures = TRUE;
496 pGC->clipOrg.x = 0;
497 pGC->clipOrg.y = 0;
498 pGC->clientClip = (void *) NULL;
499 pGC->numInDashList = 2;
500 pGC->dash = DefaultDash;
501 pGC->dashOffset = 0;
502
503 /* use the default font and stipple */
504 pGC->font = defaultFont;
505 if (pGC->font) /* necessary, because open of default font could fail */
506 pGC->font->refcnt++;
507 pGC->stipple = pGC->pScreen->defaultStipple;
508 if (pGC->stipple)
509 pGC->stipple->refcnt++;
510
511 /* this is not a scratch GC */
512 pGC->scratch_inuse = FALSE;
513 return pGC;
514 }
515
516 /* CreateGC(pDrawable, mask, pval, pStatus)
517 creates a default GC for the given drawable, using mask to fill
518 in any non-default values.
519 Returns a pointer to the new GC on success, NULL otherwise.
520 returns status of non-default fields in pStatus
521 BUG:
522 should check for failure to create default tile
523
524 */
525 GCPtr
CreateGC(DrawablePtr pDrawable,BITS32 mask,XID * pval,int * pStatus,XID gcid,ClientPtr client)526 CreateGC(DrawablePtr pDrawable, BITS32 mask, XID *pval, int *pStatus,
527 XID gcid, ClientPtr client)
528 {
529 GCPtr pGC;
530
531 pGC = NewGCObject(pDrawable->pScreen, pDrawable->depth);
532 if (!pGC) {
533 *pStatus = BadAlloc;
534 return (GCPtr) NULL;
535 }
536
537 pGC->serialNumber = GC_CHANGE_SERIAL_BIT;
538 if (mask & GCForeground) {
539 /*
540 * magic special case -- ChangeGC checks for this condition
541 * and snags the Foreground value to create a pseudo default-tile
542 */
543 pGC->tileIsPixel = FALSE;
544 }
545 else {
546 pGC->tileIsPixel = TRUE;
547 }
548
549 /* security creation/labeling check */
550 *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC,
551 RT_NONE, NULL, DixCreateAccess | DixSetAttrAccess);
552 if (*pStatus != Success)
553 goto out;
554
555 pGC->stateChanges = GCAllBits;
556 if (!(*pGC->pScreen->CreateGC) (pGC))
557 *pStatus = BadAlloc;
558 else if (mask)
559 *pStatus = ChangeGCXIDs(client, pGC, mask, pval);
560 else
561 *pStatus = Success;
562
563 out:
564 if (*pStatus != Success) {
565 if (!pGC->tileIsPixel && !pGC->tile.pixmap)
566 pGC->tileIsPixel = TRUE; /* undo special case */
567 FreeGC(pGC, (XID) 0);
568 pGC = (GCPtr) NULL;
569 }
570
571 return pGC;
572 }
573
574 static Bool
CreateDefaultTile(GCPtr pGC)575 CreateDefaultTile(GCPtr pGC)
576 {
577 ChangeGCVal tmpval[3];
578 PixmapPtr pTile;
579 GCPtr pgcScratch;
580 xRectangle rect;
581 CARD16 w, h;
582
583 w = 1;
584 h = 1;
585 (*pGC->pScreen->QueryBestSize) (TileShape, &w, &h, pGC->pScreen);
586 pTile = (PixmapPtr)
587 (*pGC->pScreen->CreatePixmap) (pGC->pScreen, w, h, pGC->depth, 0);
588 pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen);
589 if (!pTile || !pgcScratch) {
590 if (pTile)
591 (*pTile->drawable.pScreen->DestroyPixmap) (pTile);
592 if (pgcScratch)
593 FreeScratchGC(pgcScratch);
594 return FALSE;
595 }
596 tmpval[0].val = GXcopy;
597 tmpval[1].val = pGC->tile.pixel;
598 tmpval[2].val = FillSolid;
599 (void) ChangeGC(NullClient, pgcScratch,
600 GCFunction | GCForeground | GCFillStyle, tmpval);
601 ValidateGC((DrawablePtr) pTile, pgcScratch);
602 rect.x = 0;
603 rect.y = 0;
604 rect.width = w;
605 rect.height = h;
606 (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pTile, pgcScratch, 1,
607 &rect);
608 /* Always remember to free the scratch graphics context after use. */
609 FreeScratchGC(pgcScratch);
610
611 pGC->tileIsPixel = FALSE;
612 pGC->tile.pixmap = pTile;
613 return TRUE;
614 }
615
616 int
CopyGC(GC * pgcSrc,GC * pgcDst,BITS32 mask)617 CopyGC(GC * pgcSrc, GC * pgcDst, BITS32 mask)
618 {
619 BITS32 index2;
620 BITS32 maskQ;
621 int error = 0;
622
623 if (pgcSrc == pgcDst)
624 return Success;
625 pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT;
626 pgcDst->stateChanges |= mask;
627 maskQ = mask;
628 while (mask) {
629 index2 = (BITS32) lowbit(mask);
630 mask &= ~index2;
631 switch (index2) {
632 case GCFunction:
633 pgcDst->alu = pgcSrc->alu;
634 break;
635 case GCPlaneMask:
636 pgcDst->planemask = pgcSrc->planemask;
637 break;
638 case GCForeground:
639 pgcDst->fgPixel = pgcSrc->fgPixel;
640 break;
641 case GCBackground:
642 pgcDst->bgPixel = pgcSrc->bgPixel;
643 break;
644 case GCLineWidth:
645 pgcDst->lineWidth = pgcSrc->lineWidth;
646 break;
647 case GCLineStyle:
648 pgcDst->lineStyle = pgcSrc->lineStyle;
649 break;
650 case GCCapStyle:
651 pgcDst->capStyle = pgcSrc->capStyle;
652 break;
653 case GCJoinStyle:
654 pgcDst->joinStyle = pgcSrc->joinStyle;
655 break;
656 case GCFillStyle:
657 pgcDst->fillStyle = pgcSrc->fillStyle;
658 break;
659 case GCFillRule:
660 pgcDst->fillRule = pgcSrc->fillRule;
661 break;
662 case GCTile:
663 {
664 if (EqualPixUnion(pgcDst->tileIsPixel,
665 pgcDst->tile,
666 pgcSrc->tileIsPixel, pgcSrc->tile)) {
667 break;
668 }
669 if (!pgcDst->tileIsPixel)
670 (*pgcDst->pScreen->DestroyPixmap) (pgcDst->tile.pixmap);
671 pgcDst->tileIsPixel = pgcSrc->tileIsPixel;
672 pgcDst->tile = pgcSrc->tile;
673 if (!pgcDst->tileIsPixel)
674 pgcDst->tile.pixmap->refcnt++;
675 break;
676 }
677 case GCStipple:
678 {
679 if (pgcDst->stipple == pgcSrc->stipple)
680 break;
681 if (pgcDst->stipple)
682 (*pgcDst->pScreen->DestroyPixmap) (pgcDst->stipple);
683 pgcDst->stipple = pgcSrc->stipple;
684 if (pgcDst->stipple)
685 pgcDst->stipple->refcnt++;
686 break;
687 }
688 case GCTileStipXOrigin:
689 pgcDst->patOrg.x = pgcSrc->patOrg.x;
690 break;
691 case GCTileStipYOrigin:
692 pgcDst->patOrg.y = pgcSrc->patOrg.y;
693 break;
694 case GCFont:
695 if (pgcDst->font == pgcSrc->font)
696 break;
697 if (pgcDst->font)
698 CloseFont(pgcDst->font, (Font) 0);
699 if ((pgcDst->font = pgcSrc->font) != NullFont)
700 (pgcDst->font)->refcnt++;
701 break;
702 case GCSubwindowMode:
703 pgcDst->subWindowMode = pgcSrc->subWindowMode;
704 break;
705 case GCGraphicsExposures:
706 pgcDst->graphicsExposures = pgcSrc->graphicsExposures;
707 break;
708 case GCClipXOrigin:
709 pgcDst->clipOrg.x = pgcSrc->clipOrg.x;
710 break;
711 case GCClipYOrigin:
712 pgcDst->clipOrg.y = pgcSrc->clipOrg.y;
713 break;
714 case GCClipMask:
715 (*pgcDst->funcs->CopyClip) (pgcDst, pgcSrc);
716 break;
717 case GCDashOffset:
718 pgcDst->dashOffset = pgcSrc->dashOffset;
719 break;
720 case GCDashList:
721 if (pgcSrc->dash == DefaultDash) {
722 if (pgcDst->dash != DefaultDash) {
723 free(pgcDst->dash);
724 pgcDst->numInDashList = pgcSrc->numInDashList;
725 pgcDst->dash = pgcSrc->dash;
726 }
727 }
728 else {
729 unsigned char *dash;
730 unsigned int i;
731
732 dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char));
733 if (dash) {
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 if (!CreateDefaultTile(pgcDst)) {
754 pgcDst->fillStyle = FillSolid;
755 error = BadAlloc;
756 }
757 }
758 (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst);
759 return error;
760 }
761
762 /**
763 * does the diX part of freeing the characteristics in the GC.
764 *
765 * \param value must conform to DeleteType
766 */
767 int
FreeGC(void * value,XID gid)768 FreeGC(void *value, XID gid)
769 {
770 GCPtr pGC = (GCPtr) value;
771
772 CloseFont(pGC->font, (Font) 0);
773 (*pGC->funcs->DestroyClip) (pGC);
774
775 if (!pGC->tileIsPixel)
776 (*pGC->pScreen->DestroyPixmap) (pGC->tile.pixmap);
777 if (pGC->stipple)
778 (*pGC->pScreen->DestroyPixmap) (pGC->stipple);
779
780 (*pGC->funcs->DestroyGC) (pGC);
781 if (pGC->dash != DefaultDash)
782 free(pGC->dash);
783 dixFreeObjectWithPrivates(pGC, PRIVATE_GC);
784 return Success;
785 }
786
787 /* CreateScratchGC(pScreen, depth)
788 like CreateGC, but doesn't do the default tile or stipple,
789 since we can't create them without already having a GC. any code
790 using the tile or stipple has to set them explicitly anyway,
791 since the state of the scratch gc is unknown. This is OK
792 because ChangeGC() has to be able to deal with NULL tiles and
793 stipples anyway (in case the CreateGC() call has provided a
794 value for them -- we can't set the default tile until the
795 client-supplied attributes are installed, since the fgPixel
796 is what fills the default tile. (maybe this comment should
797 go with CreateGC() or ChangeGC().)
798 */
799
800 static GCPtr
CreateScratchGC(ScreenPtr pScreen,unsigned depth)801 CreateScratchGC(ScreenPtr pScreen, unsigned depth)
802 {
803 GCPtr pGC;
804
805 pGC = NewGCObject(pScreen, depth);
806 if (!pGC)
807 return (GCPtr) NULL;
808
809 pGC->stateChanges = GCAllBits;
810 if (!(*pScreen->CreateGC) (pGC)) {
811 FreeGC(pGC, (XID) 0);
812 pGC = (GCPtr) NULL;
813 }
814 pGC->graphicsExposures = FALSE;
815 return pGC;
816 }
817
818 void
FreeGCperDepth(int screenNum)819 FreeGCperDepth(int screenNum)
820 {
821 int i;
822 ScreenPtr pScreen;
823 GCPtr *ppGC;
824
825 pScreen = screenInfo.screens[screenNum];
826 ppGC = pScreen->GCperDepth;
827
828 for (i = 0; i <= pScreen->numDepths; i++) {
829 (void) FreeGC(ppGC[i], (XID) 0);
830 ppGC[i] = NULL;
831 }
832 }
833
834 Bool
CreateGCperDepth(int screenNum)835 CreateGCperDepth(int screenNum)
836 {
837 int i;
838 ScreenPtr pScreen;
839 DepthPtr pDepth;
840 GCPtr *ppGC;
841
842 pScreen = screenInfo.screens[screenNum];
843 ppGC = pScreen->GCperDepth;
844 /* do depth 1 separately because it's not included in list */
845 if (!(ppGC[0] = CreateScratchGC(pScreen, 1)))
846 return FALSE;
847 /* Make sure we don't overflow GCperDepth[] */
848 if (pScreen->numDepths > MAXFORMATS)
849 return FALSE;
850
851 pDepth = pScreen->allowedDepths;
852 for (i = 0; i < pScreen->numDepths; i++, pDepth++) {
853 if (!(ppGC[i + 1] = CreateScratchGC(pScreen, pDepth->depth))) {
854 for (; i >= 0; i--)
855 (void) FreeGC(ppGC[i], (XID) 0);
856 return FALSE;
857 }
858 }
859 return TRUE;
860 }
861
862 Bool
CreateDefaultStipple(int screenNum)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->defaultStipple = pScreen->CreatePixmap(pScreen, w, h, 1, 0)))
877 return FALSE;
878 /* fill stipple with 1 */
879 tmpval[0].val = GXcopy;
880 tmpval[1].val = 1;
881 tmpval[2].val = FillSolid;
882 pgcScratch = GetScratchGC(1, pScreen);
883 if (!pgcScratch) {
884 (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
885 return FALSE;
886 }
887 (void) ChangeGC(NullClient, pgcScratch,
888 GCFunction | GCForeground | GCFillStyle, tmpval);
889 ValidateGC((DrawablePtr) pScreen->defaultStipple, pgcScratch);
890 rect.x = 0;
891 rect.y = 0;
892 rect.width = w;
893 rect.height = h;
894 (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pScreen->defaultStipple,
895 pgcScratch, 1, &rect);
896 FreeScratchGC(pgcScratch);
897 return TRUE;
898 }
899
900 void
FreeDefaultStipple(int screenNum)901 FreeDefaultStipple(int screenNum)
902 {
903 ScreenPtr pScreen = screenInfo.screens[screenNum];
904
905 (*pScreen->DestroyPixmap) (pScreen->defaultStipple);
906 }
907
908 int
SetDashes(GCPtr pGC,unsigned offset,unsigned ndash,unsigned char * pdash)909 SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash)
910 {
911 long i;
912 unsigned char *p, *indash;
913 BITS32 maskQ = 0;
914
915 i = ndash;
916 p = pdash;
917 while (i--) {
918 if (!*p++) {
919 /* dash segment must be > 0 */
920 return BadValue;
921 }
922 }
923
924 if (ndash & 1)
925 p = malloc(2 * ndash * sizeof(unsigned char));
926 else
927 p = malloc(ndash * sizeof(unsigned char));
928 if (!p)
929 return BadAlloc;
930
931 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
932 if (offset != pGC->dashOffset) {
933 pGC->dashOffset = offset;
934 pGC->stateChanges |= GCDashOffset;
935 maskQ |= GCDashOffset;
936 }
937
938 if (pGC->dash != DefaultDash)
939 free(pGC->dash);
940 pGC->numInDashList = ndash;
941 pGC->dash = p;
942 if (ndash & 1) {
943 pGC->numInDashList += ndash;
944 indash = pdash;
945 i = ndash;
946 while (i--)
947 *p++ = *indash++;
948 }
949 while (ndash--)
950 *p++ = *pdash++;
951 pGC->stateChanges |= GCDashList;
952 maskQ |= GCDashList;
953
954 if (pGC->funcs->ChangeGC)
955 (*pGC->funcs->ChangeGC) (pGC, maskQ);
956 return Success;
957 }
958
959 int
VerifyRectOrder(int nrects,xRectangle * prects,int ordering)960 VerifyRectOrder(int nrects, xRectangle *prects, int ordering)
961 {
962 xRectangle *prectP, *prectN;
963 int i;
964
965 switch (ordering) {
966 case Unsorted:
967 return CT_UNSORTED;
968 case YSorted:
969 if (nrects > 1) {
970 for (i = 1, prectP = prects, prectN = prects + 1;
971 i < nrects; i++, prectP++, prectN++)
972 if (prectN->y < prectP->y)
973 return -1;
974 }
975 return CT_YSORTED;
976 case YXSorted:
977 if (nrects > 1) {
978 for (i = 1, prectP = prects, prectN = prects + 1;
979 i < nrects; i++, prectP++, prectN++)
980 if ((prectN->y < prectP->y) ||
981 ((prectN->y == prectP->y) && (prectN->x < prectP->x)))
982 return -1;
983 }
984 return CT_YXSORTED;
985 case YXBanded:
986 if (nrects > 1) {
987 for (i = 1, prectP = prects, prectN = prects + 1;
988 i < nrects; i++, prectP++, prectN++)
989 if ((prectN->y != prectP->y &&
990 prectN->y < prectP->y + (int) prectP->height) ||
991 ((prectN->y == prectP->y) &&
992 (prectN->height != prectP->height ||
993 prectN->x < prectP->x + (int) prectP->width)))
994 return -1;
995 }
996 return CT_YXBANDED;
997 }
998 return -1;
999 }
1000
1001 int
SetClipRects(GCPtr pGC,int xOrigin,int yOrigin,int nrects,xRectangle * prects,int ordering)1002 SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects,
1003 xRectangle *prects, int ordering)
1004 {
1005 int newct, size;
1006 xRectangle *prectsNew;
1007
1008 newct = VerifyRectOrder(nrects, prects, ordering);
1009 if (newct < 0)
1010 return BadMatch;
1011 size = nrects * sizeof(xRectangle);
1012 prectsNew = malloc(size);
1013 if (!prectsNew && size)
1014 return BadAlloc;
1015
1016 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT;
1017 pGC->clipOrg.x = xOrigin;
1018 pGC->stateChanges |= GCClipXOrigin;
1019
1020 pGC->clipOrg.y = yOrigin;
1021 pGC->stateChanges |= GCClipYOrigin;
1022
1023 if (size)
1024 memmove((char *) prectsNew, (char *) prects, size);
1025 (*pGC->funcs->ChangeClip) (pGC, newct, (void *) prectsNew, nrects);
1026 if (pGC->funcs->ChangeGC)
1027 (*pGC->funcs->ChangeGC) (pGC,
1028 GCClipXOrigin | GCClipYOrigin | GCClipMask);
1029 return Success;
1030 }
1031
1032 /*
1033 sets reasonable defaults
1034 if we can get a pre-allocated one, use it and mark it as used.
1035 if we can't, create one out of whole cloth (The Velveteen GC -- if
1036 you use it often enough it will become real.)
1037 */
1038 GCPtr
GetScratchGC(unsigned depth,ScreenPtr pScreen)1039 GetScratchGC(unsigned depth, ScreenPtr pScreen)
1040 {
1041 int i;
1042 GCPtr pGC;
1043
1044 for (i = 0; i <= pScreen->numDepths; i++) {
1045 pGC = pScreen->GCperDepth[i];
1046 if (pGC && pGC->depth == depth && !pGC->scratch_inuse) {
1047 pGC->scratch_inuse = TRUE;
1048
1049 pGC->alu = GXcopy;
1050 pGC->planemask = ~0;
1051 pGC->serialNumber = 0;
1052 pGC->fgPixel = 0;
1053 pGC->bgPixel = 1;
1054 pGC->lineWidth = 0;
1055 pGC->lineStyle = LineSolid;
1056 pGC->capStyle = CapButt;
1057 pGC->joinStyle = JoinMiter;
1058 pGC->fillStyle = FillSolid;
1059 pGC->fillRule = EvenOddRule;
1060 pGC->arcMode = ArcChord;
1061 pGC->patOrg.x = 0;
1062 pGC->patOrg.y = 0;
1063 pGC->subWindowMode = ClipByChildren;
1064 pGC->graphicsExposures = FALSE;
1065 pGC->clipOrg.x = 0;
1066 pGC->clipOrg.y = 0;
1067 if (pGC->clientClip)
1068 (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0);
1069 pGC->stateChanges = GCAllBits;
1070 return pGC;
1071 }
1072 }
1073 /* if we make it this far, need to roll our own */
1074 return CreateScratchGC(pScreen, depth);
1075 }
1076
1077 /*
1078 if the gc to free is in the table of pre-existing ones,
1079 mark it as available.
1080 if not, free it for real
1081 */
1082 void
FreeScratchGC(GCPtr pGC)1083 FreeScratchGC(GCPtr pGC)
1084 {
1085 if (pGC->scratch_inuse)
1086 pGC->scratch_inuse = FALSE;
1087 else
1088 FreeGC(pGC, (GContext) 0);
1089 }
1090