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 
35 typedef 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 
41 struct _PangoFT2Renderer
42 {
43   PangoRenderer parent_instance;
44 
45   FT_Bitmap *bitmap;
46 };
47 
48 struct _PangoFT2RendererClass
49 {
50   PangoRendererClass parent_class;
51 };
52 
53 static void pango_ft2_renderer_draw_glyph     (PangoRenderer    *renderer,
54 					       PangoFont        *font,
55 					       PangoGlyph        glyph,
56 					       double            x,
57 					       double            y);
58 static 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 
G_DEFINE_TYPE(PangoFT2Renderer,pango_ft2_renderer,PANGO_TYPE_RENDERER)67 G_DEFINE_TYPE (PangoFT2Renderer, pango_ft2_renderer, PANGO_TYPE_RENDERER)
68 
69 static void
70 pango_ft2_renderer_init (PangoFT2Renderer *renderer G_GNUC_UNUSED)
71 {
72 }
73 
74 static void
pango_ft2_renderer_class_init(PangoFT2RendererClass * klass)75 pango_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 
83 static void
pango_ft2_renderer_set_bitmap(PangoFT2Renderer * renderer,FT_Bitmap * bitmap)84 pango_ft2_renderer_set_bitmap (PangoFT2Renderer *renderer,
85 			      FT_Bitmap         *bitmap)
86 {
87   renderer->bitmap = bitmap;
88 }
89 
90 typedef struct
91 {
92   FT_Bitmap bitmap;
93   int bitmap_left;
94   int bitmap_top;
95 } PangoFT2RenderedGlyph;
96 
97 static void
pango_ft2_free_rendered_glyph(PangoFT2RenderedGlyph * rendered)98 pango_ft2_free_rendered_glyph (PangoFT2RenderedGlyph *rendered)
99 {
100   g_free (rendered->bitmap.buffer);
101   g_slice_free (PangoFT2RenderedGlyph, rendered);
102 }
103 
104 static PangoFT2RenderedGlyph *
pango_ft2_font_render_box_glyph(int width,int height,int top,gboolean invalid)105 pango_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 (box->bitmap.rows, 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 
185 static PangoFT2RenderedGlyph *
pango_ft2_font_render_glyph(PangoFont * font,PangoGlyph glyph_index)186 pango_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_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, ft2font->load_flags);
226       FT_Render_Glyph (face->glyph,
227 		       (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 (face->glyph->bitmap.buffer,
232                                            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     {
245 generic_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_input);
250     }
251 }
252 
253 static void
pango_ft2_renderer_draw_glyph(PangoRenderer * renderer,PangoFont * font,PangoGlyph glyph,double x,double y)254 pango_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 + 0.5);
268   int iyoff = floor (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);
287   add_glyph_to_cache = FALSE;
288   if (rendered_glyph == NULL)
289     {
290       rendered_glyph = pango_ft2_font_render_glyph (font, 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 					       (GDestroyNotify) pango_ft2_free_rendered_glyph);
376       _pango_ft2_font_set_cache_glyph_data (font,
377 					    glyph, rendered_glyph);
378     }
379 }
380 
381 typedef struct {
382   double y;
383   double x1;
384   double x2;
385 } Position;
386 
387 static void
draw_simple_trap(PangoRenderer * renderer,Position * t,Position * b)388 draw_simple_trap (PangoRenderer *renderer,
389 		  Position      *t,
390 		  Position      *b)
391 {
392   FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap;
393   int iy = floor (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 (t->x1);
404   else
405     x1 = floor (b->x1);
406 
407   if (t->x2 > b->x2)
408     x2 = ceil (t->x2);
409   else
410     x2 = ceil (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 
433 static void
interpolate_position(Position * result,Position * top,Position * bottom,double val,double val1,double val2)434 interpolate_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  */
453 static void
pango_ft2_renderer_draw_trapezoid(PangoRenderer * renderer,PangoRenderPart part G_GNUC_UNUSED,double y1,double x11,double x21,double y2,double x12,double x22)454 pango_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 (pos.y) + 1;
505       if (y_next < pos_next.y)
506 	{
507 	  interpolate_position (&pos_next, &t, &b,
508 				y_next, t.y, 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 (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 (&pos_next, &t, &b,
526 				    x1_next, t.x1, 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 (&pos_next, &t, &b,
538 				    x1_next, t.x1, 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 (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 (&pos_next, &t, &b,
557 				    x2_next, t.x2, 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 (&pos_next, &t, &b,
569 				    x2_next, t.x2, b.x2);
570 	      pos_next.x2 = x2_next;
571 	      done = FALSE;
572 	    }
573 	}
574 
575       draw_simple_trap (renderer, &pos, &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  */
597 void
pango_ft2_render_layout_subpixel(FT_Bitmap * bitmap,PangoLayout * layout,int x,int y)598 pango_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  */
628 void
pango_ft2_render_layout(FT_Bitmap * bitmap,PangoLayout * layout,int x,int y)629 pango_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 * PANGO_SCALE, 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  */
654 void
pango_ft2_render_layout_line_subpixel(FT_Bitmap * bitmap,PangoLayoutLine * line,int x,int y)655 pango_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 (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  */
685 void
pango_ft2_render_layout_line(FT_Bitmap * bitmap,PangoLayoutLine * line,int x,int y)686 pango_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 * PANGO_SCALE, 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  */
716 void
pango_ft2_render_transformed(FT_Bitmap * bitmap,const PangoMatrix * matrix,PangoFont * font,PangoGlyphString * glyphs,int x,int y)717 pango_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  */
750 void
pango_ft2_render(FT_Bitmap * bitmap,PangoFont * font,PangoGlyphString * glyphs,int x,int y)751 pango_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 * PANGO_SCALE, y * PANGO_SCALE);
758 }
759 
760