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