gc.c revision 9ace9065
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 531 /* use the default font and stipple */ 532 pGC->font = defaultFont; 533 defaultFont->refcnt++; 534 pGC->stipple = pGC->pScreen->PixmapPerDepth[0]; 535 pGC->stipple->refcnt++; 536 537 /* this is not a scratch GC */ 538 pGC->scratch_inuse = FALSE; 539 540 /* security creation/labeling check */ 541 *pStatus = XaceHook(XACE_RESOURCE_ACCESS, client, gcid, RT_GC, pGC, 542 RT_NONE, NULL, DixCreateAccess|DixSetAttrAccess); 543 if (*pStatus != Success) 544 goto out; 545 546 pGC->stateChanges = GCAllBits; 547 if (!(*pGC->pScreen->CreateGC)(pGC)) 548 *pStatus = BadAlloc; 549 else if (mask) 550 *pStatus = ChangeGCXIDs(client, pGC, mask, pval); 551 else 552 *pStatus = Success; 553 554out: 555 if (*pStatus != Success) 556 { 557 if (!pGC->tileIsPixel && !pGC->tile.pixmap) 558 pGC->tileIsPixel = TRUE; /* undo special case */ 559 FreeGC(pGC, (XID)0); 560 pGC = (GCPtr)NULL; 561 } 562 563 return pGC; 564} 565 566static Bool 567CreateDefaultTile (GCPtr pGC) 568{ 569 ChangeGCVal tmpval[3]; 570 PixmapPtr pTile; 571 GCPtr pgcScratch; 572 xRectangle rect; 573 CARD16 w, h; 574 575 w = 1; 576 h = 1; 577 (*pGC->pScreen->QueryBestSize)(TileShape, &w, &h, pGC->pScreen); 578 pTile = (PixmapPtr) 579 (*pGC->pScreen->CreatePixmap)(pGC->pScreen, 580 w, h, pGC->depth, 0); 581 pgcScratch = GetScratchGC(pGC->depth, pGC->pScreen); 582 if (!pTile || !pgcScratch) 583 { 584 if (pTile) 585 (*pTile->drawable.pScreen->DestroyPixmap)(pTile); 586 if (pgcScratch) 587 FreeScratchGC(pgcScratch); 588 return FALSE; 589 } 590 tmpval[0].val = GXcopy; 591 tmpval[1].val = pGC->tile.pixel; 592 tmpval[2].val = FillSolid; 593 (void)ChangeGC(NullClient, pgcScratch, GCFunction | GCForeground | GCFillStyle, tmpval); 594 ValidateGC((DrawablePtr)pTile, pgcScratch); 595 rect.x = 0; 596 rect.y = 0; 597 rect.width = w; 598 rect.height = h; 599 (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pTile, pgcScratch, 1, &rect); 600 /* Always remember to free the scratch graphics context after use. */ 601 FreeScratchGC(pgcScratch); 602 603 pGC->tileIsPixel = FALSE; 604 pGC->tile.pixmap = pTile; 605 return TRUE; 606} 607 608int 609CopyGC(GC *pgcSrc, GC *pgcDst, BITS32 mask) 610{ 611 BITS32 index2; 612 BITS32 maskQ; 613 int error = 0; 614 615 if (pgcSrc == pgcDst) 616 return Success; 617 pgcDst->serialNumber |= GC_CHANGE_SERIAL_BIT; 618 pgcDst->stateChanges |= mask; 619 maskQ = mask; 620 while (mask) 621 { 622 index2 = (BITS32) lowbit (mask); 623 mask &= ~index2; 624 switch (index2) 625 { 626 case GCFunction: 627 pgcDst->alu = pgcSrc->alu; 628 break; 629 case GCPlaneMask: 630 pgcDst->planemask = pgcSrc->planemask; 631 break; 632 case GCForeground: 633 pgcDst->fgPixel = pgcSrc->fgPixel; 634 break; 635 case GCBackground: 636 pgcDst->bgPixel = pgcSrc->bgPixel; 637 break; 638 case GCLineWidth: 639 pgcDst->lineWidth = pgcSrc->lineWidth; 640 break; 641 case GCLineStyle: 642 pgcDst->lineStyle = pgcSrc->lineStyle; 643 break; 644 case GCCapStyle: 645 pgcDst->capStyle = pgcSrc->capStyle; 646 break; 647 case GCJoinStyle: 648 pgcDst->joinStyle = pgcSrc->joinStyle; 649 break; 650 case GCFillStyle: 651 pgcDst->fillStyle = pgcSrc->fillStyle; 652 break; 653 case GCFillRule: 654 pgcDst->fillRule = pgcSrc->fillRule; 655 break; 656 case GCTile: 657 { 658 if (EqualPixUnion(pgcDst->tileIsPixel, 659 pgcDst->tile, 660 pgcSrc->tileIsPixel, 661 pgcSrc->tile)) 662 { 663 break; 664 } 665 if (!pgcDst->tileIsPixel) 666 (* pgcDst->pScreen->DestroyPixmap)(pgcDst->tile.pixmap); 667 pgcDst->tileIsPixel = pgcSrc->tileIsPixel; 668 pgcDst->tile = pgcSrc->tile; 669 if (!pgcDst->tileIsPixel) 670 pgcDst->tile.pixmap->refcnt++; 671 break; 672 } 673 case GCStipple: 674 { 675 if (pgcDst->stipple == pgcSrc->stipple) 676 break; 677 if (pgcDst->stipple) 678 (* pgcDst->pScreen->DestroyPixmap)(pgcDst->stipple); 679 pgcDst->stipple = pgcSrc->stipple; 680 if (pgcDst->stipple) 681 pgcDst->stipple->refcnt ++; 682 break; 683 } 684 case GCTileStipXOrigin: 685 pgcDst->patOrg.x = pgcSrc->patOrg.x; 686 break; 687 case GCTileStipYOrigin: 688 pgcDst->patOrg.y = pgcSrc->patOrg.y; 689 break; 690 case GCFont: 691 if (pgcDst->font == pgcSrc->font) 692 break; 693 if (pgcDst->font) 694 CloseFont(pgcDst->font, (Font)0); 695 if ((pgcDst->font = pgcSrc->font) != NullFont) 696 (pgcDst->font)->refcnt++; 697 break; 698 case GCSubwindowMode: 699 pgcDst->subWindowMode = pgcSrc->subWindowMode; 700 break; 701 case GCGraphicsExposures: 702 pgcDst->graphicsExposures = pgcSrc->graphicsExposures; 703 break; 704 case GCClipXOrigin: 705 pgcDst->clipOrg.x = pgcSrc->clipOrg.x; 706 break; 707 case GCClipYOrigin: 708 pgcDst->clipOrg.y = pgcSrc->clipOrg.y; 709 break; 710 case GCClipMask: 711 (* pgcDst->funcs->CopyClip)(pgcDst, pgcSrc); 712 break; 713 case GCDashOffset: 714 pgcDst->dashOffset = pgcSrc->dashOffset; 715 break; 716 case GCDashList: 717 if (pgcSrc->dash == DefaultDash) 718 { 719 if (pgcDst->dash != DefaultDash) 720 { 721 free(pgcDst->dash); 722 pgcDst->numInDashList = pgcSrc->numInDashList; 723 pgcDst->dash = pgcSrc->dash; 724 } 725 } 726 else 727 { 728 unsigned char *dash; 729 unsigned int i; 730 731 dash = malloc(pgcSrc->numInDashList * sizeof(unsigned char)); 732 if (dash) 733 { 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 { 754 if (!CreateDefaultTile (pgcDst)) 755 { 756 pgcDst->fillStyle = FillSolid; 757 error = BadAlloc; 758 } 759 } 760 (*pgcDst->funcs->CopyGC) (pgcSrc, maskQ, pgcDst); 761 return error; 762} 763 764/** 765 * does the diX part of freeing the characteristics in the GC. 766 * 767 * \param value must conform to DeleteType 768 */ 769int 770FreeGC(pointer value, XID gid) 771{ 772 GCPtr pGC = (GCPtr)value; 773 774 CloseFont(pGC->font, (Font)0); 775 (* pGC->funcs->DestroyClip)(pGC); 776 777 if (!pGC->tileIsPixel) 778 (* pGC->pScreen->DestroyPixmap)(pGC->tile.pixmap); 779 if (pGC->stipple) 780 (* pGC->pScreen->DestroyPixmap)(pGC->stipple); 781 782 (*pGC->funcs->DestroyGC) (pGC); 783 if (pGC->dash != DefaultDash) 784 free(pGC->dash); 785 dixFreeObjectWithPrivates(pGC, PRIVATE_GC); 786 return Success; 787} 788 789/* CreateScratchGC(pScreen, depth) 790 like CreateGC, but doesn't do the default tile or stipple, 791since we can't create them without already having a GC. any code 792using the tile or stipple has to set them explicitly anyway, 793since the state of the scratch gc is unknown. This is OK 794because ChangeGC() has to be able to deal with NULL tiles and 795stipples anyway (in case the CreateGC() call has provided a 796value for them -- we can't set the default tile until the 797client-supplied attributes are installed, since the fgPixel 798is what fills the default tile. (maybe this comment should 799go with CreateGC() or ChangeGC().) 800*/ 801 802static GCPtr 803CreateScratchGC(ScreenPtr pScreen, unsigned depth) 804{ 805 GCPtr pGC; 806 807 pGC = dixAllocateObjectWithPrivates(GC, PRIVATE_GC); 808 if (!pGC) 809 return (GCPtr)NULL; 810 811 pGC->pScreen = pScreen; 812 pGC->depth = depth; 813 pGC->alu = GXcopy; /* dst <- src */ 814 pGC->planemask = ~0; 815 pGC->serialNumber = 0; 816 pGC->fgPixel = 0; 817 pGC->bgPixel = 1; 818 pGC->lineWidth = 0; 819 pGC->lineStyle = LineSolid; 820 pGC->capStyle = CapButt; 821 pGC->joinStyle = JoinMiter; 822 pGC->fillStyle = FillSolid; 823 pGC->fillRule = EvenOddRule; 824 pGC->arcMode = ArcPieSlice; 825 pGC->font = defaultFont; 826 if ( pGC->font) /* necessary, because open of default font could fail */ 827 pGC->font->refcnt++; 828 pGC->tileIsPixel = TRUE; 829 pGC->tile.pixel = 0; 830 pGC->tile.pixmap = NullPixmap; 831 pGC->stipple = NullPixmap; 832 pGC->patOrg.x = 0; 833 pGC->patOrg.y = 0; 834 pGC->subWindowMode = ClipByChildren; 835 pGC->graphicsExposures = TRUE; 836 pGC->clipOrg.x = 0; 837 pGC->clipOrg.y = 0; 838 pGC->clientClipType = CT_NONE; 839 pGC->dashOffset = 0; 840 pGC->numInDashList = 2; 841 pGC->dash = DefaultDash; 842 843 /* scratch GCs in the GCperDepth pool start off unused */ 844 pGC->scratch_inuse = FALSE; 845 846 pGC->stateChanges = GCAllBits; 847 if (!(*pScreen->CreateGC)(pGC)) 848 { 849 FreeGC(pGC, (XID)0); 850 pGC = (GCPtr)NULL; 851 } 852 return pGC; 853} 854 855void 856FreeGCperDepth(int screenNum) 857{ 858 int i; 859 ScreenPtr pScreen; 860 GCPtr *ppGC; 861 862 pScreen = screenInfo.screens[screenNum]; 863 ppGC = pScreen->GCperDepth; 864 865 for (i = 0; i <= pScreen->numDepths; i++) 866 { 867 (void)FreeGC(ppGC[i], (XID)0); 868 ppGC[i] = NULL; 869 } 870} 871 872 873Bool 874CreateGCperDepth(int screenNum) 875{ 876 int i; 877 ScreenPtr pScreen; 878 DepthPtr pDepth; 879 GCPtr *ppGC; 880 881 pScreen = screenInfo.screens[screenNum]; 882 ppGC = pScreen->GCperDepth; 883 /* do depth 1 separately because it's not included in list */ 884 if (!(ppGC[0] = CreateScratchGC(pScreen, 1))) 885 return FALSE; 886 ppGC[0]->graphicsExposures = FALSE; 887 /* Make sure we don't overflow GCperDepth[] */ 888 if( pScreen->numDepths > MAXFORMATS ) 889 return FALSE; 890 891 pDepth = pScreen->allowedDepths; 892 for (i=0; i<pScreen->numDepths; i++, pDepth++) 893 { 894 if (!(ppGC[i+1] = CreateScratchGC(pScreen, pDepth->depth))) 895 { 896 for (; i >= 0; i--) 897 (void)FreeGC(ppGC[i], (XID)0); 898 return FALSE; 899 } 900 ppGC[i+1]->graphicsExposures = FALSE; 901 } 902 return TRUE; 903} 904 905Bool 906CreateDefaultStipple(int screenNum) 907{ 908 ScreenPtr pScreen; 909 ChangeGCVal tmpval[3]; 910 xRectangle rect; 911 CARD16 w, h; 912 GCPtr pgcScratch; 913 914 pScreen = screenInfo.screens[screenNum]; 915 916 w = 16; 917 h = 16; 918 (* pScreen->QueryBestSize)(StippleShape, &w, &h, pScreen); 919 if (!(pScreen->PixmapPerDepth[0] = 920 (*pScreen->CreatePixmap)(pScreen, w, h, 1, 0))) 921 return FALSE; 922 /* fill stipple with 1 */ 923 tmpval[0].val = GXcopy; 924 tmpval[1].val = 1; 925 tmpval[2].val = FillSolid; 926 pgcScratch = GetScratchGC(1, pScreen); 927 if (!pgcScratch) 928 { 929 (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]); 930 return FALSE; 931 } 932 (void)ChangeGC(NullClient, pgcScratch, GCFunction|GCForeground|GCFillStyle, tmpval); 933 ValidateGC((DrawablePtr)pScreen->PixmapPerDepth[0], pgcScratch); 934 rect.x = 0; 935 rect.y = 0; 936 rect.width = w; 937 rect.height = h; 938 (*pgcScratch->ops->PolyFillRect)((DrawablePtr)pScreen->PixmapPerDepth[0], 939 pgcScratch, 1, &rect); 940 FreeScratchGC(pgcScratch); 941 return TRUE; 942} 943 944void 945FreeDefaultStipple(int screenNum) 946{ 947 ScreenPtr pScreen = screenInfo.screens[screenNum]; 948 (*pScreen->DestroyPixmap)(pScreen->PixmapPerDepth[0]); 949} 950 951int 952SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash) 953{ 954 long i; 955 unsigned char *p, *indash; 956 BITS32 maskQ = 0; 957 958 i = ndash; 959 p = pdash; 960 while (i--) 961 { 962 if (!*p++) 963 { 964 /* dash segment must be > 0 */ 965 return BadValue; 966 } 967 } 968 969 if (ndash & 1) 970 p = malloc(2 * ndash * sizeof(unsigned char)); 971 else 972 p = malloc(ndash * sizeof(unsigned char)); 973 if (!p) 974 return BadAlloc; 975 976 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; 977 if (offset != pGC->dashOffset) 978 { 979 pGC->dashOffset = offset; 980 pGC->stateChanges |= GCDashOffset; 981 maskQ |= GCDashOffset; 982 } 983 984 if (pGC->dash != DefaultDash) 985 free(pGC->dash); 986 pGC->numInDashList = ndash; 987 pGC->dash = p; 988 if (ndash & 1) 989 { 990 pGC->numInDashList += ndash; 991 indash = pdash; 992 i = ndash; 993 while (i--) 994 *p++ = *indash++; 995 } 996 while(ndash--) 997 *p++ = *pdash++; 998 pGC->stateChanges |= GCDashList; 999 maskQ |= GCDashList; 1000 1001 if (pGC->funcs->ChangeGC) 1002 (*pGC->funcs->ChangeGC) (pGC, maskQ); 1003 return Success; 1004} 1005 1006int 1007VerifyRectOrder(int nrects, xRectangle *prects, int ordering) 1008{ 1009 xRectangle *prectP, *prectN; 1010 int i; 1011 1012 switch(ordering) 1013 { 1014 case Unsorted: 1015 return CT_UNSORTED; 1016 case YSorted: 1017 if(nrects > 1) 1018 { 1019 for(i = 1, prectP = prects, prectN = prects + 1; 1020 i < nrects; 1021 i++, prectP++, prectN++) 1022 if(prectN->y < prectP->y) 1023 return -1; 1024 } 1025 return CT_YSORTED; 1026 case YXSorted: 1027 if(nrects > 1) 1028 { 1029 for(i = 1, prectP = prects, prectN = prects + 1; 1030 i < nrects; 1031 i++, prectP++, prectN++) 1032 if((prectN->y < prectP->y) || 1033 ( (prectN->y == prectP->y) && 1034 (prectN->x < prectP->x) ) ) 1035 return -1; 1036 } 1037 return CT_YXSORTED; 1038 case YXBanded: 1039 if(nrects > 1) 1040 { 1041 for(i = 1, prectP = prects, prectN = prects + 1; 1042 i < nrects; 1043 i++, prectP++, prectN++) 1044 if((prectN->y != prectP->y && 1045 prectN->y < prectP->y + (int) prectP->height) || 1046 ((prectN->y == prectP->y) && 1047 (prectN->height != prectP->height || 1048 prectN->x < prectP->x + (int) prectP->width))) 1049 return -1; 1050 } 1051 return CT_YXBANDED; 1052 } 1053 return -1; 1054} 1055 1056int 1057SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects, 1058 xRectangle *prects, int ordering) 1059{ 1060 int newct, size; 1061 xRectangle *prectsNew; 1062 1063 newct = VerifyRectOrder(nrects, prects, ordering); 1064 if (newct < 0) 1065 return BadMatch; 1066 size = nrects * sizeof(xRectangle); 1067 prectsNew = malloc(size); 1068 if (!prectsNew && size) 1069 return BadAlloc; 1070 1071 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; 1072 pGC->clipOrg.x = xOrigin; 1073 pGC->stateChanges |= GCClipXOrigin; 1074 1075 pGC->clipOrg.y = yOrigin; 1076 pGC->stateChanges |= GCClipYOrigin; 1077 1078 if (size) 1079 memmove((char *)prectsNew, (char *)prects, size); 1080 (*pGC->funcs->ChangeClip)(pGC, newct, (pointer)prectsNew, nrects); 1081 if (pGC->funcs->ChangeGC) 1082 (*pGC->funcs->ChangeGC) (pGC, GCClipXOrigin|GCClipYOrigin|GCClipMask); 1083 return Success; 1084} 1085 1086 1087/* 1088 sets reasonable defaults 1089 if we can get a pre-allocated one, use it and mark it as used. 1090 if we can't, create one out of whole cloth (The Velveteen GC -- if 1091 you use it often enough it will become real.) 1092*/ 1093GCPtr 1094GetScratchGC(unsigned depth, ScreenPtr pScreen) 1095{ 1096 int i; 1097 GCPtr pGC; 1098 1099 for (i=0; i<=pScreen->numDepths; i++) 1100 { 1101 pGC = pScreen->GCperDepth[i]; 1102 if (pGC && pGC->depth == depth && !pGC->scratch_inuse) 1103 { 1104 pGC->scratch_inuse = TRUE; 1105 1106 pGC->alu = GXcopy; 1107 pGC->planemask = ~0; 1108 pGC->serialNumber = 0; 1109 pGC->fgPixel = 0; 1110 pGC->bgPixel = 1; 1111 pGC->lineWidth = 0; 1112 pGC->lineStyle = LineSolid; 1113 pGC->capStyle = CapButt; 1114 pGC->joinStyle = JoinMiter; 1115 pGC->fillStyle = FillSolid; 1116 pGC->fillRule = EvenOddRule; 1117 pGC->arcMode = ArcChord; 1118 pGC->patOrg.x = 0; 1119 pGC->patOrg.y = 0; 1120 pGC->subWindowMode = ClipByChildren; 1121 pGC->graphicsExposures = FALSE; 1122 pGC->clipOrg.x = 0; 1123 pGC->clipOrg.y = 0; 1124 if (pGC->clientClipType != CT_NONE) 1125 (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0); 1126 pGC->stateChanges = GCAllBits; 1127 return pGC; 1128 } 1129 } 1130 /* if we make it this far, need to roll our own */ 1131 pGC = CreateScratchGC(pScreen, depth); 1132 if (pGC) 1133 pGC->graphicsExposures = FALSE; 1134 return pGC; 1135} 1136 1137/* 1138 if the gc to free is in the table of pre-existing ones, 1139mark it as available. 1140 if not, free it for real 1141*/ 1142void 1143FreeScratchGC(GCPtr pGC) 1144{ 1145 if (pGC->scratch_inuse) 1146 pGC->scratch_inuse = FALSE; 1147 else 1148 FreeGC(pGC, (GContext)0); 1149} 1150