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>
26 #include "gdkinternals.h"
29 #include "gdkprivate.h"
30 #include "gdkscreen.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];
55 PangoRenderPart last_part;
58 GdkDrawable *drawable;
64 static PangoAttrType gdk_pango_attr_stipple_type;
65 static PangoAttrType gdk_pango_attr_embossed_type;
72 G_DEFINE_TYPE (GdkPangoRenderer, gdk_pango_renderer, PANGO_TYPE_RENDERER)
75 gdk_pango_renderer_finalize (GObject *object)
77 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
78 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
82 g_object_unref (priv->base_gc);
84 g_object_unref (priv->drawable);
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;
123 /* The gymnastics here to adjust the matrix are because we want
124 * to offset by +1,+1 in device-space, not in user-space,
125 * so we can't just draw the layout at x + 1, y + 1
127 cairo_get_matrix (cr, &tmp_matrix);
128 tmp_matrix.x0 += 1.0;
129 tmp_matrix.y0 += 1.0;
130 cairo_set_matrix (cr, &tmp_matrix);
132 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
135 static inline gboolean
136 color_equal (PangoColor *c1, PangoColor *c2)
142 c1->red == c2->red &&
143 c1->green == c2->green &&
144 c1->blue == c2->blue)
151 get_cairo_context (GdkPangoRenderer *gdk_renderer,
152 PangoRenderPart part)
154 PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer);
155 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
159 const PangoMatrix *matrix;
161 priv->cr = gdk_cairo_create (priv->drawable);
163 matrix = pango_renderer_get_matrix (renderer);
166 cairo_matrix_t cairo_matrix;
168 cairo_matrix_init (&cairo_matrix,
169 matrix->xx, matrix->yx,
170 matrix->xy, matrix->yy,
171 matrix->x0, matrix->y0);
172 cairo_set_matrix (priv->cr, &cairo_matrix);
176 if (part != priv->last_part)
178 PangoColor *pango_color;
183 pango_color = pango_renderer_get_color (renderer, part);
185 if (priv->last_part != -1)
186 changed = priv->gc_changed ||
187 priv->stipple[priv->last_part] != priv->stipple[part] ||
188 !color_equal (pango_color,
189 pango_renderer_get_color (renderer, priv->last_part));
197 tmp_color.red = pango_color->red;
198 tmp_color.green = pango_color->green;
199 tmp_color.blue = pango_color->blue;
206 _gdk_gc_update_context (priv->base_gc,
213 priv->last_part = part;
214 priv->gc_changed = FALSE;
221 gdk_pango_renderer_draw_glyphs (PangoRenderer *renderer,
223 PangoGlyphString *glyphs,
227 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
228 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
231 cr = get_cairo_context (gdk_renderer,
232 PANGO_RENDER_PART_FOREGROUND);
238 cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
239 pango_cairo_show_glyph_string (cr, font, glyphs);
243 cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
244 pango_cairo_show_glyph_string (cr, font, glyphs);
247 /* Draws an error underline that looks like one of:
250 * A/ \ / \ / \ A/ \ / \ |
251 * \ \ / \ / /D \ \ / \ |
252 * \ \/ C \/ / \ \/ C \ | height = HEIGHT_SQUARES * square
253 * \ /\ F / \ F /\ \ |
259 * unit_width = (HEIGHT_SQUARES - 1) * square
261 * The x, y, width, height passed in give the desired bounding box;
262 * x/width are adjusted to make the underline a integer number of units
265 #define HEIGHT_SQUARES 2.5
267 /* Cut-and-pasted between here and pango/pango/pangocairo-render.c */
269 draw_error_underline (cairo_t *cr,
275 double square = height / HEIGHT_SQUARES;
276 double unit_width = (HEIGHT_SQUARES - 1) * square;
277 int width_units = (width + unit_width / 2) / unit_width;
278 double y_top, y_bottom;
281 x += (width - width_units * unit_width);
282 width = width_units * unit_width;
285 y_bottom = y + height;
287 /* Bottom of squiggle */
288 cairo_move_to (cr, x - square / 2, y_top + square / 2); /* A */
289 for (i = 0; i < width_units; i += 2)
291 double x_middle = x + (i + 1) * unit_width;
292 double x_right = x + (i + 2) * unit_width;
294 cairo_line_to (cr, x_middle, y_bottom); /* B */
296 if (i + 1 == width_units)
298 else if (i + 2 == width_units)
299 cairo_line_to (cr, x_right + square / 2, y_top + square / 2); /* D */
301 cairo_line_to (cr, x_right, y_top + square); /* C */
304 /* Top of squiggle */
305 for (i -= 2; i >= 0; i -= 2)
307 double x_left = x + i * unit_width;
308 double x_middle = x + (i + 1) * unit_width;
309 double x_right = x + (i + 2) * unit_width;
311 if (i + 1 == width_units)
312 cairo_line_to (cr, x_middle + square / 2, y_bottom - square / 2); /* G */
314 if (i + 2 == width_units)
315 cairo_line_to (cr, x_right, y_top); /* E */
316 cairo_line_to (cr, x_middle, y_bottom - square); /* F */
319 cairo_line_to (cr, x_left, y_top); /* H */
322 cairo_close_path (cr);
327 gdk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
328 PangoRenderPart part,
334 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
335 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
338 cr = get_cairo_context (gdk_renderer, part);
340 if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
345 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
346 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
353 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
354 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
359 gdk_pango_renderer_draw_error_underline (PangoRenderer *renderer,
365 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
366 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
369 cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE);
375 draw_error_underline (cr,
376 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
377 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
381 draw_error_underline (cr,
382 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
383 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
387 gdk_pango_renderer_part_changed (PangoRenderer *renderer,
388 PangoRenderPart part)
390 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
392 if (gdk_renderer->priv->last_part == part)
393 gdk_renderer->priv->last_part = (PangoRenderPart)-1;
397 gdk_pango_renderer_begin (PangoRenderer *renderer)
399 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
400 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
402 if (!priv->drawable || !priv->base_gc)
404 g_warning ("gdk_pango_renderer_set_drawable() and gdk_pango_renderer_set_drawable()"
405 "must be used to set the target drawable and GC before using the renderer\n");
410 gdk_pango_renderer_end (PangoRenderer *renderer)
412 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
413 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
417 cairo_destroy (priv->cr);
420 priv->last_part = (PangoRenderPart)-1;
424 gdk_pango_renderer_prepare_run (PangoRenderer *renderer,
427 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
428 gboolean embossed = FALSE;
429 GdkBitmap *stipple = NULL;
436 for (l = run->item->analysis.extra_attrs; l; l = l->next)
438 PangoAttribute *attr = l->data;
440 /* stipple_type and embossed_type aren't necessarily
441 * initialized, but they are 0, which is an
442 * invalid type so won't occur.
444 if (attr->klass->type == gdk_pango_attr_stipple_type)
446 stipple = ((GdkPangoAttrStipple*)attr)->stipple;
448 else if (attr->klass->type == gdk_pango_attr_embossed_type)
450 embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
454 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, stipple);
455 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_BACKGROUND, stipple);
456 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_UNDERLINE, stipple);
457 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_STRIKETHROUGH, stipple);
459 if (embossed != gdk_renderer->priv->embossed)
461 gdk_renderer->priv->embossed = embossed;
462 pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
465 PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->prepare_run (renderer, run);
467 for (i = 0; i <= MAX_RENDER_PART; i++)
469 if (gdk_renderer->priv->override_color_set[i])
470 pango_renderer_set_color (renderer, i, &gdk_renderer->priv->override_color[i]);
475 gdk_pango_renderer_set_property (GObject *object,
480 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
485 gdk_renderer->priv->screen = g_value_get_object (value);
488 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
494 gdk_pango_renderer_get_property (GObject *object,
499 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
504 g_value_set_object (value, gdk_renderer->priv->screen);
507 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
513 gdk_pango_renderer_init (GdkPangoRenderer *renderer)
515 renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer,
516 GDK_TYPE_PANGO_RENDERER,
517 GdkPangoRendererPrivate);
519 renderer->priv->last_part = (PangoRenderPart)-1;
520 renderer->priv->gc_changed = TRUE;
524 gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
526 GObjectClass *object_class = G_OBJECT_CLASS (klass);
528 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
530 renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
531 renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
532 renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
533 renderer_class->part_changed = gdk_pango_renderer_part_changed;
534 renderer_class->begin = gdk_pango_renderer_begin;
535 renderer_class->end = gdk_pango_renderer_end;
536 renderer_class->prepare_run = gdk_pango_renderer_prepare_run;
538 object_class->finalize = gdk_pango_renderer_finalize;
539 object_class->constructor = gdk_pango_renderer_constructor;
540 object_class->set_property = gdk_pango_renderer_set_property;
541 object_class->get_property = gdk_pango_renderer_get_property;
543 g_object_class_install_property (object_class,
545 g_param_spec_object ("screen",
547 P_("the GdkScreen for the renderer"),
549 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
550 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
551 G_PARAM_STATIC_BLURB));
553 g_type_class_add_private (object_class, sizeof (GdkPangoRendererPrivate));
557 * gdk_pango_renderer_new:
558 * @screen: a #GdkScreen
560 * Creates a new #PangoRenderer for @screen. Normally you can use the
561 * results of gdk_pango_renderer_get_default() rather than creating a new
564 * Return value: a newly created #PangoRenderer. Free with g_object_unref().
569 gdk_pango_renderer_new (GdkScreen *screen)
571 g_return_val_if_fail (screen != NULL, NULL);
573 return g_object_new (GDK_TYPE_PANGO_RENDERER,
579 on_renderer_display_closed (GdkDisplay *display,
581 GdkPangoRenderer *renderer)
583 g_signal_handlers_disconnect_by_func (display,
584 on_renderer_display_closed,
586 g_object_set_data (G_OBJECT (renderer->priv->screen),
587 g_intern_static_string ("gdk-pango-renderer"), NULL);
591 * gdk_pango_renderer_get_default:
592 * @screen: a #GdkScreen
594 * Gets the default #PangoRenderer for a screen. This default renderer
595 * is shared by all users of the display, so properties such as the color
596 * or transformation matrix set for the renderer may be overwritten
597 * by functions such as gdk_draw_layout().
599 * Before using the renderer, you need to call gdk_pango_renderer_set_drawable()
600 * and gdk_pango_renderer_set_gc() to set the drawable and graphics context
601 * to use for drawing.
603 * Return value: the default #PangoRenderer for @screen. The
604 * renderer is owned by GTK+ and will be kept around until the
610 gdk_pango_renderer_get_default (GdkScreen *screen)
612 PangoRenderer *renderer;
614 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
616 renderer = g_object_get_data (G_OBJECT (screen), "gdk-pango-renderer");
619 renderer = gdk_pango_renderer_new (screen);
620 g_object_set_data_full (G_OBJECT (screen),
621 g_intern_static_string ("gdk-pango-renderer"), renderer,
622 (GDestroyNotify)g_object_unref);
624 g_signal_connect (gdk_screen_get_display (screen), "closed",
625 G_CALLBACK (on_renderer_display_closed), renderer);
632 * gdk_pango_renderer_set_drawable:
633 * @gdk_renderer: a #GdkPangoRenderer
634 * @drawable: the new target drawable, or %NULL
636 * Sets the drawable the renderer draws to.
641 gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer,
642 GdkDrawable *drawable)
644 GdkPangoRendererPrivate *priv;
646 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
647 g_return_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable));
649 priv = gdk_renderer->priv;
651 if (priv->drawable != drawable)
654 g_object_unref (priv->drawable);
655 priv->drawable = drawable;
657 g_object_ref (priv->drawable);
662 * gdk_pango_renderer_set_gc:
663 * @gdk_renderer: a #GdkPangoRenderer
664 * @gc: the new GC to use for drawing, or %NULL
666 * Sets the GC the renderer draws with. Note that the GC must not be
667 * modified until it is unset by calling the function again with
668 * %NULL for the @gc parameter, since GDK may make internal copies
669 * of the GC which won't be updated to follow changes to the
675 gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
678 GdkPangoRendererPrivate *priv;
680 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
681 g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
683 priv = gdk_renderer->priv;
685 if (priv->base_gc != gc)
688 g_object_unref (priv->base_gc);
691 g_object_ref (priv->base_gc);
693 priv->gc_changed = TRUE;
699 * gdk_pango_renderer_set_stipple:
700 * @gdk_renderer: a #GdkPangoRenderer
701 * @part: the part to render with the stipple
702 * @stipple: the new stipple value.
704 * Sets the stipple for one render part (foreground, background, underline,
705 * etc.) Note that this is overwritten when iterating through the individual
706 * styled runs of a #PangoLayout or #PangoLayoutLine. This function is thus
707 * only useful when you call low level functions like pango_renderer_draw_glyphs()
708 * directly, or in the 'prepare_run' virtual function of a subclass of
714 gdk_pango_renderer_set_stipple (GdkPangoRenderer *gdk_renderer,
715 PangoRenderPart part,
718 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
720 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
723 if (stipple != gdk_renderer->priv->stipple[part])
725 if (gdk_renderer->priv->stipple[part])
726 g_object_unref (gdk_renderer->priv->stipple[part]);
728 gdk_renderer->priv->stipple[part] = stipple;
730 if (gdk_renderer->priv->stipple[part])
731 g_object_ref (gdk_renderer->priv->stipple[part]);
733 pango_renderer_part_changed (PANGO_RENDERER (gdk_renderer), part);
738 * gdk_pango_renderer_set_override_color:
739 * @gdk_renderer: a #GdkPangoRenderer
740 * @part: the part to render to set the color of
741 * @color: the color to use, or %NULL to unset a previously
742 * set override color.
744 * Sets the color for a particular render part (foreground,
745 * background, underline, etc.), overriding any attributes on the layouts
746 * renderered with this renderer.
751 gdk_pango_renderer_set_override_color (GdkPangoRenderer *gdk_renderer,
752 PangoRenderPart part,
753 const GdkColor *color)
755 GdkPangoRendererPrivate *priv;
757 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
759 priv = gdk_renderer->priv;
761 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
766 priv->override_color[part].red = color->red;
767 priv->override_color[part].green = color->green;
768 priv->override_color[part].blue = color->blue;
769 priv->override_color_set[part] = TRUE;
772 priv->override_color_set[part] = FALSE;
776 * gdk_pango_context_set_colormap:
777 * @context: a #PangoContext
778 * @colormap: a #GdkColormap
780 * This function used to set the colormap to be used for drawing with
781 * @context. The colormap is now always derived from the graphics
782 * context used for drawing, so calling this function is no longer
786 gdk_pango_context_set_colormap (PangoContext *context,
787 GdkColormap *colormap)
789 g_return_if_fail (PANGO_IS_CONTEXT (context));
790 g_return_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap));
793 /* Gets a renderer to draw with, setting the properties of the
794 * renderer and activating it. Note that since we activate the
795 * renderer here, the implicit setting of the matrix that
796 * pango_renderer_draw_layout_[line] normally do when they
797 * activate the renderer is suppressed. */
798 static PangoRenderer *
799 get_renderer (GdkDrawable *drawable,
801 const GdkColor *foreground,
802 const GdkColor *background)
804 GdkScreen *screen = gdk_drawable_get_screen (drawable);
805 PangoRenderer *renderer = gdk_pango_renderer_get_default (screen);
806 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
808 gdk_pango_renderer_set_drawable (gdk_renderer, drawable);
809 gdk_pango_renderer_set_gc (gdk_renderer, gc);
811 gdk_pango_renderer_set_override_color (gdk_renderer,
812 PANGO_RENDER_PART_FOREGROUND,
814 gdk_pango_renderer_set_override_color (gdk_renderer,
815 PANGO_RENDER_PART_UNDERLINE,
817 gdk_pango_renderer_set_override_color (gdk_renderer,
818 PANGO_RENDER_PART_STRIKETHROUGH,
821 gdk_pango_renderer_set_override_color (gdk_renderer,
822 PANGO_RENDER_PART_BACKGROUND,
825 pango_renderer_activate (renderer);
830 /* Cleans up the renderer obtained with get_renderer() */
832 release_renderer (PangoRenderer *renderer)
834 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
836 pango_renderer_deactivate (renderer);
838 gdk_pango_renderer_set_override_color (gdk_renderer,
839 PANGO_RENDER_PART_FOREGROUND,
841 gdk_pango_renderer_set_override_color (gdk_renderer,
842 PANGO_RENDER_PART_UNDERLINE,
844 gdk_pango_renderer_set_override_color (gdk_renderer,
845 PANGO_RENDER_PART_STRIKETHROUGH,
847 gdk_pango_renderer_set_override_color (gdk_renderer,
848 PANGO_RENDER_PART_BACKGROUND,
851 gdk_pango_renderer_set_drawable (gdk_renderer, NULL);
852 gdk_pango_renderer_set_gc (gdk_renderer, NULL);
856 * gdk_draw_layout_line_with_colors:
857 * @drawable: the drawable on which to draw the line
858 * @gc: base graphics to use
859 * @x: the x position of start of string (in pixels)
860 * @y: the y position of baseline (in pixels)
861 * @line: a #PangoLayoutLine
862 * @foreground: foreground override color, or %NULL for none
863 * @background: background override color, or %NULL for none
865 * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
866 * layout's normal colors with @foreground and/or @background.
867 * @foreground and @background need not be allocated.
869 * If the layout's #PangoContext has a transformation matrix set, then
870 * @x and @y specify the position of the left edge of the baseline
871 * (left is in before-tranform user coordinates) in after-transform
872 * device coordinates.
875 gdk_draw_layout_line_with_colors (GdkDrawable *drawable,
879 PangoLayoutLine *line,
880 const GdkColor *foreground,
881 const GdkColor *background)
883 PangoRenderer *renderer;
884 const PangoMatrix *matrix;
886 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
887 g_return_if_fail (GDK_IS_GC (gc));
888 g_return_if_fail (line != NULL);
890 renderer = get_renderer (drawable, gc, foreground, background);
892 /* When we have a matrix, we do positioning by adjusting the matrix, and
893 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
894 * a matrix when the caller didn't provide one, however, since that adds
895 * lots of floating point arithmetic for each glyph.
897 matrix = pango_context_get_matrix (pango_layout_get_context (line->layout));
900 PangoMatrix tmp_matrix;
902 tmp_matrix = *matrix;
905 pango_renderer_set_matrix (renderer, &tmp_matrix);
911 pango_renderer_set_matrix (renderer, NULL);
913 pango_renderer_draw_layout_line (renderer, line, x * PANGO_SCALE, y * PANGO_SCALE);
915 release_renderer (renderer);
918 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
919 * between here and gtklabel.c */
921 get_rotated_layout_bounds (PangoLayout *layout,
924 PangoContext *context = pango_layout_get_context (layout);
925 const PangoMatrix *matrix = pango_context_get_matrix (context);
926 gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
927 PangoRectangle logical_rect;
930 pango_layout_get_extents (layout, NULL, &logical_rect);
932 for (i = 0; i < 2; i++)
934 gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
935 for (j = 0; j < 2; j++)
937 gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
939 gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
940 gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
942 if (i == 0 && j == 0)
961 rect->x = floor (x_min);
962 rect->width = ceil (x_max) - rect->x;
963 rect->y = floor (y_min);
964 rect->height = floor (y_max) - rect->y;
968 * gdk_draw_layout_with_colors:
969 * @drawable: the drawable on which to draw string
970 * @gc: base graphics context to use
971 * @x: the X position of the left of the layout (in pixels)
972 * @y: the Y position of the top of the layout (in pixels)
973 * @layout: a #PangoLayout
974 * @foreground: foreground override color, or %NULL for none
975 * @background: background override color, or %NULL for none
977 * Render a #PangoLayout onto a #GdkDrawable, overriding the
978 * layout's normal colors with @foreground and/or @background.
979 * @foreground and @background need not be allocated.
981 * If the layout's #PangoContext has a transformation matrix set, then
982 * @x and @y specify the position of the top left corner of the
983 * bounding box (in device space) of the transformed layout.
985 * If you're using GTK+, the ususal way to obtain a #PangoLayout
986 * is gtk_widget_create_pango_layout().
989 gdk_draw_layout_with_colors (GdkDrawable *drawable,
994 const GdkColor *foreground,
995 const GdkColor *background)
997 PangoRenderer *renderer;
998 const PangoMatrix *matrix;
1000 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1001 g_return_if_fail (GDK_IS_GC (gc));
1002 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1004 renderer = get_renderer (drawable, gc, foreground, background);
1006 /* When we have a matrix, we do positioning by adjusting the matrix, and
1007 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
1008 * a matrix when the caller didn't provide one, however, since that adds
1009 * lots of floating point arithmetic for each glyph.
1011 matrix = pango_context_get_matrix (pango_layout_get_context (layout));
1014 PangoMatrix tmp_matrix;
1017 get_rotated_layout_bounds (layout, &rect);
1019 tmp_matrix = *matrix;
1020 tmp_matrix.x0 += x - rect.x;
1021 tmp_matrix.y0 += y - rect.y;
1022 pango_renderer_set_matrix (renderer, &tmp_matrix);
1028 pango_renderer_set_matrix (renderer, NULL);
1030 pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE);
1032 release_renderer (renderer);
1036 * gdk_draw_layout_line:
1037 * @drawable: the drawable on which to draw the line
1038 * @gc: base graphics to use
1039 * @x: the x position of start of string (in pixels)
1040 * @y: the y position of baseline (in pixels)
1041 * @line: a #PangoLayoutLine
1043 * Render a #PangoLayoutLine onto an GDK drawable
1045 * If the layout's #PangoContext has a transformation matrix set, then
1046 * @x and @y specify the position of the left edge of the baseline
1047 * (left is in before-tranform user coordinates) in after-transform
1048 * device coordinates.
1051 gdk_draw_layout_line (GdkDrawable *drawable,
1055 PangoLayoutLine *line)
1057 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1058 g_return_if_fail (GDK_IS_GC (gc));
1059 g_return_if_fail (line != NULL);
1061 gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL);
1066 * @drawable: the drawable on which to draw string
1067 * @gc: base graphics context to use
1068 * @x: the X position of the left of the layout (in pixels)
1069 * @y: the Y position of the top of the layout (in pixels)
1070 * @layout: a #PangoLayout
1072 * Render a #PangoLayout onto a GDK drawable
1074 * If the layout's #PangoContext has a transformation matrix set, then
1075 * @x and @y specify the position of the top left corner of the
1076 * bounding box (in device space) of the transformed layout.
1078 * If you're using GTK+, the usual way to obtain a #PangoLayout
1079 * is gtk_widget_create_pango_layout().
1082 gdk_draw_layout (GdkDrawable *drawable,
1086 PangoLayout *layout)
1088 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1089 g_return_if_fail (GDK_IS_GC (gc));
1090 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1092 gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
1095 static PangoAttribute *
1096 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
1098 const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
1100 return gdk_pango_attr_stipple_new (src->stipple);
1104 gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
1106 GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
1109 g_object_unref (st->stipple);
1115 gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
1116 const PangoAttribute *attr2)
1118 const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
1119 const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
1121 return a->stipple == b->stipple;
1125 * gdk_pango_attr_stipple_new:
1126 * @stipple: a bitmap to be set as stipple
1128 * Creates a new attribute containing a stipple bitmap to be used when
1129 * rendering the text.
1131 * Return value: new #PangoAttribute
1135 gdk_pango_attr_stipple_new (GdkBitmap *stipple)
1137 GdkPangoAttrStipple *result;
1139 static PangoAttrClass klass = {
1141 gdk_pango_attr_stipple_copy,
1142 gdk_pango_attr_stipple_destroy,
1143 gdk_pango_attr_stipple_compare
1147 klass.type = gdk_pango_attr_stipple_type =
1148 pango_attr_type_register ("GdkPangoAttrStipple");
1150 result = g_new (GdkPangoAttrStipple, 1);
1151 result->attr.klass = &klass;
1154 g_object_ref (stipple);
1156 result->stipple = stipple;
1158 return (PangoAttribute *)result;
1161 static PangoAttribute *
1162 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
1164 const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
1166 return gdk_pango_attr_embossed_new (e->embossed);
1170 gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
1176 gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
1177 const PangoAttribute *attr2)
1179 const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
1180 const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
1182 return e1->embossed == e2->embossed;
1186 * gdk_pango_attr_embossed_new:
1187 * @embossed: a bitmap to be set as embossed
1189 * Creates a new attribute containing a embossed bitmap to be used when
1190 * rendering the text.
1192 * Return value: new #PangoAttribute
1196 gdk_pango_attr_embossed_new (gboolean embossed)
1198 GdkPangoAttrEmbossed *result;
1200 static PangoAttrClass klass = {
1202 gdk_pango_attr_embossed_copy,
1203 gdk_pango_attr_embossed_destroy,
1204 gdk_pango_attr_embossed_compare
1208 klass.type = gdk_pango_attr_embossed_type =
1209 pango_attr_type_register ("GdkPangoAttrEmbossed");
1211 result = g_new (GdkPangoAttrEmbossed, 1);
1212 result->attr.klass = &klass;
1213 result->embossed = embossed;
1215 return (PangoAttribute *)result;
1218 /* Get a clip region to draw only part of a layout. index_ranges
1219 * contains alternating range starts/stops. The region is the
1220 * region which contains the given ranges, i.e. if you draw with the
1221 * region as clip, only the given ranges are drawn.
1225 * gdk_pango_layout_line_get_clip_region:
1226 * @line: a #PangoLayoutLine
1227 * @x_origin: X pixel where you intend to draw the layout line with this clip
1228 * @y_origin: baseline pixel where you intend to draw the layout line with this clip
1229 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1230 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1232 * Obtains a clip region which contains the areas where the given
1233 * ranges of text would be drawn. @x_origin and @y_origin are the same
1234 * position you would pass to gdk_draw_layout_line(). @index_ranges
1235 * should contain ranges of bytes in the layout's text. The clip
1236 * region will include space to the left or right of the line (to the
1237 * layout bounding box) if you have indexes above or below the indexes
1238 * contained inside the line. This is to draw the selection all the way
1239 * to the side of the layout. However, the clip region is in line coordinates,
1240 * not layout coordinates.
1242 * Return value: a clip region containing the given ranges
1245 gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
1251 GdkRegion *clip_region;
1253 PangoRectangle logical_rect;
1254 PangoLayoutIter *iter;
1257 g_return_val_if_fail (line != NULL, NULL);
1258 g_return_val_if_fail (index_ranges != NULL, NULL);
1260 clip_region = gdk_region_new ();
1262 iter = pango_layout_get_iter (line->layout);
1263 while (pango_layout_iter_get_line (iter) != line)
1264 pango_layout_iter_next_line (iter);
1266 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1267 baseline = pango_layout_iter_get_baseline (iter);
1269 pango_layout_iter_free (iter);
1272 while (i < n_ranges)
1274 gint *pixel_ranges = NULL;
1275 gint n_pixel_ranges = 0;
1278 /* Note that get_x_ranges returns layout coordinates
1280 if (index_ranges[i*2+1] >= line->start_index &&
1281 index_ranges[i*2] < line->start_index + line->length)
1282 pango_layout_line_get_x_ranges (line,
1284 index_ranges[i*2+1],
1285 &pixel_ranges, &n_pixel_ranges);
1287 for (j = 0; j < n_pixel_ranges; j++)
1291 rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
1292 rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
1293 rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
1294 rect.height = logical_rect.height / PANGO_SCALE;
1296 gdk_region_union_with_rect (clip_region, &rect);
1299 g_free (pixel_ranges);
1307 * gdk_pango_layout_get_clip_region:
1308 * @layout: a #PangoLayout
1309 * @x_origin: X pixel where you intend to draw the layout with this clip
1310 * @y_origin: Y pixel where you intend to draw the layout with this clip
1311 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1312 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1314 * Obtains a clip region which contains the areas where the given ranges
1315 * of text would be drawn. @x_origin and @y_origin are the same position
1316 * you would pass to gdk_draw_layout_line(). @index_ranges should contain
1317 * ranges of bytes in the layout's text.
1319 * Return value: a clip region containing the given ranges
1322 gdk_pango_layout_get_clip_region (PangoLayout *layout,
1328 PangoLayoutIter *iter;
1329 GdkRegion *clip_region;
1331 g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
1332 g_return_val_if_fail (index_ranges != NULL, NULL);
1334 clip_region = gdk_region_new ();
1336 iter = pango_layout_get_iter (layout);
1340 PangoRectangle logical_rect;
1341 PangoLayoutLine *line;
1342 GdkRegion *line_region;
1345 line = pango_layout_iter_get_line (iter);
1347 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1348 baseline = pango_layout_iter_get_baseline (iter);
1350 line_region = gdk_pango_layout_line_get_clip_region (line,
1351 x_origin + logical_rect.x / PANGO_SCALE,
1352 y_origin + baseline / PANGO_SCALE,
1356 gdk_region_union (clip_region, line_region);
1357 gdk_region_destroy (line_region);
1359 while (pango_layout_iter_next_line (iter));
1361 pango_layout_iter_free (iter);
1367 * gdk_pango_context_get:
1369 * Creates a #PangoContext for the default GDK screen.
1371 * The context must be freed when you're finished with it.
1373 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1374 * instead of this function, to get the appropriate context for
1375 * the widget you intend to render text onto.
1377 * The newly created context will have the default font options (see
1378 * #cairo_font_options_t) for the default screen; if these options
1379 * change it will not be updated. Using gtk_widget_get_pango_context()
1380 * is more convenient if you want to keep a context around and track
1381 * changes to the screen's font rendering settings.
1383 * Return value: a new #PangoContext for the default display
1386 gdk_pango_context_get (void)
1388 return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
1392 * gdk_pango_context_get_for_screen:
1393 * @screen: the #GdkScreen for which the context is to be created.
1395 * Creates a #PangoContext for @screen.
1397 * The context must be freed when you're finished with it.
1399 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1400 * instead of this function, to get the appropriate context for
1401 * the widget you intend to render text onto.
1403 * The newly created context will have the default font options
1404 * (see #cairo_font_options_t) for the screen; if these options
1405 * change it will not be updated. Using gtk_widget_get_pango_context()
1406 * is more convenient if you want to keep a context around and track
1407 * changes to the screen's font rendering settings.
1409 * Return value: a new #PangoContext for @screen
1414 gdk_pango_context_get_for_screen (GdkScreen *screen)
1416 PangoFontMap *fontmap;
1417 PangoContext *context;
1418 const cairo_font_options_t *options;
1421 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1423 fontmap = pango_cairo_font_map_get_default ();
1425 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
1427 options = gdk_screen_get_font_options (screen);
1428 pango_cairo_context_set_font_options (context, options);
1430 dpi = gdk_screen_get_resolution (screen);
1431 pango_cairo_context_set_resolution (context, dpi);
1436 #define __GDK_PANGO_C__
1437 #include "gdkaliasdef.c"