xftdraw.c revision 84febdac
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 (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 = (XftDraw *) 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 = (XftDraw *) 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 = (XftDraw *) 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 ((void *) &color->color, 328 (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 = malloc ((size_t)len * sizeof (FT_UInt)); 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 <= NUM_LOCAL) 552 glyphs = glyphs_local; 553 else 554 { 555 glyphs = malloc ((size_t)len * sizeof (FT_UInt)); 556 if (!glyphs) 557 return; 558 } 559 for (i = 0; i < len; i++) 560 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]); 561 562 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len); 563 if (glyphs != glyphs_local) 564 free (glyphs); 565} 566 567_X_EXPORT void 568XftDrawString32 (XftDraw *draw, 569 _Xconst XftColor *color, 570 XftFont *pub, 571 int x, 572 int y, 573 _Xconst FcChar32 *string, 574 int len) 575{ 576 FT_UInt *glyphs, glyphs_local[NUM_LOCAL]; 577 int i; 578 579 if (len <= NUM_LOCAL) 580 glyphs = glyphs_local; 581 else 582 { 583 glyphs = malloc ((size_t)len * sizeof (FT_UInt)); 584 if (!glyphs) 585 return; 586 } 587 for (i = 0; i < len; i++) 588 glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]); 589 590 XftDrawGlyphs (draw, color, pub, x, y, glyphs, len); 591 if (glyphs != glyphs_local) 592 free (glyphs); 593} 594 595_X_EXPORT void 596XftDrawStringUtf8 (XftDraw *draw, 597 _Xconst XftColor *color, 598 XftFont *pub, 599 int x, 600 int y, 601 _Xconst FcChar8 *string, 602 int len) 603{ 604 FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL]; 605 FcChar32 ucs4; 606 int i; 607 int l; 608 int size; 609 610 i = 0; 611 glyphs = glyphs_local; 612 size = NUM_LOCAL; 613 while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0) 614 { 615 if (i == size) 616 { 617 glyphs_new = malloc ((size_t)size * 2 * sizeof (FT_UInt)); 618 if (!glyphs_new) 619 { 620 if (glyphs != glyphs_local) 621 free (glyphs); 622 return; 623 } 624 memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt)); 625 size *= 2; 626 if (glyphs != glyphs_local) 627 free (glyphs); 628 glyphs = glyphs_new; 629 } 630 glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4); 631 string += l; 632 len -= l; 633 } 634 XftDrawGlyphs (draw, color, pub, x, y, glyphs, i); 635 if (glyphs != glyphs_local) 636 free (glyphs); 637} 638 639_X_EXPORT void 640XftDrawStringUtf16 (XftDraw *draw, 641 _Xconst XftColor *color, 642 XftFont *pub, 643 int x, 644 int y, 645 _Xconst FcChar8 *string, 646 FcEndian endian, 647 int len) 648{ 649 FT_UInt *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL]; 650 FcChar32 ucs4; 651 int i; 652 int l; 653 int size; 654 655 i = 0; 656 glyphs = glyphs_local; 657 size = NUM_LOCAL; 658 while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0) 659 { 660 if (i == size) 661 { 662 glyphs_new = malloc ((size_t)size * 2 * sizeof (FT_UInt)); 663 if (!glyphs_new) 664 { 665 if (glyphs != glyphs_local) 666 free (glyphs); 667 return; 668 } 669 memcpy (glyphs_new, glyphs, (size_t)size * sizeof (FT_UInt)); 670 size *= 2; 671 if (glyphs != glyphs_local) 672 free (glyphs); 673 glyphs = glyphs_new; 674 } 675 glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4); 676 string += l; 677 len -= l; 678 } 679 XftDrawGlyphs (draw, color, pub, x, y, glyphs, i); 680 if (glyphs != glyphs_local) 681 free (glyphs); 682} 683 684_X_EXPORT void 685XftDrawGlyphSpec (XftDraw *draw, 686 _Xconst XftColor *color, 687 XftFont *pub, 688 _Xconst XftGlyphSpec *glyphs, 689 int len) 690{ 691 XftFontInt *font = (XftFontInt *) pub; 692 693 if (font->format) 694 { 695 Picture src; 696 697 if (_XftDrawRenderPrepare (draw) && 698 (src = XftDrawSrcPicture (draw, color))) 699 { 700 XftGlyphSpecRender (draw->dpy, _XftDrawOp (draw, color), 701 src, pub, draw->render.pict, 702 0, 0, glyphs, len); 703 } 704 } 705 else 706 { 707 if (_XftDrawCorePrepare (draw, color)) 708 XftGlyphSpecCore (draw, color, pub, glyphs, len); 709 } 710} 711 712_X_EXPORT void 713XftDrawGlyphFontSpec (XftDraw *draw, 714 _Xconst XftColor *color, 715 _Xconst XftGlyphFontSpec *glyphs, 716 int len) 717{ 718 int i; 719 int start; 720 721 i = 0; 722 while (i < len) 723 { 724 start = i; 725 if (((XftFontInt *) glyphs[i].font)->format) 726 { 727 Picture src; 728 while (i < len && ((XftFontInt *) glyphs[i].font)->format) 729 i++; 730 if (_XftDrawRenderPrepare (draw) && 731 (src = XftDrawSrcPicture (draw, color))) 732 { 733 XftGlyphFontSpecRender (draw->dpy, _XftDrawOp (draw, color), 734 src, draw->render.pict, 735 0, 0, glyphs + start , i - start); 736 } 737 } 738 else 739 { 740 while (i < len && !((XftFontInt *) glyphs[i].font)->format) 741 i++; 742 if (_XftDrawCorePrepare (draw, color)) 743 XftGlyphFontSpecCore (draw, color, glyphs + start, i - start); 744 } 745 } 746} 747 748_X_EXPORT void 749XftDrawCharSpec (XftDraw *draw, 750 _Xconst XftColor *color, 751 XftFont *pub, 752 _Xconst XftCharSpec *chars, 753 int len) 754{ 755 XftGlyphSpec *glyphs, glyphs_local[NUM_LOCAL]; 756 int i; 757 758 if (len <= NUM_LOCAL) 759 glyphs = glyphs_local; 760 else 761 { 762 glyphs = malloc ((size_t)len * sizeof (XftGlyphSpec)); 763 if (!glyphs) 764 return; 765 } 766 for (i = 0; i < len; i++) 767 { 768 glyphs[i].glyph = XftCharIndex(draw->dpy, pub, chars[i].ucs4); 769 glyphs[i].x = chars[i].x; 770 glyphs[i].y = chars[i].y; 771 } 772 773 XftDrawGlyphSpec (draw, color, pub, glyphs, len); 774 if (glyphs != glyphs_local) 775 free (glyphs); 776} 777 778_X_EXPORT void 779XftDrawCharFontSpec (XftDraw *draw, 780 _Xconst XftColor *color, 781 _Xconst XftCharFontSpec *chars, 782 int len) 783{ 784 XftGlyphFontSpec *glyphs, glyphs_local[NUM_LOCAL]; 785 int i; 786 787 if (len <= NUM_LOCAL) 788 glyphs = glyphs_local; 789 else 790 { 791 glyphs = malloc ((size_t)len * sizeof (XftGlyphFontSpec)); 792 if (!glyphs) 793 return; 794 } 795 for (i = 0; i < len; i++) 796 { 797 glyphs[i].font = chars[i].font; 798 glyphs[i].glyph = XftCharIndex(draw->dpy, glyphs[i].font, chars[i].ucs4); 799 glyphs[i].x = chars[i].x; 800 glyphs[i].y = chars[i].y; 801 } 802 803 XftDrawGlyphFontSpec (draw, color, glyphs, len); 804 if (glyphs != glyphs_local) 805 free (glyphs); 806} 807 808_X_EXPORT void 809XftDrawRect (XftDraw *draw, 810 _Xconst XftColor *color, 811 int x, 812 int y, 813 unsigned int width, 814 unsigned int height) 815{ 816 if (_XftDrawRenderPrepare (draw)) 817 { 818 XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.pict, 819 &color->color, x, y, width, height); 820 } 821 else if (_XftDrawCorePrepare (draw, color)) 822 { 823 /* note: not XftRectCore() */ 824 XSetForeground (draw->dpy, draw->core.gc, color->pixel); 825 XFillRectangle (draw->dpy, draw->drawable, draw->core.gc, 826 x, y, width, height); 827 } 828} 829 830_X_EXPORT Bool 831XftDrawSetClip (XftDraw *draw, 832 Region r) 833{ 834 Region n = NULL; 835 836 /* 837 * Check for quick exits 838 */ 839 if (!r && draw->clip_type == XftClipTypeNone) 840 return True; 841 842 if (r && 843 draw->clip_type == XftClipTypeRegion && 844 XEqualRegion (r, draw->clip.region)) 845 { 846 return True; 847 } 848 849 /* 850 * Duplicate the region so future changes can be short circuited 851 */ 852 if (r) 853 { 854 n = XCreateRegion (); 855 if (n) 856 { 857 if (!XUnionRegion (n, r, n)) 858 { 859 XDestroyRegion (n); 860 return False; 861 } 862 } 863 } 864 865 /* 866 * Destroy existing clip 867 */ 868 switch (draw->clip_type) { 869 case XftClipTypeRegion: 870 XDestroyRegion (draw->clip.region); 871 break; 872 case XftClipTypeRectangles: 873 free (draw->clip.rect); 874 break; 875 case XftClipTypeNone: 876 break; 877 } 878 879 /* 880 * Set the clip 881 */ 882 if (n) 883 { 884 draw->clip_type = XftClipTypeRegion; 885 draw->clip.region = n; 886 } 887 else 888 { 889 draw->clip_type = XftClipTypeNone; 890 } 891 /* 892 * Apply new clip to existing objects 893 */ 894 if (draw->render.pict) 895 { 896 if (n) 897 XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n); 898 else 899 { 900 XRenderPictureAttributes pa; 901 pa.clip_mask = None; 902 XRenderChangePicture (draw->dpy, draw->render.pict, 903 CPClipMask, &pa); 904 } 905 } 906 if (draw->core.gc) 907 { 908 if (n) 909 XSetRegion (draw->dpy, draw->core.gc, draw->clip.region); 910 else 911 XSetClipMask (draw->dpy, draw->core.gc, None); 912 } 913 return True; 914} 915 916_X_EXPORT Bool 917XftDrawSetClipRectangles (XftDraw *draw, 918 int xOrigin, 919 int yOrigin, 920 _Xconst XRectangle *rects, 921 int n) 922{ 923 XftClipRect *new = NULL; 924 925 /* 926 * Check for quick exit 927 */ 928 if (draw->clip_type == XftClipTypeRectangles && 929 draw->clip.rect->n == n && 930 (n == 0 || (draw->clip.rect->xOrigin == xOrigin && 931 draw->clip.rect->yOrigin == yOrigin)) && 932 !memcmp (XftClipRects (draw->clip.rect), rects, (size_t)n * sizeof (XRectangle))) 933 { 934 return True; 935 } 936 937 /* 938 * Duplicate the region so future changes can be short circuited 939 */ 940 new = malloc (sizeof (XftClipRect) + (size_t)n * sizeof (XRectangle)); 941 if (!new) 942 return False; 943 944 new->n = n; 945 new->xOrigin = xOrigin; 946 new->yOrigin = yOrigin; 947 memcpy (XftClipRects (new), rects, (size_t)n * sizeof (XRectangle)); 948 949 /* 950 * Destroy existing clip 951 */ 952 switch (draw->clip_type) { 953 case XftClipTypeRegion: 954 XDestroyRegion (draw->clip.region); 955 break; 956 case XftClipTypeRectangles: 957 free (draw->clip.rect); 958 break; 959 case XftClipTypeNone: 960 break; 961 } 962 963 /* 964 * Set the clip 965 */ 966 draw->clip_type = XftClipTypeRectangles; 967 draw->clip.rect = new; 968 /* 969 * Apply new clip to existing objects 970 */ 971 if (draw->render.pict) 972 { 973 XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict, 974 new->xOrigin, 975 new->yOrigin, 976 XftClipRects(new), 977 new->n); 978 } 979 if (draw->core.gc) 980 { 981 XSetClipRectangles (draw->dpy, draw->core.gc, 982 new->xOrigin, 983 new->yOrigin, 984 XftClipRects (new), 985 new->n, 986 Unsorted); 987 } 988 return True; 989} 990 991_X_EXPORT void 992XftDrawSetSubwindowMode (XftDraw *draw, int mode) 993{ 994 if (mode == draw->subwindow_mode) 995 return; 996 draw->subwindow_mode = mode; 997 if (draw->render.pict) 998 { 999 XRenderPictureAttributes pa; 1000 1001 pa.subwindow_mode = mode; 1002 XRenderChangePicture (draw->dpy, draw->render.pict, 1003 CPSubwindowMode, &pa); 1004 } 1005 if (draw->core.gc) 1006 XSetSubwindowMode (draw->dpy, draw->core.gc, mode); 1007} 1008