upload tizen2.0 source
[framework/uifw/xorg/lib/libxft.git] / src / xftdraw.c
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 (formats[i].depth == depth)
116                 {
117                     draw->bits_per_pixel = 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 = (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 *
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 *
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 = 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 = XftDrawDepth (draw);
220         pf.direct.alpha = 0;
221         pf.direct.alphaMask = (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 ((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      * Recreate if it was for the wrong screen
338      */
339     if (info->colors[i].screen != draw->screen && info->colors[i].pict)
340     {
341         XRenderFreePicture (dpy, info->colors[i].pict);
342         info->colors[i].pict = 0;
343     }
344     /*
345      * Create picture if necessary
346      */
347     if (!info->colors[i].pict)
348     {
349         Pixmap                      pix;
350         XRenderPictureAttributes    pa;
351
352         pix = XCreatePixmap (dpy, RootWindow (dpy, draw->screen), 1, 1,
353                              info->solidFormat->depth);
354         pa.repeat = True;
355         info->colors[i].pict = XRenderCreatePicture (draw->dpy,
356                                                      pix,
357                                                      info->solidFormat,
358                                                      CPRepeat, &pa);
359         XFreePixmap (dpy, pix);
360     }
361     /*
362      * Set to the new color
363      */
364     info->colors[i].color = color->color;
365     info->colors[i].screen = draw->screen;
366     XRenderFillRectangle (dpy, PictOpSrc,
367                           info->colors[i].pict,
368                           &color->color, 0, 0, 1, 1);
369     return info->colors[i].pict;
370 }
371
372 static int
373 _XftDrawOp (_Xconst XftDraw *draw, _Xconst XftColor *color)
374 {
375     if (draw->visual || draw->depth != 1)
376         return PictOpOver;
377     if (color->color.alpha >= 0x8000)
378         return PictOpOver;
379     return PictOpOutReverse;
380 }
381
382 static FcBool
383 _XftDrawRenderPrepare (XftDraw  *draw)
384 {
385     if (!draw->render.pict)
386     {
387         XRenderPictFormat           *format;
388         XRenderPictureAttributes    pa;
389         unsigned long               mask = 0;
390
391         format = _XftDrawFormat (draw);
392         if (!format)
393             return FcFalse;
394
395         if (draw->subwindow_mode == IncludeInferiors)
396         {
397             pa.subwindow_mode = IncludeInferiors;
398             mask |= CPSubwindowMode;
399         }
400         draw->render.pict = XRenderCreatePicture (draw->dpy, draw->drawable,
401                                                   format, mask, &pa);
402         if (!draw->render.pict)
403             return FcFalse;
404         switch (draw->clip_type) {
405         case XftClipTypeRegion:
406             XRenderSetPictureClipRegion (draw->dpy, draw->render.pict,
407                                          draw->clip.region);
408             break;
409         case XftClipTypeRectangles:
410             XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
411                                              draw->clip.rect->xOrigin,
412                                              draw->clip.rect->yOrigin,
413                                              XftClipRects(draw->clip.rect),
414                                              draw->clip.rect->n);
415             break;
416         case XftClipTypeNone:
417             break;
418         }
419     }
420     return FcTrue;
421 }
422
423 static FcBool
424 _XftDrawCorePrepare (XftDraw *draw, _Xconst XftColor *color)
425 {
426     if (!draw->core.gc)
427     {
428         XGCValues       gcv;
429         unsigned long   mask = 0;
430         if (draw->subwindow_mode == IncludeInferiors)
431         {
432             gcv.subwindow_mode = IncludeInferiors;
433             mask |= GCSubwindowMode;
434         }
435         draw->core.gc = XCreateGC (draw->dpy, draw->drawable, mask, &gcv);
436         if (!draw->core.gc)
437             return FcFalse;
438         switch (draw->clip_type) {
439         case XftClipTypeRegion:
440             XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
441             break;
442         case XftClipTypeRectangles:
443             XSetClipRectangles (draw->dpy, draw->core.gc,
444                                 draw->clip.rect->xOrigin,
445                                 draw->clip.rect->yOrigin,
446                                 XftClipRects (draw->clip.rect),
447                                 draw->clip.rect->n,
448                                 Unsorted);
449             break;
450         case XftClipTypeNone:
451             break;
452         }
453     }
454     XSetForeground (draw->dpy, draw->core.gc, color->pixel);
455     return FcTrue;
456 }
457
458 _X_EXPORT Picture
459 XftDrawPicture (XftDraw *draw)
460 {
461     if (!_XftDrawRenderPrepare (draw))
462         return 0;
463     return draw->render.pict;
464 }
465
466 #define NUM_LOCAL   1024
467
468 _X_EXPORT void
469 XftDrawGlyphs (XftDraw          *draw,
470                _Xconst XftColor *color,
471                XftFont          *pub,
472                int              x,
473                int              y,
474                _Xconst FT_UInt  *glyphs,
475                int              nglyphs)
476 {
477     XftFontInt  *font = (XftFontInt *) pub;
478
479     if (font->format)
480     {
481         Picture     src;
482
483         if (_XftDrawRenderPrepare (draw) &&
484             (src = XftDrawSrcPicture (draw, color)))
485             XftGlyphRender (draw->dpy, _XftDrawOp (draw, color),
486                              src, pub, draw->render.pict,
487                              0, 0, x, y, glyphs, nglyphs);
488     }
489     else
490     {
491         if (_XftDrawCorePrepare (draw, color))
492             XftGlyphCore (draw, color, pub, x, y, glyphs, nglyphs);
493     }
494 }
495
496 _X_EXPORT void
497 XftDrawString8 (XftDraw             *draw,
498                 _Xconst XftColor    *color,
499                 XftFont             *pub,
500                 int                 x,
501                 int                 y,
502                 _Xconst FcChar8     *string,
503                 int                 len)
504 {
505     FT_UInt         *glyphs, glyphs_local[NUM_LOCAL];
506     int             i;
507
508     if (XftDebug () & XFT_DBG_DRAW)
509         printf ("DrawString \"%*.*s\"\n", len, len, string);
510
511     if (len <= NUM_LOCAL)
512         glyphs = glyphs_local;
513     else
514     {
515         glyphs = malloc (len * sizeof (FT_UInt));
516         if (!glyphs)
517             return;
518     }
519     for (i = 0; i < len; i++)
520         glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
521     XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
522     if (glyphs != glyphs_local)
523         free (glyphs);
524 }
525
526 _X_EXPORT void
527 XftDrawString16 (XftDraw            *draw,
528                  _Xconst XftColor   *color,
529                  XftFont            *pub,
530                  int                x,
531                  int                y,
532                  _Xconst FcChar16   *string,
533                  int                len)
534 {
535     FT_UInt         *glyphs, glyphs_local[NUM_LOCAL];
536     int             i;
537
538     if (len <= NUM_LOCAL)
539         glyphs = glyphs_local;
540     else
541     {
542         glyphs = malloc (len * sizeof (FT_UInt));
543         if (!glyphs)
544             return;
545     }
546     for (i = 0; i < len; i++)
547         glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
548
549     XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
550     if (glyphs != glyphs_local)
551         free (glyphs);
552 }
553
554 _X_EXPORT void
555 XftDrawString32 (XftDraw            *draw,
556                  _Xconst XftColor   *color,
557                  XftFont            *pub,
558                  int                x,
559                  int                y,
560                  _Xconst FcChar32   *string,
561                  int                len)
562 {
563     FT_UInt         *glyphs, glyphs_local[NUM_LOCAL];
564     int             i;
565
566     if (len <= NUM_LOCAL)
567         glyphs = glyphs_local;
568     else
569     {
570         glyphs = malloc (len * sizeof (FT_UInt));
571         if (!glyphs)
572             return;
573     }
574     for (i = 0; i < len; i++)
575         glyphs[i] = XftCharIndex (draw->dpy, pub, string[i]);
576
577     XftDrawGlyphs (draw, color, pub, x, y, glyphs, len);
578     if (glyphs != glyphs_local)
579         free (glyphs);
580 }
581
582 _X_EXPORT void
583 XftDrawStringUtf8 (XftDraw          *draw,
584                    _Xconst XftColor *color,
585                    XftFont          *pub,
586                    int              x,
587                    int              y,
588                    _Xconst FcChar8  *string,
589                    int              len)
590 {
591     FT_UInt         *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
592     FcChar32        ucs4;
593     int             i;
594     int             l;
595     int             size;
596
597     i = 0;
598     glyphs = glyphs_local;
599     size = NUM_LOCAL;
600     while (len && (l = FcUtf8ToUcs4 (string, &ucs4, len)) > 0)
601     {
602         if (i == size)
603         {
604             glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
605             if (!glyphs_new)
606             {
607                 if (glyphs != glyphs_local)
608                     free (glyphs);
609                 return;
610             }
611             memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
612             size *= 2;
613             if (glyphs != glyphs_local)
614                 free (glyphs);
615             glyphs = glyphs_new;
616         }
617         glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
618         string += l;
619         len -= l;
620     }
621     XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
622     if (glyphs != glyphs_local)
623         free (glyphs);
624 }
625
626 _X_EXPORT void
627 XftDrawStringUtf16 (XftDraw             *draw,
628                     _Xconst XftColor    *color,
629                     XftFont             *pub,
630                     int                 x,
631                     int                 y,
632                     _Xconst FcChar8     *string,
633                     FcEndian            endian,
634                     int                 len)
635 {
636     FT_UInt         *glyphs, *glyphs_new, glyphs_local[NUM_LOCAL];
637     FcChar32        ucs4;
638     int             i;
639     int             l;
640     int             size;
641
642     i = 0;
643     glyphs = glyphs_local;
644     size = NUM_LOCAL;
645     while (len && (l = FcUtf16ToUcs4 (string, endian, &ucs4, len)) > 0)
646     {
647         if (i == size)
648         {
649             glyphs_new = malloc (size * 2 * sizeof (FT_UInt));
650             if (!glyphs_new)
651             {
652                 if (glyphs != glyphs_local)
653                     free (glyphs);
654                 return;
655             }
656             memcpy (glyphs_new, glyphs, size * sizeof (FT_UInt));
657             size *= 2;
658             if (glyphs != glyphs_local)
659                 free (glyphs);
660             glyphs = glyphs_new;
661         }
662         glyphs[i++] = XftCharIndex (draw->dpy, pub, ucs4);
663         string += l;
664         len -= l;
665     }
666     XftDrawGlyphs (draw, color, pub, x, y, glyphs, i);
667     if (glyphs != glyphs_local)
668         free (glyphs);
669 }
670
671 _X_EXPORT void
672 XftDrawGlyphSpec (XftDraw               *draw,
673                   _Xconst XftColor      *color,
674                   XftFont               *pub,
675                   _Xconst XftGlyphSpec  *glyphs,
676                   int                   len)
677 {
678     XftFontInt  *font = (XftFontInt *) pub;
679
680     if (font->format)
681     {
682         Picture src;
683
684         if (_XftDrawRenderPrepare (draw) &&
685             (src = XftDrawSrcPicture (draw, color)))
686         {
687             XftGlyphSpecRender (draw->dpy, _XftDrawOp (draw, color),
688                                 src, pub, draw->render.pict,
689                                 0, 0, glyphs, len);
690         }
691     }
692     else
693     {
694         if (_XftDrawCorePrepare (draw, color))
695             XftGlyphSpecCore (draw, color, pub, glyphs, len);
696     }
697 }
698
699 _X_EXPORT void
700 XftDrawGlyphFontSpec (XftDraw                   *draw,
701                       _Xconst XftColor          *color,
702                       _Xconst XftGlyphFontSpec  *glyphs,
703                       int                       len)
704 {
705     int         i;
706     int         start;
707
708     i = 0;
709     while (i < len)
710     {
711         start = i;
712         if (((XftFontInt *) glyphs[i].font)->format)
713         {
714             Picture     src;
715             while (i < len && ((XftFontInt *) glyphs[i].font)->format)
716                 i++;
717             if (_XftDrawRenderPrepare (draw) &&
718                 (src = XftDrawSrcPicture (draw, color)))
719             {
720                 XftGlyphFontSpecRender (draw->dpy, _XftDrawOp (draw, color),
721                                         src, draw->render.pict,
722                                         0, 0, glyphs + start , i - start);
723             }
724         }
725         else
726         {
727             while (i < len && !((XftFontInt *) glyphs[i].font)->format)
728                 i++;
729             if (_XftDrawCorePrepare (draw, color))
730                 XftGlyphFontSpecCore (draw, color, glyphs + start, i - start);
731         }
732     }
733 }
734
735 _X_EXPORT void
736 XftDrawCharSpec (XftDraw                *draw,
737                  _Xconst XftColor       *color,
738                  XftFont                *pub,
739                  _Xconst XftCharSpec    *chars,
740                  int                    len)
741 {
742     XftGlyphSpec    *glyphs, glyphs_local[NUM_LOCAL];
743     int             i;
744
745     if (len <= NUM_LOCAL)
746         glyphs = glyphs_local;
747     else
748     {
749         glyphs = malloc (len * sizeof (XftGlyphSpec));
750         if (!glyphs)
751             return;
752     }
753     for (i = 0; i < len; i++)
754     {
755         glyphs[i].glyph = XftCharIndex(draw->dpy, pub, chars[i].ucs4);
756         glyphs[i].x = chars[i].x;
757         glyphs[i].y = chars[i].y;
758     }
759
760     XftDrawGlyphSpec (draw, color, pub, glyphs, len);
761     if (glyphs != glyphs_local)
762         free (glyphs);
763 }
764
765 _X_EXPORT void
766 XftDrawCharFontSpec (XftDraw                    *draw,
767                      _Xconst XftColor           *color,
768                      _Xconst XftCharFontSpec    *chars,
769                      int                        len)
770 {
771     XftGlyphFontSpec    *glyphs, glyphs_local[NUM_LOCAL];
772     int                 i;
773
774     if (len <= NUM_LOCAL)
775         glyphs = glyphs_local;
776     else
777     {
778         glyphs = malloc (len * sizeof (XftGlyphFontSpec));
779         if (!glyphs)
780             return;
781     }
782     for (i = 0; i < len; i++)
783     {
784         glyphs[i].font = chars[i].font;
785         glyphs[i].glyph = XftCharIndex(draw->dpy, glyphs[i].font, chars[i].ucs4);
786         glyphs[i].x = chars[i].x;
787         glyphs[i].y = chars[i].y;
788     }
789
790     XftDrawGlyphFontSpec (draw, color, glyphs, len);
791     if (glyphs != glyphs_local)
792         free (glyphs);
793 }
794
795 _X_EXPORT void
796 XftDrawRect (XftDraw            *draw,
797              _Xconst XftColor   *color,
798              int                x,
799              int                y,
800              unsigned int       width,
801              unsigned int       height)
802 {
803     if (_XftDrawRenderPrepare (draw))
804     {
805         XRenderFillRectangle (draw->dpy, PictOpSrc, draw->render.pict,
806                               &color->color, x, y, width, height);
807     }
808     else if (_XftDrawCorePrepare (draw, color))
809     {
810         /* note: not XftRectCore() */
811         XSetForeground (draw->dpy, draw->core.gc, color->pixel);
812         XFillRectangle (draw->dpy, draw->drawable, draw->core.gc,
813                         x, y, width, height);
814     }
815 }
816
817 _X_EXPORT Bool
818 XftDrawSetClip (XftDraw *draw,
819                 Region  r)
820 {
821     Region                      n = NULL;
822
823     /*
824      * Check for quick exits
825      */
826     if (!r && draw->clip_type == XftClipTypeNone)
827         return True;
828
829     if (r &&
830         draw->clip_type == XftClipTypeRegion &&
831         XEqualRegion (r, draw->clip.region))
832     {
833         return True;
834     }
835
836     /*
837      * Duplicate the region so future changes can be short circuited
838      */
839     if (r)
840     {
841         n = XCreateRegion ();
842         if (n)
843         {
844             if (!XUnionRegion (n, r, n))
845             {
846                 XDestroyRegion (n);
847                 return False;
848             }
849         }
850     }
851
852     /*
853      * Destroy existing clip
854      */
855     switch (draw->clip_type) {
856     case XftClipTypeRegion:
857         XDestroyRegion (draw->clip.region);
858         break;
859     case XftClipTypeRectangles:
860         free (draw->clip.rect);
861         break;
862     case XftClipTypeNone:
863         break;
864     }
865
866     /*
867      * Set the clip
868      */
869     if (n)
870     {
871         draw->clip_type = XftClipTypeRegion;
872         draw->clip.region = n;
873     }
874     else
875     {
876         draw->clip_type = XftClipTypeNone;
877     }
878     /*
879      * Apply new clip to existing objects
880      */
881     if (draw->render.pict)
882     {
883         if (n)
884             XRenderSetPictureClipRegion (draw->dpy, draw->render.pict, n);
885         else
886         {
887             XRenderPictureAttributes    pa;
888             pa.clip_mask = None;
889             XRenderChangePicture (draw->dpy, draw->render.pict,
890                                   CPClipMask, &pa);
891         }
892     }
893     if (draw->core.gc)
894     {
895         if (n)
896             XSetRegion (draw->dpy, draw->core.gc, draw->clip.region);
897         else
898             XSetClipMask (draw->dpy, draw->core.gc, None);
899     }
900     return True;
901 }
902
903 _X_EXPORT Bool
904 XftDrawSetClipRectangles (XftDraw               *draw,
905                           int                   xOrigin,
906                           int                   yOrigin,
907                           _Xconst XRectangle    *rects,
908                           int                   n)
909 {
910     XftClipRect *new = NULL;
911
912     /*
913      * Check for quick exit
914      */
915     if (draw->clip_type == XftClipTypeRectangles &&
916         draw->clip.rect->n == n &&
917         (n == 0 || (draw->clip.rect->xOrigin == xOrigin &&
918                     draw->clip.rect->yOrigin == yOrigin)) &&
919         !memcmp (XftClipRects (draw->clip.rect), rects, n * sizeof (XRectangle)))
920     {
921         return True;
922     }
923
924     /*
925      * Duplicate the region so future changes can be short circuited
926      */
927     new = malloc (sizeof (XftClipRect) + n * sizeof (XRectangle));
928     if (!new)
929         return False;
930
931     new->n = n;
932     new->xOrigin = xOrigin;
933     new->yOrigin = yOrigin;
934     memcpy (XftClipRects (new), rects, n * sizeof (XRectangle));
935
936     /*
937      * Destroy existing clip
938      */
939     switch (draw->clip_type) {
940     case XftClipTypeRegion:
941         XDestroyRegion (draw->clip.region);
942         break;
943     case XftClipTypeRectangles:
944         free (draw->clip.rect);
945         break;
946     case XftClipTypeNone:
947         break;
948     }
949
950     /*
951      * Set the clip
952      */
953     draw->clip_type = XftClipTypeRectangles;
954     draw->clip.rect = new;
955     /*
956      * Apply new clip to existing objects
957      */
958     if (draw->render.pict)
959     {
960         XRenderSetPictureClipRectangles (draw->dpy, draw->render.pict,
961                                          new->xOrigin,
962                                          new->yOrigin,
963                                          XftClipRects(new),
964                                          new->n);
965     }
966     if (draw->core.gc)
967     {
968         XSetClipRectangles (draw->dpy, draw->core.gc,
969                             new->xOrigin,
970                             new->yOrigin,
971                             XftClipRects (new),
972                             new->n,
973                             Unsorted);
974     }
975     return True;
976 }
977
978 _X_EXPORT void
979 XftDrawSetSubwindowMode (XftDraw *draw, int mode)
980 {
981     if (mode == draw->subwindow_mode)
982         return;
983     draw->subwindow_mode = mode;
984     if (draw->render.pict)
985     {
986         XRenderPictureAttributes    pa;
987
988         pa.subwindow_mode = mode;
989         XRenderChangePicture (draw->dpy, draw->render.pict,
990                               CPSubwindowMode, &pa);
991     }
992     if (draw->core.gc)
993         XSetSubwindowMode (draw->dpy, draw->core.gc, mode);
994 }