Home | History | Annotate | Line # | Download | only in src
      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 
     30 static 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
     84 XftDrawDepth (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
    100 XftDrawBitsPerPixel (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 *
    128 XftDrawCreate (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 *
    156 XftDrawCreateBitmap (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 *
    181 XftDrawCreateAlpha (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 
    206 static 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
    235 XftDrawChange (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 *
    252 XftDrawDisplay (XftDraw *draw)
    253 {
    254     return draw->dpy;
    255 }
    256 
    257 _X_EXPORT Drawable
    258 XftDrawDrawable (XftDraw *draw)
    259 {
    260     return draw->drawable;
    261 }
    262 
    263 _X_EXPORT Colormap
    264 XftDrawColormap (XftDraw *draw)
    265 {
    266     return draw->colormap;
    267 }
    268 
    269 _X_EXPORT Visual *
    270 XftDrawVisual (XftDraw *draw)
    271 {
    272     return draw->visual;
    273 }
    274 
    275 _X_EXPORT void
    276 XftDrawDestroy (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
    297 XftDrawSrcPicture (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 
    385 static 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 
    395 static 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 
    436 static 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
    472 XftDrawPicture (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
    482 XftDrawGlyphs (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
    510 XftDrawString8 (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
    540 XftDrawString16 (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
    571 XftDrawString32 (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
    602 XftDrawStringUtf8 (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
    649 XftDrawStringUtf16 (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
    697 XftDrawGlyphSpec (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
    725 XftDrawGlyphFontSpec (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
    761 XftDrawCharSpec (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
    794 XftDrawCharFontSpec (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
    827 XftDrawRect (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
    849 XftDrawSetClip (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
    935 XftDrawSetClipRectangles (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
   1010 XftDrawSetSubwindowMode (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