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

source code of gtk/subprojects/pango/pango/pangoft2-render.c