2 * pangoft2-render.c: Rendering routines to FT_Bitmap objects
4 * Copyright (C) 2004 Red Hat Software
5 * Copyright (C) 2000 Tor Lillqvist
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.
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.
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.
26 #include "pangoft2-private.h"
28 /* for compatibility with older freetype versions */
29 #ifndef FT_LOAD_TARGET_MONO
30 #define FT_LOAD_TARGET_MONO FT_LOAD_MONOCHROME
33 typedef struct _PangoFT2RendererClass PangoFT2RendererClass;
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))
39 struct _PangoFT2Renderer
41 PangoRenderer parent_instance;
46 struct _PangoFT2RendererClass
48 PangoRendererClass parent_class;
51 static void pango_ft2_renderer_draw_glyph (PangoRenderer *renderer,
56 static void pango_ft2_renderer_draw_trapezoid (PangoRenderer *renderer,
65 G_DEFINE_TYPE (PangoFT2Renderer, pango_ft2_renderer, PANGO_TYPE_RENDERER)
68 pango_ft2_renderer_init (PangoFT2Renderer *renderer G_GNUC_UNUSED)
73 pango_ft2_renderer_class_init (PangoFT2RendererClass *klass)
75 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
77 renderer_class->draw_glyph = pango_ft2_renderer_draw_glyph;
78 renderer_class->draw_trapezoid = pango_ft2_renderer_draw_trapezoid;
82 pango_ft2_renderer_set_bitmap (PangoFT2Renderer *renderer,
85 renderer->bitmap = bitmap;
93 } PangoFT2RenderedGlyph;
96 pango_ft2_free_rendered_glyph (PangoFT2RenderedGlyph *rendered)
98 g_free (rendered->bitmap.buffer);
99 g_slice_free (PangoFT2RenderedGlyph, rendered);
102 static PangoFT2RenderedGlyph *
103 pango_ft2_font_render_box_glyph (int width,
108 PangoFT2RenderedGlyph *box;
109 int i, j, offset1, offset2, line_width;
111 line_width = MAX ((height + 43) / 44, 1);
112 if (width < 1 || height < 1)
115 box = g_slice_new (PangoFT2RenderedGlyph);
117 box->bitmap_left = 0;
118 box->bitmap_top = top;
120 box->bitmap.pixel_mode = ft_pixel_mode_grays;
122 box->bitmap.width = width;
123 box->bitmap.rows = height;
124 box->bitmap.pitch = height;
126 box->bitmap.buffer = g_malloc0 (box->bitmap.rows * box->bitmap.pitch);
129 for (j = 0; j < line_width; j++)
131 offset1 = box->bitmap.pitch * (MIN (1 + j, height - 1));
132 offset2 = box->bitmap.pitch * (MAX (box->bitmap.rows - 2 - j, 0));
134 i < box->bitmap.width - 1;
137 box->bitmap.buffer[offset1 + i] = 0xff;
138 box->bitmap.buffer[offset2 + i] = 0xff;
141 for (j = 0; j < line_width; j++)
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)
149 box->bitmap.buffer[offset1 + i] = 0xff;
150 box->bitmap.buffer[offset2 + i] = 0xff;
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)
164 for (j = 0; j < line_width; j++)
166 box->bitmap.buffer[PANGO_PIXELS (offset1) + i + j] = 0xff;
167 box->bitmap.buffer[PANGO_PIXELS (offset2) + i + j] = 0xff;
178 static PangoFT2RenderedGlyph *
179 pango_ft2_font_render_glyph (PangoFont *font,
180 PangoGlyph glyph_index)
183 gboolean invalid_input;
185 invalid_input = glyph_index == PANGO_GLYPH_INVALID_INPUT || (glyph_index & ~PANGO_GLYPH_UNKNOWN_FLAG) > 0x10FFFF;
187 if (glyph_index & PANGO_GLYPH_UNKNOWN_FLAG)
189 PangoFT2RenderedGlyph *box;
190 PangoFontMetrics *metrics;
195 metrics = pango_font_get_metrics (font, NULL);
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),
203 pango_font_metrics_unref (metrics);
208 face = pango_ft2_font_get_face (font);
212 PangoFT2RenderedGlyph *rendered;
213 PangoFT2Font *ft2font = (PangoFT2Font *) font;
215 rendered = g_slice_new (PangoFT2RenderedGlyph);
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));
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;
234 return pango_ft2_font_render_box_glyph (PANGO_UNKNOWN_GLYPH_WIDTH,
235 PANGO_UNKNOWN_GLYPH_HEIGHT,
236 PANGO_UNKNOWN_GLYPH_HEIGHT,
242 pango_ft2_renderer_draw_glyph (PangoRenderer *renderer,
248 FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap;
249 PangoFT2RenderedGlyph *rendered_glyph;
250 gboolean add_glyph_to_cache;
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);
259 if (glyph & PANGO_GLYPH_UNKNOWN_FLAG)
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.
266 gunichar wc = glyph & (~PANGO_GLYPH_UNKNOWN_FLAG);
268 if (G_UNLIKELY (glyph == PANGO_GLYPH_INVALID_INPUT || wc > 0x10FFFF))
269 glyph = PANGO_GLYPH_INVALID_INPUT;
271 glyph = PANGO_GLYPH_UNKNOWN_FLAG;
274 rendered_glyph = _pango_ft2_font_get_cache_glyph_data (font, glyph);
275 add_glyph_to_cache = FALSE;
276 if (rendered_glyph == NULL)
278 rendered_glyph = pango_ft2_font_render_glyph (font, glyph);
279 add_glyph_to_cache = TRUE;
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));
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));
290 src = rendered_glyph->bitmap.buffer +
291 y_start * rendered_glyph->bitmap.pitch;
293 dest = bitmap->buffer +
294 (y_start + iyoff - rendered_glyph->bitmap_top) * bitmap->pitch +
295 x_start + ixoff + rendered_glyph->bitmap_left;
297 switch (rendered_glyph->bitmap.pixel_mode)
299 case ft_pixel_mode_grays:
301 for (iy = y_start; iy < y_limit; iy++)
306 for (ix = x_start; ix < x_limit; ix++)
315 *d = MIN ((gushort) *d + (gushort) *s, 0xff);
323 dest += bitmap->pitch;
324 src += rendered_glyph->bitmap.pitch;
328 case ft_pixel_mode_mono:
330 for (iy = y_start; iy < y_limit; iy++)
335 for (ix = x_start; ix < x_limit; ix++)
337 if ((*s) & (1 << (7 - (ix % 8))))
345 dest += bitmap->pitch;
346 src += rendered_glyph->bitmap.pitch;
351 g_warning ("pango_ft2_render: "
352 "Unrecognized glyph bitmap pixel mode %d\n",
353 rendered_glyph->bitmap.pixel_mode);
357 if (add_glyph_to_cache)
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);
373 draw_simple_trap (PangoRenderer *renderer,
377 FT_Bitmap *bitmap = PANGO_FT2_RENDERER (renderer)->bitmap;
378 int iy = floor (t->y);
380 double dy = b->y - t->y;
383 if (iy < 0 || iy >= bitmap->rows)
385 dest = bitmap->buffer + iy * bitmap->pitch;
397 x1 = CLAMP (x1, 0, bitmap->width);
398 x2 = CLAMP (x2, 0, bitmap->width);
400 for (x = x1; x < x2; x++)
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));
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.
414 dest[x] = MIN (dest[x] + ic, 255);
419 interpolate_position (Position *result,
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);
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.
439 pango_ft2_renderer_draw_trapezoid (PangoRenderer *renderer,
440 PangoRenderPart part G_GNUC_UNUSED,
451 gboolean done = FALSE;
466 double y_next, x1_next, x2_next;
469 /* The algorithm here is written to emphasize simplicity and
470 * numerical stability as opposed to speed.
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.
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)
488 /* Check for crossing vertical pixel boundaries */
489 y_next = floor (pos.y) + 1;
490 if (y_next < pos_next.y)
492 interpolate_position (&pos_next, &t, &b,
498 /* Check left side for crossing horizontal pixel boundaries */
499 ix1 = floor (pos.x1);
508 if (x1_next > pos_next.x1)
510 interpolate_position (&pos_next, &t, &b,
511 x1_next, t.x1, b.x1);
512 pos_next.x1 = x1_next;
516 else if (b.x1 > t.x1)
520 if (x1_next < pos_next.x1)
522 interpolate_position (&pos_next, &t, &b,
523 x1_next, t.x1, b.x1);
524 pos_next.x1 = x1_next;
529 /* Check right side for crossing horizontal pixel boundaries */
530 ix2 = floor (pos.x2);
539 if (x2_next > pos_next.x2)
541 interpolate_position (&pos_next, &t, &b,
542 x2_next, t.x2, b.x2);
543 pos_next.x2 = x2_next;
551 if (x2_next < pos_next.x2)
553 interpolate_position (&pos_next, &t, &b,
554 x2_next, t.x2, b.x2);
555 pos_next.x2 = x2_next;
560 draw_simple_trap (renderer, &pos, &pos_next);
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)
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.)
581 pango_ft2_render_layout_subpixel (FT_Bitmap *bitmap,
586 PangoContext *context;
587 PangoFontMap *fontmap;
588 PangoRenderer *renderer;
590 g_return_if_fail (bitmap != NULL);
591 g_return_if_fail (PANGO_IS_LAYOUT (layout));
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));
597 pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
599 pango_renderer_draw_layout (renderer, layout, x, y);
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)
609 * Render a #PangoLayout onto a FreeType2 bitmap
612 pango_ft2_render_layout (FT_Bitmap *bitmap,
617 pango_ft2_render_layout_subpixel (bitmap, layout, x * PANGO_SCALE, y * PANGO_SCALE);
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)
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.)
636 pango_ft2_render_layout_line_subpixel (FT_Bitmap *bitmap,
637 PangoLayoutLine *line,
641 PangoContext *context;
642 PangoFontMap *fontmap;
643 PangoRenderer *renderer;
645 g_return_if_fail (bitmap != NULL);
646 g_return_if_fail (line != NULL);
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));
652 pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
654 pango_renderer_draw_layout_line (renderer, line, x, y);
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)
664 * Render a #PangoLayoutLine onto a FreeType2 bitmap
667 pango_ft2_render_layout_line (FT_Bitmap *bitmap,
668 PangoLayoutLine *line,
672 pango_ft2_render_layout_line_subpixel (bitmap, line, x * PANGO_SCALE, y * PANGO_SCALE);
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)
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.
696 pango_ft2_render_transformed (FT_Bitmap *bitmap,
697 const PangoMatrix *matrix,
699 PangoGlyphString *glyphs,
703 PangoFontMap *fontmap;
704 PangoRenderer *renderer;
706 g_return_if_fail (bitmap != NULL);
707 g_return_if_fail (glyphs != NULL);
708 g_return_if_fail (PANGO_FT2_IS_FONT (font));
710 fontmap = PANGO_FC_FONT (font)->fontmap;
711 renderer = _pango_ft2_font_map_get_renderer (PANGO_FT2_FONT_MAP (fontmap));
713 pango_ft2_renderer_set_bitmap (PANGO_FT2_RENDERER (renderer), bitmap);
714 pango_renderer_set_matrix (renderer, matrix);
716 pango_renderer_draw_glyphs (renderer, font, glyphs, x, y);
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)
727 * Renders a #PangoGlyphString onto a FreeType2 bitmap.
730 pango_ft2_render (FT_Bitmap *bitmap,
732 PangoGlyphString *glyphs,
736 pango_ft2_render_transformed (bitmap, NULL, font, glyphs, x * PANGO_SCALE, y * PANGO_SCALE);