Git init
[external/pango1.0.git] / pango / pangoft2-render.c
1 /* Pango
2  * pangoft2-render.c: Rendering routines to FT_Bitmap objects
3  *
4  * Copyright (C) 2004 Red Hat Software
5  * Copyright (C) 2000 Tor Lillqvist
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20  * Boston, MA 02111-1307, USA.
21  */
22
23 #include "config.h"
24 #include <math.h>
25
26 #include "pangoft2-private.h"
27
28 /* for compatibility with older freetype versions */
29 #ifndef FT_LOAD_TARGET_MONO
30 #define FT_LOAD_TARGET_MONO  FT_LOAD_MONOCHROME
31 #endif
32
33 typedef struct _PangoFT2RendererClass PangoFT2RendererClass;
34
35 #define PANGO_FT2_RENDERER_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass))
36 #define PANGO_IS_FT2_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_FT2_RENDERER))
37 #define PANGO_FT2_RENDERER_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_FT2_RENDERER, PangoFT2RendererClass))
38
39 struct _PangoFT2Renderer
40 {
41   PangoRenderer parent_instance;
42
43   FT_Bitmap *bitmap;
44 };
45
46 struct _PangoFT2RendererClass
47 {
48   PangoRendererClass parent_class;
49 };
50
51 static void pango_ft2_renderer_draw_glyph     (PangoRenderer    *renderer,
52                                                PangoFont        *font,
53                                                PangoGlyph        glyph,
54                                                double            x,
55                                                double            y);
56 static void pango_ft2_renderer_draw_trapezoid (PangoRenderer    *renderer,
57                                                PangoRenderPart   part,
58                                                double            y1,
59                                                double            x11,
60                                                double            x21,
61                                                double            y2,
62                                                double            x12,
63                                                double            x22);
64
65 G_DEFINE_TYPE (PangoFT2Renderer, pango_ft2_renderer, PANGO_TYPE_RENDERER)
66
67 static void
68 pango_ft2_renderer_init (PangoFT2Renderer *renderer G_GNUC_UNUSED)
69 {
70 }
71
72 static void
73 pango_ft2_renderer_class_init (PangoFT2RendererClass *klass)
74 {
75   PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
76
77   renderer_class->draw_glyph = pango_ft2_renderer_draw_glyph;
78   renderer_class->draw_trapezoid = pango_ft2_renderer_draw_trapezoid;
79 }
80
81 static void
82 pango_ft2_renderer_set_bitmap (PangoFT2Renderer *renderer,
83                               FT_Bitmap         *bitmap)
84 {
85   renderer->bitmap = bitmap;
86 }
87
88 typedef struct
89 {
90   FT_Bitmap bitmap;
91   int bitmap_left;
92   int bitmap_top;
93 } PangoFT2RenderedGlyph;
94
95 static void
96 pango_ft2_free_rendered_glyph (PangoFT2RenderedGlyph *rendered)
97 {
98   g_free (rendered->bitmap.buffer);
99   g_slice_free (PangoFT2RenderedGlyph, rendered);
100 }
101
102 static PangoFT2RenderedGlyph *
103 pango_ft2_font_render_box_glyph (int      width,
104                                  int      height,
105                                  int      top,
106                                  gboolean invalid)
107 {
108   PangoFT2RenderedGlyph *box;
109   int i, j, offset1, offset2, line_width;
110
111   line_width = MAX ((height + 43) / 44, 1);
112   if (width < 1 || height < 1)
113     line_width = 0;
114
115   box = g_slice_new (PangoFT2RenderedGlyph);
116
117   box->bitmap_left = 0;
118   box->bitmap_top = top;
119
120   box->bitmap.pixel_mode = ft_pixel_mode_grays;
121
122   box->bitmap.width = width;
123   box->bitmap.rows = height;
124   box->bitmap.pitch = height;
125
126   box->bitmap.buffer = g_malloc0 (box->bitmap.rows * box->bitmap.pitch);
127
128   /* draw the box */
129   for (j = 0; j < line_width; j++)
130     {
131       offset1 = box->bitmap.pitch * (MIN (1 + j, height - 1));
132       offset2 = box->bitmap.pitch * (MAX (box->bitmap.rows - 2 - j, 0));
133       for (i = 1;
134            i < box->bitmap.width - 1;
135            i++)
136         {
137           box->bitmap.buffer[offset1 + i] = 0xff;
138           box->bitmap.buffer[offset2 + i] = 0xff;
139         }
140     }
141   for (j = 0; j < line_width; j++)
142     {
143       offset1 = MIN (1 + j, width - 1);
144       offset2 = MAX (box->bitmap.width - 2 - j, 0);
145       for (i = box->bitmap.pitch;
146            i < (box->bitmap.rows - 1) * box->bitmap.pitch;
147            i += box->bitmap.pitch)
148         {
149           box->bitmap.buffer[offset1 + i] = 0xff;
150           box->bitmap.buffer[offset2 + i] = 0xff;
151         }
152     }
153
154   if (invalid)
155     {
156       /* XXX This may scrabble memory.  Didn't check close enough */
157       int inc = PANGO_SCALE * MAX (width - line_width, 0) / (height + 1);
158       offset1 = PANGO_SCALE;
159       offset2 = PANGO_SCALE * MAX (width - line_width - 1, 0) ;
160       for (i = box->bitmap.pitch;
161            i < (box->bitmap.rows - 1) * box->bitmap.pitch;
162            i += box->bitmap.pitch)
163         {
164           for (j = 0; j < line_width; j++)
165             {
166               box->bitmap.buffer[PANGO_PIXELS (offset1) + i + j] = 0xff;
167               box->bitmap.buffer[PANGO_PIXELS (offset2) + i + j] = 0xff;
168             }
169           offset1 += inc;
170           offset2 -= inc;
171         }
172
173     }
174
175   return box;
176 }
177
178 static PangoFT2RenderedGlyph *
179 pango_ft2_font_render_glyph (PangoFont *font,
180                              PangoGlyph glyph_index)
181 {
182   FT_Face face;
183   gboolean invalid_input;
184
185   invalid_input = glyph_index == PANGO_GLYPH_INVALID_INPUT || (glyph_index & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0x10FFFF;
186
187   if (glyph_index & PANGO_GLYPH_UNKNOWN_FLAG)
188     {
189       PangoFT2RenderedGlyph *box;
190       PangoFontMetrics *metrics;
191
192       if (!font)
193         goto generic_box;
194
195       metrics = pango_font_get_metrics (font, NULL);
196       if (!metrics)
197         goto generic_box;
198
199       box = pango_ft2_font_render_box_glyph (PANGO_PIXELS (metrics->approximate_char_width),
200                                              PANGO_PIXELS (metrics->ascent + metrics->descent),
201                                              PANGO_PIXELS (metrics->ascent),
202                                              invalid_input);
203       pango_font_metrics_unref (metrics);
204
205       return box;
206     }
207
208   face = pango_ft2_font_get_face (font);
209
210   if (face)
211     {
212       PangoFT2RenderedGlyph *rendered;
213       PangoFT2Font *ft2font = (PangoFT2Font *) font;
214
215       rendered = g_slice_new (PangoFT2RenderedGlyph);
216
217       /* Draw glyph */
218       FT_Load_Glyph (face, glyph_index, ft2font->load_flags);
219       FT_Render_Glyph (face->glyph,
220                        (ft2font->load_flags & FT_LOAD_TARGET_MONO ?
221                         ft_render_mode_mono : ft_render_mode_normal));
222
223       rendered->bitmap = face->glyph->bitmap;
224       rendered->bitmap.buffer = g_memdup (face->glyph->bitmap.buffer,
225                                           face->glyph->bitmap.rows * face->glyph->bitmap.pitch);
226       rendered->bitmap_left = face->glyph->bitmap_left;
227       rendered->bitmap_top = face->glyph->bitmap_top;
228
229       return rendered;
230     }
231   else
232     {
233 generic_box:
234       return  pango_ft2_font_render_box_glyph (PANGO_UNKNOWN_GLYPH_WIDTH,
235                                                PANGO_UNKNOWN_GLYPH_HEIGHT,
236                                                PANGO_UNKNOWN_GLYPH_HEIGHT,
237                                                invalid_input);
238     }
239 }
240
241 static void
242 pango_ft2_renderer_draw_glyph (PangoRenderer *renderer,
243                                PangoFont     *font,
244                                PangoGlyph     glyph,
245                                double         x,
246                                double         y)
247 {
248   FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap;
249   PangoFT2RenderedGlyph *rendered_glyph;
250   gboolean add_glyph_to_cache;
251   guchar *src, *dest;
252
253   int x_start, x_limit;
254   int y_start, y_limit;
255   int ixoff = floor (x + 0.5);
256   int iyoff = floor (y + 0.5);
257   int ix, iy;
258
259   if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
260     {
261       /* Since we don't draw hexbox for FT2 renderer,
262        * unifiy the rendered bitmap in the cache by converting
263        * all missing glyphs to either INVALID_INPUT or UNKNOWN_FLAG.
264        */
265
266       gunichar wc = glyph & (~PANGO_GLYPH_UNKNOWN_FLAG);
267
268       if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || wc > 0x10FFFF))
269         glyph = PANGO_GLYPH_INVALID_INPUT;
270       else
271         glyph = PANGO_GLYPH_UNKNOWN_FLAG;
272     }
273
274   rendered_glyph = _pango_ft2_font_get_cache_glyph_data (font, glyph);
275   add_glyph_to_cache = FALSE;
276   if (rendered_glyph == NULL)
277     {
278       rendered_glyph = pango_ft2_font_render_glyph (font, glyph);
279       add_glyph_to_cache = TRUE;
280     }
281
282   x_start = MAX (0, - (ixoff + rendered_glyph->bitmap_left));
283   x_limit = MIN (rendered_glyph->bitmap.width,
284                  bitmap->width - (ixoff + rendered_glyph->bitmap_left));
285
286   y_start = MAX (0,  - (iyoff - rendered_glyph->bitmap_top));
287   y_limit = MIN (rendered_glyph->bitmap.rows,
288                  bitmap->rows - (iyoff - rendered_glyph->bitmap_top));
289
290   src = rendered_glyph->bitmap.buffer +
291     y_start * rendered_glyph->bitmap.pitch;
292
293   dest = bitmap->buffer +
294     (y_start + iyoff - rendered_glyph->bitmap_top) * bitmap->pitch +
295     x_start + ixoff + rendered_glyph->bitmap_left;
296
297   switch (rendered_glyph->bitmap.pixel_mode)
298     {
299     case ft_pixel_mode_grays:
300       src += x_start;
301       for (iy = y_start; iy < y_limit; iy++)
302         {
303           guchar *s = src;
304           guchar *d = dest;
305
306           for (ix = x_start; ix < x_limit; ix++)
307             {
308               switch (*s)
309                 {
310                 case 0:
311                   break;
312                 case 0xff:
313                   *d = 0xff;
314                 default:
315                   *d = MIN ((gushort) *d + (gushort) *s, 0xff);
316                   break;
317                 }
318
319               s++;
320               d++;
321             }
322
323           dest += bitmap->pitch;
324           src  += rendered_glyph->bitmap.pitch;
325         }
326       break;
327
328     case ft_pixel_mode_mono:
329       src += x_start / 8;
330       for (iy = y_start; iy < y_limit; iy++)
331         {
332           guchar *s = src;
333           guchar *d = dest;
334
335           for (ix = x_start; ix < x_limit; ix++)
336             {
337               if ((*s) & (1 << (7 - (ix % 8))))
338                 *d |= 0xff;
339
340               if ((ix % 8) == 7)
341                 s++;
342               d++;
343             }
344
345           dest += bitmap->pitch;
346           src  += rendered_glyph->bitmap.pitch;
347         }
348       break;
349
350     default:
351       g_warning ("pango_ft2_render: "
352                  "Unrecognized glyph bitmap pixel mode %d\n",
353                  rendered_glyph->bitmap.pixel_mode);
354       break;
355     }
356
357   if (add_glyph_to_cache)
358     {
359       _pango_ft2_font_set_glyph_cache_destroy (font,
360                                                (GDestroyNotify) pango_ft2_free_rendered_glyph);
361       _pango_ft2_font_set_cache_glyph_data (font,
362                                             glyph, rendered_glyph);
363     }
364 }
365
366 typedef struct {
367   double y;
368   double x1;
369   double x2;
370 } Position;
371
372 static void
373 draw_simple_trap (PangoRenderer *renderer,
374                   Position      *t,
375                   Position      *b)
376 {
377   FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap;
378   int iy = floor (t->y);
379   int x1, x2, x;
380   double dy = b->y - t->y;
381   guchar *dest;
382
383   if (iy < 0 || iy >= bitmap->rows)
384     return;
385   dest = bitmap->buffer + iy * bitmap->pitch;
386
387   if (t->x1 < b->x1)
388     x1 = floor (t->x1);
389   else
390     x1 = floor (b->x1);
391
392   if (t->x2 > b->x2)
393     x2 = ceil (t->x2);
394   else
395     x2 = ceil (b->x2);
396
397   x1 = CLAMP (x1, 0, bitmap->width);
398   x2 = CLAMP (x2, 0, bitmap->width);
399
400   for (x = x1; x < x2; x++)
401     {
402       double top_left = MAX (t->x1, x);
403       double top_right = MIN (t->x2, x + 1);
404       double bottom_left = MAX (b->x1, x);
405       double bottom_right = MIN (b->x2, x + 1);
406       double c = 0.5 * dy * ((top_right - top_left) + (bottom_right - bottom_left));
407
408       /* When converting to [0,255], we round up. This is intended
409        * to prevent the problem of pixels that get divided into
410        * multiple slices not being fully black.
411        */
412       int ic = c * 256;
413
414       dest[x] = MIN (dest[x] + ic, 255);
415     }
416 }
417
418 static void
419 interpolate_position (Position *result,
420                       Position *top,
421                       Position *bottom,
422                       double    val,
423                       double    val1,
424                       double    val2)
425 {
426   result->y  = (top->y *  (val2 - val) + bottom->y *  (val - val1)) / (val2 - val1);
427   result->x1 = (top->x1 * (val2 - val) + bottom->x1 * (val - val1)) / (val2 - val1);
428   result->x2 = (top->x2 * (val2 - val) + bottom->x2 * (val - val1)) / (val2 - val1);
429 }
430
431 /* This draws a trapezoid with the parallel sides aligned with
432  * the X axis. We do this by subdividing the trapezoid vertically
433  * into thin slices (themselves trapezoids) where two edge sides are each
434  * contained within a single pixel and then rasterizing each
435  * slice. There are frequently multiple slices within a single
436  * line so we have to accumulate to get the final result.
437  */
438 static void
439 pango_ft2_renderer_draw_trapezoid (PangoRenderer   *renderer,
440                                    PangoRenderPart  part G_GNUC_UNUSED,
441                                    double           y1,
442                                    double           x11,
443                                    double           x21,
444                                    double           y2,
445                                    double           x12,
446                                    double           x22)
447 {
448   Position pos;
449   Position t;
450   Position b;
451   gboolean done = FALSE;
452
453   if (y1 == y2)
454     return;
455
456   pos.y = t.y = y1;
457   pos.x1 = t.x1 = x11;
458   pos.x2 = t.x2 = x21;
459   b.y = y2;
460   b.x1 = x12;
461   b.x2 = x22;
462
463   while (!done)
464     {
465       Position pos_next;
466       double y_next, x1_next, x2_next;
467       double ix1, ix2;
468
469       /* The algorithm here is written to emphasize simplicity and
470        * numerical stability as opposed to speed.
471        *
472        * While the end result is slicing up the polygon vertically,
473        * conceptually we aren't walking in the X direction, rather we
474        * are walking along the edges. When we compute crossing of
475        * horizontal pixel boundaries, we use the X coordinate as the
476        * interpolating variable, when we compute crossing for vertical
477        * pixel boundaries, we use the Y coordinate.
478        *
479        * This allows us to handle almost exactly horizontal edges without
480        * running into difficulties. (Almost exactly horizontal edges
481        * come up frequently due to inexactness in computing, say,
482        * a 90 degree rotation transformation)
483        */
484
485       pos_next = b;
486       done = TRUE;
487
488       /* Check for crossing vertical pixel boundaries */
489       y_next = floor (pos.y) + 1;
490       if (y_next < pos_next.y)
491         {
492           interpolate_position (&pos_next, &t, &b,
493                                 y_next, t.y, b.y);
494           pos_next.y = y_next;
495           done = FALSE;
496         }
497
498       /* Check left side for crossing horizontal pixel boundaries */
499       ix1 = floor (pos.x1);
500
501       if (b.x1 < t.x1)
502         {
503           if (ix1 == pos.x1)
504             x1_next = ix1 - 1;
505           else
506             x1_next = ix1;
507
508           if (x1_next > pos_next.x1)
509             {
510               interpolate_position (&pos_next, &t, &b,
511                                     x1_next, t.x1, b.x1);
512               pos_next.x1 = x1_next;
513               done = FALSE;
514             }
515         }
516       else if (b.x1 > t.x1)
517         {
518           x1_next = ix1 + 1;
519
520           if (x1_next < pos_next.x1)
521             {
522               interpolate_position (&pos_next, &t, &b,
523                                     x1_next, t.x1, b.x1);
524               pos_next.x1 = x1_next;
525               done = FALSE;
526             }
527         }
528
529       /* Check right side for crossing horizontal pixel boundaries */
530       ix2 = floor (pos.x2);
531
532       if (b.x2 < t.x2)
533         {
534           if (ix2 == pos.x2)
535             x2_next = ix2 - 1;
536           else
537             x2_next = ix2;
538
539           if (x2_next > pos_next.x2)
540             {
541               interpolate_position (&pos_next, &t, &b,
542                                     x2_next, t.x2, b.x2);
543               pos_next.x2 = x2_next;
544               done = FALSE;
545             }
546         }
547       else if (x22 > x21)
548         {
549           x2_next = ix2 + 1;
550
551           if (x2_next < pos_next.x2)
552             {
553               interpolate_position (&pos_next, &t, &b,
554                                     x2_next, t.x2, b.x2);
555               pos_next.x2 = x2_next;
556               done = FALSE;
557             }
558         }
559
560       draw_simple_trap (renderer, &pos, &pos_next);
561       pos = pos_next;
562     }
563 }
564
565 /**
566  * pango_ft2_render_layout_subpixel:
567  * @bitmap:    a <type>FT_Bitmap</type> to render the layout onto
568  * @layout:    a #PangoLayout
569  * @x:         the X position of the left of the layout (in Pango units)
570  * @y:         the Y position of the top of the layout (in Pango units)
571  *
572  * Render a #PangoLayout onto a FreeType2 bitmap, with he
573  * location specified in fixed-point Pango units rather than
574  * pixels. (Using this will avoid extra inaccuracies from
575  * rounding to integer pixels multiple times, even if the
576  * final glyph positions are integers.)
577  *
578  * Since: 1.6
579  */
580 void
581 pango_ft2_render_layout_subpixel (FT_Bitmap   *bitmap,
582                                   PangoLayout *layout,
583                                   int          x,
584                                   int          y)
585 {
586   PangoContext *context;
587   PangoFontMap *fontmap;
588   PangoRenderer *renderer;
589
590   g_return_if_fail (bitmap != NULL);
591   g_return_if_fail (PANGO_IS_LAYOUT (layout));
592
593   context = pango_layout_get_context (layout);
594   fontmap = pango_context_get_font_map (context);
595   renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap));
596
597   pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
598
599   pango_renderer_draw_layout (renderer, layout, x, y);
600 }
601
602 /**
603  * pango_ft2_render_layout:
604  * @bitmap:    a <type>FT_Bitmap</type> to render the layout onto
605  * @layout:    a #PangoLayout
606  * @x:         the X position of the left of the layout (in pixels)
607  * @y:         the Y position of the top of the layout (in pixels)
608  *
609  * Render a #PangoLayout onto a FreeType2 bitmap
610  */
611 void
612 pango_ft2_render_layout (FT_Bitmap   *bitmap,
613                          PangoLayout *layout,
614                          int          x,
615                          int          y)
616 {
617   pango_ft2_render_layout_subpixel (bitmap, layout, x * PANGO_SCALE, y * PANGO_SCALE);
618 }
619
620 /**
621  * pango_ft2_render_layout_line_subpixel:
622  * @bitmap:    a <type>FT_Bitmap</type> to render the line onto
623  * @line:      a #PangoLayoutLine
624  * @x:         the x position of start of string (in Pango units)
625  * @y:         the y position of baseline (in Pango units)
626  *
627  * Render a #PangoLayoutLine onto a FreeType2 bitmap, with he
628  * location specified in fixed-point Pango units rather than
629  * pixels. (Using this will avoid extra inaccuracies from
630  * rounding to integer pixels multiple times, even if the
631  * final glyph positions are integers.)
632  *
633  * Since: 1.6
634  */
635 void
636 pango_ft2_render_layout_line_subpixel (FT_Bitmap       *bitmap,
637                                        PangoLayoutLine *line,
638                                        int              x,
639                                        int              y)
640 {
641   PangoContext *context;
642   PangoFontMap *fontmap;
643   PangoRenderer *renderer;
644
645   g_return_if_fail (bitmap != NULL);
646   g_return_if_fail (line != NULL);
647
648   context = pango_layout_get_context (line->layout);
649   fontmap = pango_context_get_font_map (context);
650   renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap));
651
652   pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
653
654   pango_renderer_draw_layout_line (renderer, line, x, y);
655 }
656
657 /**
658  * pango_ft2_render_layout_line:
659  * @bitmap:    a <type>FT_Bitmap</type> to render the line onto
660  * @line:      a #PangoLayoutLine
661  * @x:         the x position of start of string (in pixels)
662  * @y:         the y position of baseline (in pixels)
663  *
664  * Render a #PangoLayoutLine onto a FreeType2 bitmap
665  */
666 void
667 pango_ft2_render_layout_line (FT_Bitmap       *bitmap,
668                               PangoLayoutLine *line,
669                               int              x,
670                               int              y)
671 {
672   pango_ft2_render_layout_line_subpixel (bitmap, line, x * PANGO_SCALE, y * PANGO_SCALE);
673 }
674
675 /**
676  * pango_ft2_render_transformed:
677  * @bitmap:  the FreeType2 bitmap onto which to draw the string
678  * @font:    the font in which to draw the string
679  * @matrix:  a #PangoMatrix, or %NULL to use an identity transformation
680  * @glyphs:  the glyph string to draw
681  * @x:       the x position of the start of the string (in Pango
682  *           units in user space coordinates)
683  * @y:       the y position of the baseline (in Pango units
684  *           in user space coordinates)
685  *
686  * Renders a #PangoGlyphString onto a FreeType2 bitmap, possibly
687  * transforming the layed-out coordinates through a transformation
688  * matrix. Note that the transformation matrix for @font is not
689  * changed, so to produce correct rendering results, the @font
690  * must have been loaded using a #PangoContext with an identical
691  * transformation matrix to that passed in to this function.
692  *
693  * Since: 1.6
694  **/
695 void
696 pango_ft2_render_transformed (FT_Bitmap         *bitmap,
697                               const PangoMatrix *matrix,
698                               PangoFont         *font,
699                               PangoGlyphString  *glyphs,
700                               int                x,
701                               int                y)
702 {
703   PangoFontMap *fontmap;
704   PangoRenderer *renderer;
705
706   g_return_if_fail (bitmap != NULL);
707   g_return_if_fail (glyphs != NULL);
708   g_return_if_fail (PANGO_FT2_IS_FONT (font));
709
710   fontmap = PANGO_FC_FONT (font)->fontmap;
711   renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap));
712
713   pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
714   pango_renderer_set_matrix (renderer, matrix);
715
716   pango_renderer_draw_glyphs (renderer, font, glyphs, x, y);
717 }
718
719 /**
720  * pango_ft2_render:
721  * @bitmap:  the FreeType2 bitmap onto which to draw the string
722  * @font:    the font in which to draw the string
723  * @glyphs:  the glyph string to draw
724  * @x:       the x position of the start of the string (in pixels)
725  * @y:       the y position of the baseline (in pixels)
726  *
727  * Renders a #PangoGlyphString onto a FreeType2 bitmap.
728  **/
729 void
730 pango_ft2_render (FT_Bitmap        *bitmap,
731                   PangoFont        *font,
732                   PangoGlyphString *glyphs,
733                   int               x,
734                   int               y)
735 {
736   pango_ft2_render_transformed (bitmap, NULL, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE);
737 }
738