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
_XftDrawScreen(Display * dpy,Drawable drawable,Visual * visual)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
XftDrawDepth(XftDraw * draw)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
XftDrawBitsPerPixel(XftDraw * draw)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 (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 *
XftDrawCreate(Display * dpy,Drawable drawable,Visual * visual,Colormap colormap)128 XftDrawCreate (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 *
XftDrawCreateBitmap(Display * dpy,Pixmap bitmap)156 XftDrawCreateBitmap (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 *
XftDrawCreateAlpha(Display * dpy,Pixmap pixmap,int depth)181 XftDrawCreateAlpha (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 
206 static XRenderPictFormat *
_XftDrawFormat(XftDraw * draw)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
XftDrawChange(XftDraw * draw,Drawable drawable)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 *
XftDrawDisplay(XftDraw * draw)252 XftDrawDisplay (XftDraw *draw)
253 {
254     return draw->dpy;
255 }
256 
257 _X_EXPORT Drawable
XftDrawDrawable(XftDraw * draw)258 XftDrawDrawable (XftDraw *draw)
259 {
260     return draw->drawable;
261 }
262 
263 _X_EXPORT Colormap
XftDrawColormap(XftDraw * draw)264 XftDrawColormap (XftDraw *draw)
265 {
266     return draw->colormap;
267 }
268 
269 _X_EXPORT Visual *
XftDrawVisual(XftDraw * draw)270 XftDrawVisual (XftDraw *draw)
271 {
272     return draw->visual;
273 }
274 
275 _X_EXPORT void
XftDrawDestroy(XftDraw * draw)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
XftDrawSrcPicture(XftDraw * draw,_Xconst XftColor * color)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 ((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 
385 static int
_XftDrawOp(_Xconst XftDraw * draw,_Xconst XftColor * color)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
_XftDrawRenderPrepare(XftDraw * draw)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
_XftDrawCorePrepare(XftDraw * draw,_Xconst XftColor * color)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
XftDrawPicture(XftDraw * draw)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
XftDrawGlyphs(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,int x,int y,_Xconst FT_UInt * glyphs,int nglyphs)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
XftDrawString8(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,int x,int y,_Xconst FcChar8 * string,int len)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 = 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
XftDrawString16(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,int x,int y,_Xconst FcChar16 * string,int len)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 <= 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
XftDrawString32(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,int x,int y,_Xconst FcChar32 * string,int len)568 XftDrawString32 (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
XftDrawStringUtf8(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,int x,int y,_Xconst FcChar8 * string,int len)596 XftDrawStringUtf8 (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
XftDrawStringUtf16(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,int x,int y,_Xconst FcChar8 * string,FcEndian endian,int len)640 XftDrawStringUtf16 (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
XftDrawGlyphSpec(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,_Xconst XftGlyphSpec * glyphs,int len)685 XftDrawGlyphSpec (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
XftDrawGlyphFontSpec(XftDraw * draw,_Xconst XftColor * color,_Xconst XftGlyphFontSpec * glyphs,int len)713 XftDrawGlyphFontSpec (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
XftDrawCharSpec(XftDraw * draw,_Xconst XftColor * color,XftFont * pub,_Xconst XftCharSpec * chars,int len)749 XftDrawCharSpec (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
XftDrawCharFontSpec(XftDraw * draw,_Xconst XftColor * color,_Xconst XftCharFontSpec * chars,int len)779 XftDrawCharFontSpec (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
XftDrawRect(XftDraw * draw,_Xconst XftColor * color,int x,int y,unsigned int width,unsigned int height)809 XftDrawRect (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
XftDrawSetClip(XftDraw * draw,Region r)831 XftDrawSetClip (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
XftDrawSetClipRectangles(XftDraw * draw,int xOrigin,int yOrigin,_Xconst XRectangle * rects,int n)917 XftDrawSetClipRectangles (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
XftDrawSetSubwindowMode(XftDraw * draw,int mode)992 XftDrawSetSubwindowMode (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