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