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