1 /* GDK - The GIMP Drawing Kit
2 * Copyright (C) 2000 Red Hat, Inc.
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
22 #include <pango/pangocairo.h>
25 #include "gdkinternals.h"
28 #include "gdkprivate.h"
29 #include "gdkscreen.h"
32 /* This is for P_() ... a bit non-kosher, but works fine */
33 #include "gtk/gtkintl.h"
35 #define GDK_INFO_KEY "gdk-info"
37 /* We have various arrays indexed by render part; if PangoRenderPart
38 * is extended, we want to make sure not to overwrite the end of
41 #define MAX_RENDER_PART PANGO_RENDER_PART_STRIKETHROUGH
43 struct _GdkPangoRendererPrivate
47 /* GdkPangoRenderer specific state */
48 PangoColor override_color[MAX_RENDER_PART + 1];
49 gboolean override_color_set[MAX_RENDER_PART + 1];
51 GdkBitmap *stipple[MAX_RENDER_PART + 1];
52 cairo_surface_t *stipple_surface[MAX_RENDER_PART + 1];
56 GdkDrawable *drawable;
60 static PangoAttrType gdk_pango_attr_stipple_type;
61 static PangoAttrType gdk_pango_attr_embossed_type;
68 G_DEFINE_TYPE (GdkPangoRenderer, gdk_pango_renderer, PANGO_TYPE_RENDERER)
71 gdk_pango_renderer_finalize (GObject *object)
73 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
74 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
78 g_object_unref (priv->base_gc);
80 g_object_unref (priv->drawable);
82 for (i = 0; i <= MAX_RENDER_PART; i++)
83 if (priv->stipple_surface[i])
84 cairo_surface_destroy (priv->stipple_surface[i]);
86 for (i = 0; i <= MAX_RENDER_PART; i++)
88 g_object_unref (priv->stipple[i]);
90 G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->finalize (object);
94 gdk_pango_renderer_constructor (GType type,
95 guint n_construct_properties,
96 GObjectConstructParam *construct_params)
99 GdkPangoRenderer *gdk_renderer;
101 object = (* G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->constructor) (type,
102 n_construct_properties,
105 gdk_renderer = GDK_PANGO_RENDERER (object);
107 if (!gdk_renderer->priv->screen)
109 g_warning ("Screen must be specified at construct time for GdkPangoRenderer");
110 gdk_renderer->priv->screen = gdk_screen_get_default ();
116 /* Adjusts matrix and color for the renderer to draw the secondary
117 * "shadow" copy for embossed text */
119 emboss_context (cairo_t *cr)
121 cairo_matrix_t *tmp_matrix = cairo_matrix_create ();
122 double a, b, c, d, tx, ty;
124 /* The gymnastics here to adjust the matrix are because we want
125 * to offset by +1,+1 in device-space, not in user-space,
126 * so we can't just draw the layout at x + 1, y + 1
128 cairo_get_matrix (cr, tmp_matrix);
129 cairo_matrix_get_affine (tmp_matrix, &a, &b, &c, &d, &tx, &ty);
130 cairo_matrix_set_affine (tmp_matrix, a, b, c, d, tx + 1, ty + 1);
131 cairo_set_matrix (cr, tmp_matrix);
132 cairo_matrix_destroy (tmp_matrix);
134 cairo_set_rgb_color (cr, 1.0, 1.0, 1.0);
138 set_part_color (GdkPangoRenderer *gdk_renderer,
140 PangoRenderPart part)
142 PangoColor *color = pango_renderer_get_color (PANGO_RENDERER (gdk_renderer),
146 cairo_set_rgb_color (cr,
148 color->green / 65535.,
149 color->blue / 65535.);
155 _gdk_windowing_gc_get_foreground (gdk_renderer->priv->base_gc, &gc_color);
156 gdk_cairo_set_source_color (cr, &gc_color);
160 static cairo_surface_t *
161 get_stipple_surface (GdkPangoRenderer *gdk_renderer,
163 PangoRenderPart part)
165 if (!gdk_renderer->priv->stipple_surface[part])
168 cairo_surface_t *surface;
169 cairo_surface_t *alpha_surface;
172 gdk_drawable_get_size (gdk_renderer->priv->stipple[part],
175 alpha_surface = _gdk_drawable_ref_cairo_surface (gdk_renderer->priv->stipple[part]);
177 surface = cairo_surface_create_similar (cairo_get_target_surface (cr),
181 tmp_cr = cairo_create ();
182 cairo_set_target_surface (tmp_cr, surface);
184 cairo_set_operator (tmp_cr, CAIRO_OPERATOR_SRC);
185 cairo_show_surface (tmp_cr, alpha_surface, width, height);
187 set_part_color (gdk_renderer, tmp_cr, part);
188 cairo_set_operator (tmp_cr, CAIRO_OPERATOR_ATOP);
190 cairo_rectangle (tmp_cr, 0, 0, width, height);
193 cairo_destroy (tmp_cr);
194 cairo_surface_destroy (alpha_surface);
196 gdk_renderer->priv->stipple_surface[part] = surface;
199 return gdk_renderer->priv->stipple_surface[part];
203 create_cairo_context (GdkPangoRenderer *gdk_renderer,
204 PangoRenderPart part)
206 PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer);
207 const PangoMatrix *matrix;
208 cairo_t *cr = gdk_drawable_create_cairo_context (gdk_renderer->priv->drawable);
210 if (gdk_renderer->priv->stipple[part])
212 cairo_surface_t *surface = get_stipple_surface (gdk_renderer, cr, part);
213 cairo_pattern_t *pattern;
215 pattern = cairo_pattern_create_for_surface (surface);
216 cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
218 if (gdk_renderer->priv->base_gc->ts_x_origin != 0 ||
219 gdk_renderer->priv->base_gc->ts_y_origin != 0)
221 cairo_matrix_t *matrix = cairo_matrix_create ();
222 cairo_matrix_translate (matrix,
223 - gdk_renderer->priv->base_gc->ts_x_origin,
224 - gdk_renderer->priv->base_gc->ts_y_origin);
225 cairo_pattern_set_matrix (pattern, matrix);
226 cairo_matrix_destroy (matrix);
229 cairo_set_pattern (cr, pattern);
230 cairo_pattern_destroy (pattern);
234 set_part_color (gdk_renderer, cr, part);
237 matrix = pango_renderer_get_matrix (renderer);
240 cairo_matrix_t *cairo_matrix;
242 cairo_matrix = cairo_matrix_create ();
243 cairo_matrix_set_affine (cairo_matrix,
244 matrix->xx, matrix->yx,
245 matrix->xy, matrix->yy,
246 matrix->x0, matrix->y0);
248 cairo_set_matrix (cr, cairo_matrix);
249 cairo_matrix_destroy (cairo_matrix);
256 gdk_pango_renderer_draw_glyphs (PangoRenderer *renderer,
258 PangoGlyphString *glyphs,
262 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
263 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
266 cr = create_cairo_context (gdk_renderer,
267 PANGO_RENDER_PART_FOREGROUND);
273 cairo_move_to (cr, x / PANGO_SCALE, y / PANGO_SCALE);
274 pango_cairo_show_glyph_string (cr, font, glyphs);
278 cairo_move_to (cr, x / PANGO_SCALE, y / PANGO_SCALE);
279 pango_cairo_show_glyph_string (cr, font, glyphs);
284 /* Draws an error underline that looks like one of:
287 * A/ \ / \ / \ A/ \ / \ |
288 * \ \ / \ / /D \ \ / \ |
289 * \ \/ C \/ / \ \/ C \ | height = HEIGHT_SQUARES * square
290 * \ /\ F / \ F /\ \ |
296 * unit_width = (HEIGHT_SQUARES - 1) * square
298 * The x, y, width, height passed in give the desired bounding box;
299 * x/width are adjusted to make the underline a integer number of units
302 #define HEIGHT_SQUARES 2.5
305 draw_error_underline (cairo_t *cr,
311 double square = height / HEIGHT_SQUARES;
312 double unit_width = (HEIGHT_SQUARES - 1) * square;
313 int width_units = (width + unit_width / 2) / unit_width;
314 double y_top, y_bottom;
317 x += (width - width_units * unit_width);
318 width = width_units * unit_width;
321 y_bottom = y + height;
323 /* Bottom of squiggle */
324 cairo_move_to (cr, x - square / 2, y_top + square / 2); /* A */
325 for (i = 0; i < width_units; i += 2)
327 double x_middle = x + (i + 1) * unit_width;
328 double x_right = x + (i + 2) * unit_width;
330 cairo_line_to (cr, x_middle, y_bottom); /* B */
332 if (i + 1 == width_units)
334 else if (i + 2 == width_units)
335 cairo_line_to (cr, x_right + square / 2, y_top + square / 2); /* D */
337 cairo_line_to (cr, x_right, y_top + square); /* C */
340 /* Top of squiggle */
341 for (i -= 2; i >= 0; i -= 2)
343 double x_left = x + i * unit_width;
344 double x_middle = x + (i + 1) * unit_width;
345 double x_right = x + (i + 2) * unit_width;
347 if (i + 1 == width_units)
348 cairo_line_to (cr, x_middle + square / 2, y_bottom - square / 2); /* G */
350 if (i + 2 == width_units)
351 cairo_line_to (cr, x_right, y_top); /* E */
352 cairo_line_to (cr, x_middle, y_bottom - square); /* F */
355 cairo_line_to (cr, x_left, y_top); /* H */
358 cairo_close_path (cr);
363 gdk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
364 PangoRenderPart part,
370 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
371 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
374 cr = create_cairo_context (gdk_renderer, part);
376 if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
381 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
382 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
389 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
390 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
397 gdk_pango_renderer_draw_error_underline (PangoRenderer *renderer,
403 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
404 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
407 cr = create_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE);
413 draw_error_underline (cr,
414 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
415 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
419 draw_error_underline (cr,
420 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
421 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
427 gdk_pango_renderer_part_changed (PangoRenderer *renderer,
428 PangoRenderPart part)
430 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
432 if (gdk_renderer->priv->stipple_surface[part])
434 cairo_surface_destroy (gdk_renderer->priv->stipple_surface[part]);
435 gdk_renderer->priv->stipple_surface[part] = NULL;
440 gdk_pango_renderer_begin (PangoRenderer *renderer)
442 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
444 if (!gdk_renderer->priv->drawable || !gdk_renderer->priv->base_gc)
446 g_warning ("gdk_pango_renderer_set_drawable() and gdk_pango_renderer_set_drawable()"
447 "must be used to set the target drawable and GC before using the renderer\n");
452 gdk_pango_renderer_prepare_run (PangoRenderer *renderer,
455 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
456 gboolean embossed = FALSE;
457 GdkBitmap *stipple = NULL;
464 for (l = run->item->analysis.extra_attrs; l; l = l->next)
466 PangoAttribute *attr = l->data;
468 /* stipple_type and embossed_type aren't necessarily
469 * initialized, but they are 0, which is an
470 * invalid type so won't occur.
472 if (attr->klass->type == gdk_pango_attr_stipple_type)
474 stipple = ((GdkPangoAttrStipple*)attr)->stipple;
476 else if (attr->klass->type == gdk_pango_attr_embossed_type)
478 embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
482 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, stipple);
483 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_BACKGROUND, stipple);
484 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_UNDERLINE, stipple);
485 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_STRIKETHROUGH, stipple);
487 if (embossed != gdk_renderer->priv->embossed)
489 gdk_renderer->priv->embossed = embossed;
490 pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
493 PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->prepare_run (renderer, run);
495 for (i = 0; i <= MAX_RENDER_PART; i++)
497 if (gdk_renderer->priv->override_color_set[i])
498 pango_renderer_set_color (renderer, i, &gdk_renderer->priv->override_color[i]);
503 gdk_pango_renderer_set_property (GObject *object,
508 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
513 gdk_renderer->priv->screen = g_value_get_object (value);
516 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
522 gdk_pango_renderer_get_property (GObject *object,
527 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
532 g_value_set_object (value, gdk_renderer->priv->screen);
535 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
541 gdk_pango_renderer_init (GdkPangoRenderer *renderer)
543 renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer,
544 GDK_TYPE_PANGO_RENDERER,
545 GdkPangoRendererPrivate);
549 gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
551 GObjectClass *object_class = G_OBJECT_CLASS (klass);
553 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
555 renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
556 renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
557 renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
558 renderer_class->part_changed = gdk_pango_renderer_part_changed;
559 renderer_class->begin = gdk_pango_renderer_begin;
560 renderer_class->prepare_run = gdk_pango_renderer_prepare_run;
562 object_class->finalize = gdk_pango_renderer_finalize;
563 object_class->constructor = gdk_pango_renderer_constructor;
564 object_class->set_property = gdk_pango_renderer_set_property;
565 object_class->get_property = gdk_pango_renderer_get_property;
567 g_object_class_install_property (object_class,
569 g_param_spec_object ("screen",
571 P_("the GdkScreen for the renderer"),
573 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
574 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
575 G_PARAM_STATIC_BLURB));
577 g_type_class_add_private (object_class, sizeof (GdkPangoRendererPrivate));
581 * gdk_pango_renderer_new:
582 * @screen: a #GdkScreen
584 * Creates a new #PangoRenderer for @screen. Normally you can use the
585 * results of gdk_pango_renderer_get_default() rather than creating a new
588 * Return value: a newly created #PangoRenderer. Free with g_object_unref().
593 gdk_pango_renderer_new (GdkScreen *screen)
595 g_return_val_if_fail (screen != NULL, NULL);
597 return g_object_new (GDK_TYPE_PANGO_RENDERER,
603 on_renderer_display_closed (GdkDisplay *display,
604 GdkPangoRenderer *renderer)
606 g_signal_handlers_disconnect_by_func (renderer->priv->screen,
607 (gpointer)on_renderer_display_closed,
609 g_object_set_data (G_OBJECT (renderer->priv->screen), "gdk-pango-renderer", NULL);
613 * gdk_pango_renderer_get_default:
614 * @screen: a #GdkScreen
616 * Gets the default #PangoRenderer for a screen. This default renderer
617 * is shared by all users of the display, so properties such as the color
618 * or transformation matrix set for the renderer may be overwritten
619 * by functions such as gdk_draw_layout().
621 * Before using the renderer, you need to call gdk_pango_renderer_set_drawable()
622 * and gdk_pango_renderer_set_drawable() to set the drawable and graphics context
623 * to use for drawing.
625 * Return value: the default #PangoRenderer for @screen. The
626 * renderer is owned by GTK+ and will be kept around until the
632 gdk_pango_renderer_get_default (GdkScreen *screen)
634 PangoRenderer *renderer;
636 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
638 renderer = g_object_get_data (G_OBJECT (screen), "gdk-pango-renderer");
641 renderer = gdk_pango_renderer_new (screen);
642 g_object_set_data_full (G_OBJECT (screen), "gdk-pango-renderer", renderer,
643 (GDestroyNotify)g_object_unref);
645 g_signal_connect (gdk_screen_get_display (screen), "closed",
646 G_CALLBACK (on_renderer_display_closed), renderer);
653 * gdk_pango_renderer_set_drawable:
654 * @gdk_renderer: a #GdkPangoRenderer
655 * @drawable: the new target drawable, or %NULL
657 * Sets the drawable the renderer draws to.
662 gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer,
663 GdkDrawable *drawable)
665 GdkPangoRendererPrivate *priv;
667 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
668 g_return_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable));
670 priv = gdk_renderer->priv;
672 if (priv->drawable != drawable)
675 g_object_unref (priv->drawable);
676 priv->drawable = drawable;
678 g_object_ref (priv->drawable);
683 * gdk_pango_renderer_set_gc:
684 * @gdk_renderer: a #GdkPangoRenderer
685 * @gc: the new GC to use for drawing, or %NULL
687 * Sets the GC the renderer draws with. Note that the GC must not be
688 * modified until it is unset by calling the function again with
689 * %NULL for the @gc parameter, since GDK may make internal copies
690 * of the GC which won't be updated to follow changes to the
696 gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
699 GdkPangoRendererPrivate *priv;
701 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
702 g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
704 priv = gdk_renderer->priv;
706 if (priv->base_gc != gc)
709 g_object_unref (priv->base_gc);
712 g_object_ref (priv->base_gc);
718 * gdk_pango_renderer_set_stipple:
719 * @gdk_renderer: a #GdkPangoRenderer
720 * @part: the part to render with the stipple
721 * @stipple: the new stipple value.
723 * Sets the stipple for one render part (foreground, background, underline,
724 * etc.) Note that this is overwritten when iterating through the individual
725 * styled runs of a #PangoLayout or #PangoLayoutLine. This function is thus
726 * only useful when you call low level functions like pango_renderer_draw_glyphs()
727 * directly, or in the 'prepare_run' virtual function of a subclass of
733 gdk_pango_renderer_set_stipple (GdkPangoRenderer *gdk_renderer,
734 PangoRenderPart part,
737 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
739 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
742 if (stipple != gdk_renderer->priv->stipple[part])
744 if (gdk_renderer->priv->stipple[part])
745 g_object_unref (gdk_renderer->priv->stipple[part]);
747 gdk_renderer->priv->stipple[part] = stipple;
749 if (gdk_renderer->priv->stipple[part])
750 g_object_ref (gdk_renderer->priv->stipple[part]);
752 pango_renderer_part_changed (PANGO_RENDERER (gdk_renderer), part);
757 * gdk_pango_renderer_set_override_color:
758 * @gdk_renderer: a #GdkPangoRenderer
759 * @part: the part to render to set the color of
760 * @color: the color to use, or %NULL to unset a previously
761 * set override color.
763 * Sets the color for a particular render part (foreground,
764 * background, underline, etc.), overriding any attributes on the layouts
765 * renderered with this renderer.
770 gdk_pango_renderer_set_override_color (GdkPangoRenderer *gdk_renderer,
771 PangoRenderPart part,
772 const GdkColor *color)
774 GdkPangoRendererPrivate *priv;
776 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
778 priv = gdk_renderer->priv;
780 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
785 priv->override_color[part].red = color->red;
786 priv->override_color[part].green = color->green;
787 priv->override_color[part].blue = color->blue;
788 priv->override_color_set[part] = TRUE;
791 priv->override_color_set[part] = FALSE;
795 * gdk_pango_context_set_colormap:
796 * @context: a #PangoContext
797 * @colormap: a #GdkColormap
799 * This function used to set the colormap to be used for drawing with
800 * @context. The colormap is now always derived from the graphics
801 * context used for drawing, so calling this function is no longer
805 gdk_pango_context_set_colormap (PangoContext *context,
806 GdkColormap *colormap)
808 g_return_if_fail (PANGO_IS_CONTEXT (context));
809 g_return_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap));
812 /* Gets a renderer to draw with, setting the properties of the
813 * renderer and activating it. Note that since we activate the
814 * renderer here, the implicit setting of the matrix that
815 * pango_renderer_draw_layout_[line] normally do when they
816 * activate the renderer is suppressed. */
817 static PangoRenderer *
818 get_renderer (GdkDrawable *drawable,
820 const GdkColor *foreground,
821 const GdkColor *background)
823 GdkScreen *screen = gdk_drawable_get_screen (drawable);
824 PangoRenderer *renderer = gdk_pango_renderer_get_default (screen);
825 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
827 gdk_pango_renderer_set_drawable (gdk_renderer, drawable);
828 gdk_pango_renderer_set_gc (gdk_renderer, gc);
830 gdk_pango_renderer_set_override_color (gdk_renderer,
831 PANGO_RENDER_PART_FOREGROUND,
833 gdk_pango_renderer_set_override_color (gdk_renderer,
834 PANGO_RENDER_PART_UNDERLINE,
836 gdk_pango_renderer_set_override_color (gdk_renderer,
837 PANGO_RENDER_PART_STRIKETHROUGH,
840 gdk_pango_renderer_set_override_color (gdk_renderer,
841 PANGO_RENDER_PART_BACKGROUND,
844 pango_renderer_activate (renderer);
849 /* Cleans up the renderer obtained with get_renderer() */
851 release_renderer (PangoRenderer *renderer)
853 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
855 pango_renderer_deactivate (renderer);
857 gdk_pango_renderer_set_override_color (gdk_renderer,
858 PANGO_RENDER_PART_FOREGROUND,
860 gdk_pango_renderer_set_override_color (gdk_renderer,
861 PANGO_RENDER_PART_UNDERLINE,
863 gdk_pango_renderer_set_override_color (gdk_renderer,
864 PANGO_RENDER_PART_STRIKETHROUGH,
866 gdk_pango_renderer_set_override_color (gdk_renderer,
867 PANGO_RENDER_PART_BACKGROUND,
870 gdk_pango_renderer_set_drawable (gdk_renderer, NULL);
871 gdk_pango_renderer_set_gc (gdk_renderer, NULL);
875 * gdk_draw_layout_line_with_colors:
876 * @drawable: the drawable on which to draw the line
877 * @gc: base graphics to use
878 * @x: the x position of start of string (in pixels)
879 * @y: the y position of baseline (in pixels)
880 * @line: a #PangoLayoutLine
881 * @foreground: foreground override color, or %NULL for none
882 * @background: background override color, or %NULL for none
884 * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
885 * layout's normal colors with @foreground and/or @background.
886 * @foreground and @background need not be allocated.
888 * If the layout's #PangoContext has a transformation matrix set, then
889 * @x and @y specify the position of the left edge of the baseline
890 * (left is in before-tranform user coordinates) in after-transform
891 * device coordinates.
894 gdk_draw_layout_line_with_colors (GdkDrawable *drawable,
898 PangoLayoutLine *line,
899 const GdkColor *foreground,
900 const GdkColor *background)
902 PangoRenderer *renderer;
903 const PangoMatrix *matrix;
905 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
906 g_return_if_fail (GDK_IS_GC (gc));
907 g_return_if_fail (line != NULL);
909 renderer = get_renderer (drawable, gc, foreground, background);
911 /* When we have a matrix, we do positioning by adjusting the matrix, and
912 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
913 * a matrix when the caller didn't provide one, however, since that adds
914 * lots of floating point arithmetic for each glyph.
916 matrix = pango_context_get_matrix (pango_layout_get_context (line->layout));
919 PangoMatrix tmp_matrix;
921 tmp_matrix = *matrix;
924 pango_renderer_set_matrix (renderer, &tmp_matrix);
930 pango_renderer_set_matrix (renderer, NULL);
932 pango_renderer_draw_layout_line (renderer, line, x * PANGO_SCALE, y * PANGO_SCALE);
934 release_renderer (renderer);
937 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
938 * between here and gtklabel.c */
940 get_rotated_layout_bounds (PangoLayout *layout,
943 PangoContext *context = pango_layout_get_context (layout);
944 const PangoMatrix *matrix = pango_context_get_matrix (context);
945 gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
946 PangoRectangle logical_rect;
949 pango_layout_get_extents (layout, NULL, &logical_rect);
951 for (i = 0; i < 2; i++)
953 gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
954 for (j = 0; j < 2; j++)
956 gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
958 gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
959 gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
961 if (i == 0 && j == 0)
980 rect->x = floor (x_min);
981 rect->width = ceil (x_max) - rect->x;
982 rect->y = floor (y_min);
983 rect->height = floor (y_max) - rect->y;
987 * gdk_draw_layout_with_colors:
988 * @drawable: the drawable on which to draw string
989 * @gc: base graphics context to use
990 * @x: the X position of the left of the layout (in pixels)
991 * @y: the Y position of the top of the layout (in pixels)
992 * @layout: a #PangoLayout
993 * @foreground: foreground override color, or %NULL for none
994 * @background: background override color, or %NULL for none
996 * Render a #PangoLayout onto a #GdkDrawable, overriding the
997 * layout's normal colors with @foreground and/or @background.
998 * @foreground and @background need not be allocated.
1000 * If the layout's #PangoContext has a transformation matrix set, then
1001 * @x and @y specify the position of the top left corner of the
1002 * bounding box (in device space) of the transformed layout.
1004 * If you're using GTK+, the ususal way to obtain a #PangoLayout
1005 * is gtk_widget_create_pango_layout().
1008 gdk_draw_layout_with_colors (GdkDrawable *drawable,
1012 PangoLayout *layout,
1013 const GdkColor *foreground,
1014 const GdkColor *background)
1016 PangoRenderer *renderer;
1017 const PangoMatrix *matrix;
1019 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1020 g_return_if_fail (GDK_IS_GC (gc));
1021 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1023 renderer = get_renderer (drawable, gc, foreground, background);
1025 /* When we have a matrix, we do positioning by adjusting the matrix, and
1026 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
1027 * a matrix when the caller didn't provide one, however, since that adds
1028 * lots of floating point arithmetic for each glyph.
1030 matrix = pango_context_get_matrix (pango_layout_get_context (layout));
1033 PangoMatrix tmp_matrix;
1036 get_rotated_layout_bounds (layout, &rect);
1038 tmp_matrix = *matrix;
1039 tmp_matrix.x0 += x - rect.x;
1040 tmp_matrix.y0 += y - rect.y;
1041 pango_renderer_set_matrix (renderer, &tmp_matrix);
1047 pango_renderer_set_matrix (renderer, NULL);
1049 pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE);
1051 release_renderer (renderer);
1055 * gdk_draw_layout_line:
1056 * @drawable: the drawable on which to draw the line
1057 * @gc: base graphics to use
1058 * @x: the x position of start of string (in pixels)
1059 * @y: the y position of baseline (in pixels)
1060 * @line: a #PangoLayoutLine
1062 * Render a #PangoLayoutLine onto an GDK drawable
1064 * If the layout's #PangoContext has a transformation matrix set, then
1065 * @x and @y specify the position of the left edge of the baseline
1066 * (left is in before-tranform user coordinates) in after-transform
1067 * device coordinates.
1070 gdk_draw_layout_line (GdkDrawable *drawable,
1074 PangoLayoutLine *line)
1076 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1077 g_return_if_fail (GDK_IS_GC (gc));
1078 g_return_if_fail (line != NULL);
1080 gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL);
1085 * @drawable: the drawable on which to draw string
1086 * @gc: base graphics context to use
1087 * @x: the X position of the left of the layout (in pixels)
1088 * @y: the Y position of the top of the layout (in pixels)
1089 * @layout: a #PangoLayout
1091 * Render a #PangoLayout onto a GDK drawable
1093 * If the layout's #PangoContext has a transformation matrix set, then
1094 * @x and @y specify the position of the top left corner of the
1095 * bounding box (in device space) of the transformed layout.
1097 * If you're using GTK+, the usual way to obtain a #PangoLayout
1098 * is gtk_widget_create_pango_layout().
1101 gdk_draw_layout (GdkDrawable *drawable,
1105 PangoLayout *layout)
1107 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1108 g_return_if_fail (GDK_IS_GC (gc));
1109 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1111 gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
1114 static PangoAttribute *
1115 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
1117 const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
1119 return gdk_pango_attr_stipple_new (src->stipple);
1123 gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
1125 GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
1128 g_object_unref (st->stipple);
1134 gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
1135 const PangoAttribute *attr2)
1137 const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
1138 const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
1140 return a->stipple == b->stipple;
1144 * gdk_pango_attr_stipple_new:
1145 * @stipple: a bitmap to be set as stipple
1147 * Creates a new attribute containing a stipple bitmap to be used when
1148 * rendering the text.
1150 * Return value: new #PangoAttribute
1154 gdk_pango_attr_stipple_new (GdkBitmap *stipple)
1156 GdkPangoAttrStipple *result;
1158 static PangoAttrClass klass = {
1160 gdk_pango_attr_stipple_copy,
1161 gdk_pango_attr_stipple_destroy,
1162 gdk_pango_attr_stipple_compare
1166 klass.type = gdk_pango_attr_stipple_type =
1167 pango_attr_type_register ("GdkPangoAttrStipple");
1169 result = g_new (GdkPangoAttrStipple, 1);
1170 result->attr.klass = &klass;
1173 g_object_ref (stipple);
1175 result->stipple = stipple;
1177 return (PangoAttribute *)result;
1180 static PangoAttribute *
1181 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
1183 const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
1185 return gdk_pango_attr_embossed_new (e->embossed);
1189 gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
1195 gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
1196 const PangoAttribute *attr2)
1198 const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
1199 const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
1201 return e1->embossed == e2->embossed;
1205 * gdk_pango_attr_embossed_new:
1206 * @embossed: a bitmap to be set as embossed
1208 * Creates a new attribute containing a embossed bitmap to be used when
1209 * rendering the text.
1211 * Return value: new #PangoAttribute
1215 gdk_pango_attr_embossed_new (gboolean embossed)
1217 GdkPangoAttrEmbossed *result;
1219 static PangoAttrClass klass = {
1221 gdk_pango_attr_embossed_copy,
1222 gdk_pango_attr_embossed_destroy,
1223 gdk_pango_attr_embossed_compare
1227 klass.type = gdk_pango_attr_embossed_type =
1228 pango_attr_type_register ("GdkPangoAttrEmbossed");
1230 result = g_new (GdkPangoAttrEmbossed, 1);
1231 result->attr.klass = &klass;
1232 result->embossed = embossed;
1234 return (PangoAttribute *)result;
1237 /* Get a clip region to draw only part of a layout. index_ranges
1238 * contains alternating range starts/stops. The region is the
1239 * region which contains the given ranges, i.e. if you draw with the
1240 * region as clip, only the given ranges are drawn.
1244 * gdk_pango_layout_line_get_clip_region:
1245 * @line: a #PangoLayoutLine
1246 * @x_origin: X pixel where you intend to draw the layout line with this clip
1247 * @y_origin: baseline pixel where you intend to draw the layout line with this clip
1248 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1249 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1251 * Obtains a clip region which contains the areas where the given
1252 * ranges of text would be drawn. @x_origin and @y_origin are the same
1253 * position you would pass to gdk_draw_layout_line(). @index_ranges
1254 * should contain ranges of bytes in the layout's text. The clip
1255 * region will include space to the left or right of the line (to the
1256 * layout bounding box) if you have indexes above or below the indexes
1257 * contained inside the line. This is to draw the selection all the way
1258 * to the side of the layout. However, the clip region is in line coordinates,
1259 * not layout coordinates.
1261 * Return value: a clip region containing the given ranges
1264 gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
1270 GdkRegion *clip_region;
1272 PangoRectangle logical_rect;
1273 PangoLayoutIter *iter;
1276 g_return_val_if_fail (line != NULL, NULL);
1277 g_return_val_if_fail (index_ranges != NULL, NULL);
1279 clip_region = gdk_region_new ();
1281 iter = pango_layout_get_iter (line->layout);
1282 while (pango_layout_iter_get_line (iter) != line)
1283 pango_layout_iter_next_line (iter);
1285 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1286 baseline = pango_layout_iter_get_baseline (iter);
1288 pango_layout_iter_free (iter);
1291 while (i < n_ranges)
1293 gint *pixel_ranges = NULL;
1294 gint n_pixel_ranges = 0;
1297 /* Note that get_x_ranges returns layout coordinates
1299 pango_layout_line_get_x_ranges (line,
1301 index_ranges[i*2+1],
1302 &pixel_ranges, &n_pixel_ranges);
1304 for (j=0; j < n_pixel_ranges; j++)
1308 rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
1309 rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
1310 rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
1311 rect.height = logical_rect.height / PANGO_SCALE;
1313 gdk_region_union_with_rect (clip_region, &rect);
1316 g_free (pixel_ranges);
1324 * gdk_pango_layout_get_clip_region:
1325 * @layout: a #PangoLayout
1326 * @x_origin: X pixel where you intend to draw the layout with this clip
1327 * @y_origin: Y pixel where you intend to draw the layout with this clip
1328 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1329 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1331 * Obtains a clip region which contains the areas where the given ranges
1332 * of text would be drawn. @x_origin and @y_origin are the same position
1333 * you would pass to gdk_draw_layout_line(). @index_ranges should contain
1334 * ranges of bytes in the layout's text.
1336 * Return value: a clip region containing the given ranges
1339 gdk_pango_layout_get_clip_region (PangoLayout *layout,
1345 PangoLayoutIter *iter;
1346 GdkRegion *clip_region;
1348 g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
1349 g_return_val_if_fail (index_ranges != NULL, NULL);
1351 clip_region = gdk_region_new ();
1353 iter = pango_layout_get_iter (layout);
1357 PangoRectangle logical_rect;
1358 PangoLayoutLine *line;
1359 GdkRegion *line_region;
1362 line = pango_layout_iter_get_line (iter);
1364 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1365 baseline = pango_layout_iter_get_baseline (iter);
1367 line_region = gdk_pango_layout_line_get_clip_region (line,
1368 x_origin + logical_rect.x / PANGO_SCALE,
1369 y_origin + baseline / PANGO_SCALE,
1373 gdk_region_union (clip_region, line_region);
1374 gdk_region_destroy (line_region);
1376 while (pango_layout_iter_next_line (iter));
1378 pango_layout_iter_free (iter);
1384 * gdk_pango_context_get:
1386 * Creates a #PangoContext for the default GDK screen.
1388 * The context must be freed when you're finished with it.
1390 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1391 * instead of this function, to get the appropriate context for
1392 * the widget you intend to render text onto.
1394 * Return value: a new #PangoContext for the default display
1397 gdk_pango_context_get (void)
1399 return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
1403 * gdk_pango_context_get_for_screen:
1404 * @screen: the #GdkScreen for which the context is to be created.
1406 * Creates a #PangoContext for @screen.
1408 * The context must be freed when you're finished with it.
1410 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1411 * instead of this function, to get the appropriate context for
1412 * the widget you intend to render text onto.
1414 * Return value: a new #PangoContext for @screen
1419 gdk_pango_context_get_for_screen (GdkScreen *screen)
1421 PangoFontMap *fontmap;
1423 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1425 fontmap = pango_cairo_font_map_get_default ();
1427 return pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
1430 #define __GDK_PANGO_C__
1431 #include "gdkaliasdef.c"