2 * pango-renderer.h: Base class for rendering
4 * Copyright (C) 2004 Red Hat, Inc.
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.
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.
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.
25 #include "pango-renderer.h"
26 #include "pango-impl-utils.h"
28 #define N_RENDER_PARTS 4
30 #define PANGO_IS_RENDERER_FAST(renderer) (renderer != NULL)
31 #define IS_VALID_PART(part) ((guint)part < N_RENDER_PARTS)
33 typedef struct _LineState LineState;
34 typedef struct _Point Point;
43 PangoUnderline underline;
44 PangoRectangle underline_rect;
46 gboolean strikethrough;
47 PangoRectangle strikethrough_rect;
52 struct _PangoRendererPrivate
54 PangoColor color[N_RENDER_PARTS];
55 gboolean color_set[N_RENDER_PARTS];
57 PangoLayoutLine *line;
58 LineState *line_state;
61 static void pango_renderer_finalize (GObject *gobject);
62 static void pango_renderer_default_draw_glyphs (PangoRenderer *renderer,
64 PangoGlyphString *glyphs,
67 static void pango_renderer_default_draw_glyph_item (PangoRenderer *renderer,
69 PangoGlyphItem *glyph_item,
72 static void pango_renderer_default_draw_rectangle (PangoRenderer *renderer,
78 static void pango_renderer_default_draw_error_underline (PangoRenderer *renderer,
83 static void pango_renderer_default_prepare_run (PangoRenderer *renderer,
86 static void pango_renderer_prepare_run (PangoRenderer *renderer,
90 to_device (PangoMatrix *matrix,
97 result->x = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
98 result->y = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
102 result->x = x / PANGO_SCALE;
103 result->y = y / PANGO_SCALE;
107 G_DEFINE_ABSTRACT_TYPE (PangoRenderer, pango_renderer, G_TYPE_OBJECT)
109 static GObjectClass *parent_class;
112 pango_renderer_class_init (PangoRendererClass *klass)
114 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
116 parent_class = G_OBJECT_CLASS (g_type_class_peek_parent (klass));
118 klass->draw_glyphs = pango_renderer_default_draw_glyphs;
119 klass->draw_glyph_item = pango_renderer_default_draw_glyph_item;
120 klass->draw_rectangle = pango_renderer_default_draw_rectangle;
121 klass->draw_error_underline = pango_renderer_default_draw_error_underline;
122 klass->prepare_run = pango_renderer_default_prepare_run;
124 gobject_class->finalize = pango_renderer_finalize;
126 g_type_class_add_private (gobject_class, sizeof (PangoRendererPrivate));
130 pango_renderer_init (PangoRenderer *renderer)
132 renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer,
134 PangoRendererPrivate);
135 renderer->matrix = NULL;
139 pango_renderer_finalize (GObject *gobject)
141 PangoRenderer *renderer = PANGO_RENDERER (gobject);
143 if (renderer->matrix)
144 pango_matrix_free (renderer->matrix);
146 parent_class->finalize (gobject);
150 * pango_renderer_draw_layout:
151 * @renderer: a #PangoRenderer
152 * @layout: a #PangoLayout
153 * @x: X position of left edge of baseline, in user space coordinates
155 * @y: Y position of left edge of baseline, in user space coordinates
158 * Draws @layout with the specified #PangoRenderer.
163 pango_renderer_draw_layout (PangoRenderer *renderer,
168 PangoLayoutIter *iter;
170 g_return_if_fail (PANGO_IS_RENDERER (renderer));
171 g_return_if_fail (PANGO_IS_LAYOUT (layout));
173 /* We only change the matrix if the renderer isn't already
176 if (!renderer->active_count)
178 PangoContext *context = pango_layout_get_context (layout);
179 pango_renderer_set_matrix (renderer,
180 pango_context_get_matrix (context));
183 pango_renderer_activate (renderer);
185 iter = pango_layout_get_iter (layout);
189 PangoRectangle logical_rect;
190 PangoLayoutLine *line;
193 line = pango_layout_iter_get_line_readonly (iter);
195 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
196 baseline = pango_layout_iter_get_baseline (iter);
198 pango_renderer_draw_layout_line (renderer,
203 while (pango_layout_iter_next_line (iter));
205 pango_layout_iter_free (iter);
207 pango_renderer_deactivate (renderer);
211 draw_underline (PangoRenderer *renderer,
214 PangoRectangle *rect = &state->underline_rect;
215 PangoUnderline underline = state->underline;
217 state->underline = PANGO_UNDERLINE_NONE;
221 case PANGO_UNDERLINE_NONE:
223 case PANGO_UNDERLINE_DOUBLE:
224 pango_renderer_draw_rectangle (renderer,
225 PANGO_RENDER_PART_UNDERLINE,
227 rect->y + 2 * rect->height,
231 case PANGO_UNDERLINE_SINGLE:
232 case PANGO_UNDERLINE_LOW:
233 pango_renderer_draw_rectangle (renderer,
234 PANGO_RENDER_PART_UNDERLINE,
240 case PANGO_UNDERLINE_ERROR:
241 pango_renderer_draw_error_underline (renderer,
251 draw_strikethrough (PangoRenderer *renderer,
254 PangoRectangle *rect = &state->strikethrough_rect;
255 gboolean strikethrough = state->strikethrough;
257 state->strikethrough = FALSE;
260 pango_renderer_draw_rectangle (renderer,
261 PANGO_RENDER_PART_STRIKETHROUGH,
269 handle_line_state_change (PangoRenderer *renderer,
270 PangoRenderPart part)
272 LineState *state = renderer->priv->line_state;
276 if (part == PANGO_RENDER_PART_UNDERLINE &&
277 state->underline != PANGO_UNDERLINE_NONE)
279 PangoRectangle *rect = &state->underline_rect;
281 rect->width = state->logical_rect_end - rect->x;
282 draw_underline (renderer, state);
283 state->underline = renderer->underline;
284 rect->x = state->logical_rect_end;
288 if (part == PANGO_RENDER_PART_STRIKETHROUGH &&
289 state->strikethrough)
291 PangoRectangle *rect = &state->strikethrough_rect;
293 rect->width = state->logical_rect_end - rect->x;
294 draw_strikethrough (renderer, state);
295 state->strikethrough = renderer->strikethrough;
296 rect->x = state->logical_rect_end;
302 add_underline (PangoRenderer *renderer,
304 PangoFontMetrics *metrics,
307 PangoRectangle *ink_rect,
308 PangoRectangle *logical_rect)
310 PangoRectangle *current_rect = &state->underline_rect;
311 PangoRectangle new_rect;
313 int underline_thickness = pango_font_metrics_get_underline_thickness (metrics);
314 int underline_position = pango_font_metrics_get_underline_position (metrics);
316 new_rect.x = base_x + logical_rect->x;
317 new_rect.width = logical_rect->width;
318 new_rect.height = underline_thickness;
321 switch (renderer->underline)
323 case PANGO_UNDERLINE_NONE:
324 g_assert_not_reached ();
326 case PANGO_UNDERLINE_SINGLE:
327 case PANGO_UNDERLINE_DOUBLE:
328 case PANGO_UNDERLINE_ERROR:
329 new_rect.y -= underline_position;
331 case PANGO_UNDERLINE_LOW:
332 new_rect.y += ink_rect->y + ink_rect->height + underline_thickness;
336 if (renderer->underline == state->underline &&
337 new_rect.y == current_rect->y &&
338 new_rect.height == current_rect->height)
340 current_rect->width = new_rect.x + new_rect.width - current_rect->x;
344 draw_underline (renderer, state);
346 *current_rect = new_rect;
347 state->underline = renderer->underline;
352 add_strikethrough (PangoRenderer *renderer,
354 PangoFontMetrics *metrics,
357 PangoRectangle *ink_rect G_GNUC_UNUSED,
358 PangoRectangle *logical_rect)
360 PangoRectangle *current_rect = &state->strikethrough_rect;
361 PangoRectangle new_rect;
363 int strikethrough_thickness = pango_font_metrics_get_strikethrough_thickness (metrics);
364 int strikethrough_position = pango_font_metrics_get_strikethrough_position (metrics);
366 new_rect.x = base_x + logical_rect->x;
367 new_rect.width = logical_rect->width;
368 new_rect.y = base_y - strikethrough_position;
369 new_rect.height = strikethrough_thickness;
371 if (state->strikethrough &&
372 new_rect.y == current_rect->y &&
373 new_rect.height == current_rect->height)
375 current_rect->width = new_rect.x + new_rect.width - current_rect->x;
379 draw_strikethrough (renderer, state);
381 *current_rect = new_rect;
382 state->strikethrough = TRUE;
387 get_item_properties (PangoItem *item,
389 PangoAttrShape **shape_attr)
399 for (l = item->analysis.extra_attrs; l; l = l->next)
401 PangoAttribute *attr = l->data;
403 switch ((int) attr->klass->type)
405 case PANGO_ATTR_SHAPE:
407 *shape_attr = (PangoAttrShape *)attr;
410 case PANGO_ATTR_RISE:
412 *rise = ((PangoAttrInt *)attr)->value;
422 draw_shaped_glyphs (PangoRenderer *renderer,
423 PangoGlyphString *glyphs,
424 PangoAttrShape *attr,
428 PangoRendererClass *class = PANGO_RENDERER_GET_CLASS (renderer);
431 if (!class->draw_shape)
434 for (i = 0; i < glyphs->num_glyphs; i++)
436 PangoGlyphInfo *gi = &glyphs->glyphs[i];
438 class->draw_shape (renderer, attr, x, y);
440 x += gi->geometry.width;
446 * pango_renderer_draw_layout_line:
447 * @renderer: a #PangoRenderer
448 * @line: a #PangoLayoutLine
449 * @x: X position of left edge of baseline, in user space coordinates
451 * @y: Y position of left edge of baseline, in user space coordinates
454 * Draws @line with the specified #PangoRenderer.
459 pango_renderer_draw_layout_line (PangoRenderer *renderer,
460 PangoLayoutLine *line,
465 int glyph_string_width;
468 gboolean got_overall = FALSE;
469 PangoRectangle overall_rect;
472 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
474 /* We only change the matrix if the renderer isn't already
477 if (!renderer->active_count)
478 pango_renderer_set_matrix (renderer,
479 G_LIKELY (line->layout) ?
480 pango_context_get_matrix
481 (pango_layout_get_context (line->layout)) :
484 pango_renderer_activate (renderer);
486 renderer->priv->line = line;
487 renderer->priv->line_state = &state;
489 state.underline = PANGO_UNDERLINE_NONE;
490 state.strikethrough = FALSE;
492 text = G_LIKELY (line->layout) ? pango_layout_get_text (line->layout) : NULL;
494 for (l = line->runs; l; l = l->next)
496 PangoFontMetrics *metrics;
498 PangoLayoutRun *run = l->data;
499 PangoAttrShape *shape_attr;
500 PangoRectangle ink_rect, *ink = NULL;
501 PangoRectangle logical_rect, *logical = NULL;
503 if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)
504 logical = &logical_rect;
506 pango_renderer_prepare_run (renderer, run);
508 get_item_properties (run->item, &rise, &shape_attr);
513 logical = &logical_rect;
514 _pango_shape_get_extents (run->glyphs->num_glyphs,
515 &shape_attr->ink_rect,
516 &shape_attr->logical_rect,
519 glyph_string_width = logical->width;
523 if (renderer->underline != PANGO_UNDERLINE_NONE ||
524 renderer->strikethrough)
527 logical = &logical_rect;
529 if (G_UNLIKELY (ink || logical))
530 pango_glyph_string_extents (run->glyphs, run->item->analysis.font,
533 glyph_string_width = logical_rect.width;
535 glyph_string_width = pango_glyph_string_get_width (run->glyphs);
538 state.logical_rect_end = x + x_off + glyph_string_width;
540 if (run->item->analysis.flags & PANGO_ANALYSIS_FLAG_CENTERED_BASELINE)
542 gboolean is_hinted = ((logical_rect.y | logical_rect.height) & (PANGO_SCALE - 1)) == 0;
543 int adjustment = logical_rect.y + logical_rect.height / 2;
546 adjustment = PANGO_UNITS_ROUND (adjustment);
552 if (renderer->priv->color_set[PANGO_RENDER_PART_BACKGROUND])
556 pango_layout_line_get_extents (line, NULL, &overall_rect);
560 pango_renderer_draw_rectangle (renderer,
561 PANGO_RENDER_PART_BACKGROUND,
565 overall_rect.height);
570 draw_shaped_glyphs (renderer, run->glyphs, shape_attr, x + x_off, y - rise);
574 pango_renderer_draw_glyph_item (renderer,
577 x + x_off, y - rise);
580 if (renderer->underline != PANGO_UNDERLINE_NONE ||
581 renderer->strikethrough)
583 metrics = pango_font_get_metrics (run->item->analysis.font,
584 run->item->analysis.language);
586 if (renderer->underline != PANGO_UNDERLINE_NONE)
587 add_underline (renderer, &state,metrics,
591 if (renderer->strikethrough)
592 add_strikethrough (renderer, &state, metrics,
596 pango_font_metrics_unref (metrics);
599 if (renderer->underline == PANGO_UNDERLINE_NONE &&
600 state.underline != PANGO_UNDERLINE_NONE)
601 draw_underline (renderer, &state);
603 if (!renderer->strikethrough && state.strikethrough)
604 draw_strikethrough (renderer, &state);
606 x_off += glyph_string_width;
609 /* Finish off any remaining underlines
611 draw_underline (renderer, &state);
612 draw_strikethrough (renderer, &state);
614 renderer->priv->line_state = NULL;
615 renderer->priv->line = NULL;
617 pango_renderer_deactivate (renderer);
621 * pango_renderer_draw_glyphs:
622 * @renderer: a #PangoRenderer
623 * @font: a #PangoFont
624 * @glyphs: a #PangoGlyphString
625 * @x: X position of left edge of baseline, in user space coordinates
627 * @y: Y position of left edge of baseline, in user space coordinates
630 * Draws the glyphs in @glyphs with the specified #PangoRenderer.
635 pango_renderer_draw_glyphs (PangoRenderer *renderer,
637 PangoGlyphString *glyphs,
641 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
643 pango_renderer_activate (renderer);
645 PANGO_RENDERER_GET_CLASS (renderer)->draw_glyphs (renderer, font, glyphs, x, y);
647 pango_renderer_deactivate (renderer);
651 pango_renderer_default_draw_glyphs (PangoRenderer *renderer,
653 PangoGlyphString *glyphs,
660 for (i = 0; i < glyphs->num_glyphs; i++)
662 PangoGlyphInfo *gi = &glyphs->glyphs[i];
665 to_device (renderer->matrix,
666 x + x_position + gi->geometry.x_offset,
667 y + gi->geometry.y_offset,
670 pango_renderer_draw_glyph (renderer, font, gi->glyph, p.x, p.y);
672 x_position += gi->geometry.width;
677 * pango_renderer_draw_glyph_item:
678 * @renderer: a #PangoRenderer
679 * @text: the UTF-8 text that @glyph_item refers to, or %NULL
680 * @glyph_item: a #PangoGlyphItem
681 * @x: X position of left edge of baseline, in user space coordinates
683 * @y: Y position of left edge of baseline, in user space coordinates
686 * Draws the glyphs in @glyph_item with the specified #PangoRenderer,
687 * embedding the text associated with the glyphs in the output if the
688 * output format supports it (PDF for example).
690 * Note that @text is the start of the text for layout, which is then
691 * indexed by <literal>@glyph_item->item->offset</literal>.
693 * If @text is %NULL, this simply calls pango_renderer_draw_glyphs().
695 * The default implementation of this method simply falls back to
696 * pango_renderer_draw_glyphs().
701 pango_renderer_draw_glyph_item (PangoRenderer *renderer,
703 PangoGlyphItem *glyph_item,
707 if (G_UNLIKELY (text))
709 pango_renderer_draw_glyphs (renderer,
710 glyph_item->item->analysis.font,
716 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
718 pango_renderer_activate (renderer);
720 PANGO_RENDERER_GET_CLASS (renderer)->draw_glyph_item (renderer, text, glyph_item, x, y);
722 pango_renderer_deactivate (renderer);
726 pango_renderer_default_draw_glyph_item (PangoRenderer *renderer,
727 const char *text G_GNUC_UNUSED,
728 PangoGlyphItem *glyph_item,
732 pango_renderer_draw_glyphs (renderer,
733 glyph_item->item->analysis.font,
739 * pango_renderer_draw_rectangle:
740 * @renderer: a #PangoRenderer
741 * @part: type of object this rectangle is part of
742 * @x: X position at which to draw rectangle, in user space coordinates in Pango units
743 * @y: Y position at which to draw rectangle, in user space coordinates in Pango units
744 * @width: width of rectangle in Pango units in user space coordinates
745 * @height: height of rectangle in Pango units in user space coordinates
747 * Draws an axis-aligned rectangle in user space coordinates with the
748 * specified #PangoRenderer.
750 * This should be called while @renderer is already active. Use
751 * pango_renderer_activate() to activate a renderer.
756 pango_renderer_draw_rectangle (PangoRenderer *renderer,
757 PangoRenderPart part,
763 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
764 g_return_if_fail (IS_VALID_PART (part));
765 g_return_if_fail (renderer->active_count > 0);
767 PANGO_RENDERER_GET_CLASS (renderer)->draw_rectangle (renderer, part, x, y, width, height);
771 compare_points (const void *a,
779 else if (pa->y > pb->y)
781 else if (pa->x < pb->x)
783 else if (pa->x > pb->x)
790 draw_rectangle (PangoRenderer *renderer,
792 PangoRenderPart part,
800 /* Convert the points to device coordinates, and sort
801 * in ascending Y order. (Ordering by X for ties)
803 to_device (matrix, x, y, &points[0]);
804 to_device (matrix, x + width, y, &points[1]);
805 to_device (matrix, x, y + height, &points[2]);
806 to_device (matrix, x + width, y + height, &points[3]);
808 qsort (points, 4, sizeof (Point), compare_points);
810 /* There are essentially three cases. (There is a fourth
811 * case where trapezoid B is degenerate and we just have
812 * two triangles, but we don't need to handle it separately.)
818 * / B / /____\ /____\
819 * /_____/ / B / \ B \
825 if (points[0].y == points[1].y)
827 /* Case 1 (pure shear) */
828 pango_renderer_draw_trapezoid (renderer, part, /* B */
829 points[0].y, points[0].x, points[1].x,
830 points[2].y, points[2].x, points[3].x);
832 else if (points[1].x < points[2].x)
835 double tmp_width = ((points[2].x - points[0].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y);
836 double base_width = tmp_width + points[0].x - points[1].x;
838 pango_renderer_draw_trapezoid (renderer, part, /* A */
839 points[0].y, points[0].x, points[0].x,
840 points[1].y, points[1].x, points[1].x + base_width);
841 pango_renderer_draw_trapezoid (renderer, part, /* B */
842 points[1].y, points[1].x, points[1].x + base_width,
843 points[2].y, points[2].x - base_width, points[2].x);
844 pango_renderer_draw_trapezoid (renderer, part, /* C */
845 points[2].y, points[2].x - base_width, points[2].x,
846 points[3].y, points[3].x, points[3].x);
851 double tmp_width = ((points[0].x - points[2].x) * (points[1].y - points[0].y)) / (points[2].y - points[0].y);
852 double base_width = tmp_width + points[1].x - points[0].x;
854 pango_renderer_draw_trapezoid (renderer, part, /* A */
855 points[0].y, points[0].x, points[0].x,
856 points[1].y, points[1].x - base_width, points[1].x);
857 pango_renderer_draw_trapezoid (renderer, part, /* B */
858 points[1].y, points[1].x - base_width, points[1].x,
859 points[2].y, points[2].x, points[2].x + base_width);
860 pango_renderer_draw_trapezoid (renderer, part, /* C */
861 points[2].y, points[2].x, points[2].x + base_width,
862 points[3].y, points[3].x, points[3].x);
867 pango_renderer_default_draw_rectangle (PangoRenderer *renderer,
868 PangoRenderPart part,
874 draw_rectangle (renderer, renderer->matrix, part, x, y, width, height);
878 * pango_renderer_draw_error_underline:
879 * @renderer: a #PangoRenderer
880 * @x: X coordinate of underline, in Pango units in user coordinate system
881 * @y: Y coordinate of underline, in Pango units in user coordinate system
882 * @width: width of underline, in Pango units in user coordinate system
883 * @height: height of underline, in Pango units in user coordinate system
885 * Draw a squiggly line that approximately covers the given rectangle
886 * in the style of an underline used to indicate a spelling error.
887 * (The width of the underline is rounded to an integer number
888 * of up/down segments and the resulting rectangle is centered
889 * in the original rectangle)
891 * This should be called while @renderer is already active. Use
892 * pango_renderer_activate() to activate a renderer.
897 pango_renderer_draw_error_underline (PangoRenderer *renderer,
903 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
904 g_return_if_fail (renderer->active_count > 0);
906 PANGO_RENDERER_GET_CLASS (renderer)->draw_error_underline (renderer, x, y, width, height);
909 /* We are drawing an error underline that looks like one of:
912 * / \ / \ / \ / \ / \ |
913 * \ \ /\ \ / / \ \ /\ \ |
914 * \ \/B \ \/ C / \ \/B \ \ | height = HEIGHT_SQUARES * square
915 * \ A \ /\ A \ / \ A \ /\ A \ |
916 * \ \/ \ \/ \ \/ \ \ |
920 * unit_width = (HEIGHT_SQUARES - 1) * square
922 * To do this conveniently, we work in a coordinate system where A,B,C
923 * are axis aligned rectangles. (If fonts were square, the diagrams
937 * Note that the long side in this coordinate system is HEIGHT_SQUARES + 1
940 * The diagrams above are shown with HEIGHT_SQUARES an integer, but
941 * that is actually incidental; the value 2.5 below seems better than
942 * either HEIGHT_SQUARES=3 (a little long and skinny) or
943 * HEIGHT_SQUARES=2 (a bit short and stubby)
946 #define HEIGHT_SQUARES 2.5
949 get_total_matrix (PangoMatrix *total,
950 const PangoMatrix *global,
956 gdouble scale = 0.5 * square;
958 /* The local matrix translates from the axis aligned coordinate system
959 * to the original user space coordinate system.
969 pango_matrix_concat (total, &local);
971 total->x0 = (global->xx * x + global->xy * y) / PANGO_SCALE + global->x0;
972 total->y0 = (global->yx * x + global->yy * y) / PANGO_SCALE + global->y0;
976 pango_renderer_default_draw_error_underline (PangoRenderer *renderer,
982 int square = height / HEIGHT_SQUARES;
983 int unit_width = (HEIGHT_SQUARES - 1) * square;
984 int width_units = (width + unit_width / 2) / unit_width;
985 static const PangoMatrix identity = PANGO_MATRIX_INIT;
986 const PangoMatrix *matrix;
991 x += (width - width_units * unit_width) / 2;
992 width = width_units * unit_width;
994 if (renderer->matrix)
995 matrix = renderer->matrix;
999 get_total_matrix (&total, matrix, x, y, square);
1000 dx = unit_width * 2;
1001 dx0 = (matrix->xx * dx) / PANGO_SCALE;
1002 dy0 = (matrix->yx * dx) / PANGO_SCALE;
1004 i = (width_units - 1) / 2;
1007 draw_rectangle (renderer, &total, PANGO_RENDER_PART_UNDERLINE, /* A */
1009 HEIGHT_SQUARES * 2 - 1, 1);
1015 draw_rectangle (renderer, &total, PANGO_RENDER_PART_UNDERLINE, /* B */
1016 HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 3),
1017 1, HEIGHT_SQUARES * 2 - 3);
1022 if (width_units % 2 == 0)
1024 draw_rectangle (renderer, &total, PANGO_RENDER_PART_UNDERLINE, /* C */
1025 HEIGHT_SQUARES * 2 - 2, - (HEIGHT_SQUARES * 2 - 2),
1026 1, HEIGHT_SQUARES * 2 - 2);
1031 * pango_renderer_draw_trapezoid:
1032 * @renderer: a #PangoRenderer
1033 * @part: type of object this trapezoid is part of
1034 * @y1_: Y coordinate of top of trapezoid
1035 * @x11: X coordinate of left end of top of trapezoid
1036 * @x21: X coordinate of right end of top of trapezoid
1037 * @y2: Y coordinate of bottom of trapezoid
1038 * @x12: X coordinate of left end of bottom of trapezoid
1039 * @x22: X coordinate of right end of bottom of trapezoid
1041 * Draws a trapezoid with the parallel sides aligned with the X axis
1042 * using the given #PangoRenderer; coordinates are in device space.
1047 pango_renderer_draw_trapezoid (PangoRenderer *renderer,
1048 PangoRenderPart part,
1056 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1057 g_return_if_fail (renderer->active_count > 0);
1059 if (PANGO_RENDERER_GET_CLASS (renderer)->draw_trapezoid)
1060 PANGO_RENDERER_GET_CLASS (renderer)->draw_trapezoid (renderer, part,
1066 * pango_renderer_draw_glyph:
1067 * @renderer: a #PangoRenderer
1068 * @font: a #PangoFont
1069 * @glyph: the glyph index of a single glyph
1070 * @x: X coordinate of left edge of baseline of glyph
1071 * @y: Y coordinate of left edge of baseline of glyph
1073 * Draws a single glyph with coordinates in device space.
1078 pango_renderer_draw_glyph (PangoRenderer *renderer,
1084 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1085 g_return_if_fail (renderer->active_count > 0);
1087 if (glyph == PANGO_GLYPH_EMPTY) /* glyph PANGO_GLYPH_EMPTY never renders */
1090 if (PANGO_RENDERER_GET_CLASS (renderer)->draw_glyph)
1091 PANGO_RENDERER_GET_CLASS (renderer)->draw_glyph (renderer, font, glyph, x, y);
1095 * pango_renderer_activate:
1096 * @renderer: a #PangoRenderer
1098 * Does initial setup before rendering operations on @renderer.
1099 * pango_renderer_deactivate() should be called when done drawing.
1100 * Calls such as pango_renderer_draw_layout() automatically
1101 * activate the layout before drawing on it. Calls to
1102 * pango_renderer_activate() and pango_renderer_deactivate() can
1103 * be nested and the renderer will only be initialized and
1104 * deinitialized once.
1109 pango_renderer_activate (PangoRenderer *renderer)
1111 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1113 renderer->active_count++;
1114 if (renderer->active_count == 1)
1116 if (PANGO_RENDERER_GET_CLASS (renderer)->begin)
1117 PANGO_RENDERER_GET_CLASS (renderer)->begin (renderer);
1122 * pango_renderer_deactivate:
1123 * @renderer: a #PangoRenderer
1125 * Cleans up after rendering operations on @renderer. See
1126 * docs for pango_renderer_activate().
1131 pango_renderer_deactivate (PangoRenderer *renderer)
1133 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1134 g_return_if_fail (renderer->active_count > 0);
1136 if (renderer->active_count == 1)
1138 if (PANGO_RENDERER_GET_CLASS (renderer)->end)
1139 PANGO_RENDERER_GET_CLASS (renderer)->end (renderer);
1141 renderer->active_count--;
1145 * pango_renderer_set_color:
1146 * @renderer: a #PangoRenderer
1147 * @part: the part to change the color of
1148 * @color: the new color or %NULL to unset the current color
1150 * Sets the color for part of the rendering.
1155 pango_renderer_set_color (PangoRenderer *renderer,
1156 PangoRenderPart part,
1157 const PangoColor *color)
1159 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1160 g_return_if_fail (IS_VALID_PART (part));
1162 if ((!color && !renderer->priv->color_set[part]) ||
1163 (color && renderer->priv->color_set[part] &&
1164 renderer->priv->color[part].red == color->red &&
1165 renderer->priv->color[part].green == color->green &&
1166 renderer->priv->color[part].blue == color->blue))
1169 pango_renderer_part_changed (renderer, part);
1173 renderer->priv->color_set[part] = TRUE;
1174 renderer->priv->color[part] = *color;
1178 renderer->priv->color_set[part] = FALSE;
1183 * pango_renderer_get_color:
1184 * @renderer: a #PangoRenderer
1185 * @part: the part to get the color for
1187 * Gets the current rendering color for the specified part.
1189 * Return value: the color for the specified part, or %NULL
1190 * if it hasn't been set and should be inherited from the
1196 pango_renderer_get_color (PangoRenderer *renderer,
1197 PangoRenderPart part)
1199 g_return_val_if_fail (PANGO_IS_RENDERER_FAST (renderer), NULL);
1200 g_return_val_if_fail (IS_VALID_PART (part), NULL);
1202 if (renderer->priv->color_set[part])
1203 return &renderer->priv->color[part];
1209 * pango_renderer_part_changed:
1210 * @renderer: a #PangoRenderer
1211 * @part: the part for which rendering has changed.
1213 * Informs Pango that the way that the rendering is done
1214 * for @part has changed in a way that would prevent multiple
1215 * pieces being joined together into one drawing call. For
1216 * instance, if a subclass of #PangoRenderer was to add a stipple
1217 * option for drawing underlines, it needs to call
1219 * <informalexample><programlisting>
1220 * pango_renderer_part_changed (render, PANGO_RENDER_PART_UNDERLINE);
1221 * </programlisting></informalexample>
1223 * When the stipple changes or underlines with different stipples
1224 * might be joined together. Pango automatically calls this for
1225 * changes to colors. (See pango_renderer_set_color())
1230 pango_renderer_part_changed (PangoRenderer *renderer,
1231 PangoRenderPart part)
1233 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1234 g_return_if_fail (IS_VALID_PART (part));
1235 g_return_if_fail (renderer->active_count > 0);
1237 handle_line_state_change (renderer, part);
1239 if (PANGO_RENDERER_GET_CLASS (renderer)->part_changed)
1240 PANGO_RENDERER_GET_CLASS (renderer)->part_changed (renderer, part);
1244 * pango_renderer_prepare_run:
1245 * @renderer: a #PangoRenderer
1246 * @run: a #PangoLayoutRun
1248 * Set up the state of the #PangoRenderer for rendering @run.
1253 pango_renderer_prepare_run (PangoRenderer *renderer,
1254 PangoLayoutRun *run)
1256 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1258 PANGO_RENDERER_GET_CLASS (renderer)->prepare_run (renderer, run);
1262 pango_renderer_default_prepare_run (PangoRenderer *renderer,
1263 PangoLayoutRun *run)
1265 PangoColor *fg_color = NULL;
1266 PangoColor *bg_color = NULL;
1267 PangoColor *underline_color = NULL;
1268 PangoColor *strikethrough_color = NULL;
1271 renderer->underline = PANGO_UNDERLINE_NONE;
1272 renderer->strikethrough = FALSE;
1274 for (l = run->item->analysis.extra_attrs; l; l = l->next)
1276 PangoAttribute *attr = l->data;
1278 switch ((int) attr->klass->type)
1280 case PANGO_ATTR_UNDERLINE:
1281 renderer->underline = ((PangoAttrInt *)attr)->value;
1284 case PANGO_ATTR_STRIKETHROUGH:
1285 renderer->strikethrough = ((PangoAttrInt *)attr)->value;
1288 case PANGO_ATTR_FOREGROUND:
1289 fg_color = &((PangoAttrColor *)attr)->color;
1292 case PANGO_ATTR_BACKGROUND:
1293 bg_color = &((PangoAttrColor *)attr)->color;
1296 case PANGO_ATTR_UNDERLINE_COLOR:
1297 underline_color = &((PangoAttrColor *)attr)->color;
1300 case PANGO_ATTR_STRIKETHROUGH_COLOR:
1301 strikethrough_color = &((PangoAttrColor *)attr)->color;
1309 if (!underline_color)
1310 underline_color = fg_color;
1312 if (!strikethrough_color)
1313 strikethrough_color = fg_color;
1315 pango_renderer_set_color (renderer, PANGO_RENDER_PART_FOREGROUND, fg_color);
1316 pango_renderer_set_color (renderer, PANGO_RENDER_PART_BACKGROUND, bg_color);
1317 pango_renderer_set_color (renderer, PANGO_RENDER_PART_UNDERLINE, underline_color);
1318 pango_renderer_set_color (renderer, PANGO_RENDER_PART_STRIKETHROUGH, strikethrough_color);
1322 * pango_renderer_set_matrix:
1323 * @renderer: a #PangoRenderer
1324 * @matrix: a #PangoMatrix, or %NULL to unset any existing matrix.
1325 * (No matrix set is the same as setting the identity matrix.)
1327 * Sets the transformation matrix that will be applied when rendering.
1332 pango_renderer_set_matrix (PangoRenderer *renderer,
1333 const PangoMatrix *matrix)
1335 g_return_if_fail (PANGO_IS_RENDERER_FAST (renderer));
1337 pango_matrix_free (renderer->matrix);
1338 renderer->matrix = pango_matrix_copy (matrix);
1342 * pango_renderer_get_matrix:
1343 * @renderer: a #PangoRenderer
1345 * Gets the transformation matrix that will be applied when
1346 * rendering. See pango_renderer_set_matrix().
1348 * Return value: the matrix, or %NULL if no matrix has been set
1349 * (which is the same as the identity matrix). The returned
1350 * matrix is owned by Pango and must not be modified or
1355 G_CONST_RETURN PangoMatrix *
1356 pango_renderer_get_matrix (PangoRenderer *renderer)
1358 g_return_val_if_fail (PANGO_IS_RENDERER (renderer), NULL);
1360 return renderer->matrix;
1364 * pango_renderer_get_layout:
1365 * @renderer: a #PangoRenderer
1367 * Gets the layout currently being rendered using @renderer.
1368 * Calling this function only makes sense from inside a subclass's
1369 * methods, like in its draw_shape<!---->() for example.
1371 * The returned layout should not be modified while still being
1374 * Return value: the layout, or %NULL if no layout is being
1375 * rendered using @renderer at this time.
1380 pango_renderer_get_layout (PangoRenderer *renderer)
1382 if (G_UNLIKELY (renderer->priv->line == NULL))
1385 return renderer->priv->line->layout;
1389 * pango_renderer_get_layout_line:
1390 * @renderer: a #PangoRenderer
1392 * Gets the layout line currently being rendered using @renderer.
1393 * Calling this function only makes sense from inside a subclass's
1394 * methods, like in its draw_shape<!---->() for example.
1396 * The returned layout line should not be modified while still being
1399 * Return value: the layout line, or %NULL if no layout line is being
1400 * rendered using @renderer at this time.
1405 pango_renderer_get_layout_line (PangoRenderer *renderer)
1407 return renderer->priv->line;