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"
34 #define GDK_INFO_KEY "gdk-info"
36 /* We have various arrays indexed by render part; if PangoRenderPart
37 * is extended, we want to make sure not to overwrite the end of
40 #define MAX_RENDER_PART PANGO_RENDER_PART_STRIKETHROUGH
42 struct _GdkPangoRendererPrivate
46 /* GdkPangoRenderer specific state */
47 PangoColor override_color[MAX_RENDER_PART + 1];
48 gboolean override_color_set[MAX_RENDER_PART + 1];
50 GdkBitmap *stipple[MAX_RENDER_PART + 1];
51 PangoColor emboss_color;
55 PangoRenderPart last_part;
58 GdkDrawable *drawable;
64 static PangoAttrType gdk_pango_attr_stipple_type;
65 static PangoAttrType gdk_pango_attr_embossed_type;
66 static PangoAttrType gdk_pango_attr_emboss_color_type;
73 G_DEFINE_TYPE (GdkPangoRenderer, gdk_pango_renderer, PANGO_TYPE_RENDERER)
76 gdk_pango_renderer_finalize (GObject *object)
78 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
79 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
83 g_object_unref (priv->base_gc);
85 g_object_unref (priv->drawable);
87 for (i = 0; i <= MAX_RENDER_PART; i++)
89 g_object_unref (priv->stipple[i]);
91 G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->finalize (object);
95 gdk_pango_renderer_constructor (GType type,
96 guint n_construct_properties,
97 GObjectConstructParam *construct_params)
100 GdkPangoRenderer *gdk_renderer;
102 object = (* G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->constructor) (type,
103 n_construct_properties,
106 gdk_renderer = GDK_PANGO_RENDERER (object);
108 if (!gdk_renderer->priv->screen)
110 g_warning ("Screen must be specified at construct time for GdkPangoRenderer");
111 gdk_renderer->priv->screen = gdk_screen_get_default ();
117 /* Adjusts matrix and color for the renderer to draw the secondary
118 * "shadow" copy for embossed text */
120 emboss_context (GdkPangoRenderer *renderer, cairo_t *cr)
122 GdkPangoRendererPrivate *priv = renderer->priv;
123 cairo_matrix_t tmp_matrix;
124 double red, green, blue;
126 /* The gymnastics here to adjust the matrix are because we want
127 * to offset by +1,+1 in device-space, not in user-space,
128 * so we can't just draw the layout at x + 1, y + 1
130 cairo_get_matrix (cr, &tmp_matrix);
131 tmp_matrix.x0 += 1.0;
132 tmp_matrix.y0 += 1.0;
133 cairo_set_matrix (cr, &tmp_matrix);
135 red = (double) priv->emboss_color.red / 65535.;
136 green = (double) priv->emboss_color.green / 65535.;
137 blue = (double) priv->emboss_color.blue / 65535.;
139 cairo_set_source_rgb (cr, red, green, blue);
142 static inline gboolean
143 color_equal (const PangoColor *c1, const PangoColor *c2)
149 c1->red == c2->red &&
150 c1->green == c2->green &&
151 c1->blue == c2->blue)
158 get_cairo_context (GdkPangoRenderer *gdk_renderer,
159 PangoRenderPart part)
161 PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer);
162 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
166 const PangoMatrix *matrix;
168 priv->cr = gdk_cairo_create (priv->drawable);
170 matrix = pango_renderer_get_matrix (renderer);
173 cairo_matrix_t cairo_matrix;
175 cairo_matrix_init (&cairo_matrix,
176 matrix->xx, matrix->yx,
177 matrix->xy, matrix->yy,
178 matrix->x0, matrix->y0);
179 cairo_set_matrix (priv->cr, &cairo_matrix);
183 if (part != priv->last_part)
185 PangoColor *pango_color;
190 pango_color = pango_renderer_get_color (renderer, part);
192 if (priv->last_part != -1)
193 changed = priv->gc_changed ||
194 priv->stipple[priv->last_part] != priv->stipple[part] ||
195 !color_equal (pango_color,
196 pango_renderer_get_color (renderer, priv->last_part));
204 tmp_color.red = pango_color->red;
205 tmp_color.green = pango_color->green;
206 tmp_color.blue = pango_color->blue;
213 _gdk_gc_update_context (priv->base_gc,
220 priv->last_part = part;
221 priv->gc_changed = FALSE;
228 gdk_pango_renderer_draw_glyphs (PangoRenderer *renderer,
230 PangoGlyphString *glyphs,
234 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
235 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
238 cr = get_cairo_context (gdk_renderer,
239 PANGO_RENDER_PART_FOREGROUND);
244 emboss_context (gdk_renderer, cr);
245 cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
246 pango_cairo_show_glyph_string (cr, font, glyphs);
250 cairo_move_to (cr, (double)x / PANGO_SCALE, (double)y / PANGO_SCALE);
251 pango_cairo_show_glyph_string (cr, font, glyphs);
255 gdk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
256 PangoRenderPart part,
262 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
263 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
266 cr = get_cairo_context (gdk_renderer, part);
268 if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
271 emboss_context (gdk_renderer, cr);
273 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
274 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
281 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
282 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
287 gdk_pango_renderer_draw_error_underline (PangoRenderer *renderer,
293 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
294 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
297 cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE);
302 emboss_context (gdk_renderer, cr);
303 pango_cairo_show_error_underline (cr,
304 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
305 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
309 pango_cairo_show_error_underline (cr,
310 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
311 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
315 gdk_pango_renderer_part_changed (PangoRenderer *renderer,
316 PangoRenderPart part)
318 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
320 if (gdk_renderer->priv->last_part == part)
321 gdk_renderer->priv->last_part = (PangoRenderPart)-1;
325 gdk_pango_renderer_begin (PangoRenderer *renderer)
327 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
328 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
330 if (!priv->drawable || !priv->base_gc)
332 g_warning ("gdk_pango_renderer_set_drawable() and gdk_pango_renderer_set_drawable()"
333 "must be used to set the target drawable and GC before using the renderer\n");
338 gdk_pango_renderer_end (PangoRenderer *renderer)
340 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
341 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
345 cairo_destroy (priv->cr);
348 priv->last_part = (PangoRenderPart)-1;
352 gdk_pango_renderer_prepare_run (PangoRenderer *renderer,
355 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
356 gboolean embossed = FALSE;
357 GdkBitmap *stipple = NULL;
358 gboolean changed = FALSE;
359 PangoColor emboss_color;
363 emboss_color.red = 0xffff;
364 emboss_color.green = 0xffff;
365 emboss_color.blue = 0xffff;
367 for (l = run->item->analysis.extra_attrs; l; l = l->next)
369 PangoAttribute *attr = l->data;
371 /* stipple_type and embossed_type aren't necessarily
372 * initialized, but they are 0, which is an
373 * invalid type so won't occur.
375 if (attr->klass->type == gdk_pango_attr_stipple_type)
377 stipple = ((GdkPangoAttrStipple*)attr)->stipple;
379 else if (attr->klass->type == gdk_pango_attr_embossed_type)
381 embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
383 else if (attr->klass->type == gdk_pango_attr_emboss_color_type)
385 emboss_color = ((GdkPangoAttrEmbossColor*)attr)->color;
389 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, stipple);
390 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_BACKGROUND, stipple);
391 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_UNDERLINE, stipple);
392 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_STRIKETHROUGH, stipple);
394 if (embossed != gdk_renderer->priv->embossed)
396 gdk_renderer->priv->embossed = embossed;
400 if (!color_equal (&gdk_renderer->priv->emboss_color, &emboss_color))
402 gdk_renderer->priv->emboss_color = emboss_color;
407 pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
409 PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->prepare_run (renderer, run);
411 for (i = 0; i <= MAX_RENDER_PART; i++)
413 if (gdk_renderer->priv->override_color_set[i])
414 pango_renderer_set_color (renderer, i, &gdk_renderer->priv->override_color[i]);
419 gdk_pango_renderer_set_property (GObject *object,
424 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
429 gdk_renderer->priv->screen = g_value_get_object (value);
432 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
438 gdk_pango_renderer_get_property (GObject *object,
443 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
448 g_value_set_object (value, gdk_renderer->priv->screen);
451 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
457 gdk_pango_renderer_init (GdkPangoRenderer *renderer)
459 renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer,
460 GDK_TYPE_PANGO_RENDERER,
461 GdkPangoRendererPrivate);
463 renderer->priv->last_part = (PangoRenderPart)-1;
464 renderer->priv->gc_changed = TRUE;
468 gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
470 GObjectClass *object_class = G_OBJECT_CLASS (klass);
472 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
474 renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
475 renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
476 renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
477 renderer_class->part_changed = gdk_pango_renderer_part_changed;
478 renderer_class->begin = gdk_pango_renderer_begin;
479 renderer_class->end = gdk_pango_renderer_end;
480 renderer_class->prepare_run = gdk_pango_renderer_prepare_run;
482 object_class->finalize = gdk_pango_renderer_finalize;
483 object_class->constructor = gdk_pango_renderer_constructor;
484 object_class->set_property = gdk_pango_renderer_set_property;
485 object_class->get_property = gdk_pango_renderer_get_property;
487 g_object_class_install_property (object_class,
489 g_param_spec_object ("screen",
491 P_("the GdkScreen for the renderer"),
493 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
494 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
495 G_PARAM_STATIC_BLURB));
497 g_type_class_add_private (object_class, sizeof (GdkPangoRendererPrivate));
501 * gdk_pango_renderer_new:
502 * @screen: a #GdkScreen
504 * Creates a new #PangoRenderer for @screen. Normally you can use the
505 * results of gdk_pango_renderer_get_default() rather than creating a new
508 * Return value: a newly created #PangoRenderer. Free with g_object_unref().
513 gdk_pango_renderer_new (GdkScreen *screen)
515 g_return_val_if_fail (screen != NULL, NULL);
517 return g_object_new (GDK_TYPE_PANGO_RENDERER,
523 on_renderer_display_closed (GdkDisplay *display,
525 GdkPangoRenderer *renderer)
527 g_signal_handlers_disconnect_by_func (display,
528 on_renderer_display_closed,
530 g_object_set_data (G_OBJECT (renderer->priv->screen),
531 g_intern_static_string ("gdk-pango-renderer"), NULL);
535 * gdk_pango_renderer_get_default:
536 * @screen: a #GdkScreen
538 * Gets the default #PangoRenderer for a screen. This default renderer
539 * is shared by all users of the display, so properties such as the color
540 * or transformation matrix set for the renderer may be overwritten
541 * by functions such as gdk_draw_layout().
543 * Before using the renderer, you need to call gdk_pango_renderer_set_drawable()
544 * and gdk_pango_renderer_set_gc() to set the drawable and graphics context
545 * to use for drawing.
547 * Return value: the default #PangoRenderer for @screen. The
548 * renderer is owned by GTK+ and will be kept around until the
554 gdk_pango_renderer_get_default (GdkScreen *screen)
556 PangoRenderer *renderer;
558 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
560 renderer = g_object_get_data (G_OBJECT (screen), "gdk-pango-renderer");
563 renderer = gdk_pango_renderer_new (screen);
564 g_object_set_data_full (G_OBJECT (screen),
565 g_intern_static_string ("gdk-pango-renderer"), renderer,
566 (GDestroyNotify)g_object_unref);
568 g_signal_connect (gdk_screen_get_display (screen), "closed",
569 G_CALLBACK (on_renderer_display_closed), renderer);
576 * gdk_pango_renderer_set_drawable:
577 * @gdk_renderer: a #GdkPangoRenderer
578 * @drawable: the new target drawable, or %NULL
580 * Sets the drawable the renderer draws to.
585 gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer,
586 GdkDrawable *drawable)
588 GdkPangoRendererPrivate *priv;
590 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
591 g_return_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable));
593 priv = gdk_renderer->priv;
595 if (priv->drawable != drawable)
598 g_object_unref (priv->drawable);
599 priv->drawable = drawable;
601 g_object_ref (priv->drawable);
606 * gdk_pango_renderer_set_gc:
607 * @gdk_renderer: a #GdkPangoRenderer
608 * @gc: the new GC to use for drawing, or %NULL
610 * Sets the GC the renderer draws with. Note that the GC must not be
611 * modified until it is unset by calling the function again with
612 * %NULL for the @gc parameter, since GDK may make internal copies
613 * of the GC which won't be updated to follow changes to the
619 gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
622 GdkPangoRendererPrivate *priv;
624 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
625 g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
627 priv = gdk_renderer->priv;
629 if (priv->base_gc != gc)
632 g_object_unref (priv->base_gc);
635 g_object_ref (priv->base_gc);
637 priv->gc_changed = TRUE;
643 * gdk_pango_renderer_set_stipple:
644 * @gdk_renderer: a #GdkPangoRenderer
645 * @part: the part to render with the stipple
646 * @stipple: the new stipple value.
648 * Sets the stipple for one render part (foreground, background, underline,
649 * etc.) Note that this is overwritten when iterating through the individual
650 * styled runs of a #PangoLayout or #PangoLayoutLine. This function is thus
651 * only useful when you call low level functions like pango_renderer_draw_glyphs()
652 * directly, or in the 'prepare_run' virtual function of a subclass of
658 gdk_pango_renderer_set_stipple (GdkPangoRenderer *gdk_renderer,
659 PangoRenderPart part,
662 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
664 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
667 if (stipple != gdk_renderer->priv->stipple[part])
669 if (gdk_renderer->priv->stipple[part])
670 g_object_unref (gdk_renderer->priv->stipple[part]);
672 gdk_renderer->priv->stipple[part] = stipple;
674 if (gdk_renderer->priv->stipple[part])
675 g_object_ref (gdk_renderer->priv->stipple[part]);
677 pango_renderer_part_changed (PANGO_RENDERER (gdk_renderer), part);
682 * gdk_pango_renderer_set_override_color:
683 * @gdk_renderer: a #GdkPangoRenderer
684 * @part: the part to render to set the color of
685 * @color: the color to use, or %NULL to unset a previously
686 * set override color.
688 * Sets the color for a particular render part (foreground,
689 * background, underline, etc.), overriding any attributes on the layouts
690 * renderered with this renderer.
695 gdk_pango_renderer_set_override_color (GdkPangoRenderer *gdk_renderer,
696 PangoRenderPart part,
697 const GdkColor *color)
699 GdkPangoRendererPrivate *priv;
701 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
703 priv = gdk_renderer->priv;
705 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
710 priv->override_color[part].red = color->red;
711 priv->override_color[part].green = color->green;
712 priv->override_color[part].blue = color->blue;
713 priv->override_color_set[part] = TRUE;
716 priv->override_color_set[part] = FALSE;
720 * gdk_pango_context_set_colormap:
721 * @context: a #PangoContext
722 * @colormap: a #GdkColormap
724 * This function used to set the colormap to be used for drawing with
725 * @context. The colormap is now always derived from the graphics
726 * context used for drawing, so calling this function is no longer
730 gdk_pango_context_set_colormap (PangoContext *context,
731 GdkColormap *colormap)
733 g_return_if_fail (PANGO_IS_CONTEXT (context));
734 g_return_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap));
737 /* Gets a renderer to draw with, setting the properties of the
738 * renderer and activating it. Note that since we activate the
739 * renderer here, the implicit setting of the matrix that
740 * pango_renderer_draw_layout_[line] normally do when they
741 * activate the renderer is suppressed. */
742 static PangoRenderer *
743 get_renderer (GdkDrawable *drawable,
745 const GdkColor *foreground,
746 const GdkColor *background)
748 GdkScreen *screen = gdk_drawable_get_screen (drawable);
749 PangoRenderer *renderer = gdk_pango_renderer_get_default (screen);
750 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
752 gdk_pango_renderer_set_drawable (gdk_renderer, drawable);
753 gdk_pango_renderer_set_gc (gdk_renderer, gc);
755 gdk_pango_renderer_set_override_color (gdk_renderer,
756 PANGO_RENDER_PART_FOREGROUND,
758 gdk_pango_renderer_set_override_color (gdk_renderer,
759 PANGO_RENDER_PART_UNDERLINE,
761 gdk_pango_renderer_set_override_color (gdk_renderer,
762 PANGO_RENDER_PART_STRIKETHROUGH,
765 gdk_pango_renderer_set_override_color (gdk_renderer,
766 PANGO_RENDER_PART_BACKGROUND,
769 pango_renderer_activate (renderer);
774 /* Cleans up the renderer obtained with get_renderer() */
776 release_renderer (PangoRenderer *renderer)
778 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
780 pango_renderer_deactivate (renderer);
782 gdk_pango_renderer_set_override_color (gdk_renderer,
783 PANGO_RENDER_PART_FOREGROUND,
785 gdk_pango_renderer_set_override_color (gdk_renderer,
786 PANGO_RENDER_PART_UNDERLINE,
788 gdk_pango_renderer_set_override_color (gdk_renderer,
789 PANGO_RENDER_PART_STRIKETHROUGH,
791 gdk_pango_renderer_set_override_color (gdk_renderer,
792 PANGO_RENDER_PART_BACKGROUND,
795 gdk_pango_renderer_set_drawable (gdk_renderer, NULL);
796 gdk_pango_renderer_set_gc (gdk_renderer, NULL);
800 * gdk_draw_layout_line_with_colors:
801 * @drawable: the drawable on which to draw the line
802 * @gc: base graphics to use
803 * @x: the x position of start of string (in pixels)
804 * @y: the y position of baseline (in pixels)
805 * @line: a #PangoLayoutLine
806 * @foreground: foreground override color, or %NULL for none
807 * @background: background override color, or %NULL for none
809 * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
810 * layout's normal colors with @foreground and/or @background.
811 * @foreground and @background need not be allocated.
813 * If the layout's #PangoContext has a transformation matrix set, then
814 * @x and @y specify the position of the left edge of the baseline
815 * (left is in before-tranform user coordinates) in after-transform
816 * device coordinates.
819 gdk_draw_layout_line_with_colors (GdkDrawable *drawable,
823 PangoLayoutLine *line,
824 const GdkColor *foreground,
825 const GdkColor *background)
827 PangoRenderer *renderer;
828 const PangoMatrix *matrix;
830 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
831 g_return_if_fail (GDK_IS_GC (gc));
832 g_return_if_fail (line != NULL);
834 renderer = get_renderer (drawable, gc, foreground, background);
836 /* When we have a matrix, we do positioning by adjusting the matrix, and
837 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
838 * a matrix when the caller didn't provide one, however, since that adds
839 * lots of floating point arithmetic for each glyph.
841 matrix = pango_context_get_matrix (pango_layout_get_context (line->layout));
844 PangoMatrix tmp_matrix;
846 tmp_matrix = *matrix;
849 pango_renderer_set_matrix (renderer, &tmp_matrix);
854 /* Fall back to introduce a matrix if the coords would scale out of range.
855 * The x and y here will be added to in-layout coordinates. So we cannot
856 * support the entire range here safely. So, we just accept the middle half
857 * and use fallback for the rest. */
858 else if (GDK_PANGO_UNITS_OVERFLOWS (x, y))
860 PangoMatrix tmp_matrix = PANGO_MATRIX_INIT;
863 pango_renderer_set_matrix (renderer, &tmp_matrix);
869 pango_renderer_set_matrix (renderer, NULL);
871 pango_renderer_draw_layout_line (renderer, line, x * PANGO_SCALE, y * PANGO_SCALE);
873 release_renderer (renderer);
876 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
877 * between here and gtklabel.c */
879 get_rotated_layout_bounds (PangoLayout *layout,
882 PangoContext *context = pango_layout_get_context (layout);
883 const PangoMatrix *matrix = pango_context_get_matrix (context);
884 gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
885 PangoRectangle logical_rect;
888 pango_layout_get_extents (layout, NULL, &logical_rect);
890 for (i = 0; i < 2; i++)
892 gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
893 for (j = 0; j < 2; j++)
895 gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
897 gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
898 gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
900 if (i == 0 && j == 0)
919 rect->x = floor (x_min);
920 rect->width = ceil (x_max) - rect->x;
921 rect->y = floor (y_min);
922 rect->height = floor (y_max) - rect->y;
926 * gdk_draw_layout_with_colors:
927 * @drawable: the drawable on which to draw string
928 * @gc: base graphics context to use
929 * @x: the X position of the left of the layout (in pixels)
930 * @y: the Y position of the top of the layout (in pixels)
931 * @layout: a #PangoLayout
932 * @foreground: foreground override color, or %NULL for none
933 * @background: background override color, or %NULL for none
935 * Render a #PangoLayout onto a #GdkDrawable, overriding the
936 * layout's normal colors with @foreground and/or @background.
937 * @foreground and @background need not be allocated.
939 * If the layout's #PangoContext has a transformation matrix set, then
940 * @x and @y specify the position of the top left corner of the
941 * bounding box (in device space) of the transformed layout.
943 * If you're using GTK+, the ususal way to obtain a #PangoLayout
944 * is gtk_widget_create_pango_layout().
947 gdk_draw_layout_with_colors (GdkDrawable *drawable,
952 const GdkColor *foreground,
953 const GdkColor *background)
955 PangoRenderer *renderer;
956 const PangoMatrix *matrix;
958 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
959 g_return_if_fail (GDK_IS_GC (gc));
960 g_return_if_fail (PANGO_IS_LAYOUT (layout));
962 renderer = get_renderer (drawable, gc, foreground, background);
964 /* When we have a matrix, we do positioning by adjusting the matrix, and
965 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
966 * a matrix when the caller didn't provide one, however, since that adds
967 * lots of floating point arithmetic for each glyph.
969 matrix = pango_context_get_matrix (pango_layout_get_context (layout));
972 PangoMatrix tmp_matrix;
975 get_rotated_layout_bounds (layout, &rect);
977 tmp_matrix = *matrix;
978 tmp_matrix.x0 += x - rect.x;
979 tmp_matrix.y0 += y - rect.y;
980 pango_renderer_set_matrix (renderer, &tmp_matrix);
985 else if (GDK_PANGO_UNITS_OVERFLOWS (x, y))
987 PangoMatrix tmp_matrix = PANGO_MATRIX_INIT;
990 pango_renderer_set_matrix (renderer, &tmp_matrix);
996 pango_renderer_set_matrix (renderer, NULL);
998 pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE);
1000 release_renderer (renderer);
1004 * gdk_draw_layout_line:
1005 * @drawable: the drawable on which to draw the line
1006 * @gc: base graphics to use
1007 * @x: the x position of start of string (in pixels)
1008 * @y: the y position of baseline (in pixels)
1009 * @line: a #PangoLayoutLine
1011 * Render a #PangoLayoutLine onto an GDK drawable
1013 * If the layout's #PangoContext has a transformation matrix set, then
1014 * @x and @y specify the position of the left edge of the baseline
1015 * (left is in before-tranform user coordinates) in after-transform
1016 * device coordinates.
1019 gdk_draw_layout_line (GdkDrawable *drawable,
1023 PangoLayoutLine *line)
1025 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1026 g_return_if_fail (GDK_IS_GC (gc));
1027 g_return_if_fail (line != NULL);
1029 gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL);
1034 * @drawable: the drawable on which to draw string
1035 * @gc: base graphics context to use
1036 * @x: the X position of the left of the layout (in pixels)
1037 * @y: the Y position of the top of the layout (in pixels)
1038 * @layout: a #PangoLayout
1040 * Render a #PangoLayout onto a GDK drawable
1042 * If the layout's #PangoContext has a transformation matrix set, then
1043 * @x and @y specify the position of the top left corner of the
1044 * bounding box (in device space) of the transformed layout.
1046 * If you're using GTK+, the usual way to obtain a #PangoLayout
1047 * is gtk_widget_create_pango_layout().
1050 gdk_draw_layout (GdkDrawable *drawable,
1054 PangoLayout *layout)
1056 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1057 g_return_if_fail (GDK_IS_GC (gc));
1058 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1060 gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
1063 /* GdkPangoAttrStipple */
1065 static PangoAttribute *
1066 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
1068 const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
1070 return gdk_pango_attr_stipple_new (src->stipple);
1074 gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
1076 GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
1079 g_object_unref (st->stipple);
1085 gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
1086 const PangoAttribute *attr2)
1088 const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
1089 const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
1091 return a->stipple == b->stipple;
1095 * gdk_pango_attr_stipple_new:
1096 * @stipple: a bitmap to be set as stipple
1098 * Creates a new attribute containing a stipple bitmap to be used when
1099 * rendering the text.
1101 * Return value: new #PangoAttribute
1105 gdk_pango_attr_stipple_new (GdkBitmap *stipple)
1107 GdkPangoAttrStipple *result;
1109 static PangoAttrClass klass = {
1111 gdk_pango_attr_stipple_copy,
1112 gdk_pango_attr_stipple_destroy,
1113 gdk_pango_attr_stipple_compare
1117 klass.type = gdk_pango_attr_stipple_type =
1118 pango_attr_type_register ("GdkPangoAttrStipple");
1120 result = g_new (GdkPangoAttrStipple, 1);
1121 result->attr.klass = &klass;
1124 g_object_ref (stipple);
1126 result->stipple = stipple;
1128 return (PangoAttribute *)result;
1131 /* GdkPangoAttrEmbossed */
1133 static PangoAttribute *
1134 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
1136 const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
1138 return gdk_pango_attr_embossed_new (e->embossed);
1142 gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
1148 gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
1149 const PangoAttribute *attr2)
1151 const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
1152 const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
1154 return e1->embossed == e2->embossed;
1158 * gdk_pango_attr_embossed_new:
1159 * @embossed: if the region should be embossed
1161 * Creates a new attribute flagging a region as embossed or not.
1163 * Return value: new #PangoAttribute
1167 gdk_pango_attr_embossed_new (gboolean embossed)
1169 GdkPangoAttrEmbossed *result;
1171 static PangoAttrClass klass = {
1173 gdk_pango_attr_embossed_copy,
1174 gdk_pango_attr_embossed_destroy,
1175 gdk_pango_attr_embossed_compare
1179 klass.type = gdk_pango_attr_embossed_type =
1180 pango_attr_type_register ("GdkPangoAttrEmbossed");
1182 result = g_new (GdkPangoAttrEmbossed, 1);
1183 result->attr.klass = &klass;
1184 result->embossed = embossed;
1186 return (PangoAttribute *)result;
1189 /* GdkPangoAttrEmbossColor */
1191 static PangoAttribute *
1192 gdk_pango_attr_emboss_color_copy (const PangoAttribute *attr)
1194 const GdkPangoAttrEmbossColor *old = (const GdkPangoAttrEmbossColor*) attr;
1195 GdkPangoAttrEmbossColor *copy;
1197 copy = g_new (GdkPangoAttrEmbossColor, 1);
1198 copy->attr.klass = old->attr.klass;
1199 copy->color = old->color;
1201 return (PangoAttribute *) copy;
1205 gdk_pango_attr_emboss_color_destroy (PangoAttribute *attr)
1211 gdk_pango_attr_emboss_color_compare (const PangoAttribute *attr1,
1212 const PangoAttribute *attr2)
1214 const GdkPangoAttrEmbossColor *c1 = (const GdkPangoAttrEmbossColor*) attr1;
1215 const GdkPangoAttrEmbossColor *c2 = (const GdkPangoAttrEmbossColor*) attr2;
1217 return color_equal (&c1->color, &c2->color);
1221 * gdk_pango_attr_emboss_color_new:
1222 * @color: a GdkColor representing the color to emboss with
1224 * Creates a new attribute specifying the color to emboss text with.
1226 * Return value: new #PangoAttribute
1231 gdk_pango_attr_emboss_color_new (const GdkColor *color)
1233 GdkPangoAttrEmbossColor *result;
1235 static PangoAttrClass klass = {
1237 gdk_pango_attr_emboss_color_copy,
1238 gdk_pango_attr_emboss_color_destroy,
1239 gdk_pango_attr_emboss_color_compare
1243 klass.type = gdk_pango_attr_emboss_color_type =
1244 pango_attr_type_register ("GdkPangoAttrEmbossColor");
1246 result = g_new (GdkPangoAttrEmbossColor, 1);
1247 result->attr.klass = &klass;
1248 result->color.red = color->red;
1249 result->color.green = color->green;
1250 result->color.blue = color->blue;
1252 return (PangoAttribute *) result;
1255 /* Get a clip region to draw only part of a layout. index_ranges
1256 * contains alternating range starts/stops. The region is the
1257 * region which contains the given ranges, i.e. if you draw with the
1258 * region as clip, only the given ranges are drawn.
1261 layout_iter_get_line_clip_region (PangoLayoutIter *iter,
1267 PangoLayoutLine *line;
1268 GdkRegion *clip_region;
1269 PangoRectangle logical_rect;
1273 line = pango_layout_iter_get_line_readonly (iter);
1275 clip_region = gdk_region_new ();
1277 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1278 baseline = pango_layout_iter_get_baseline (iter);
1281 while (i < n_ranges)
1283 gint *pixel_ranges = NULL;
1284 gint n_pixel_ranges = 0;
1287 /* Note that get_x_ranges returns layout coordinates
1289 if (index_ranges[i*2+1] >= line->start_index &&
1290 index_ranges[i*2] < line->start_index + line->length)
1291 pango_layout_line_get_x_ranges (line,
1293 index_ranges[i*2+1],
1294 &pixel_ranges, &n_pixel_ranges);
1296 for (j = 0; j < n_pixel_ranges; j++)
1301 x_off = PANGO_PIXELS (pixel_ranges[2*j] - logical_rect.x);
1302 y_off = PANGO_PIXELS (baseline - logical_rect.y);
1304 rect.x = x_origin + x_off;
1305 rect.y = y_origin - y_off;
1306 rect.width = PANGO_PIXELS (pixel_ranges[2*j + 1] - logical_rect.x) - x_off;
1307 rect.height = PANGO_PIXELS (baseline - logical_rect.y + logical_rect.height) - y_off;
1309 gdk_region_union_with_rect (clip_region, &rect);
1312 g_free (pixel_ranges);
1319 * gdk_pango_layout_line_get_clip_region:
1320 * @line: a #PangoLayoutLine
1321 * @x_origin: X pixel where you intend to draw the layout line with this clip
1322 * @y_origin: baseline pixel where you intend to draw the layout line with this clip
1323 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1324 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1326 * Obtains a clip region which contains the areas where the given
1327 * ranges of text would be drawn. @x_origin and @y_origin are the same
1328 * position you would pass to gdk_draw_layout_line(). @index_ranges
1329 * should contain ranges of bytes in the layout's text. The clip
1330 * region will include space to the left or right of the line (to the
1331 * layout bounding box) if you have indexes above or below the indexes
1332 * contained inside the line. This is to draw the selection all the way
1333 * to the side of the layout. However, the clip region is in line coordinates,
1334 * not layout coordinates.
1336 * Note that the regions returned correspond to logical extents of the text
1337 * ranges, not ink extents. So the drawn line may in fact touch areas out of
1338 * the clip region. The clip region is mainly useful for highlightling parts
1339 * of text, such as when text is selected.
1341 * Return value: a clip region containing the given ranges
1344 gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
1350 GdkRegion *clip_region;
1351 PangoLayoutIter *iter;
1353 g_return_val_if_fail (line != NULL, NULL);
1354 g_return_val_if_fail (index_ranges != NULL, NULL);
1356 iter = pango_layout_get_iter (line->layout);
1357 while (pango_layout_iter_get_line_readonly (iter) != line)
1358 pango_layout_iter_next_line (iter);
1360 clip_region = layout_iter_get_line_clip_region(iter, x_origin, y_origin, index_ranges, n_ranges);
1362 pango_layout_iter_free (iter);
1368 * gdk_pango_layout_get_clip_region:
1369 * @layout: a #PangoLayout
1370 * @x_origin: X pixel where you intend to draw the layout with this clip
1371 * @y_origin: Y pixel where you intend to draw the layout with this clip
1372 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1373 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1375 * Obtains a clip region which contains the areas where the given ranges
1376 * of text would be drawn. @x_origin and @y_origin are the same position
1377 * you would pass to gdk_draw_layout_line(). @index_ranges should contain
1378 * ranges of bytes in the layout's text.
1380 * Note that the regions returned correspond to logical extents of the text
1381 * ranges, not ink extents. So the drawn layout may in fact touch areas out of
1382 * the clip region. The clip region is mainly useful for highlightling parts
1383 * of text, such as when text is selected.
1385 * Return value: a clip region containing the given ranges
1388 gdk_pango_layout_get_clip_region (PangoLayout *layout,
1394 PangoLayoutIter *iter;
1395 GdkRegion *clip_region;
1397 g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
1398 g_return_val_if_fail (index_ranges != NULL, NULL);
1400 clip_region = gdk_region_new ();
1402 iter = pango_layout_get_iter (layout);
1406 PangoRectangle logical_rect;
1407 GdkRegion *line_region;
1410 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1411 baseline = pango_layout_iter_get_baseline (iter);
1413 line_region = layout_iter_get_line_clip_region(iter,
1414 x_origin + logical_rect.x / PANGO_SCALE,
1415 y_origin + baseline / PANGO_SCALE,
1419 gdk_region_union (clip_region, line_region);
1420 gdk_region_destroy (line_region);
1422 while (pango_layout_iter_next_line (iter));
1424 pango_layout_iter_free (iter);
1430 * gdk_pango_context_get:
1432 * Creates a #PangoContext for the default GDK screen.
1434 * The context must be freed when you're finished with it.
1436 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1437 * instead of this function, to get the appropriate context for
1438 * the widget you intend to render text onto.
1440 * The newly created context will have the default font options (see
1441 * #cairo_font_options_t) for the default screen; if these options
1442 * change it will not be updated. Using gtk_widget_get_pango_context()
1443 * is more convenient if you want to keep a context around and track
1444 * changes to the screen's font rendering settings.
1446 * Return value: a new #PangoContext for the default display
1449 gdk_pango_context_get (void)
1451 return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
1455 * gdk_pango_context_get_for_screen:
1456 * @screen: the #GdkScreen for which the context is to be created.
1458 * Creates a #PangoContext for @screen.
1460 * The context must be freed when you're finished with it.
1462 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1463 * instead of this function, to get the appropriate context for
1464 * the widget you intend to render text onto.
1466 * The newly created context will have the default font options
1467 * (see #cairo_font_options_t) for the screen; if these options
1468 * change it will not be updated. Using gtk_widget_get_pango_context()
1469 * is more convenient if you want to keep a context around and track
1470 * changes to the screen's font rendering settings.
1472 * Return value: a new #PangoContext for @screen
1477 gdk_pango_context_get_for_screen (GdkScreen *screen)
1479 PangoFontMap *fontmap;
1480 PangoContext *context;
1481 const cairo_font_options_t *options;
1484 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1486 fontmap = pango_cairo_font_map_get_default ();
1488 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
1490 options = gdk_screen_get_font_options (screen);
1491 pango_cairo_context_set_font_options (context, options);
1493 dpi = gdk_screen_get_resolution (screen);
1494 pango_cairo_context_set_resolution (context, dpi);
1499 #define __GDK_PANGO_C__
1500 #include "gdkaliasdef.c"