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