1/* 2 * Copyright © 2000 Keith Packard 3 * 4 * Permission to use, copy, modify, distribute, and sell this software and its 5 * documentation for any purpose is hereby granted without fee, provided that 6 * the above copyright notice appear in all copies and that both that 7 * copyright notice and this permission notice appear in supporting 8 * documentation, and that the name of Keith Packard not be used in 9 * advertising or publicity pertaining to distribution of the software without 10 * specific, written prior permission. Keith Packard makes no 11 * representations about the suitability of this software for any purpose. It 12 * is provided "as is" without express or implied warranty. 13 * 14 * KEITH PACKARD DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, 15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO 16 * EVENT SHALL KEITH PACKARD BE LIABLE FOR ANY SPECIAL, INDIRECT OR 17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, 18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER 19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 20 * PERFORMANCE OF THIS SOFTWARE. 21 */ 22 23#include "xftint.h" 24 25/* 26 * Ok, this is a pain. To share source pictures across multiple destinations, 27 * the screen for each drawable must be discovered. 28 */ 29 30static int 31_XftDrawScreen (Display *dpy, Drawable drawable, Visual *visual) 32{ 33 int s; 34 Window root; 35 int x, y; 36 unsigned int width, height, borderWidth, depth; 37 /* Special case the most common environment */ 38 if (ScreenCount (dpy) == 1) 39 return 0; 40 /* 41 * If we've got a visual, look for the screen that points at it. 42 * This requires no round trip. 43 */ 44 if (visual) 45 { 46 for (s = 0; s < ScreenCount (dpy); s++) 47 { 48 XVisualInfo template, *ret; 49 int nret; 50 51 template.visualid = visual->visualid; 52 template.screen = s; 53 ret = XGetVisualInfo (dpy, VisualIDMask|VisualScreenMask, 54 &template, &nret); 55 if (ret) 56 { 57 XFree (ret); 58 return s; 59 } 60 } 61 } 62 /* 63 * Otherwise, as the server for the drawable geometry and find 64 * the screen from the root window. 65 * This takes a round trip. 66 */ 67 if (XGetGeometry (dpy, drawable, &root, &x, &y, &width, &height, 68 &borderWidth, &depth)) 69 { 70 for (s = 0; s < ScreenCount (dpy); s++) 71 { 72 if (RootWindow (dpy, s) == root) 73 return s; 74 } 75 } 76 /* 77 * Make a guess -- it's probably wrong, but then the app probably 78 * handed us a bogus drawable in this case 79 */ 80 return 0; 81} 82 83_X_HIDDEN unsigned int 84XftDrawDepth (XftDraw *draw) 85{ 86 if (!draw->depth) 87 { 88 Window root; 89 int x, y; 90 unsigned int width, height, borderWidth, depth; 91 if (XGetGeometry (draw->dpy, draw->drawable, 92 &root, &x, &y, &width, &height, 93 &borderWidth, &depth)) 94 draw->depth = depth; 95 } 96 return draw->depth; 97} 98 99_X_HIDDEN unsigned int 100XftDrawBitsPerPixel (XftDraw *draw) 101{ 102 if (!draw->bits_per_pixel) 103 { 104 XPixmapFormatValues *formats; 105 int nformats; 106 unsigned int depth; 107 108 if ((depth = XftDrawDepth (draw)) && 109 (formats = XListPixmapFormats (draw->dpy, &nformats))) 110 { 111 int i; 112 113 for (i = 0; i < nformats; i++) 114 { 115 if ((unsigned) formats[i].depth == depth) 116 { 117 draw->bits_per_pixel = (unsigned)formats[i].bits_per_pixel; 118 break; 119 } 120 } 121 XFree (formats); 122 } 123 } 124 return draw->bits_per_pixel; 125} 126 127_X_EXPORT XftDraw * 128XftDrawCreate (Display *dpy, 129 Drawable drawable, 130 Visual *visual, 131 Colormap colormap) 132{ 133 XftDraw *draw; 134 135 draw = malloc (sizeof (XftDraw)); 136 if (!draw) 137 return NULL; 138 139 draw->dpy = dpy; 140 draw->drawable = drawable; 141 draw->screen = _XftDrawScreen (dpy, drawable, visual); 142 draw->depth = 0; /* don't find out unless we need to know */ 143 draw->bits_per_pixel = 0; /* don't find out unless we need to know */ 144 draw->visual = visual; 145 draw->colormap = colormap; 146 draw->render.pict = 0; 147 draw->core.gc = NULL; 148 draw->core.use_pixmap = 0; 149 draw->clip_type = XftClipTypeNone; 150 draw->subwindow_mode = ClipByChildren; 151 XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw)); 152 return draw; 153} 154 155_X_EXPORT XftDraw * 156XftDrawCreateBitmap (Display *dpy, 157 Pixmap bitmap) 158{ 159 XftDraw *draw; 160 161 draw = malloc (sizeof (XftDraw)); 162 if (!draw) 163 return NULL; 164 draw->dpy = dpy; 165 draw->drawable = (Drawable) bitmap; 166 draw->screen = _XftDrawScreen (dpy, bitmap, NULL); 167 draw->depth = 1; 168 draw->bits_per_pixel = 1; 169 draw->visual = NULL; 170 draw->colormap = 0; 171 draw->render.pict = 0; 172 draw->core.gc = NULL; 173 draw->core.use_pixmap = 0; 174 draw->clip_type = XftClipTypeNone; 175 draw->subwindow_mode = ClipByChildren; 176 XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw)); 177 return draw; 178} 179 180_X_EXPORT XftDraw * 181XftDrawCreateAlpha (Display *dpy, 182 Pixmap pixmap, 183 int depth) 184{ 185 XftDraw *draw; 186 187 draw = malloc (sizeof (XftDraw)); 188 if (!draw) 189 return NULL; 190 draw->dpy = dpy; 191 draw->drawable = (Drawable) pixmap; 192 draw->screen = _XftDrawScreen (dpy, pixmap, NULL); 193 draw->depth = (unsigned)depth; 194 draw->bits_per_pixel = 0; /* don't find out until we need it */ 195 draw->visual = NULL; 196 draw->colormap = 0; 197 draw->render.pict = 0; 198 draw->core.gc = NULL; 199 draw->core.use_pixmap = 0; 200 draw->clip_type = XftClipTypeNone; 201 draw->subwindow_mode = ClipByChildren; 202 XftMemAlloc (XFT_MEM_DRAW, sizeof (XftDraw)); 203 return draw; 204} 205 206static XRenderPictFormat * 207_XftDrawFormat (XftDraw *draw) 208{ 209 XftDisplayInfo *info = _XftDisplayInfoGet (draw->dpy, True); 210 211 if (!info || !info->hasRender) 212 return NULL; 213 214 if (draw->visual == NULL) 215 { 216 XRenderPictFormat pf; 217 218 pf.type = PictTypeDirect; 219 pf.depth = (int)XftDrawDepth (draw); 220 pf.direct.alpha = 0; 221 pf.direct.alphaMask = (short)((1 << pf.depth) - 1); 222 return XRenderFindFormat (draw->dpy, 223 (PictFormatType| 224 PictFormatDepth| 225 PictFormatAlpha| 226 PictFormatAlphaMask), 227 &pf, 228 0); 229 } 230 else 231 return XRenderFindVisualFormat (draw->dpy, draw->visual); 232} 233 234_X_EXPORT void 235XftDrawChange (XftDraw *draw, 236 Drawable drawable) 237{ 238 draw->drawable = drawable; 239 if (draw->render.pict) 240 { 241 XRenderFreePicture (draw->dpy, draw->render.pict); 242 draw->render.pict = 0; 243 } 244 if (draw->core.gc) 245 { 246 XFreeGC (draw->dpy, draw->core.gc); 247 draw->core.gc = NULL; 248 } 249} 250 251_X_EXPORT Display * 252XftDrawDisplay (XftDraw *draw) 253{ 254 return draw->dpy; 255} 256 257_X_EXPORT Drawable 258XftDrawDrawable (XftDraw *draw) 259{ 260 return draw->drawable; 261} 262 263_X_EXPORT Colormap 264XftDrawColormap (XftDraw *draw) 265{ 266 return draw->colormap; 267} 268 269_X_EXPORT Visual * 270XftDrawVisual (XftDraw *draw) 271{ 272 return draw->visual; 273} 274 275_X_EXPORT void 276XftDrawDestroy (XftDraw *draw) 277{ 278 if (draw->render.pict) 279 XRenderFreePicture (draw->dpy, draw->render.pict); 280 if (draw->core.gc) 281 XFreeGC (draw->dpy, draw->core.gc); 282 switch (draw->clip_type) { 283 case XftClipTypeRegion: 284 XDestroyRegion (draw->clip.region); 285 break; 286 case XftClipTypeRectangles: 287 free (draw->clip.rect); 288 break; 289 case XftClipTypeNone: 290 break; 291 } 292 XftMemFree (XFT_MEM_DRAW, sizeof (XftDraw)); 293 free (draw); 294} 295 296_X_EXPORT Picture 297XftDrawSrcPicture (XftDraw *draw, _Xconst XftColor *color) 298{ 299 Display *dpy = draw->dpy; 300 XftDisplayInfo *info = _XftDisplayInfoGet (dpy, True); 301 int i; 302 XftColor bitmapColor; 303 304 if (!info || !info->solidFormat) 305 return 0; 306 307 /* 308 * Monochrome targets require special handling; the PictOp controls 309 * the color, and the color must be opaque 310 */ 311 if (!draw->visual && draw->depth == 1) 312 { 313 bitmapColor.color.alpha = 0xffff; 314 bitmapColor.color.red = 0xffff; 315 bitmapColor.color.green = 0xffff; 316 bitmapColor.color.blue = 0xffff; 317 color = &bitmapColor; 318 } 319 320 /* 321 * See if there's one already available 322 */ 323 for (i = 0; i < XFT_NUM_SOLID_COLOR; i++) 324 { 325 if (info->colors[i].pict && 326 info->colors[i].screen == draw->screen && 327 !memcmp ((const void *) &color->color, 328 (const void *) &info->colors[i].color, 329 sizeof (XRenderColor))) 330 return info->colors[i].pict; 331 } 332 /* 333 * Pick one to replace at random 334 */ 335 i = (unsigned int) rand () % XFT_NUM_SOLID_COLOR; 336 337 if (info->hasSolid) { 338 /* 339 * Free any existing entry 340 */ 341 if (info->colors[i].pict) 342 XRenderFreePicture (dpy, info->colors[i].pict); 343 /* 344 * Create picture 345 */ 346 info->colors[i].pict = XRenderCreateSolidFill (draw->dpy, &color->color); 347 } else { 348 if (info->colors[i].screen != draw->screen && info->colors[i].pict) 349 { 350 XRenderFreePicture (dpy, info->colors[i].pict); 351 info->colors[i].pict = 0; 352 } 353 /* 354 * Create picture if necessary 355 */ 356 if (!info->colors[i].pict) 357 { 358 Pixmap pix; 359 XRenderPictureAttributes pa; 360 361 pix = XCreatePixmap (dpy, RootWindow (dpy, draw->screen), 1, 1, 362 (unsigned)info->solidFormat->depth); 363 pa.repeat = True; 364 info->colors[i].pict = XRenderCreatePicture (draw->dpy, 365 pix, 366 info->solidFormat, 367 CPRepeat, &pa); 368 XFreePixmap (dpy, pix); 369 } 370 /* 371 * Set to the new color 372 */ 373 info->colors[i].color = color->color; 374 info->colors[i].screen = draw->screen; 375 XRenderFillRectangle (dpy, PictOpSrc, 376 info->colors[i].pict, 377 &color->color, 0, 0, 1, 1); 378 } 379 info->colors[i].color = color->color; 380 info->colors[i].screen = draw->screen; 381 382 return info->colors[i].pict; 383} 384 385static int 386_XftDrawOp (_Xconst XftDraw *draw, _Xconst XftColor *color) 387{ 388 if (draw->visual || draw->depth != 1) 389 return PictOpOver; 390 if (color->color.alpha >= 0x8000) 391 return PictOpOver; 392 return PictOpOutReverse; 393} 394 395static FcBool 396_XftDrawRenderPrepare (XftDraw *draw) 397{ 398 if (!draw->render.pict) 399 { 400 XRenderPictFormat *format; 401 XRenderPictureAttributes pa; 402 unsigned long mask = 0; 403 404 format = _XftDrawFormat (draw); 405 if (!format) 406 return FcFalse; 407 408 if (draw->subwindow_mode == IncludeInferiors) 409 { 410 pa.subwindow_mode = IncludeInferiors; 411 mask |= CPSubwindowMode; 412 } 413 draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable, 414 format, mask, &pa); 415 if (!draw->render.pict) 416 return FcFalse; 417 switch (draw->clip_type) { 418 case XftClipTypeRegion: 419 XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, 420 draw->clip.region); 421 break; 422 case XftClipTypeRectangles: 423 XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict, 424 draw->clip.rect->xOrigin, 425 draw->clip.rect->yOrigin, 426 XftClipRects(draw->clip.rect), 427 draw->clip.rect->n); 428 break; 429 case XftClipTypeNone: 430 break; 431 } 432 } 433 return FcTrue; 434} 435 436static FcBool 437_XftDrawCorePrepare (XftDraw *draw, _Xconst XftColor *color) 438{ 439 if (!draw->core.gc) 440 { 441 XGCValues gcv; 442 unsigned long mask = 0; 443 if (draw->subwindow_mode == IncludeInferiors) 444 { 445 gcv.subwindow_mode = IncludeInferiors; 446 mask |= GCSubwindowMode; 447 } 448 draw->core.gc = XCreateGC (draw->dpy, draw->drawable, mask, &gcv); 449 if (!draw->core.gc) 450 return FcFalse; 451 switch (draw->clip_type) { 452 case XftClipTypeRegion: 453 XSetRegion (draw->dpy, draw->core.gc, draw->clip.region); 454 break; 455 case XftClipTypeRectangles: 456 XSetClipRectangles (draw->dpy, draw->core.gc, 457 draw->clip.rect->xOrigin, 458 draw->clip.rect->yOrigin, 459 XftClipRects (draw->clip.rect), 460 draw->clip.rect->n, 461 Unsorted); 462 break; 463 case XftClipTypeNone: 464 break; 465 } 466 } 467 XSetForeground (draw->dpy, draw->core.gc, color->pixel); 468 return FcTrue; 469} 470 471_X_EXPORT Picture 472XftDrawPicture (XftDraw *draw) 473{ 474 if (!_XftDrawRenderPrepare (draw)) 475 return 0; 476 return draw->render.pict; 477} 478 479#define NUM_LOCAL 1024 480 481_X_EXPORT void 482XftDrawGlyphs (XftDraw *draw, 483 _Xconst XftColor *color, 484 XftFont *pub, 485 int x, 486 int y, 487 _Xconst FT_UInt *glyphs, 488 int nglyphs) 489{ 490 XftFontInt *font = (XftFontInt *) pub; 491 492 if (font->format) 493 { 494 Picture src; 495 496 if (_XftDrawRenderPrepare (draw) && 497 (src = XftDrawSrcPicture (draw, color))) 498 XftGlyphRender (draw->dpy, _XftDrawOp (draw, color), 499 src, pub, draw->render.pict, 500 0, 0, x, y, glyphs, nglyphs); 501 } 502 else 503 { 504 if (_XftDrawCorePrepare (draw, color)) 505 XftGlyphCore (draw, color, pub, x, y, glyphs, nglyphs); 506 } 507} 508 509_X_EXPORT void 510XftDrawString8 (XftDraw *draw, 511 _Xconst XftColor *color, 512 XftFont *pub, 513 int x, 514 int y, 515 _Xconst FcChar8 *string, 516 int len) 517{ 518 FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; 519 int i; 520 521 if (XftDebug () & XFT_DBG_DRAW) 522 printf ("DrawString \"%*.*s\"\n", len, len, string); 523 524 if (len <= NUM_LOCAL) 525 glyphs = glyphs_local; 526 else 527 { 528 glyphs = AllocUIntArray (len); 529 if (!glyphs) 530 return; 531 } 532 for (i = 0; i < len; i++) 533 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]); 534 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len); 535 if (glyphs != glyphs_local) 536 free (glyphs); 537} 538 539_X_EXPORT void 540XftDrawString16 (XftDraw *draw, 541 _Xconst XftColor *color, 542 XftFont *pub, 543 int x, 544 int y, 545 _Xconst FcChar16 *string, 546 int len) 547{ 548 FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; 549 int i; 550 551 if (len <= 0) 552 return; 553 554 if (len <= NUM_LOCAL) 555 glyphs = glyphs_local; 556 else 557 { 558 glyphs = AllocUIntArray (len); 559 if (!glyphs) 560 return; 561 } 562 for (i = 0; i < len; i++) 563 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]); 564 565 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len); 566 if (glyphs != glyphs_local) 567 free (glyphs); 568} 569 570_X_EXPORT void 571XftDrawString32 (XftDraw *draw, 572 _Xconst XftColor *color, 573 XftFont *pub, 574 int x, 575 int y, 576 _Xconst FcChar32 *string, 577 int len) 578{ 579 FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; 580 int i; 581 582 if (len <= 0) 583 return; 584 585 if (len <= NUM_LOCAL) 586 glyphs = glyphs_local; 587 else 588 { 589 glyphs = AllocUIntArray (len); 590 if (!glyphs) 591 return; 592 } 593 for (i = 0; i < len; i++) 594 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]); 595 596 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len); 597 if (glyphs != glyphs_local) 598 free (glyphs); 599} 600 601_X_EXPORT void 602XftDrawStringUtf8 (XftDraw *draw, 603 _Xconst XftColor *color, 604 XftFont *pub, 605 int x, 606 int y, 607 _Xconst FcChar8 *string, 608 int len) 609{ 610 FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL]; 611 FcChar32 ucs4; 612 int i; 613 int l; 614 int size; 615 616 if (len <= 0) 617 return; 618 619 i = 0; 620 glyphs = glyphs_local; 621 size = NUM_LOCAL; 622 while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0) 623 { 624 if (i == size) 625 { 626 glyphs_new = AllocUIntArray (size * 2); 627 if (!glyphs_new) 628 { 629 if (glyphs != glyphs_local) 630 free (glyphs); 631 return; 632 } 633 memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt)); 634 size *= 2; 635 if (glyphs != glyphs_local) 636 free (glyphs); 637 glyphs = glyphs_new; 638 } 639 glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4); 640 string += l; 641 len -= l; 642 } 643 XftDrawGlyphs (draw, color, pub, x, y, glyphs, i); 644 if (glyphs != glyphs_local) 645 free (glyphs); 646} 647 648_X_EXPORT void 649XftDrawStringUtf16 (XftDraw *draw, 650 _Xconst XftColor *color, 651 XftFont *pub, 652 int x, 653 int y, 654 _Xconst FcChar8 *string, 655 FcEndian endian, 656 int len) 657{ 658 FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL]; 659 FcChar32 ucs4; 660 int i; 661 int l; 662 int size; 663 664 if (len <= 0) 665 return; 666 667 i = 0; 668 glyphs = glyphs_local; 669 size = NUM_LOCAL; 670 while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0) 671 { 672 if (i == size) 673 { 674 glyphs_new = AllocUIntArray (size * 2); 675 if (!glyphs_new) 676 { 677 if (glyphs != glyphs_local) 678 free (glyphs); 679 return; 680 } 681 memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt)); 682 size *= 2; 683 if (glyphs != glyphs_local) 684 free (glyphs); 685 glyphs = glyphs_new; 686 } 687 glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4); 688 string += l; 689 len -= l; 690 } 691 XftDrawGlyphs (draw, color, pub, x, y, glyphs, i); 692 if (glyphs != glyphs_local) 693 free (glyphs); 694} 695 696_X_EXPORT void 697XftDrawGlyphSpec (XftDraw *draw, 698 _Xconst XftColor *color, 699 XftFont *pub, 700 _Xconst XftGlyphSpec *glyphs, 701 int len) 702{ 703 XftFontInt *font = (XftFontInt *) pub; 704 705 if (font->format) 706 { 707 Picture src; 708 709 if (_XftDrawRenderPrepare (draw) && 710 (src = XftDrawSrcPicture (draw, color))) 711 { 712 XftGlyphSpecRender (draw->dpy, _XftDrawOp (draw, color), 713 src, pub, draw->render.pict, 714 0, 0, glyphs, len); 715 } 716 } 717 else 718 { 719 if (_XftDrawCorePrepare (draw, color)) 720 XftGlyphSpecCore (draw, color, pub, glyphs, len); 721 } 722} 723 724_X_EXPORT void 725XftDrawGlyphFontSpec (XftDraw *draw, 726 _Xconst XftColor *color, 727 _Xconst XftGlyphFontSpec *glyphs, 728 int len) 729{ 730 int i; 731 int start; 732 733 i = 0; 734 while (i < len) 735 { 736 start = i; 737 if (((XftFontInt *) glyphs[i].font)->format) 738 { 739 Picture src; 740 while (i < len && ((XftFontInt *) glyphs[i].font)->format) 741 i++; 742 if (_XftDrawRenderPrepare (draw) && 743 (src = XftDrawSrcPicture (draw, color))) 744 { 745 XftGlyphFontSpecRender (draw->dpy, _XftDrawOp (draw, color), 746 src, draw->render.pict, 747 0, 0, glyphs + start , i - start); 748 } 749 } 750 else 751 { 752 while (i < len && !((XftFontInt *) glyphs[i].font)->format) 753 i++; 754 if (_XftDrawCorePrepare (draw, color)) 755 XftGlyphFontSpecCore (draw, color, glyphs + start, i - start); 756 } 757 } 758} 759 760_X_EXPORT void 761XftDrawCharSpec (XftDraw *draw, 762 _Xconst XftColor *color, 763 XftFont *pub, 764 _Xconst XftCharSpec *chars, 765 int len) 766{ 767 XftGlyphSpec *glyphs, glyphs_local[NUM_LOCAL]; 768 int i; 769 770 if (len <= 0) 771 return; 772 773 if (len <= NUM_LOCAL) 774 glyphs = glyphs_local; 775 else 776 { 777 glyphs = AllocGlyphSpecArray (len); 778 if (!glyphs) 779 return; 780 } 781 for (i = 0; i < len; i++) 782 { 783 glyphs[i].glyph = XftCharIndex(draw->dpy, pub, chars[i].ucs4); 784 glyphs[i].x = chars[i].x; 785 glyphs[i].y = chars[i].y; 786 } 787 788 XftDrawGlyphSpec (draw, color, pub, glyphs, len); 789 if (glyphs != glyphs_local) 790 free (glyphs); 791} 792 793_X_EXPORT void 794XftDrawCharFontSpec (XftDraw *draw, 795 _Xconst XftColor *color, 796 _Xconst XftCharFontSpec *chars, 797 int len) 798{ 799 XftGlyphFontSpec *glyphs, glyphs_local[NUM_LOCAL]; 800 int i; 801 802 if (len <= 0) 803 return; 804 805 if (len <= NUM_LOCAL) 806 glyphs = glyphs_local; 807 else 808 { 809 glyphs = AllocGlyphFontSpecArray (len); 810 if (!glyphs) 811 return; 812 } 813 for (i = 0; i < len; i++) 814 { 815 glyphs[i].font = chars[i].font; 816 glyphs[i].glyph = XftCharIndex(draw->dpy, glyphs[i].font, chars[i].ucs4); 817 glyphs[i].x = chars[i].x; 818 glyphs[i].y = chars[i].y; 819 } 820 821 XftDrawGlyphFontSpec (draw, color, glyphs, len); 822 if (glyphs != glyphs_local) 823 free (glyphs); 824} 825 826_X_EXPORT void 827XftDrawRect (XftDraw *draw, 828 _Xconst XftColor *color, 829 int x, 830 int y, 831 unsigned int width, 832 unsigned int height) 833{ 834 if (_XftDrawRenderPrepare (draw)) 835 { 836 XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.pict, 837 &color->color, x, y, width, height); 838 } 839 else if (_XftDrawCorePrepare (draw, color)) 840 { 841 /* note: not XftRectCore() */ 842 XSetForeground (draw->dpy, draw->core.gc, color->pixel); 843 XFillRectangle (draw->dpy, draw->drawable, draw->core.gc, 844 x, y, width, height); 845 } 846} 847 848_X_EXPORT Bool 849XftDrawSetClip (XftDraw *draw, 850 Region r) 851{ 852 Region n = NULL; 853 854 /* 855 * Check for quick exits 856 */ 857 if (!r && draw->clip_type == XftClipTypeNone) 858 return True; 859 860 if (r && 861 draw->clip_type == XftClipTypeRegion && 862 XEqualRegion (r, draw->clip.region)) 863 { 864 return True; 865 } 866 867 /* 868 * Duplicate the region so future changes can be short circuited 869 */ 870 if (r) 871 { 872 n = XCreateRegion (); 873 if (n) 874 { 875 if (!XUnionRegion (n, r, n)) 876 { 877 XDestroyRegion (n); 878 return False; 879 } 880 } 881 } 882 883 /* 884 * Destroy existing clip 885 */ 886 switch (draw->clip_type) { 887 case XftClipTypeRegion: 888 XDestroyRegion (draw->clip.region); 889 break; 890 case XftClipTypeRectangles: 891 free (draw->clip.rect); 892 break; 893 case XftClipTypeNone: 894 break; 895 } 896 897 /* 898 * Set the clip 899 */ 900 if (n) 901 { 902 draw->clip_type = XftClipTypeRegion; 903 draw->clip.region = n; 904 } 905 else 906 { 907 draw->clip_type = XftClipTypeNone; 908 } 909 /* 910 * Apply new clip to existing objects 911 */ 912 if (draw->render.pict) 913 { 914 if (n) 915 XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n); 916 else 917 { 918 XRenderPictureAttributes pa; 919 pa.clip_mask = None; 920 XRenderChangePicture (draw->dpy, draw->render.pict, 921 CPClipMask, &pa); 922 } 923 } 924 if (draw->core.gc) 925 { 926 if (n) 927 XSetRegion (draw->dpy, draw->core.gc, draw->clip.region); 928 else 929 XSetClipMask (draw->dpy, draw->core.gc, None); 930 } 931 return True; 932} 933 934_X_EXPORT Bool 935XftDrawSetClipRectangles (XftDraw *draw, 936 int xOrigin, 937 int yOrigin, 938 _Xconst XRectangle *rects, 939 int n) 940{ 941 XftClipRect *new = NULL; 942 943 /* 944 * Check for quick exit 945 */ 946 if (draw->clip_type == XftClipTypeRectangles && 947 draw->clip.rect->n == n && 948 (n == 0 || (draw->clip.rect->xOrigin == xOrigin && 949 draw->clip.rect->yOrigin == yOrigin)) && 950 !memcmp (XftClipRects (draw->clip.rect), rects, (size_t)n * sizeof (XRectangle))) 951 { 952 return True; 953 } 954 955 /* 956 * Duplicate the region so future changes can be short circuited 957 */ 958 new = malloc (sizeof (XftClipRect) + (size_t)n * sizeof (XRectangle)); 959 if (!new) 960 return False; 961 962 new->n = n; 963 new->xOrigin = xOrigin; 964 new->yOrigin = yOrigin; 965 memcpy (XftClipRects (new), rects, (size_t)n * sizeof (XRectangle)); 966 967 /* 968 * Destroy existing clip 969 */ 970 switch (draw->clip_type) { 971 case XftClipTypeRegion: 972 XDestroyRegion (draw->clip.region); 973 break; 974 case XftClipTypeRectangles: 975 free (draw->clip.rect); 976 break; 977 case XftClipTypeNone: 978 break; 979 } 980 981 /* 982 * Set the clip 983 */ 984 draw->clip_type = XftClipTypeRectangles; 985 draw->clip.rect = new; 986 /* 987 * Apply new clip to existing objects 988 */ 989 if (draw->render.pict) 990 { 991 XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict, 992 new->xOrigin, 993 new->yOrigin, 994 XftClipRects(new), 995 new->n); 996 } 997 if (draw->core.gc) 998 { 999 XSetClipRectangles (draw->dpy, draw->core.gc, 1000 new->xOrigin, 1001 new->yOrigin, 1002 XftClipRects (new), 1003 new->n, 1004 Unsorted); 1005 } 1006 return True; 1007} 1008 1009_X_EXPORT void 1010XftDrawSetSubwindowMode (XftDraw *draw, int mode) 1011{ 1012 if (mode == draw->subwindow_mode) 1013 return; 1014 draw->subwindow_mode = mode; 1015 if (draw->render.pict) 1016 { 1017 XRenderPictureAttributes pa; 1018 1019 pa.subwindow_mode = mode; 1020 XRenderChangePicture (draw->dpy, draw->render.pict, 1021 CPSubwindowMode, &pa); 1022 } 1023 if (draw->core.gc) 1024 XSetSubwindowMode (draw->dpy, draw->core.gc, mode); 1025} 1026