Git init
[external/pango1.0.git] / pango / pangoxft-render.c
1 /* Pango
2  * pangoxft-render.c: Rendering routines for the Xft library
3  *
4  * Copyright (C) 2004 Red Hat Software
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 #include "config.h"
23 #include <math.h>
24
25 #include "pangoxft-render.h"
26 #include "pangoxft-private.h"
27
28 enum {
29   PROP_0,
30   PROP_DISPLAY,
31   PROP_SCREEN
32 };
33
34 struct _PangoXftRendererPrivate
35 {
36   PangoColor default_color;
37   guint16 alpha;
38
39   Picture src_picture;
40   Picture dest_picture;
41
42   XRenderPictFormat *mask_format;
43
44   GArray *trapezoids;
45   PangoRenderPart trapezoid_part;
46
47   GArray *glyphs;
48   PangoFont *glyph_font;
49 };
50
51 static void pango_xft_renderer_finalize     (GObject      *object);
52 static void pango_xft_renderer_set_property (GObject      *object,
53                                              guint         prop_id,
54                                              const GValue *value,
55                                              GParamSpec   *pspec);
56
57 static void pango_xft_renderer_real_composite_trapezoids (PangoXftRenderer *xftrenderer,
58                                                           PangoRenderPart   part,
59                                                           XTrapezoid       *trapezoids,
60                                                           int               n_trapezoids);
61 static void pango_xft_renderer_real_composite_glyphs     (PangoXftRenderer *xftrenderer,
62                                                           XftFont          *xft_font,
63                                                           XftGlyphSpec     *glyphs,
64                                                           int               n_glyphs);
65
66 static void pango_xft_renderer_draw_glyphs    (PangoRenderer    *renderer,
67                                                PangoFont        *font,
68                                                PangoGlyphString *glyphs,
69                                                int               x,
70                                                int               y);
71 static void pango_xft_renderer_draw_trapezoid (PangoRenderer    *renderer,
72                                                PangoRenderPart   part,
73                                                double            y1,
74                                                double            x11,
75                                                double            x21,
76                                                double            y2,
77                                                double            x12,
78                                                double            x22);
79 static void pango_xft_renderer_part_changed   (PangoRenderer    *renderer,
80                                                PangoRenderPart   part);
81 static void pango_xft_renderer_end            (PangoRenderer    *renderer);
82
83 static void flush_trapezoids (PangoXftRenderer *xftrenderer);
84 static void flush_glyphs (PangoXftRenderer *xftrenderer);
85
86 G_DEFINE_TYPE (PangoXftRenderer, pango_xft_renderer, PANGO_TYPE_RENDERER)
87
88 static void
89 pango_xft_renderer_init (PangoXftRenderer *xftrenderer)
90 {
91   xftrenderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (xftrenderer,
92                                                    PANGO_TYPE_XFT_RENDERER,
93                                                    PangoXftRendererPrivate);
94   xftrenderer->priv->alpha = 0xffff;
95 }
96
97 static void
98 pango_xft_renderer_class_init (PangoXftRendererClass *klass)
99 {
100   GObjectClass *object_class = G_OBJECT_CLASS (klass);
101   PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
102
103   klass->composite_glyphs = pango_xft_renderer_real_composite_glyphs;
104   klass->composite_trapezoids = pango_xft_renderer_real_composite_trapezoids;
105
106   renderer_class->draw_glyphs = pango_xft_renderer_draw_glyphs;
107   renderer_class->draw_trapezoid = pango_xft_renderer_draw_trapezoid;
108   renderer_class->part_changed = pango_xft_renderer_part_changed;
109   renderer_class->end = pango_xft_renderer_end;
110
111   object_class->finalize = pango_xft_renderer_finalize;
112   object_class->set_property = pango_xft_renderer_set_property;
113
114   g_object_class_install_property (object_class, PROP_DISPLAY,
115                                    g_param_spec_pointer ("display",
116                                                          "Display",
117                                                          "The display being rendered to",
118                                                          G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
119   g_object_class_install_property (object_class, PROP_SCREEN,
120                                    g_param_spec_int ("screen",
121                                                      "Screen",
122                                                      "The screen being rendered to",
123                                                      0, G_MAXINT, 0,
124                                                      G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY));
125
126   g_type_class_add_private (object_class, sizeof (PangoXftRendererPrivate));
127 }
128
129 static void
130 pango_xft_renderer_finalize (GObject *object)
131 {
132   PangoXftRenderer *renderer = PANGO_XFT_RENDERER (object);
133
134   if (renderer->priv->glyphs)
135     g_array_free (renderer->priv->glyphs, TRUE);
136   if (renderer->priv->trapezoids)
137     g_array_free (renderer->priv->trapezoids, TRUE);
138
139   G_OBJECT_CLASS (pango_xft_renderer_parent_class)->finalize (object);
140 }
141
142 static void
143 pango_xft_renderer_set_property (GObject      *object,
144                                  guint         prop_id,
145                                  const GValue *value,
146                                  GParamSpec   *pspec)
147 {
148   PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (object);
149
150   switch (prop_id)
151     {
152     case PROP_DISPLAY:
153       xftrenderer->display = g_value_get_pointer (value);
154       /* We possibly should use ARGB format when subpixel-AA is turned
155        * on for the fontmap; we could discover that using the technique
156        * for FC_DPI in pango_fc_face_list_sizes.
157        */
158       xftrenderer->priv->mask_format = XRenderFindStandardFormat (xftrenderer->display,
159                                                                   PictStandardA8);
160       break;
161     case PROP_SCREEN:
162       xftrenderer->screen = g_value_get_int (value);
163       break;
164     default:
165       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
166       break;
167     }
168 }
169
170 static void
171 pango_xft_renderer_set_pictures (PangoXftRenderer *renderer,
172                                  Picture           src_picture,
173                                  Picture           dest_picture)
174 {
175   renderer->priv->src_picture = src_picture;
176   renderer->priv->dest_picture = dest_picture;
177 }
178
179 static void
180 flush_glyphs (PangoXftRenderer *xftrenderer)
181 {
182   XftFont *xft_font;
183
184   if (!xftrenderer->priv->glyphs ||
185       xftrenderer->priv->glyphs->len == 0)
186     return;
187
188   xft_font = pango_xft_font_get_font (xftrenderer->priv->glyph_font);
189
190   PANGO_XFT_RENDERER_GET_CLASS (xftrenderer)->composite_glyphs (xftrenderer,
191                                                                 xft_font,
192                                                                 (XftGlyphSpec *)xftrenderer->priv->glyphs->data,
193                                                                 xftrenderer->priv->glyphs->len);
194
195   g_array_set_size (xftrenderer->priv->glyphs, 0);
196   g_object_unref (xftrenderer->priv->glyph_font);
197   xftrenderer->priv->glyph_font = NULL;
198 }
199
200 #define MAX_GLYPHS      1024
201
202 static void
203 draw_glyph (PangoRenderer *renderer,
204             PangoFont     *font,
205             FT_UInt        glyph,
206             int            x,
207             int            y)
208 {
209   PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer);
210   XftGlyphSpec gs;
211   int pixel_x, pixel_y;
212
213   if (renderer->matrix)
214     {
215       pixel_x = floor (0.5 + (x * renderer->matrix->xx + y * renderer->matrix->xy) / PANGO_SCALE + renderer->matrix->x0);
216       pixel_y = floor (0.5 + (x * renderer->matrix->yx + y * renderer->matrix->yy) / PANGO_SCALE + renderer->matrix->y0);
217     }
218   else
219     {
220       pixel_x = PANGO_PIXELS (x);
221       pixel_y = PANGO_PIXELS (y);
222     }
223
224   /* Clip glyphs into the X coordinate range; we really
225    * want to clip glyphs with an ink rect outside the
226    * [0,32767] x [0,32767] rectangle but looking up
227    * the ink rect here would be a noticeable speed hit.
228    * This is close enough.
229    */
230   if (pixel_x < -32768 || pixel_x > 32767 ||
231       pixel_y < -32768 || pixel_y > 32767)
232     return;
233
234   flush_trapezoids (xftrenderer);
235
236   if (!xftrenderer->priv->glyphs)
237     xftrenderer->priv->glyphs = g_array_new (FALSE, FALSE,
238                                              sizeof (XftGlyphSpec));
239
240   if (xftrenderer->priv->glyph_font != font ||
241       xftrenderer->priv->glyphs->len == MAX_GLYPHS)
242     {
243       flush_glyphs (xftrenderer);
244
245       xftrenderer->priv->glyph_font = g_object_ref (font);
246     }
247
248   gs.x = pixel_x;
249   gs.y = pixel_y;
250   gs.glyph = glyph;
251
252   g_array_append_val (xftrenderer->priv->glyphs, gs);
253 }
254
255 static gboolean
256 point_in_bounds (PangoRenderer *renderer,
257                  gint           x,
258                  gint           y)
259 {
260   gdouble pixel_x = (x * renderer->matrix->xx + y * renderer->matrix->xy) / PANGO_SCALE + renderer->matrix->x0;
261   gdouble pixel_y = (x * renderer->matrix->yx + y * renderer->matrix->yy) / PANGO_SCALE + renderer->matrix->y0;
262
263   return (pixel_x >= -32768. && pixel_x < 32768. &&
264           pixel_y >= -32768. && pixel_y < 32768.);
265 }
266
267 static gboolean
268 box_in_bounds (PangoRenderer *renderer,
269                gint           x,
270                gint           y,
271                gint           width,
272                gint           height)
273 {
274   if (!renderer->matrix)
275     {
276 #define COORD_MIN (PANGO_SCALE * -16384 - PANGO_SCALE / 2)
277 #define COORD_MAX (PANGO_SCALE * 32767 + PANGO_SCALE / 2 - 1)
278       return (x >= COORD_MIN && x + width <= COORD_MAX &&
279               y >= COORD_MIN && y + width <= COORD_MAX);
280 #undef COORD_MIN
281 #undef COORD_MAX
282     }
283   else
284     {
285       return (point_in_bounds (renderer, x, y) &&
286               point_in_bounds (renderer, x + width, y) &&
287               point_in_bounds (renderer, x + width, y + height) &&
288               point_in_bounds (renderer, x, y + height));
289     }
290 }
291
292 static void
293 get_total_matrix (PangoMatrix       *total,
294                   const PangoMatrix *global,
295                   double             x,
296                   double             y,
297                   double             width,
298                   double             height)
299 {
300   PangoMatrix local = PANGO_MATRIX_INIT;
301   gdouble angle = atan2 (height, width);
302
303   pango_matrix_translate (&local, x, y);
304   pango_matrix_rotate (&local, -angle * (180. / G_PI));
305
306   *total = *global;
307   pango_matrix_concat (total, &local);
308 }
309
310 static void
311 draw_box (PangoRenderer *renderer,
312           gint           line_width,
313           gint           x,
314           gint           y,
315           gint           width,
316           gint           height,
317           gboolean       invalid)
318 {
319   pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
320                                  x, y, width, line_width);
321   pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
322                                  x, y + line_width, line_width, height - line_width * 2);
323   pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
324                                  x + width - line_width, y + line_width, line_width, height - line_width * 2);
325   pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
326                                  x, y + height - line_width, width, line_width);
327
328   if (invalid)
329     {
330       int length;
331       double in_width, in_height;
332       PangoMatrix orig_matrix = PANGO_MATRIX_INIT, new_matrix;
333       const PangoMatrix *porig_matrix;
334
335       in_width  = pango_units_to_double (width  - 2 * line_width);
336       in_height = pango_units_to_double (height - 2 * line_width);
337       length = PANGO_SCALE * sqrt (in_width*in_width + in_height*in_height);
338
339       porig_matrix = pango_renderer_get_matrix (renderer);
340       if (porig_matrix)
341         {
342           orig_matrix = *porig_matrix;
343           porig_matrix = &orig_matrix;
344         }
345
346       get_total_matrix (&new_matrix, &orig_matrix,
347                         pango_units_to_double (x + line_width), pango_units_to_double (y + line_width),
348                         in_width, in_height);
349       pango_renderer_set_matrix (renderer, &new_matrix);
350       pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
351                                      0, -line_width / 2, length, line_width);
352
353       get_total_matrix (&new_matrix, &orig_matrix,
354                         pango_units_to_double (x + line_width), pango_units_to_double (y + height - line_width),
355                         in_width, -in_height);
356       pango_renderer_set_matrix (renderer, &new_matrix);
357       pango_renderer_draw_rectangle (renderer, PANGO_RENDER_PART_FOREGROUND,
358                                      0, -line_width / 2, length, line_width);
359
360       pango_renderer_set_matrix (renderer, porig_matrix);
361     }
362 }
363
364 static void
365 _pango_xft_renderer_draw_box_glyph (PangoRenderer    *renderer,
366                                     PangoGlyphInfo   *gi,
367                                     int               glyph_x,
368                                     int               glyph_y,
369                                     gboolean          invalid)
370 {
371   int x = glyph_x + PANGO_SCALE;
372   int y = glyph_y - PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT - 1);
373   int width = gi->geometry.width - PANGO_SCALE * 2;
374   int height = PANGO_SCALE * (PANGO_UNKNOWN_GLYPH_HEIGHT - 2);
375
376   if (box_in_bounds (renderer, x, y, width, height))
377     draw_box (renderer, PANGO_SCALE, x, y, width, height, invalid);
378 }
379
380 static void
381 _pango_xft_renderer_draw_unknown_glyph (PangoRenderer    *renderer,
382                                         PangoXftFont     *xfont,
383                                         XftFont          *xft_font,
384                                         PangoGlyphInfo   *gi,
385                                         int               glyph_x,
386                                         int               glyph_y)
387 {
388   char buf[7];
389   int ys[3];
390   int xs[4];
391   int row, col;
392   int cols;
393   gunichar ch;
394   gboolean invalid_input;
395
396   PangoFont *mini_font;
397   XftFont *mini_xft_font;
398
399   ch = gi->glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
400   if (G_UNLIKELY (gi->glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF))
401     {
402       invalid_input = TRUE;
403       cols = 1;
404     }
405   else
406     {
407       invalid_input = FALSE;
408       cols = ch > 0xffff ? 3 : 2;
409       g_snprintf (buf, sizeof(buf), (ch > 0xffff) ? "%06X" : "%04X", ch);
410     }
411
412   mini_font = _pango_xft_font_get_mini_font (xfont);
413   mini_xft_font = pango_xft_font_get_font (mini_font);
414   if (!mini_xft_font)
415     {
416       _pango_xft_renderer_draw_box_glyph (renderer, gi, glyph_x, glyph_y, invalid_input);
417       return;
418     }
419
420
421   ys[0] = glyph_y - PANGO_SCALE * xft_font->ascent + PANGO_SCALE * (((xft_font->ascent + xft_font->descent) - (xfont->mini_height * 2 + xfont->mini_pad * 5 + PANGO_SCALE / 2) / PANGO_SCALE) / 2);
422   ys[1] = ys[0] + 2 * xfont->mini_pad + xfont->mini_height;
423   ys[2] = ys[1] + xfont->mini_height + xfont->mini_pad;
424
425   xs[0] = glyph_x;
426   xs[1] = xs[0] + 2 * xfont->mini_pad;
427   xs[2] = xs[1] + xfont->mini_width + xfont->mini_pad;
428   xs[3] = xs[2] + xfont->mini_width + xfont->mini_pad;
429
430   if (box_in_bounds (renderer,
431                      xs[0], ys[0],
432                      xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1),
433                      xfont->mini_height * 2 + xfont->mini_pad * 5))
434     {
435       if (xfont->mini_pad)
436         draw_box (renderer, xfont->mini_pad,
437                   xs[0], ys[0],
438                   xfont->mini_width * cols + xfont->mini_pad * (2 * cols + 1),
439                   xfont->mini_height * 2 + xfont->mini_pad * 5,
440                   invalid_input);
441
442       if (invalid_input)
443         return;
444
445       for (row = 0; row < 2; row++)
446         for (col = 0; col < cols; col++)
447           {
448             draw_glyph (renderer, mini_font,
449                         XftCharIndex (NULL, mini_xft_font,
450                                       buf[row * cols + col] & 0xff),
451                         xs[col+1],
452                         ys[row+1]);
453           }
454     }
455 }
456
457 static void
458 pango_xft_renderer_draw_glyphs (PangoRenderer    *renderer,
459                                 PangoFont        *font,
460                                 PangoGlyphString *glyphs,
461                                 int               x,
462                                 int               y)
463 {
464   PangoXftFont *xfont = PANGO_XFT_FONT (font);
465   PangoFcFont *fcfont = PANGO_FC_FONT (font);
466   XftFont *xft_font = pango_xft_font_get_font (font);
467   int i;
468   int x_off = 0;
469
470   if (!fcfont)
471     {
472       for (i=0; i<glyphs->num_glyphs; i++)
473         {
474           PangoGlyphInfo *gi = &glyphs->glyphs[i];
475
476           if (gi->glyph != PANGO_GLYPH_EMPTY)
477             {
478               int glyph_x = x + x_off + gi->geometry.x_offset;
479               int glyph_y = y + gi->geometry.y_offset;
480
481               _pango_xft_renderer_draw_unknown_glyph (renderer,
482                                                       xfont,
483                                                       xft_font,
484                                                       gi,
485                                                       glyph_x,
486                                                       glyph_y);
487             }
488
489           x_off += gi->geometry.width;
490         }
491       return;
492     }
493
494   if (!fcfont->fontmap) /* Display closed */
495     return;
496
497   for (i=0; i<glyphs->num_glyphs; i++)
498     {
499       PangoGlyphInfo *gi = &glyphs->glyphs[i];
500
501       if (gi->glyph != PANGO_GLYPH_EMPTY)
502         {
503           int glyph_x = x + x_off + gi->geometry.x_offset;
504           int glyph_y = y + gi->geometry.y_offset;
505
506           if (gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
507             {
508               _pango_xft_renderer_draw_unknown_glyph (renderer,
509                                                       xfont,
510                                                       xft_font,
511                                                       gi,
512                                                       glyph_x,
513                                                       glyph_y);
514             }
515           else
516             {
517               draw_glyph (renderer, font, gi->glyph, glyph_x, glyph_y);
518             }
519         }
520
521       x_off += gi->geometry.width;
522     }
523 }
524
525 static void
526 flush_trapezoids (PangoXftRenderer *xftrenderer)
527 {
528   if (!xftrenderer->priv->trapezoids ||
529       xftrenderer->priv->trapezoids->len == 0)
530     return;
531
532   PANGO_XFT_RENDERER_GET_CLASS (xftrenderer)->composite_trapezoids (xftrenderer,
533                                                                     xftrenderer->priv->trapezoid_part,
534                                                                     (XTrapezoid *)xftrenderer->priv->trapezoids->data,
535                                                                     xftrenderer->priv->trapezoids->len);
536
537   g_array_set_size (xftrenderer->priv->trapezoids, 0);
538 }
539
540 static void
541 pango_xft_renderer_draw_trapezoid (PangoRenderer   *renderer,
542                                    PangoRenderPart  part,
543                                    double           y1,
544                                    double           x11,
545                                    double           x21,
546                                    double           y2,
547                                    double           x12,
548                                    double           x22)
549 {
550   PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer);
551   XTrapezoid trap;
552
553   flush_glyphs (xftrenderer);
554
555   if (!xftrenderer->priv->trapezoids)
556     xftrenderer->priv->trapezoids = g_array_new (FALSE, FALSE,
557                                                  sizeof (XTrapezoid));
558
559   if (xftrenderer->draw)
560     {
561       if (xftrenderer->priv->trapezoids->len > 0 &&
562           xftrenderer->priv->trapezoid_part != part)
563         flush_trapezoids (xftrenderer);
564
565       xftrenderer->priv->trapezoid_part = part;
566     }
567
568   trap.top = XDoubleToFixed (y1);
569   trap.bottom = XDoubleToFixed (y2);
570   trap.left.p1.x = XDoubleToFixed (x11);
571   trap.left.p1.y = XDoubleToFixed (y1);
572   trap.left.p2.x = XDoubleToFixed (x12);
573   trap.left.p2.y = XDoubleToFixed (y2);
574   trap.right.p1.x = XDoubleToFixed (x21);
575   trap.right.p1.y = XDoubleToFixed (y1);
576   trap.right.p2.x = XDoubleToFixed (x22);
577   trap.right.p2.y = XDoubleToFixed (y2);
578
579   g_array_append_val (xftrenderer->priv->trapezoids, trap);
580 }
581
582 static void
583 pango_xft_renderer_part_changed (PangoRenderer   *renderer,
584                                  PangoRenderPart  part)
585 {
586   PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer);
587
588   if (part == PANGO_RENDER_PART_FOREGROUND)
589     flush_glyphs (xftrenderer);
590
591   if (part == xftrenderer->priv->trapezoid_part)
592     flush_trapezoids (xftrenderer);
593 }
594
595 static void
596 pango_xft_renderer_end (PangoRenderer *renderer)
597 {
598   PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer);
599
600   flush_glyphs (xftrenderer);
601   flush_trapezoids (xftrenderer);
602 }
603
604 static void
605 pango_xft_renderer_real_composite_trapezoids (PangoXftRenderer *xftrenderer,
606                                               PangoRenderPart   part,
607                                               XTrapezoid       *trapezoids,
608                                               int               n_trapezoids)
609 {
610   Picture src_picture;
611   Picture dest_picture;
612
613   if (!XftDefaultHasRender (xftrenderer->display))
614       return;
615
616   if (xftrenderer->priv->src_picture != None)
617     {
618       src_picture = xftrenderer->priv->src_picture;
619       dest_picture = xftrenderer->priv->dest_picture;
620     }
621   else
622     {
623       XftColor xft_color;
624       PangoColor *color = pango_renderer_get_color (PANGO_RENDERER (xftrenderer),
625                                                     part);
626       if (!color)
627         color = &xftrenderer->priv->default_color;
628
629       xft_color.color.red = color->red;
630       xft_color.color.green = color->green;
631       xft_color.color.blue = color->blue;
632       xft_color.color.alpha = xftrenderer->priv->alpha;
633
634       src_picture = XftDrawSrcPicture (xftrenderer->draw, &xft_color);
635       dest_picture = XftDrawPicture (xftrenderer->draw);
636     }
637
638   XRenderCompositeTrapezoids (xftrenderer->display,
639                               PictOpOver,
640                               src_picture, dest_picture,
641                               xftrenderer->priv->mask_format,
642                               0, 0,
643                               trapezoids, n_trapezoids);
644 }
645
646 static void
647 pango_xft_renderer_real_composite_glyphs (PangoXftRenderer *xftrenderer,
648                                           XftFont          *xft_font,
649                                           XftGlyphSpec     *glyphs,
650                                           int               n_glyphs)
651 {
652   if (xftrenderer->priv->src_picture != None)
653     {
654       XftGlyphSpecRender (xftrenderer->display, PictOpOver,
655                           xftrenderer->priv->src_picture,
656                           xft_font,
657                           xftrenderer->priv->dest_picture, 0, 0,
658                           glyphs, n_glyphs);
659     }
660   else
661     {
662       XftColor xft_color;
663       PangoColor *color = pango_renderer_get_color (PANGO_RENDERER (xftrenderer),
664                                                     PANGO_RENDER_PART_FOREGROUND);
665       if (!color)
666         color = &xftrenderer->priv->default_color;
667
668       xft_color.color.red = color->red;
669       xft_color.color.green = color->green;
670       xft_color.color.blue = color->blue;
671       xft_color.color.alpha = xftrenderer->priv->alpha;
672
673       XftDrawGlyphSpec (xftrenderer->draw, &xft_color,
674                         xft_font,
675                         glyphs, n_glyphs);
676     }
677 }
678
679 static PangoRenderer *
680 get_renderer (PangoFontMap *fontmap,
681               XftDraw      *draw,
682               XftColor     *color)
683 {
684   PangoRenderer *renderer;
685   PangoXftRenderer *xftrenderer;
686   PangoColor pango_color;
687
688   renderer = _pango_xft_font_map_get_renderer (PANGO_XFT_FONT_MAP (fontmap));
689   xftrenderer = PANGO_XFT_RENDERER (renderer);
690
691   pango_xft_renderer_set_draw (xftrenderer, draw);
692
693   pango_color.red = color->color.red;
694   pango_color.green = color->color.green;
695   pango_color.blue = color->color.blue;
696   pango_xft_renderer_set_default_color (xftrenderer, &pango_color);
697   xftrenderer->priv->alpha = color->color.alpha;
698
699   return renderer;
700 }
701
702 static void
703 release_renderer (PangoRenderer *renderer)
704 {
705   PangoXftRenderer *xftrenderer = PANGO_XFT_RENDERER (renderer);
706
707   xftrenderer->priv->alpha = 0xffff;
708 }
709
710 /**
711  * pango_xft_render_layout:
712  * @draw:      an #XftDraw
713  * @color:     the foreground color in which to draw the layout
714  *             (may be overridden by color attributes)
715  * @layout:    a #PangoLayout
716  * @x:         the X position of the left of the layout (in Pango units)
717  * @y:         the Y position of the top of the layout (in Pango units)
718  *
719  * Render a #PangoLayout onto a #XftDraw
720  *
721  * Since: 1.8
722  */
723 void
724 pango_xft_render_layout (XftDraw     *draw,
725                          XftColor    *color,
726                          PangoLayout *layout,
727                          int          x,
728                          int          y)
729 {
730   PangoContext *context;
731   PangoFontMap *fontmap;
732   PangoRenderer *renderer;
733
734   g_return_if_fail (draw != NULL);
735   g_return_if_fail (color != NULL);
736   g_return_if_fail (PANGO_IS_LAYOUT (layout));
737
738   context = pango_layout_get_context (layout);
739   fontmap = pango_context_get_font_map (context);
740   renderer = get_renderer (fontmap, draw, color);
741
742   pango_renderer_draw_layout (renderer, layout, x, y);
743
744   release_renderer (renderer);
745 }
746
747 /**
748  * pango_xft_render_layout_line:
749  * @draw:      an #XftDraw
750  * @color:     the foreground color in which to draw the layout line
751  *             (may be overridden by color attributes)
752  * @line:      a #PangoLayoutLine
753  * @x:         the x position of start of string (in Pango units)
754  * @y:         the y position of baseline (in Pango units)
755  *
756  * Render a #PangoLayoutLine onto a #XftDraw
757  *
758  * Since: 1.8
759  */
760 void
761 pango_xft_render_layout_line (XftDraw         *draw,
762                               XftColor        *color,
763                               PangoLayoutLine *line,
764                               int              x,
765                               int              y)
766 {
767   PangoContext *context;
768   PangoFontMap *fontmap;
769   PangoRenderer *renderer;
770
771   g_return_if_fail (draw != NULL);
772   g_return_if_fail (color != NULL);
773   g_return_if_fail (line != NULL);
774
775   context = pango_layout_get_context (line->layout);
776   fontmap = pango_context_get_font_map (context);
777   renderer = get_renderer (fontmap, draw, color);
778
779   pango_renderer_draw_layout_line (renderer, line, x, y);
780
781   release_renderer (renderer);
782 }
783
784 /**
785  * pango_xft_render_transformed:
786  * @draw:    an #XftDraw
787  * @color:   the color in which to draw the glyphs
788  * @font:    the font in which to draw the string
789  * @matrix:  a #PangoMatrix, or %NULL to use an identity transformation
790  * @glyphs:  the glyph string to draw
791  * @x:       the x position of the start of the string (in Pango
792  *           units in user space coordinates)
793  * @y:       the y position of the baseline (in Pango units
794  *           in user space coordinates)
795  *
796  * Renders a #PangoGlyphString onto a #XftDraw, possibly
797  * transforming the layed-out coordinates through a transformation
798  * matrix. Note that the transformation matrix for @font is not
799  * changed, so to produce correct rendering results, the @font
800  * must have been loaded using a #PangoContext with an identical
801  * transformation matrix to that passed in to this function.
802  *
803  * Since: 1.8
804  **/
805 void
806 pango_xft_render_transformed (XftDraw          *draw,
807                               XftColor         *color,
808                               PangoMatrix      *matrix,
809                               PangoFont        *font,
810                               PangoGlyphString *glyphs,
811                               int               x,
812                               int               y)
813 {
814   PangoFontMap *fontmap;
815   PangoRenderer *renderer;
816
817   g_return_if_fail (draw != NULL);
818   g_return_if_fail (color != NULL);
819   g_return_if_fail (PANGO_XFT_IS_FONT (font));
820   g_return_if_fail (glyphs != NULL);
821
822   fontmap = PANGO_FC_FONT (font)->fontmap;
823   renderer = get_renderer (fontmap, draw, color);
824
825   pango_renderer_set_matrix (renderer, matrix);
826
827   pango_renderer_draw_glyphs (renderer, font, glyphs, x, y);
828
829   release_renderer (renderer);
830 }
831
832 /**
833  * pango_xft_render:
834  * @draw:    the <type>XftDraw</type> object.
835  * @color:   the color in which to draw the string
836  * @font:    the font in which to draw the string
837  * @glyphs:  the glyph string to draw
838  * @x:       the x position of start of string (in pixels)
839  * @y:       the y position of baseline (in pixels)
840  *
841  * Renders a #PangoGlyphString onto an <type>XftDraw</type> object wrapping an X drawable.
842  */
843 void
844 pango_xft_render (XftDraw          *draw,
845                   XftColor         *color,
846                   PangoFont        *font,
847                   PangoGlyphString *glyphs,
848                   gint              x,
849                   gint              y)
850 {
851   g_return_if_fail (draw != NULL);
852   g_return_if_fail (color != NULL);
853   g_return_if_fail (PANGO_XFT_IS_FONT (font));
854   g_return_if_fail (glyphs != NULL);
855
856   pango_xft_render_transformed (draw, color, NULL, font, glyphs,
857                                 x * PANGO_SCALE, y * PANGO_SCALE);
858 }
859
860 /**
861  * pango_xft_picture_render:
862  * @display:      an X display
863  * @src_picture:  the source picture to draw the string with
864  * @dest_picture: the destination picture to draw the string onto
865  * @font:         the font in which to draw the string
866  * @glyphs:       the glyph string to draw
867  * @x:            the x position of start of string (in pixels)
868  * @y:            the y position of baseline (in pixels)
869  *
870  * Renders a #PangoGlyphString onto an Xrender <type>Picture</type> object.
871  */
872 void
873 pango_xft_picture_render (Display          *display,
874                           Picture           src_picture,
875                           Picture           dest_picture,
876                           PangoFont        *font,
877                           PangoGlyphString *glyphs,
878                           gint              x,
879                           gint              y)
880 {
881   PangoFontMap *fontmap;
882   PangoRenderer *renderer;
883
884   g_return_if_fail (display != NULL);
885   g_return_if_fail (src_picture != None);
886   g_return_if_fail (dest_picture != None);
887   g_return_if_fail (PANGO_XFT_IS_FONT (font));
888   g_return_if_fail (glyphs != NULL);
889
890   fontmap = PANGO_FC_FONT (font)->fontmap;
891   renderer = _pango_xft_font_map_get_renderer (PANGO_XFT_FONT_MAP (fontmap));
892
893   pango_xft_renderer_set_pictures (PANGO_XFT_RENDERER (renderer),
894                                    src_picture, dest_picture);
895   pango_renderer_set_matrix (renderer, NULL);
896
897   pango_renderer_draw_glyphs (renderer, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE);
898
899   pango_xft_renderer_set_pictures (PANGO_XFT_RENDERER (renderer),
900                                    None, None);
901 }
902
903 /**
904  * pango_xft_renderer_new:
905  * @display: an X display
906  * @screen:   the index of the screen for @display to which rendering will be done
907  *
908  * Create a new #PangoXftRenderer to allow rendering Pango objects
909  * with the Xft library. You must call pango_xft_renderer_set_draw() before
910  * using the renderer.
911  *
912  * Return value: the newly created #PangoXftRenderer, which should
913  *               be freed with g_object_unref().
914  *
915  * Since: 1.8
916  **/
917 PangoRenderer *
918 pango_xft_renderer_new (Display *display,
919                         int      screen)
920 {
921   PangoXftRenderer *xftrenderer;
922
923   xftrenderer = g_object_new (PANGO_TYPE_XFT_RENDERER,
924                               "display", display,
925                               "screen", screen,
926                               NULL);
927
928   return PANGO_RENDERER (xftrenderer);
929 }
930
931 /**
932  * pango_xft_renderer_set_draw:
933  * @xftrenderer: a #PangoXftRenderer
934  * @draw: a #XftDraw
935  *
936  * Sets the #XftDraw object that the renderer is drawing to.
937  * The renderer must not be currently active.
938  *
939  * Since: 1.8
940  **/
941 void
942 pango_xft_renderer_set_draw (PangoXftRenderer *xftrenderer,
943                              XftDraw          *draw)
944 {
945   g_return_if_fail (PANGO_IS_XFT_RENDERER (xftrenderer));
946
947   xftrenderer->draw = draw;
948 }
949
950 /**
951  * pango_xft_renderer_set_default_color:
952  * @xftrenderer: a #XftRenderer
953  * @default_color: the default foreground color
954  *
955  * Sets the default foreground color for a #XftRenderer.
956  *
957  * Since: 1.8
958  **/
959 void
960 pango_xft_renderer_set_default_color (PangoXftRenderer *xftrenderer,
961                                       PangoColor       *default_color)
962 {
963   g_return_if_fail (PANGO_IS_XFT_RENDERER (xftrenderer));
964
965   xftrenderer->priv->default_color = *default_color;
966 }