Imported Upstream version 1.15.1
[deb_xorg-server.git] / dix / gc.c
CommitLineData
a09e091a
JB
1/***********************************************************
2
3Copyright 1987, 1998 The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27 All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
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
68extern FontPtr defaultFont;
69
70static Bool CreateDefaultTile(GCPtr pGC);
71
72static unsigned char DefaultDash[2] = { 4, 4 };
73
74void
75ValidateGC(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
122int
123ChangeGC(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
417static 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
428int
429ChangeGCXIDs(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
461static GCPtr
462NewGCObject(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
520BUG:
521 should check for failure to create default tile
522
523*/
524GCPtr
525CreateGC(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
573static Bool
574CreateDefaultTile(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
615int
616CopyGC(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 */
766int
767FreeGC(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,
788since we can't create them without already having a GC. any code
789using the tile or stipple has to set them explicitly anyway,
790since the state of the scratch gc is unknown. This is OK
791because ChangeGC() has to be able to deal with NULL tiles and
792stipples anyway (in case the CreateGC() call has provided a
793value for them -- we can't set the default tile until the
794client-supplied attributes are installed, since the fgPixel
795is what fills the default tile. (maybe this comment should
796go with CreateGC() or ChangeGC().)
797*/
798
799static GCPtr
800CreateScratchGC(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
816void
817FreeGCperDepth(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
832Bool
833CreateGCperDepth(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
862Bool
863CreateDefaultStipple(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
901void
902FreeDefaultStipple(int screenNum)
903{
904 ScreenPtr pScreen = screenInfo.screens[screenNum];
905
906 (*pScreen->DestroyPixmap) (pScreen->PixmapPerDepth[0]);
907}
908
909int
910SetDashes(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
960int
961VerifyRectOrder(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
1002int
1003SetClipRects(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*/
1039GCPtr
1040GetScratchGC(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,
1083mark it as available.
1084 if not, free it for real
1085*/
1086void
1087FreeScratchGC(GCPtr pGC)
1088{
1089 if (pGC->scratch_inuse)
1090 pGC->scratch_inuse = FALSE;
1091 else
1092 FreeGC(pGC, (GContext) 0);
1093}