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