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 25Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 26 27 All Rights Reserved 28 29Permission to use, copy, modify, and distribute this software and its 30documentation for any purpose and without fee is hereby granted, 31provided that the above copyright notice appear in all copies and that 32both that copyright notice and this permission notice appear in 33supporting documentation, and that the name of Digital not be 34used in advertising or publicity pertaining to distribution of the 35software without specific, written prior permission. 36 37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 43SOFTWARE. 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 68extern FontPtr defaultFont; 69 70static Bool CreateDefaultTile(GCPtr pGC); 71 72static unsigned char DefaultDash[2] = { 4, 4 }; 73 74void 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 * 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 122int 123ChangeGC(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 419static 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 430int 431ChangeGCXIDs(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 463static GCPtr 464NewGCObject(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 521BUG: 522 should check for failure to create default tile 523 524*/ 525GCPtr 526CreateGC(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 574static Bool 575CreateDefaultTile(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 616int 617CopyGC(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 */ 767int 768FreeGC(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, 789since we can't create them without already having a GC. any code 790using the tile or stipple has to set them explicitly anyway, 791since the state of the scratch gc is unknown. This is OK 792because ChangeGC() has to be able to deal with NULL tiles and 793stipples anyway (in case the CreateGC() call has provided a 794value for them -- we can't set the default tile until the 795client-supplied attributes are installed, since the fgPixel 796is what fills the default tile. (maybe this comment should 797go with CreateGC() or ChangeGC().) 798*/ 799 800static GCPtr 801CreateScratchGC(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 else 815 pGC->graphicsExposures = FALSE; 816 return pGC; 817} 818 819void 820FreeGCperDepth(int screenNum) 821{ 822 int i; 823 ScreenPtr pScreen; 824 GCPtr *ppGC; 825 826 pScreen = screenInfo.screens[screenNum]; 827 ppGC = pScreen->GCperDepth; 828 829 for (i = 0; i <= pScreen->numDepths; i++) { 830 (void) FreeGC(ppGC[i], (XID) 0); 831 ppGC[i] = NULL; 832 } 833} 834 835Bool 836CreateGCperDepth(int screenNum) 837{ 838 int i; 839 ScreenPtr pScreen; 840 DepthPtr pDepth; 841 GCPtr *ppGC; 842 843 pScreen = screenInfo.screens[screenNum]; 844 ppGC = pScreen->GCperDepth; 845 /* do depth 1 separately because it's not included in list */ 846 if (!(ppGC[0] = CreateScratchGC(pScreen, 1))) 847 return FALSE; 848 /* Make sure we don't overflow GCperDepth[] */ 849 if (pScreen->numDepths > MAXFORMATS) 850 return FALSE; 851 852 pDepth = pScreen->allowedDepths; 853 for (i = 0; i < pScreen->numDepths; i++, pDepth++) { 854 if (!(ppGC[i + 1] = CreateScratchGC(pScreen, pDepth->depth))) { 855 for (; i >= 0; i--) 856 (void) FreeGC(ppGC[i], (XID) 0); 857 return FALSE; 858 } 859 } 860 return TRUE; 861} 862 863Bool 864CreateDefaultStipple(int screenNum) 865{ 866 ScreenPtr pScreen; 867 ChangeGCVal tmpval[3]; 868 xRectangle rect; 869 CARD16 w, h; 870 GCPtr pgcScratch; 871 872 pScreen = screenInfo.screens[screenNum]; 873 874 w = 16; 875 h = 16; 876 (*pScreen->QueryBestSize) (StippleShape, &w, &h, pScreen); 877 if (!(pScreen->defaultStipple = pScreen->CreatePixmap(pScreen, w, h, 1, 0))) 878 return FALSE; 879 /* fill stipple with 1 */ 880 tmpval[0].val = GXcopy; 881 tmpval[1].val = 1; 882 tmpval[2].val = FillSolid; 883 pgcScratch = GetScratchGC(1, pScreen); 884 if (!pgcScratch) { 885 (*pScreen->DestroyPixmap) (pScreen->defaultStipple); 886 return FALSE; 887 } 888 (void) ChangeGC(NullClient, pgcScratch, 889 GCFunction | GCForeground | GCFillStyle, tmpval); 890 ValidateGC((DrawablePtr) pScreen->defaultStipple, pgcScratch); 891 rect.x = 0; 892 rect.y = 0; 893 rect.width = w; 894 rect.height = h; 895 (*pgcScratch->ops->PolyFillRect) ((DrawablePtr) pScreen->defaultStipple, 896 pgcScratch, 1, &rect); 897 FreeScratchGC(pgcScratch); 898 return TRUE; 899} 900 901void 902FreeDefaultStipple(int screenNum) 903{ 904 ScreenPtr pScreen = screenInfo.screens[screenNum]; 905 906 (*pScreen->DestroyPixmap) (pScreen->defaultStipple); 907} 908 909int 910SetDashes(GCPtr pGC, unsigned offset, unsigned ndash, unsigned char *pdash) 911{ 912 long i; 913 unsigned char *p, *indash; 914 BITS32 maskQ = 0; 915 916 i = ndash; 917 p = pdash; 918 while (i--) { 919 if (!*p++) { 920 /* dash segment must be > 0 */ 921 return BadValue; 922 } 923 } 924 925 if (ndash & 1) 926 p = malloc(2 * ndash * sizeof(unsigned char)); 927 else 928 p = malloc(ndash * sizeof(unsigned char)); 929 if (!p) 930 return BadAlloc; 931 932 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; 933 if (offset != pGC->dashOffset) { 934 pGC->dashOffset = offset; 935 pGC->stateChanges |= GCDashOffset; 936 maskQ |= GCDashOffset; 937 } 938 939 if (pGC->dash != DefaultDash) 940 free(pGC->dash); 941 pGC->numInDashList = ndash; 942 pGC->dash = p; 943 if (ndash & 1) { 944 pGC->numInDashList += ndash; 945 indash = pdash; 946 i = ndash; 947 while (i--) 948 *p++ = *indash++; 949 } 950 while (ndash--) 951 *p++ = *pdash++; 952 pGC->stateChanges |= GCDashList; 953 maskQ |= GCDashList; 954 955 if (pGC->funcs->ChangeGC) 956 (*pGC->funcs->ChangeGC) (pGC, maskQ); 957 return Success; 958} 959 960int 961VerifyRectOrder(int nrects, xRectangle *prects, int ordering) 962{ 963 xRectangle *prectP, *prectN; 964 int i; 965 966 switch (ordering) { 967 case Unsorted: 968 return CT_UNSORTED; 969 case YSorted: 970 if (nrects > 1) { 971 for (i = 1, prectP = prects, prectN = prects + 1; 972 i < nrects; i++, prectP++, prectN++) 973 if (prectN->y < prectP->y) 974 return -1; 975 } 976 return CT_YSORTED; 977 case YXSorted: 978 if (nrects > 1) { 979 for (i = 1, prectP = prects, prectN = prects + 1; 980 i < nrects; i++, prectP++, prectN++) 981 if ((prectN->y < prectP->y) || 982 ((prectN->y == prectP->y) && (prectN->x < prectP->x))) 983 return -1; 984 } 985 return CT_YXSORTED; 986 case YXBanded: 987 if (nrects > 1) { 988 for (i = 1, prectP = prects, prectN = prects + 1; 989 i < nrects; i++, prectP++, prectN++) 990 if ((prectN->y != prectP->y && 991 prectN->y < prectP->y + (int) prectP->height) || 992 ((prectN->y == prectP->y) && 993 (prectN->height != prectP->height || 994 prectN->x < prectP->x + (int) prectP->width))) 995 return -1; 996 } 997 return CT_YXBANDED; 998 } 999 return -1; 1000} 1001 1002int 1003SetClipRects(GCPtr pGC, int xOrigin, int yOrigin, int nrects, 1004 xRectangle *prects, int ordering) 1005{ 1006 int newct, size; 1007 xRectangle *prectsNew; 1008 1009 newct = VerifyRectOrder(nrects, prects, ordering); 1010 if (newct < 0) 1011 return BadMatch; 1012 size = nrects * sizeof(xRectangle); 1013 prectsNew = malloc(size); 1014 if (!prectsNew && size) 1015 return BadAlloc; 1016 1017 pGC->serialNumber |= GC_CHANGE_SERIAL_BIT; 1018 pGC->clipOrg.x = xOrigin; 1019 pGC->stateChanges |= GCClipXOrigin; 1020 1021 pGC->clipOrg.y = yOrigin; 1022 pGC->stateChanges |= GCClipYOrigin; 1023 1024 if (size) 1025 memmove((char *) prectsNew, (char *) prects, size); 1026 (*pGC->funcs->ChangeClip) (pGC, newct, (void *) prectsNew, nrects); 1027 if (pGC->funcs->ChangeGC) 1028 (*pGC->funcs->ChangeGC) (pGC, 1029 GCClipXOrigin | GCClipYOrigin | GCClipMask); 1030 return Success; 1031} 1032 1033/* 1034 sets reasonable defaults 1035 if we can get a pre-allocated one, use it and mark it as used. 1036 if we can't, create one out of whole cloth (The Velveteen GC -- if 1037 you use it often enough it will become real.) 1038*/ 1039GCPtr 1040GetScratchGC(unsigned depth, ScreenPtr pScreen) 1041{ 1042 int i; 1043 GCPtr pGC; 1044 1045 for (i = 0; i <= pScreen->numDepths; i++) { 1046 pGC = pScreen->GCperDepth[i]; 1047 if (pGC && pGC->depth == depth && !pGC->scratch_inuse) { 1048 pGC->scratch_inuse = TRUE; 1049 1050 pGC->alu = GXcopy; 1051 pGC->planemask = ~0; 1052 pGC->serialNumber = 0; 1053 pGC->fgPixel = 0; 1054 pGC->bgPixel = 1; 1055 pGC->lineWidth = 0; 1056 pGC->lineStyle = LineSolid; 1057 pGC->capStyle = CapButt; 1058 pGC->joinStyle = JoinMiter; 1059 pGC->fillStyle = FillSolid; 1060 pGC->fillRule = EvenOddRule; 1061 pGC->arcMode = ArcChord; 1062 pGC->patOrg.x = 0; 1063 pGC->patOrg.y = 0; 1064 pGC->subWindowMode = ClipByChildren; 1065 pGC->graphicsExposures = FALSE; 1066 pGC->clipOrg.x = 0; 1067 pGC->clipOrg.y = 0; 1068 if (pGC->clientClip) 1069 (*pGC->funcs->ChangeClip) (pGC, CT_NONE, NULL, 0); 1070 pGC->stateChanges = GCAllBits; 1071 return pGC; 1072 } 1073 } 1074 /* if we make it this far, need to roll our own */ 1075 return CreateScratchGC(pScreen, depth); 1076} 1077 1078/* 1079 if the gc to free is in the table of pre-existing ones, 1080mark it as available. 1081 if not, free it for real 1082*/ 1083void 1084FreeScratchGC(GCPtr pGC) 1085{ 1086 if (pGC->scratch_inuse) 1087 pGC->scratch_inuse = FALSE; 1088 else 1089 FreeGC(pGC, (GContext) 0); 1090} 1091