2 * pangocairo-render.c: Rendering routines to Cairo surfaces
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.
26 #include "pangocairo-private.h"
27 #include "pango-glyph-item.h"
29 typedef struct _PangoCairoRendererClass PangoCairoRendererClass;
31 #define PANGO_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), PANGO_TYPE_CAIRO_RENDERER, PangoCairoRendererClass))
32 #define PANGO_IS_CAIRO_RENDERER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANGO_TYPE_CAIRO_RENDERER))
33 #define PANGO_CAIRO_RENDERER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), PANGO_TYPE_CAIRO_RENDERER, PangoCairoRendererClass))
35 struct _PangoCairoRenderer
37 PangoRenderer parent_instance;
41 gboolean has_show_text_glyphs;
42 double x_offset, y_offset;
44 /* house-keeping options */
45 gboolean is_cached_renderer;
46 gboolean cr_had_current_point;
49 struct _PangoCairoRendererClass
51 PangoRendererClass parent_class;
54 G_DEFINE_TYPE (PangoCairoRenderer, pango_cairo_renderer, PANGO_TYPE_RENDERER)
57 set_color (PangoCairoRenderer *crenderer,
60 PangoColor *color = pango_renderer_get_color ((PangoRenderer *) (crenderer), part);
63 cairo_set_source_rgb (crenderer->cr,
65 color->green / 65535.,
66 color->blue / 65535.);
69 /* note: modifies crenderer->cr without doing cairo_save/restore() */
71 _pango_cairo_renderer_draw_frame (PangoCairoRenderer *crenderer,
79 cairo_t *cr = crenderer->cr;
81 if (crenderer->do_path)
83 double d2 = line_width * .5, d = line_width;
85 /* we draw an outer box in one winding direction and an inner one in the
86 * opposite direction. This works for both cairo windings rules.
88 * what we really want is cairo_stroke_to_path(), but that's not
89 * implemented in cairo yet.
93 cairo_rectangle (cr, x-d2, y-d2, width+d, height+d);
98 /* delicacies of computing the joint... this is REALLY slow */
100 double alpha, tan_alpha2, cos_alpha;
103 alpha = atan2 (height, width);
105 tan_alpha2 = tan (alpha * .5);
106 if (tan_alpha2 < 1e-5 || (sx = d2 / tan_alpha2, 2. * sx > width - d))
107 sx = (width - d) * .5;
109 cos_alpha = cos (alpha);
110 if (cos_alpha < 1e-5 || (sy = d2 / cos_alpha, 2. * sy > height - d))
111 sy = (height - d) * .5;
114 cairo_new_sub_path (cr);
115 cairo_line_to (cr, x+width-sx, y+d2);
116 cairo_line_to (cr, x+sx, y+d2);
117 cairo_line_to (cr, x+.5*width, y+.5*height-sy);
118 cairo_close_path (cr);
120 /* bottom triangle */
121 cairo_new_sub_path (cr);
122 cairo_line_to (cr, x+width-sx, y+height-d2);
123 cairo_line_to (cr, x+.5*width, y+.5*height+sy);
124 cairo_line_to (cr, x+sx, y+height-d2);
125 cairo_close_path (cr);
128 alpha = G_PI_2 - alpha;
129 tan_alpha2 = tan (alpha * .5);
130 if (tan_alpha2 < 1e-5 || (sy = d2 / tan_alpha2, 2. * sy > height - d))
131 sy = (width - d) * .5;
133 cos_alpha = cos (alpha);
134 if (cos_alpha < 1e-5 || (sx = d2 / cos_alpha, 2. * sx > width - d))
135 sx = (width - d) * .5;
138 cairo_new_sub_path (cr);
139 cairo_line_to (cr, x+d2, y+sy);
140 cairo_line_to (cr, x+d2, y+height-sy);
141 cairo_line_to (cr, x+.5*width-sx, y+.5*height);
142 cairo_close_path (cr);
145 cairo_new_sub_path (cr);
146 cairo_line_to (cr, x+width-d2, y+sy);
147 cairo_line_to (cr, x+.5*width+sx, y+.5*height);
148 cairo_line_to (cr, x+width-d2, y+height-sy);
149 cairo_close_path (cr);
152 cairo_rectangle (cr, x+width-d2, y+d2, - (width-d), height-d);
156 cairo_rectangle (cr, x, y, width, height);
162 cairo_new_sub_path (cr);
163 cairo_move_to (cr, x, y);
164 cairo_rel_line_to (cr, width, height);
166 cairo_new_sub_path (cr);
167 cairo_move_to (cr, x + width, y);
168 cairo_rel_line_to (cr, -width, height);
170 cairo_set_line_cap (cr, CAIRO_LINE_CAP_BUTT);
173 cairo_set_line_width (cr, line_width);
174 cairo_set_line_join (cr, CAIRO_LINE_JOIN_MITER);
175 cairo_set_miter_limit (cr, 2.);
181 _pango_cairo_renderer_draw_box_glyph (PangoCairoRenderer *crenderer,
187 cairo_save (crenderer->cr);
189 _pango_cairo_renderer_draw_frame (crenderer,
191 cy + 1.5 - PANGO_UNKNOWN_GLYPH_HEIGHT,
192 (double)gi->geometry.width / PANGO_SCALE - 3.0,
193 PANGO_UNKNOWN_GLYPH_HEIGHT - 3.0,
197 cairo_restore (crenderer->cr);
201 _pango_cairo_renderer_draw_unknown_glyph (PangoCairoRenderer *crenderer,
211 char hexbox_string[2] = {0, 0};
212 PangoCairoFontHexBoxInfo *hbi;
214 gboolean invalid_input;
216 cairo_save (crenderer->cr);
218 ch = gi->glyph & ~PANGO_GLYPH_UNKNOWN_FLAG;
219 invalid_input = G_UNLIKELY (gi->glyph == PANGO_GLYPH_INVALID_INPUT || ch > 0x10FFFF);
221 hbi = _pango_cairo_font_get_hex_box_info ((PangoCairoFont *)font);
222 if (!hbi || !_pango_cairo_font_install ((PangoFont *)(hbi->font), crenderer->cr))
224 _pango_cairo_renderer_draw_box_glyph (crenderer, gi, cx, cy, invalid_input);
229 if (G_UNLIKELY (invalid_input))
235 cols = (ch > 0xffff ? 6 : 4) / rows;
236 g_snprintf (buf, sizeof(buf), (ch > 0xffff) ? "%06X" : "%04X", ch);
239 _pango_cairo_renderer_draw_frame (crenderer,
240 cx + hbi->pad_x * 1.5,
241 cy + hbi->box_descent - hbi->box_height + hbi->pad_y * 0.5,
242 (double)gi->geometry.width / PANGO_SCALE - 3 * hbi->pad_x,
243 (hbi->box_height - hbi->pad_y),
250 x0 = cx + hbi->pad_x * 3.0;
251 y0 = cy + hbi->box_descent - hbi->pad_y * 2;
253 for (row = 0; row < rows; row++)
255 double y = y0 - (rows - 1 - row) * (hbi->digit_height + hbi->pad_y);
256 for (col = 0; col < cols; col++)
258 double x = x0 + col * (hbi->digit_width + hbi->pad_x);
260 cairo_move_to (crenderer->cr, x, y);
262 hexbox_string[0] = buf[row * cols + col];
264 if (crenderer->do_path)
265 cairo_text_path (crenderer->cr, hexbox_string);
267 cairo_show_text (crenderer->cr, hexbox_string);
272 cairo_restore (crenderer->cr);
275 #ifndef STACK_BUFFER_SIZE
276 #define STACK_BUFFER_SIZE (512 * sizeof (int))
279 #define STACK_ARRAY_LENGTH(T) (STACK_BUFFER_SIZE / sizeof(T))
282 pango_cairo_renderer_show_text_glyphs (PangoRenderer *renderer,
285 PangoGlyphString *glyphs,
286 cairo_text_cluster_t *clusters,
293 PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
297 cairo_glyph_t *cairo_glyphs;
298 cairo_glyph_t stack_glyphs[STACK_ARRAY_LENGTH (cairo_glyph_t)];
299 double base_x = crenderer->x_offset + (double)x / PANGO_SCALE;
300 double base_y = crenderer->y_offset + (double)y / PANGO_SCALE;
302 cairo_save (crenderer->cr);
303 if (!crenderer->do_path)
304 set_color (crenderer, PANGO_RENDER_PART_FOREGROUND);
306 if (!_pango_cairo_font_install (font, crenderer->cr))
308 for (i = 0; i < glyphs->num_glyphs; i++)
310 PangoGlyphInfo *gi = &glyphs->glyphs[i];
312 if (gi->glyph != PANGO_GLYPH_EMPTY)
314 double cx = base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
315 double cy = gi->geometry.y_offset == 0 ?
317 base_y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
319 _pango_cairo_renderer_draw_unknown_glyph (crenderer, font, gi, cx, cy);
321 x_position += gi->geometry.width;
327 if (glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_glyphs))
328 cairo_glyphs = g_new (cairo_glyph_t, glyphs->num_glyphs);
330 cairo_glyphs = stack_glyphs;
333 for (i = 0; i < glyphs->num_glyphs; i++)
335 PangoGlyphInfo *gi = &glyphs->glyphs[i];
337 if (gi->glyph != PANGO_GLYPH_EMPTY)
339 double cx = base_x + (double)(x_position + gi->geometry.x_offset) / PANGO_SCALE;
340 double cy = gi->geometry.y_offset == 0 ?
342 base_y + (double)(gi->geometry.y_offset) / PANGO_SCALE;
344 if (gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
345 _pango_cairo_renderer_draw_unknown_glyph (crenderer, font, gi, cx, cy);
348 cairo_glyphs[count].index = gi->glyph;
349 cairo_glyphs[count].x = cx;
350 cairo_glyphs[count].y = cy;
354 x_position += gi->geometry.width;
357 if (G_UNLIKELY (crenderer->do_path))
358 cairo_glyph_path (crenderer->cr, cairo_glyphs, count);
360 if (G_UNLIKELY (clusters))
361 cairo_show_text_glyphs (crenderer->cr,
364 clusters, num_clusters,
365 backward ? CAIRO_TEXT_CLUSTER_FLAG_BACKWARD : 0);
367 cairo_show_glyphs (crenderer->cr, cairo_glyphs, count);
369 if (cairo_glyphs != stack_glyphs)
370 g_free (cairo_glyphs);
373 cairo_restore (crenderer->cr);
377 pango_cairo_renderer_draw_glyphs (PangoRenderer *renderer,
379 PangoGlyphString *glyphs,
383 pango_cairo_renderer_show_text_glyphs (renderer,
393 pango_cairo_renderer_draw_glyph_item (PangoRenderer *renderer,
395 PangoGlyphItem *glyph_item,
399 PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
400 PangoFont *font = glyph_item->item->analysis.font;
401 PangoGlyphString *glyphs = glyph_item->glyphs;
402 PangoItem *item = glyph_item->item;
403 gboolean backward = (item->analysis.level & 1) != 0;
405 PangoGlyphItemIter iter;
406 cairo_text_cluster_t *cairo_clusters;
407 cairo_text_cluster_t stack_clusters[STACK_ARRAY_LENGTH (cairo_text_cluster_t)];
410 if (!crenderer->has_show_text_glyphs || crenderer->do_path)
412 pango_cairo_renderer_show_text_glyphs (renderer,
422 if (glyphs->num_glyphs > (int) G_N_ELEMENTS (stack_clusters))
423 cairo_clusters = g_new (cairo_text_cluster_t, glyphs->num_glyphs);
425 cairo_clusters = stack_clusters;
428 if (pango_glyph_item_iter_init_start (&iter, glyph_item, text))
431 int num_bytes, num_glyphs, i;
433 num_bytes = iter.end_index - iter.start_index;
434 num_glyphs = backward ? iter.start_glyph - iter.end_glyph : iter.end_glyph - iter.start_glyph;
437 g_warning ("pango_cairo_renderer_draw_glyph_item: bad cluster has num_bytess %d", num_bytes);
439 g_warning ("pango_cairo_renderer_draw_glyph_item: bad cluster has num_glyphs %d", num_glyphs);
441 /* Discount empty and unknown glyphs */
442 for (i = MIN (iter.start_glyph, iter.end_glyph+1);
443 i < MAX (iter.start_glyph+1, iter.end_glyph);
446 PangoGlyphInfo *gi = &glyphs->glyphs[i];
448 if (gi->glyph == PANGO_GLYPH_EMPTY ||
449 gi->glyph & PANGO_GLYPH_UNKNOWN_FLAG)
453 cairo_clusters[num_clusters].num_bytes = num_bytes;
454 cairo_clusters[num_clusters].num_glyphs = num_glyphs;
456 } while (pango_glyph_item_iter_next_cluster (&iter));
459 pango_cairo_renderer_show_text_glyphs (renderer,
460 text + item->offset, item->length,
462 cairo_clusters, num_clusters,
467 if (cairo_clusters != stack_clusters)
468 g_free (cairo_clusters);
472 pango_cairo_renderer_draw_rectangle (PangoRenderer *renderer,
473 PangoRenderPart part,
479 PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
481 if (!crenderer->do_path)
483 cairo_save (crenderer->cr);
485 set_color (crenderer, part);
488 cairo_rectangle (crenderer->cr,
489 crenderer->x_offset + (double)x / PANGO_SCALE,
490 crenderer->y_offset + (double)y / PANGO_SCALE,
491 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
493 if (!crenderer->do_path)
495 cairo_fill (crenderer->cr);
497 cairo_restore (crenderer->cr);
502 pango_cairo_renderer_draw_trapezoid (PangoRenderer *renderer,
503 PangoRenderPart part,
511 PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
519 if (!crenderer->do_path)
520 set_color (crenderer, part);
522 x = crenderer->x_offset,
523 y = crenderer->y_offset;
524 cairo_user_to_device_distance (cr, &x, &y);
525 cairo_identity_matrix (cr);
526 cairo_translate (cr, x, y);
528 cairo_move_to (cr, x11, y1_);
529 cairo_line_to (cr, x21, y1_);
530 cairo_line_to (cr, x22, y2);
531 cairo_line_to (cr, x12, y2);
532 cairo_close_path (cr);
534 if (!crenderer->do_path)
540 /* Draws an error underline that looks like one of:
543 * A/ \ / \ / \ A/ \ / \ |
544 * \ \ / \ / /D \ \ / \ |
545 * \ \/ C \/ / \ \/ C \ | height = HEIGHT_SQUARES * square
546 * \ /\ F / \ F /\ \ |
552 * unit_width = (HEIGHT_SQUARES - 1) * square
554 * The x, y, width, height passed in give the desired bounding box;
555 * x/width are adjusted to make the underline a integer number of units
558 #define HEIGHT_SQUARES 2.5
561 draw_error_underline (cairo_t *cr,
567 double square = height / HEIGHT_SQUARES;
568 double unit_width = (HEIGHT_SQUARES - 1) * square;
569 double double_width = 2 * unit_width;
570 int width_units = (width + unit_width / 2) / unit_width;
571 double y_top, y_bottom;
572 double x_left, x_middle, x_right;
575 x += (width - width_units * unit_width) / 2;
576 width = width_units * unit_width;
579 y_bottom = y + height;
581 /* Bottom of squiggle */
582 x_middle = x + unit_width;
583 x_right = x + double_width;
584 cairo_move_to (cr, x - square / 2, y_top + square / 2); /* A */
585 for (i = 0; i < width_units-2; i += 2)
587 cairo_line_to (cr, x_middle, y_bottom); /* B */
588 cairo_line_to (cr, x_right, y_top + square); /* C */
590 x_middle += double_width;
591 x_right += double_width;
593 cairo_line_to (cr, x_middle, y_bottom); /* B */
595 if (i + 1 == width_units)
596 cairo_line_to (cr, x_middle + square / 2, y_bottom - square / 2); /* G */
597 else if (i + 2 == width_units) {
598 cairo_line_to (cr, x_right + square / 2, y_top + square / 2); /* D */
599 cairo_line_to (cr, x_right, y_top); /* E */
602 /* Top of squiggle */
603 x_left = x_middle - unit_width;
604 for (; i >= 0; i -= 2)
606 cairo_line_to (cr, x_middle, y_bottom - square); /* F */
607 cairo_line_to (cr, x_left, y_top); /* H */
609 x_left -= double_width;
610 x_middle -= double_width;
615 pango_cairo_renderer_draw_error_underline (PangoRenderer *renderer,
621 PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
622 cairo_t *cr = crenderer->cr;
624 if (!crenderer->do_path)
628 set_color (crenderer, PANGO_RENDER_PART_UNDERLINE);
633 draw_error_underline (cr,
634 crenderer->x_offset + (double)x / PANGO_SCALE,
635 crenderer->y_offset + (double)y / PANGO_SCALE,
636 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
638 if (!crenderer->do_path)
647 pango_cairo_renderer_draw_shape (PangoRenderer *renderer,
648 PangoAttrShape *attr,
652 PangoCairoRenderer *crenderer = (PangoCairoRenderer *) (renderer);
653 cairo_t *cr = crenderer->cr;
655 PangoCairoShapeRendererFunc shape_renderer;
656 gpointer shape_renderer_data;
657 double base_x, base_y;
659 layout = pango_renderer_get_layout (renderer);
664 shape_renderer = pango_cairo_context_get_shape_renderer (pango_layout_get_context (layout),
665 &shape_renderer_data);
670 base_x = crenderer->x_offset + (double)x / PANGO_SCALE;
671 base_y = crenderer->y_offset + (double)y / PANGO_SCALE;
674 if (!crenderer->do_path)
675 set_color (crenderer, PANGO_RENDER_PART_FOREGROUND);
677 cairo_move_to (cr, base_x, base_y);
679 shape_renderer (cr, attr, crenderer->do_path, shape_renderer_data);
685 pango_cairo_renderer_init (PangoCairoRenderer *renderer G_GNUC_UNUSED)
690 pango_cairo_renderer_class_init (PangoCairoRendererClass *klass)
692 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
694 renderer_class->draw_glyphs = pango_cairo_renderer_draw_glyphs;
695 renderer_class->draw_glyph_item = pango_cairo_renderer_draw_glyph_item;
696 renderer_class->draw_rectangle = pango_cairo_renderer_draw_rectangle;
697 renderer_class->draw_trapezoid = pango_cairo_renderer_draw_trapezoid;
698 renderer_class->draw_error_underline = pango_cairo_renderer_draw_error_underline;
699 renderer_class->draw_shape = pango_cairo_renderer_draw_shape;
702 static PangoCairoRenderer *cached_renderer = NULL;
703 G_LOCK_DEFINE_STATIC (cached_renderer);
705 static PangoCairoRenderer *
706 acquire_renderer (void)
708 PangoCairoRenderer *renderer;
710 if (G_LIKELY (G_TRYLOCK (cached_renderer)))
712 if (G_UNLIKELY (!cached_renderer))
714 cached_renderer = g_object_new (PANGO_TYPE_CAIRO_RENDERER, NULL);
715 cached_renderer->is_cached_renderer = TRUE;
718 renderer = cached_renderer;
722 renderer = g_object_new (PANGO_TYPE_CAIRO_RENDERER, NULL);
729 release_renderer (PangoCairoRenderer *renderer)
731 if (G_LIKELY (renderer->is_cached_renderer))
734 renderer->do_path = FALSE;
735 renderer->has_show_text_glyphs = FALSE;
736 renderer->x_offset = 0.;
737 renderer->y_offset = 0.;
739 G_UNLOCK (cached_renderer);
742 g_object_unref (renderer);
746 save_current_point (PangoCairoRenderer *renderer)
748 renderer->cr_had_current_point = cairo_has_current_point (renderer->cr);
749 cairo_get_current_point (renderer->cr, &renderer->x_offset, &renderer->y_offset);
751 /* abuse save_current_point() to cache cairo_has_show_text_glyphs() result */
752 renderer->has_show_text_glyphs = cairo_surface_has_show_text_glyphs (cairo_get_target (renderer->cr));
756 restore_current_point (PangoCairoRenderer *renderer)
758 if (renderer->cr_had_current_point)
759 /* XXX should do cairo_set_current_point() when we have that function */
760 cairo_move_to (renderer->cr, renderer->x_offset, renderer->y_offset);
762 cairo_new_sub_path (renderer->cr);
766 /* convenience wrappers using the default renderer */
770 _pango_cairo_do_glyph_string (cairo_t *cr,
772 PangoGlyphString *glyphs,
775 PangoCairoRenderer *crenderer = acquire_renderer ();
776 PangoRenderer *renderer = (PangoRenderer *) crenderer;
779 crenderer->do_path = do_path;
780 save_current_point (crenderer);
784 /* unset all part colors, since when drawing just a glyph string,
785 * prepare_run() isn't called.
788 pango_renderer_activate (renderer);
790 pango_renderer_set_color (renderer, PANGO_RENDER_PART_FOREGROUND, NULL);
791 pango_renderer_set_color (renderer, PANGO_RENDER_PART_BACKGROUND, NULL);
792 pango_renderer_set_color (renderer, PANGO_RENDER_PART_UNDERLINE, NULL);
793 pango_renderer_set_color (renderer, PANGO_RENDER_PART_STRIKETHROUGH, NULL);
796 pango_renderer_draw_glyphs (renderer, font, glyphs, 0, 0);
800 pango_renderer_deactivate (renderer);
803 restore_current_point (crenderer);
805 release_renderer (crenderer);
809 _pango_cairo_do_glyph_item (cairo_t *cr,
811 PangoGlyphItem *glyph_item,
814 PangoCairoRenderer *crenderer = acquire_renderer ();
815 PangoRenderer *renderer = (PangoRenderer *) crenderer;
818 crenderer->do_path = do_path;
819 save_current_point (crenderer);
823 /* unset all part colors, since when drawing just a glyph string,
824 * prepare_run() isn't called.
827 pango_renderer_activate (renderer);
829 pango_renderer_set_color (renderer, PANGO_RENDER_PART_FOREGROUND, NULL);
830 pango_renderer_set_color (renderer, PANGO_RENDER_PART_BACKGROUND, NULL);
831 pango_renderer_set_color (renderer, PANGO_RENDER_PART_UNDERLINE, NULL);
832 pango_renderer_set_color (renderer, PANGO_RENDER_PART_STRIKETHROUGH, NULL);
835 pango_renderer_draw_glyph_item (renderer, text, glyph_item, 0, 0);
839 pango_renderer_deactivate (renderer);
842 restore_current_point (crenderer);
844 release_renderer (crenderer);
848 _pango_cairo_do_layout_line (cairo_t *cr,
849 PangoLayoutLine *line,
852 PangoCairoRenderer *crenderer = acquire_renderer ();
853 PangoRenderer *renderer = (PangoRenderer *) crenderer;
856 crenderer->do_path = do_path;
857 save_current_point (crenderer);
859 pango_renderer_draw_layout_line (renderer, line, 0, 0);
861 restore_current_point (crenderer);
863 release_renderer (crenderer);
867 _pango_cairo_do_layout (cairo_t *cr,
871 PangoCairoRenderer *crenderer = acquire_renderer ();
872 PangoRenderer *renderer = (PangoRenderer *) crenderer;
875 crenderer->do_path = do_path;
876 save_current_point (crenderer);
878 pango_renderer_draw_layout (renderer, layout, 0, 0);
880 restore_current_point (crenderer);
882 release_renderer (crenderer);
886 _pango_cairo_do_error_underline (cairo_t *cr,
893 /* We don't use a renderer here, for a simple reason:
894 * the only renderer we can get is the default renderer, that
895 * is all implemented here, so we shortcircuit and make our
902 draw_error_underline (cr, x, y, width, height);
909 /* public wrapper of above to show or append path */
913 * pango_cairo_show_glyph_string:
914 * @cr: a Cairo context
915 * @font: a #PangoFont from a #PangoCairoFontMap
916 * @glyphs: a #PangoGlyphString
918 * Draws the glyphs in @glyphs in the specified cairo context.
919 * The origin of the glyphs (the left edge of the baseline) will
920 * be drawn at the current point of the cairo context.
925 pango_cairo_show_glyph_string (cairo_t *cr,
927 PangoGlyphString *glyphs)
929 g_return_if_fail (cr != NULL);
930 g_return_if_fail (glyphs != NULL);
932 _pango_cairo_do_glyph_string (cr, font, glyphs, FALSE);
937 * pango_cairo_show_glyph_item:
938 * @cr: a Cairo context
939 * @text: the UTF-8 text that @glyph_item refers to
940 * @glyph_item: a #PangoGlyphItem
942 * Draws the glyphs in @glyph_item in the specified cairo context,
943 * embedding the text associated with the glyphs in the output if the
944 * output format supports it (PDF for example), otherwise it acts
945 * similar to pango_cairo_show_glyph_string().
947 * The origin of the glyphs (the left edge of the baseline) will
948 * be drawn at the current point of the cairo context.
950 * Note that @text is the start of the text for layout, which is then
951 * indexed by <literal>@glyph_item->item->offset</literal>.
956 pango_cairo_show_glyph_item (cairo_t *cr,
958 PangoGlyphItem *glyph_item)
960 g_return_if_fail (cr != NULL);
961 g_return_if_fail (text != NULL);
962 g_return_if_fail (glyph_item != NULL);
964 _pango_cairo_do_glyph_item (cr, text, glyph_item, FALSE);
968 * pango_cairo_show_layout_line:
969 * @cr: a Cairo context
970 * @line: a #PangoLayoutLine
972 * Draws a #PangoLayoutLine in the specified cairo context.
973 * The origin of the glyphs (the left edge of the line) will
974 * be drawn at the current point of the cairo context.
979 pango_cairo_show_layout_line (cairo_t *cr,
980 PangoLayoutLine *line)
982 g_return_if_fail (cr != NULL);
983 g_return_if_fail (line != NULL);
985 _pango_cairo_do_layout_line (cr, line, FALSE);
989 * pango_cairo_show_layout:
990 * @cr: a Cairo context
991 * @layout: a Pango layout
993 * Draws a #PangoLayout in the specified cairo context.
994 * The top-left corner of the #PangoLayout will be drawn
995 * at the current point of the cairo context.
1000 pango_cairo_show_layout (cairo_t *cr,
1001 PangoLayout *layout)
1003 g_return_if_fail (cr != NULL);
1004 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1006 _pango_cairo_do_layout (cr, layout, FALSE);
1010 * pango_cairo_show_error_underline:
1011 * @cr: a Cairo context
1012 * @x: The X coordinate of one corner of the rectangle
1013 * @y: The Y coordinate of one corner of the rectangle
1014 * @width: Non-negative width of the rectangle
1015 * @height: Non-negative height of the rectangle
1017 * Draw a squiggly line in the specified cairo context that approximately
1018 * covers the given rectangle in the style of an underline used to indicate a
1019 * spelling error. (The width of the underline is rounded to an integer
1020 * number of up/down segments and the resulting rectangle is centered in the
1021 * original rectangle)
1026 pango_cairo_show_error_underline (cairo_t *cr,
1032 g_return_if_fail (cr != NULL);
1033 g_return_if_fail ((width >= 0) && (height >= 0));
1035 _pango_cairo_do_error_underline (cr, x, y, width, height, FALSE);
1039 * pango_cairo_glyph_string_path
1040 * @cr: a Cairo context
1041 * @font: a #PangoFont from a #PangoCairoFontMap
1042 * @glyphs: a #PangoGlyphString
1044 * Adds the glyphs in @glyphs to the current path in the specified
1045 * cairo context. The origin of the glyphs (the left edge of the baseline)
1046 * will be at the current point of the cairo context.
1051 pango_cairo_glyph_string_path (cairo_t *cr,
1053 PangoGlyphString *glyphs)
1055 g_return_if_fail (cr != NULL);
1056 g_return_if_fail (glyphs != NULL);
1058 _pango_cairo_do_glyph_string (cr, font, glyphs, TRUE);
1062 * pango_cairo_layout_line_path:
1063 * @cr: a Cairo context
1064 * @line: a #PangoLayoutLine
1066 * Adds the text in #PangoLayoutLine to the current path in the
1067 * specified cairo context. The origin of the glyphs (the left edge
1068 * of the line) will be at the current point of the cairo context.
1073 pango_cairo_layout_line_path (cairo_t *cr,
1074 PangoLayoutLine *line)
1076 g_return_if_fail (cr != NULL);
1077 g_return_if_fail (line != NULL);
1079 _pango_cairo_do_layout_line (cr, line, TRUE);
1083 * pango_cairo_layout_path:
1084 * @cr: a Cairo context
1085 * @layout: a Pango layout
1087 * Adds the text in a #PangoLayout to the current path in the
1088 * specified cairo context. The top-left corner of the #PangoLayout
1089 * will be at the current point of the cairo context.
1094 pango_cairo_layout_path (cairo_t *cr,
1095 PangoLayout *layout)
1097 g_return_if_fail (cr != NULL);
1098 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1100 _pango_cairo_do_layout (cr, layout, TRUE);
1104 * pango_cairo_error_underline_path:
1105 * @cr: a Cairo context
1106 * @x: The X coordinate of one corner of the rectangle
1107 * @y: The Y coordinate of one corner of the rectangle
1108 * @width: Non-negative width of the rectangle
1109 * @height: Non-negative height of the rectangle
1111 * Add a squiggly line to the current path in the specified cairo context that
1112 * approximately covers the given rectangle in the style of an underline used
1113 * to indicate a spelling error. (The width of the underline is rounded to an
1114 * integer number of up/down segments and the resulting rectangle is centered
1115 * in the original rectangle)
1120 pango_cairo_error_underline_path (cairo_t *cr,
1126 g_return_if_fail (cr != NULL);
1127 g_return_if_fail ((width >= 0) && (height >= 0));
1129 _pango_cairo_do_error_underline (cr, x, y, width, height, TRUE);