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