glyph.c revision ad5464f4
1/* 2 * 3 * Copyright © 2000 SuSE, Inc. 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, and that the name of SuSE not be used in advertising or 10 * publicity pertaining to distribution of the software without specific, 11 * written prior permission. SuSE makes no representations about the 12 * suitability of this software for any purpose. It is provided "as is" 13 * without express or implied warranty. 14 * 15 * SuSE DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL SuSE 17 * BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 18 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 19 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 20 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 21 * 22 * Author: Keith Packard, SuSE, Inc. 23 */ 24 25#ifdef HAVE_DIX_CONFIG_H 26#include <dix-config.h> 27#endif 28 29#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */ 30# include <sha1.h> 31#else /* Use OpenSSL's libcrypto */ 32# include <stddef.h> /* buggy openssl/sha.h wants size_t */ 33# include <openssl/sha.h> 34#endif 35 36#include "misc.h" 37#include "scrnintstr.h" 38#include "os.h" 39#include "regionstr.h" 40#include "validate.h" 41#include "windowstr.h" 42#include "input.h" 43#include "resource.h" 44#include "colormapst.h" 45#include "cursorstr.h" 46#include "dixstruct.h" 47#include "gcstruct.h" 48#include "servermd.h" 49#include "picturestr.h" 50#include "glyphstr.h" 51#include "mipict.h" 52 53/* 54 * From Knuth -- a good choice for hash/rehash values is p, p-2 where 55 * p and p-2 are both prime. These tables are sized to have an extra 10% 56 * free to avoid exponential performance degradation as the hash table fills 57 */ 58static GlyphHashSetRec glyphHashSets[] = { 59 { 32, 43, 41 }, 60 { 64, 73, 71 }, 61 { 128, 151, 149 }, 62 { 256, 283, 281 }, 63 { 512, 571, 569 }, 64 { 1024, 1153, 1151 }, 65 { 2048, 2269, 2267 }, 66 { 4096, 4519, 4517 }, 67 { 8192, 9013, 9011 }, 68 { 16384, 18043, 18041 }, 69 { 32768, 36109, 36107 }, 70 { 65536, 72091, 72089 }, 71 { 131072, 144409, 144407 }, 72 { 262144, 288361, 288359 }, 73 { 524288, 576883, 576881 }, 74 { 1048576, 1153459, 1153457 }, 75 { 2097152, 2307163, 2307161 }, 76 { 4194304, 4613893, 4613891 }, 77 { 8388608, 9227641, 9227639 }, 78 { 16777216, 18455029, 18455027 }, 79 { 33554432, 36911011, 36911009 }, 80 { 67108864, 73819861, 73819859 }, 81 { 134217728, 147639589, 147639587 }, 82 { 268435456, 295279081, 295279079 }, 83 { 536870912, 590559793, 590559791 } 84}; 85 86#define NGLYPHHASHSETS (sizeof(glyphHashSets)/sizeof(glyphHashSets[0])) 87 88static const CARD8 glyphDepths[GlyphFormatNum] = { 1, 4, 8, 16, 32 }; 89 90static GlyphHashRec globalGlyphs[GlyphFormatNum]; 91 92static void 93FreeGlyphPrivates (GlyphPtr glyph) 94{ 95 dixFreePrivates(glyph->devPrivates); 96 glyph->devPrivates = NULL; 97} 98 99void 100GlyphUninit (ScreenPtr pScreen) 101{ 102 PictureScreenPtr ps = GetPictureScreen (pScreen); 103 GlyphPtr glyph; 104 int fdepth, i; 105 106 for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++) 107 { 108 if (!globalGlyphs[fdepth].hashSet) 109 continue; 110 111 for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++) 112 { 113 glyph = globalGlyphs[fdepth].table[i].glyph; 114 if (glyph && glyph != DeletedGlyph) 115 { 116 (*ps->UnrealizeGlyph) (pScreen, glyph); 117 FreeGlyphPrivates(glyph); 118 } 119 } 120 } 121 122 for (fdepth = 0; fdepth < GlyphFormatNum; fdepth++) 123 { 124 if (!globalGlyphs[fdepth].hashSet) 125 continue; 126 127 for (i = 0; i < globalGlyphs[fdepth].hashSet->size; i++) 128 glyph = globalGlyphs[fdepth].table[i].glyph; 129 } 130} 131 132GlyphHashSetPtr 133FindGlyphHashSet (CARD32 filled) 134{ 135 int i; 136 137 for (i = 0; i < NGLYPHHASHSETS; i++) 138 if (glyphHashSets[i].entries >= filled) 139 return &glyphHashSets[i]; 140 return 0; 141} 142 143GlyphRefPtr 144FindGlyphRef (GlyphHashPtr hash, 145 CARD32 signature, 146 Bool match, 147 unsigned char sha1[20]) 148{ 149 CARD32 elt, step, s; 150 GlyphPtr glyph; 151 GlyphRefPtr table, gr, del; 152 CARD32 tableSize = hash->hashSet->size; 153 154 table = hash->table; 155 elt = signature % tableSize; 156 step = 0; 157 del = 0; 158 for (;;) 159 { 160 gr = &table[elt]; 161 s = gr->signature; 162 glyph = gr->glyph; 163 if (!glyph) 164 { 165 if (del) 166 gr = del; 167 break; 168 } 169 if (glyph == DeletedGlyph) 170 { 171 if (!del) 172 del = gr; 173 else if (gr == del) 174 break; 175 } 176 else if (s == signature && 177 (!match || 178 memcmp (glyph->sha1, sha1, 20) == 0)) 179 { 180 break; 181 } 182 if (!step) 183 { 184 step = signature % hash->hashSet->rehash; 185 if (!step) 186 step = 1; 187 } 188 elt += step; 189 if (elt >= tableSize) 190 elt -= tableSize; 191 } 192 return gr; 193} 194 195int 196HashGlyph (xGlyphInfo *gi, 197 CARD8 *bits, 198 unsigned long size, 199 unsigned char sha1[20]) 200{ 201#ifdef HAVE_SHA1_IN_LIBMD /* Use libmd for SHA1 */ 202 SHA1_CTX ctx; 203 204 SHA1Init (&ctx); 205 SHA1Update (&ctx, gi, sizeof (xGlyphInfo)); 206 SHA1Update (&ctx, bits, size); 207 SHA1Final (sha1, &ctx); 208#else /* Use OpenSSL's libcrypto */ 209 SHA_CTX ctx; 210 int success; 211 212 success = SHA1_Init (&ctx); 213 if (! success) 214 return BadAlloc; 215 216 success = SHA1_Update (&ctx, gi, sizeof (xGlyphInfo)); 217 if (! success) 218 return BadAlloc; 219 220 success = SHA1_Update (&ctx, bits, size); 221 if (! success) 222 return BadAlloc; 223 224 success = SHA1_Final (sha1, &ctx); 225 if (! success) 226 return BadAlloc; 227#endif 228 229 return Success; 230} 231 232GlyphPtr 233FindGlyphByHash (unsigned char sha1[20], int format) 234{ 235 GlyphRefPtr gr; 236 CARD32 signature = *(CARD32 *) sha1; 237 238 if (!globalGlyphs[format].hashSet) 239 return NULL; 240 241 gr = FindGlyphRef (&globalGlyphs[format], 242 signature, TRUE, sha1); 243 244 if (gr->glyph && gr->glyph != DeletedGlyph) 245 return gr->glyph; 246 else 247 return NULL; 248} 249 250#ifdef CHECK_DUPLICATES 251void 252DuplicateRef (GlyphPtr glyph, char *where) 253{ 254 ErrorF ("Duplicate Glyph 0x%x from %s\n", glyph, where); 255} 256 257void 258CheckDuplicates (GlyphHashPtr hash, char *where) 259{ 260 GlyphPtr g; 261 int i, j; 262 263 for (i = 0; i < hash->hashSet->size; i++) 264 { 265 g = hash->table[i].glyph; 266 if (!g || g == DeletedGlyph) 267 continue; 268 for (j = i + 1; j < hash->hashSet->size; j++) 269 if (hash->table[j].glyph == g) 270 DuplicateRef (g, where); 271 } 272} 273#else 274#define CheckDuplicates(a,b) 275#define DuplicateRef(a,b) 276#endif 277 278void 279FreeGlyph (GlyphPtr glyph, int format) 280{ 281 CheckDuplicates (&globalGlyphs[format], "FreeGlyph"); 282 if (--glyph->refcnt == 0) 283 { 284 PictureScreenPtr ps; 285 GlyphRefPtr gr; 286 int i; 287 int first; 288 CARD32 signature; 289 290 first = -1; 291 for (i = 0; i < globalGlyphs[format].hashSet->size; i++) 292 if (globalGlyphs[format].table[i].glyph == glyph) 293 { 294 if (first != -1) 295 DuplicateRef (glyph, "FreeGlyph check"); 296 first = i; 297 } 298 299 signature = *(CARD32 *) glyph->sha1; 300 gr = FindGlyphRef (&globalGlyphs[format], signature, 301 TRUE, glyph->sha1); 302 if (gr - globalGlyphs[format].table != first) 303 DuplicateRef (glyph, "Found wrong one"); 304 if (gr->glyph && gr->glyph != DeletedGlyph) 305 { 306 gr->glyph = DeletedGlyph; 307 gr->signature = 0; 308 globalGlyphs[format].tableEntries--; 309 } 310 311 for (i = 0; i < screenInfo.numScreens; i++) 312 { 313 ScreenPtr pScreen = screenInfo.screens[i]; 314 315 FreePicture ((pointer) GlyphPicture (glyph)[i], 0); 316 317 ps = GetPictureScreenIfSet (pScreen); 318 if (ps) 319 (*ps->UnrealizeGlyph) (pScreen, glyph); 320 } 321 322 FreeGlyphPrivates(glyph); 323 xfree (glyph); 324 } 325} 326 327void 328AddGlyph (GlyphSetPtr glyphSet, GlyphPtr glyph, Glyph id) 329{ 330 GlyphRefPtr gr; 331 CARD32 signature; 332 333 CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph top global"); 334 /* Locate existing matching glyph */ 335 signature = *(CARD32 *) glyph->sha1; 336 gr = FindGlyphRef (&globalGlyphs[glyphSet->fdepth], signature, 337 TRUE, glyph->sha1); 338 if (gr->glyph && gr->glyph != DeletedGlyph && gr->glyph != glyph) 339 { 340 PictureScreenPtr ps; 341 int i; 342 343 for (i = 0; i < screenInfo.numScreens; i++) 344 { 345 ps = GetPictureScreenIfSet (screenInfo.screens[i]); 346 if (ps) 347 (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph); 348 } 349 FreeGlyphPrivates(glyph); 350 xfree (glyph); 351 glyph = gr->glyph; 352 } 353 else if (gr->glyph != glyph) 354 { 355 gr->glyph = glyph; 356 gr->signature = signature; 357 globalGlyphs[glyphSet->fdepth].tableEntries++; 358 } 359 360 /* Insert/replace glyphset value */ 361 gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); 362 ++glyph->refcnt; 363 if (gr->glyph && gr->glyph != DeletedGlyph) 364 FreeGlyph (gr->glyph, glyphSet->fdepth); 365 else 366 glyphSet->hash.tableEntries++; 367 gr->glyph = glyph; 368 gr->signature = id; 369 CheckDuplicates (&globalGlyphs[glyphSet->fdepth], "AddGlyph bottom"); 370} 371 372Bool 373DeleteGlyph (GlyphSetPtr glyphSet, Glyph id) 374{ 375 GlyphRefPtr gr; 376 GlyphPtr glyph; 377 378 gr = FindGlyphRef (&glyphSet->hash, id, FALSE, 0); 379 glyph = gr->glyph; 380 if (glyph && glyph != DeletedGlyph) 381 { 382 gr->glyph = DeletedGlyph; 383 glyphSet->hash.tableEntries--; 384 FreeGlyph (glyph, glyphSet->fdepth); 385 return TRUE; 386 } 387 return FALSE; 388} 389 390GlyphPtr 391FindGlyph (GlyphSetPtr glyphSet, Glyph id) 392{ 393 GlyphPtr glyph; 394 395 glyph = FindGlyphRef (&glyphSet->hash, id, FALSE, 0)->glyph; 396 if (glyph == DeletedGlyph) 397 glyph = 0; 398 return glyph; 399} 400 401GlyphPtr 402AllocateGlyph (xGlyphInfo *gi, int fdepth) 403{ 404 PictureScreenPtr ps; 405 int size; 406 GlyphPtr glyph; 407 int i; 408 409 size = screenInfo.numScreens * sizeof (PicturePtr); 410 glyph = (GlyphPtr) xalloc (size + sizeof (GlyphRec)); 411 if (!glyph) 412 return 0; 413 glyph->refcnt = 0; 414 glyph->size = size + sizeof (xGlyphInfo); 415 glyph->info = *gi; 416 glyph->devPrivates = NULL; 417 418 for (i = 0; i < screenInfo.numScreens; i++) 419 { 420 ps = GetPictureScreenIfSet (screenInfo.screens[i]); 421 422 if (ps) 423 { 424 if (!(*ps->RealizeGlyph) (screenInfo.screens[i], glyph)) 425 goto bail; 426 } 427 } 428 429 return glyph; 430 431bail: 432 while (i--) 433 { 434 ps = GetPictureScreenIfSet (screenInfo.screens[i]); 435 if (ps) 436 (*ps->UnrealizeGlyph) (screenInfo.screens[i], glyph); 437 } 438 439 FreeGlyphPrivates(glyph); 440 xfree (glyph); 441 return 0; 442} 443 444Bool 445AllocateGlyphHash (GlyphHashPtr hash, GlyphHashSetPtr hashSet) 446{ 447 hash->table = xcalloc (hashSet->size, sizeof (GlyphRefRec)); 448 if (!hash->table) 449 return FALSE; 450 hash->hashSet = hashSet; 451 hash->tableEntries = 0; 452 return TRUE; 453} 454 455Bool 456ResizeGlyphHash (GlyphHashPtr hash, CARD32 change, Bool global) 457{ 458 CARD32 tableEntries; 459 GlyphHashSetPtr hashSet; 460 GlyphHashRec newHash; 461 GlyphRefPtr gr; 462 GlyphPtr glyph; 463 int i; 464 int oldSize; 465 CARD32 s; 466 467 tableEntries = hash->tableEntries + change; 468 hashSet = FindGlyphHashSet (tableEntries); 469 if (hashSet == hash->hashSet) 470 return TRUE; 471 if (global) 472 CheckDuplicates (hash, "ResizeGlyphHash top"); 473 if (!AllocateGlyphHash (&newHash, hashSet)) 474 return FALSE; 475 if (hash->table) 476 { 477 oldSize = hash->hashSet->size; 478 for (i = 0; i < oldSize; i++) 479 { 480 glyph = hash->table[i].glyph; 481 if (glyph && glyph != DeletedGlyph) 482 { 483 s = hash->table[i].signature; 484 gr = FindGlyphRef (&newHash, s, global, glyph->sha1); 485 gr->signature = s; 486 gr->glyph = glyph; 487 ++newHash.tableEntries; 488 } 489 } 490 xfree (hash->table); 491 } 492 *hash = newHash; 493 if (global) 494 CheckDuplicates (hash, "ResizeGlyphHash bottom"); 495 return TRUE; 496} 497 498Bool 499ResizeGlyphSet (GlyphSetPtr glyphSet, CARD32 change) 500{ 501 return (ResizeGlyphHash (&glyphSet->hash, change, FALSE) && 502 ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], change, TRUE)); 503} 504 505GlyphSetPtr 506AllocateGlyphSet (int fdepth, PictFormatPtr format) 507{ 508 GlyphSetPtr glyphSet; 509 int size; 510 511 if (!globalGlyphs[fdepth].hashSet) 512 { 513 if (!AllocateGlyphHash (&globalGlyphs[fdepth], &glyphHashSets[0])) 514 return FALSE; 515 } 516 517 size = sizeof (GlyphSetRec); 518 glyphSet = xcalloc (1, size); 519 if (!glyphSet) 520 return FALSE; 521 522 if (!AllocateGlyphHash (&glyphSet->hash, &glyphHashSets[0])) 523 { 524 xfree (glyphSet); 525 return FALSE; 526 } 527 glyphSet->refcnt = 1; 528 glyphSet->fdepth = fdepth; 529 glyphSet->format = format; 530 return glyphSet; 531} 532 533int 534FreeGlyphSet (pointer value, 535 XID gid) 536{ 537 GlyphSetPtr glyphSet = (GlyphSetPtr) value; 538 539 if (--glyphSet->refcnt == 0) 540 { 541 CARD32 i, tableSize = glyphSet->hash.hashSet->size; 542 GlyphRefPtr table = glyphSet->hash.table; 543 GlyphPtr glyph; 544 545 for (i = 0; i < tableSize; i++) 546 { 547 glyph = table[i].glyph; 548 if (glyph && glyph != DeletedGlyph) 549 FreeGlyph (glyph, glyphSet->fdepth); 550 } 551 if (!globalGlyphs[glyphSet->fdepth].tableEntries) 552 { 553 xfree (globalGlyphs[glyphSet->fdepth].table); 554 globalGlyphs[glyphSet->fdepth].table = 0; 555 globalGlyphs[glyphSet->fdepth].hashSet = 0; 556 } 557 else 558 ResizeGlyphHash (&globalGlyphs[glyphSet->fdepth], 0, TRUE); 559 xfree (table); 560 dixFreePrivates(glyphSet->devPrivates); 561 xfree (glyphSet); 562 } 563 return Success; 564} 565 566static void 567GlyphExtents (int nlist, 568 GlyphListPtr list, 569 GlyphPtr *glyphs, 570 BoxPtr extents) 571{ 572 int x1, x2, y1, y2; 573 int n; 574 GlyphPtr glyph; 575 int x, y; 576 577 x = 0; 578 y = 0; 579 extents->x1 = MAXSHORT; 580 extents->x2 = MINSHORT; 581 extents->y1 = MAXSHORT; 582 extents->y2 = MINSHORT; 583 while (nlist--) 584 { 585 x += list->xOff; 586 y += list->yOff; 587 n = list->len; 588 list++; 589 while (n--) 590 { 591 glyph = *glyphs++; 592 x1 = x - glyph->info.x; 593 if (x1 < MINSHORT) 594 x1 = MINSHORT; 595 y1 = y - glyph->info.y; 596 if (y1 < MINSHORT) 597 y1 = MINSHORT; 598 x2 = x1 + glyph->info.width; 599 if (x2 > MAXSHORT) 600 x2 = MAXSHORT; 601 y2 = y1 + glyph->info.height; 602 if (y2 > MAXSHORT) 603 y2 = MAXSHORT; 604 if (x1 < extents->x1) 605 extents->x1 = x1; 606 if (x2 > extents->x2) 607 extents->x2 = x2; 608 if (y1 < extents->y1) 609 extents->y1 = y1; 610 if (y2 > extents->y2) 611 extents->y2 = y2; 612 x += glyph->info.xOff; 613 y += glyph->info.yOff; 614 } 615 } 616} 617 618#define NeedsComponent(f) (PICT_FORMAT_A(f) != 0 && PICT_FORMAT_RGB(f) != 0) 619 620_X_EXPORT void 621CompositeGlyphs (CARD8 op, 622 PicturePtr pSrc, 623 PicturePtr pDst, 624 PictFormatPtr maskFormat, 625 INT16 xSrc, 626 INT16 ySrc, 627 int nlist, 628 GlyphListPtr lists, 629 GlyphPtr *glyphs) 630{ 631 PictureScreenPtr ps = GetPictureScreen(pDst->pDrawable->pScreen); 632 633 ValidatePicture (pSrc); 634 ValidatePicture (pDst); 635 (*ps->Glyphs) (op, pSrc, pDst, maskFormat, xSrc, ySrc, nlist, lists, glyphs); 636} 637 638Bool 639miRealizeGlyph (ScreenPtr pScreen, 640 GlyphPtr glyph) 641{ 642 return TRUE; 643} 644 645void 646miUnrealizeGlyph (ScreenPtr pScreen, 647 GlyphPtr glyph) 648{ 649} 650 651_X_EXPORT void 652miGlyphs (CARD8 op, 653 PicturePtr pSrc, 654 PicturePtr pDst, 655 PictFormatPtr maskFormat, 656 INT16 xSrc, 657 INT16 ySrc, 658 int nlist, 659 GlyphListPtr list, 660 GlyphPtr *glyphs) 661{ 662 PicturePtr pPicture; 663 PixmapPtr pMaskPixmap = 0; 664 PicturePtr pMask; 665 ScreenPtr pScreen = pDst->pDrawable->pScreen; 666 int width = 0, height = 0; 667 int x, y; 668 int xDst = list->xOff, yDst = list->yOff; 669 int n; 670 GlyphPtr glyph; 671 int error; 672 BoxRec extents = {0, 0, 0, 0}; 673 CARD32 component_alpha; 674 675 if (maskFormat) 676 { 677 GCPtr pGC; 678 xRectangle rect; 679 680 GlyphExtents (nlist, list, glyphs, &extents); 681 682 if (extents.x2 <= extents.x1 || extents.y2 <= extents.y1) 683 return; 684 width = extents.x2 - extents.x1; 685 height = extents.y2 - extents.y1; 686 pMaskPixmap = (*pScreen->CreatePixmap) (pScreen, width, height, 687 maskFormat->depth, 688 CREATE_PIXMAP_USAGE_SCRATCH); 689 if (!pMaskPixmap) 690 return; 691 component_alpha = NeedsComponent(maskFormat->format); 692 pMask = CreatePicture (0, &pMaskPixmap->drawable, 693 maskFormat, CPComponentAlpha, &component_alpha, 694 serverClient, &error); 695 if (!pMask) 696 { 697 (*pScreen->DestroyPixmap) (pMaskPixmap); 698 return; 699 } 700 pGC = GetScratchGC (pMaskPixmap->drawable.depth, pScreen); 701 ValidateGC (&pMaskPixmap->drawable, pGC); 702 rect.x = 0; 703 rect.y = 0; 704 rect.width = width; 705 rect.height = height; 706 (*pGC->ops->PolyFillRect) (&pMaskPixmap->drawable, pGC, 1, &rect); 707 FreeScratchGC (pGC); 708 x = -extents.x1; 709 y = -extents.y1; 710 } 711 else 712 { 713 pMask = pDst; 714 x = 0; 715 y = 0; 716 } 717 while (nlist--) 718 { 719 x += list->xOff; 720 y += list->yOff; 721 n = list->len; 722 while (n--) 723 { 724 glyph = *glyphs++; 725 pPicture = GlyphPicture (glyph)[pScreen->myNum]; 726 727 if (maskFormat) 728 { 729 CompositePicture (PictOpAdd, 730 pPicture, 731 None, 732 pMask, 733 0, 0, 734 0, 0, 735 x - glyph->info.x, 736 y - glyph->info.y, 737 glyph->info.width, 738 glyph->info.height); 739 } 740 else 741 { 742 CompositePicture (op, 743 pSrc, 744 pPicture, 745 pDst, 746 xSrc + (x - glyph->info.x) - xDst, 747 ySrc + (y - glyph->info.y) - yDst, 748 0, 0, 749 x - glyph->info.x, 750 y - glyph->info.y, 751 glyph->info.width, 752 glyph->info.height); 753 } 754 755 x += glyph->info.xOff; 756 y += glyph->info.yOff; 757 } 758 list++; 759 } 760 if (maskFormat) 761 { 762 x = extents.x1; 763 y = extents.y1; 764 CompositePicture (op, 765 pSrc, 766 pMask, 767 pDst, 768 xSrc + x - xDst, 769 ySrc + y - yDst, 770 0, 0, 771 x, y, 772 width, height); 773 FreePicture ((pointer) pMask, (XID) 0); 774 (*pScreen->DestroyPixmap) (pMaskPixmap); 775 } 776} 777