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"
33 /* This is for P_() ... a bit non-kosher, but works fine */
34 #include "gtk/gtkintl.h"
36 #define GDK_INFO_KEY "gdk-info"
38 /* We have various arrays indexed by render part; if PangoRenderPart
39 * is extended, we want to make sure not to overwrite the end of
42 #define MAX_RENDER_PART PANGO_RENDER_PART_STRIKETHROUGH
44 struct _GdkPangoRendererPrivate
48 /* GdkPangoRenderer specific state */
49 PangoColor override_color[MAX_RENDER_PART + 1];
50 gboolean override_color_set[MAX_RENDER_PART + 1];
52 GdkBitmap *stipple[MAX_RENDER_PART + 1];
56 PangoRenderPart last_part;
59 GdkDrawable *drawable;
63 static PangoAttrType gdk_pango_attr_stipple_type;
64 static PangoAttrType gdk_pango_attr_embossed_type;
71 G_DEFINE_TYPE (GdkPangoRenderer, gdk_pango_renderer, PANGO_TYPE_RENDERER)
74 gdk_pango_renderer_finalize (GObject *object)
76 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
77 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
81 g_object_unref (priv->base_gc);
83 g_object_unref (priv->drawable);
85 for (i = 0; i <= MAX_RENDER_PART; i++)
87 g_object_unref (priv->stipple[i]);
89 G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->finalize (object);
93 gdk_pango_renderer_constructor (GType type,
94 guint n_construct_properties,
95 GObjectConstructParam *construct_params)
98 GdkPangoRenderer *gdk_renderer;
100 object = (* G_OBJECT_CLASS (gdk_pango_renderer_parent_class)->constructor) (type,
101 n_construct_properties,
104 gdk_renderer = GDK_PANGO_RENDERER (object);
106 if (!gdk_renderer->priv->screen)
108 g_warning ("Screen must be specified at construct time for GdkPangoRenderer");
109 gdk_renderer->priv->screen = gdk_screen_get_default ();
115 /* Adjusts matrix and color for the renderer to draw the secondary
116 * "shadow" copy for embossed text */
118 emboss_context (cairo_t *cr)
120 cairo_matrix_t tmp_matrix;
122 /* The gymnastics here to adjust the matrix are because we want
123 * to offset by +1,+1 in device-space, not in user-space,
124 * so we can't just draw the layout at x + 1, y + 1
126 cairo_get_matrix (cr, &tmp_matrix);
127 tmp_matrix.x0 += 1.0;
128 tmp_matrix.y0 += 1.0;
129 cairo_set_matrix (cr, &tmp_matrix);
131 cairo_set_source_rgb (cr, 1.0, 1.0, 1.0);
135 get_cairo_context (GdkPangoRenderer *gdk_renderer,
136 PangoRenderPart part)
138 PangoRenderer *renderer = PANGO_RENDERER (gdk_renderer);
139 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
143 const PangoMatrix *matrix;
145 priv->cr = gdk_cairo_create (priv->drawable);
147 matrix = pango_renderer_get_matrix (renderer);
150 cairo_matrix_t cairo_matrix;
152 cairo_matrix_init (&cairo_matrix,
153 matrix->xx, matrix->yx,
154 matrix->xy, matrix->yy,
155 matrix->x0, matrix->y0);
156 cairo_set_matrix (priv->cr, &cairo_matrix);
160 priv->last_part = (PangoRenderPart)-1;
161 if (part != priv->last_part)
163 PangoColor *pango_color = pango_renderer_get_color (renderer,
165 GdkColor *color = NULL;
169 tmp_color.red = pango_color->red;
170 tmp_color.green = pango_color->green;
171 tmp_color.blue = pango_color->blue;
176 _gdk_gc_update_context (priv->base_gc,
179 priv->stipple[part]);
180 priv->last_part = part;
187 gdk_pango_renderer_draw_glyphs (PangoRenderer *renderer,
189 PangoGlyphString *glyphs,
193 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
194 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
197 cr = get_cairo_context (gdk_renderer,
198 PANGO_RENDER_PART_FOREGROUND);
204 cairo_move_to (cr, x / PANGO_SCALE, y / PANGO_SCALE);
205 pango_cairo_show_glyph_string (cr, font, glyphs);
209 cairo_move_to (cr, x / PANGO_SCALE, y / PANGO_SCALE);
210 pango_cairo_show_glyph_string (cr, font, glyphs);
213 /* Draws an error underline that looks like one of:
216 * A/ \ / \ / \ A/ \ / \ |
217 * \ \ / \ / /D \ \ / \ |
218 * \ \/ C \/ / \ \/ C \ | height = HEIGHT_SQUARES * square
219 * \ /\ F / \ F /\ \ |
225 * unit_width = (HEIGHT_SQUARES - 1) * square
227 * The x, y, width, height passed in give the desired bounding box;
228 * x/width are adjusted to make the underline a integer number of units
231 #define HEIGHT_SQUARES 2.5
233 /* Cut-and-pasted between here and pango/pango/pangocairo-render.c */
235 draw_error_underline (cairo_t *cr,
241 double square = height / HEIGHT_SQUARES;
242 double unit_width = (HEIGHT_SQUARES - 1) * square;
243 int width_units = (width + unit_width / 2) / unit_width;
244 double y_top, y_bottom;
247 x += (width - width_units * unit_width);
248 width = width_units * unit_width;
251 y_bottom = y + height;
253 /* Bottom of squiggle */
254 cairo_move_to (cr, x - square / 2, y_top + square / 2); /* A */
255 for (i = 0; i < width_units; i += 2)
257 double x_middle = x + (i + 1) * unit_width;
258 double x_right = x + (i + 2) * unit_width;
260 cairo_line_to (cr, x_middle, y_bottom); /* B */
262 if (i + 1 == width_units)
264 else if (i + 2 == width_units)
265 cairo_line_to (cr, x_right + square / 2, y_top + square / 2); /* D */
267 cairo_line_to (cr, x_right, y_top + square); /* C */
270 /* Top of squiggle */
271 for (i -= 2; i >= 0; i -= 2)
273 double x_left = x + i * unit_width;
274 double x_middle = x + (i + 1) * unit_width;
275 double x_right = x + (i + 2) * unit_width;
277 if (i + 1 == width_units)
278 cairo_line_to (cr, x_middle + square / 2, y_bottom - square / 2); /* G */
280 if (i + 2 == width_units)
281 cairo_line_to (cr, x_right, y_top); /* E */
282 cairo_line_to (cr, x_middle, y_bottom - square); /* F */
285 cairo_line_to (cr, x_left, y_top); /* H */
288 cairo_close_path (cr);
293 gdk_pango_renderer_draw_rectangle (PangoRenderer *renderer,
294 PangoRenderPart part,
300 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
301 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
304 cr = get_cairo_context (gdk_renderer, part);
306 if (priv->embossed && part != PANGO_RENDER_PART_BACKGROUND)
311 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
312 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
319 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
320 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
325 gdk_pango_renderer_draw_error_underline (PangoRenderer *renderer,
331 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
332 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
335 cr = get_cairo_context (gdk_renderer, PANGO_RENDER_PART_UNDERLINE);
341 draw_error_underline (cr,
342 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
343 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
347 draw_error_underline (cr,
348 (double)x / PANGO_SCALE, (double)y / PANGO_SCALE,
349 (double)width / PANGO_SCALE, (double)height / PANGO_SCALE);
353 gdk_pango_renderer_part_changed (PangoRenderer *renderer,
354 PangoRenderPart part)
356 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
358 if (gdk_renderer->priv->last_part == part)
359 gdk_renderer->priv->last_part = (PangoRenderPart)-1;
363 gdk_pango_renderer_begin (PangoRenderer *renderer)
365 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
366 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
368 if (!priv->drawable || !priv->base_gc)
370 g_warning ("gdk_pango_renderer_set_drawable() and gdk_pango_renderer_set_drawable()"
371 "must be used to set the target drawable and GC before using the renderer\n");
376 gdk_pango_renderer_end (PangoRenderer *renderer)
378 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
379 GdkPangoRendererPrivate *priv = gdk_renderer->priv;
383 cairo_destroy (priv->cr);
386 priv->last_part = (PangoRenderPart)-1;
390 gdk_pango_renderer_prepare_run (PangoRenderer *renderer,
393 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
394 gboolean embossed = FALSE;
395 GdkBitmap *stipple = NULL;
402 for (l = run->item->analysis.extra_attrs; l; l = l->next)
404 PangoAttribute *attr = l->data;
406 /* stipple_type and embossed_type aren't necessarily
407 * initialized, but they are 0, which is an
408 * invalid type so won't occur.
410 if (attr->klass->type == gdk_pango_attr_stipple_type)
412 stipple = ((GdkPangoAttrStipple*)attr)->stipple;
414 else if (attr->klass->type == gdk_pango_attr_embossed_type)
416 embossed = ((GdkPangoAttrEmbossed*)attr)->embossed;
420 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_FOREGROUND, stipple);
421 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_BACKGROUND, stipple);
422 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_UNDERLINE, stipple);
423 gdk_pango_renderer_set_stipple (gdk_renderer, PANGO_RENDER_PART_STRIKETHROUGH, stipple);
425 if (embossed != gdk_renderer->priv->embossed)
427 gdk_renderer->priv->embossed = embossed;
428 pango_renderer_part_changed (renderer, PANGO_RENDER_PART_FOREGROUND);
431 PANGO_RENDERER_CLASS (gdk_pango_renderer_parent_class)->prepare_run (renderer, run);
433 for (i = 0; i <= MAX_RENDER_PART; i++)
435 if (gdk_renderer->priv->override_color_set[i])
436 pango_renderer_set_color (renderer, i, &gdk_renderer->priv->override_color[i]);
441 gdk_pango_renderer_set_property (GObject *object,
446 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
451 gdk_renderer->priv->screen = g_value_get_object (value);
454 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
460 gdk_pango_renderer_get_property (GObject *object,
465 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (object);
470 g_value_set_object (value, gdk_renderer->priv->screen);
473 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
479 gdk_pango_renderer_init (GdkPangoRenderer *renderer)
481 renderer->priv = G_TYPE_INSTANCE_GET_PRIVATE (renderer,
482 GDK_TYPE_PANGO_RENDERER,
483 GdkPangoRendererPrivate);
485 renderer->priv->last_part = (PangoRenderPart)-1;
489 gdk_pango_renderer_class_init (GdkPangoRendererClass *klass)
491 GObjectClass *object_class = G_OBJECT_CLASS (klass);
493 PangoRendererClass *renderer_class = PANGO_RENDERER_CLASS (klass);
495 renderer_class->draw_glyphs = gdk_pango_renderer_draw_glyphs;
496 renderer_class->draw_rectangle = gdk_pango_renderer_draw_rectangle;
497 renderer_class->draw_error_underline = gdk_pango_renderer_draw_error_underline;
498 renderer_class->part_changed = gdk_pango_renderer_part_changed;
499 renderer_class->begin = gdk_pango_renderer_begin;
500 renderer_class->end = gdk_pango_renderer_end;
501 renderer_class->prepare_run = gdk_pango_renderer_prepare_run;
503 object_class->finalize = gdk_pango_renderer_finalize;
504 object_class->constructor = gdk_pango_renderer_constructor;
505 object_class->set_property = gdk_pango_renderer_set_property;
506 object_class->get_property = gdk_pango_renderer_get_property;
508 g_object_class_install_property (object_class,
510 g_param_spec_object ("screen",
512 P_("the GdkScreen for the renderer"),
514 G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
515 G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK |
516 G_PARAM_STATIC_BLURB));
518 g_type_class_add_private (object_class, sizeof (GdkPangoRendererPrivate));
522 * gdk_pango_renderer_new:
523 * @screen: a #GdkScreen
525 * Creates a new #PangoRenderer for @screen. Normally you can use the
526 * results of gdk_pango_renderer_get_default() rather than creating a new
529 * Return value: a newly created #PangoRenderer. Free with g_object_unref().
534 gdk_pango_renderer_new (GdkScreen *screen)
536 g_return_val_if_fail (screen != NULL, NULL);
538 return g_object_new (GDK_TYPE_PANGO_RENDERER,
544 on_renderer_display_closed (GdkDisplay *display,
545 GdkPangoRenderer *renderer)
547 g_signal_handlers_disconnect_by_func (renderer->priv->screen,
548 (gpointer)on_renderer_display_closed,
550 g_object_set_data (G_OBJECT (renderer->priv->screen), "gdk-pango-renderer", NULL);
554 * gdk_pango_renderer_get_default:
555 * @screen: a #GdkScreen
557 * Gets the default #PangoRenderer for a screen. This default renderer
558 * is shared by all users of the display, so properties such as the color
559 * or transformation matrix set for the renderer may be overwritten
560 * by functions such as gdk_draw_layout().
562 * Before using the renderer, you need to call gdk_pango_renderer_set_drawable()
563 * and gdk_pango_renderer_set_gc() to set the drawable and graphics context
564 * to use for drawing.
566 * Return value: the default #PangoRenderer for @screen. The
567 * renderer is owned by GTK+ and will be kept around until the
573 gdk_pango_renderer_get_default (GdkScreen *screen)
575 PangoRenderer *renderer;
577 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
579 renderer = g_object_get_data (G_OBJECT (screen), "gdk-pango-renderer");
582 renderer = gdk_pango_renderer_new (screen);
583 g_object_set_data_full (G_OBJECT (screen), "gdk-pango-renderer", renderer,
584 (GDestroyNotify)g_object_unref);
586 g_signal_connect (gdk_screen_get_display (screen), "closed",
587 G_CALLBACK (on_renderer_display_closed), renderer);
594 * gdk_pango_renderer_set_drawable:
595 * @gdk_renderer: a #GdkPangoRenderer
596 * @drawable: the new target drawable, or %NULL
598 * Sets the drawable the renderer draws to.
603 gdk_pango_renderer_set_drawable (GdkPangoRenderer *gdk_renderer,
604 GdkDrawable *drawable)
606 GdkPangoRendererPrivate *priv;
608 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
609 g_return_if_fail (drawable == NULL || GDK_IS_DRAWABLE (drawable));
611 priv = gdk_renderer->priv;
613 if (priv->drawable != drawable)
616 g_object_unref (priv->drawable);
617 priv->drawable = drawable;
619 g_object_ref (priv->drawable);
624 * gdk_pango_renderer_set_gc:
625 * @gdk_renderer: a #GdkPangoRenderer
626 * @gc: the new GC to use for drawing, or %NULL
628 * Sets the GC the renderer draws with. Note that the GC must not be
629 * modified until it is unset by calling the function again with
630 * %NULL for the @gc parameter, since GDK may make internal copies
631 * of the GC which won't be updated to follow changes to the
637 gdk_pango_renderer_set_gc (GdkPangoRenderer *gdk_renderer,
640 GdkPangoRendererPrivate *priv;
642 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
643 g_return_if_fail (gc == NULL || GDK_IS_GC (gc));
645 priv = gdk_renderer->priv;
647 if (priv->base_gc != gc)
650 g_object_unref (priv->base_gc);
653 g_object_ref (priv->base_gc);
659 * gdk_pango_renderer_set_stipple:
660 * @gdk_renderer: a #GdkPangoRenderer
661 * @part: the part to render with the stipple
662 * @stipple: the new stipple value.
664 * Sets the stipple for one render part (foreground, background, underline,
665 * etc.) Note that this is overwritten when iterating through the individual
666 * styled runs of a #PangoLayout or #PangoLayoutLine. This function is thus
667 * only useful when you call low level functions like pango_renderer_draw_glyphs()
668 * directly, or in the 'prepare_run' virtual function of a subclass of
674 gdk_pango_renderer_set_stipple (GdkPangoRenderer *gdk_renderer,
675 PangoRenderPart part,
678 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
680 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
683 if (stipple != gdk_renderer->priv->stipple[part])
685 if (gdk_renderer->priv->stipple[part])
686 g_object_unref (gdk_renderer->priv->stipple[part]);
688 gdk_renderer->priv->stipple[part] = stipple;
690 if (gdk_renderer->priv->stipple[part])
691 g_object_ref (gdk_renderer->priv->stipple[part]);
693 pango_renderer_part_changed (PANGO_RENDERER (gdk_renderer), part);
698 * gdk_pango_renderer_set_override_color:
699 * @gdk_renderer: a #GdkPangoRenderer
700 * @part: the part to render to set the color of
701 * @color: the color to use, or %NULL to unset a previously
702 * set override color.
704 * Sets the color for a particular render part (foreground,
705 * background, underline, etc.), overriding any attributes on the layouts
706 * renderered with this renderer.
711 gdk_pango_renderer_set_override_color (GdkPangoRenderer *gdk_renderer,
712 PangoRenderPart part,
713 const GdkColor *color)
715 GdkPangoRendererPrivate *priv;
717 g_return_if_fail (GDK_IS_PANGO_RENDERER (gdk_renderer));
719 priv = gdk_renderer->priv;
721 if (part > MAX_RENDER_PART) /* Silently ignore unknown parts */
726 priv->override_color[part].red = color->red;
727 priv->override_color[part].green = color->green;
728 priv->override_color[part].blue = color->blue;
729 priv->override_color_set[part] = TRUE;
732 priv->override_color_set[part] = FALSE;
736 * gdk_pango_context_set_colormap:
737 * @context: a #PangoContext
738 * @colormap: a #GdkColormap
740 * This function used to set the colormap to be used for drawing with
741 * @context. The colormap is now always derived from the graphics
742 * context used for drawing, so calling this function is no longer
746 gdk_pango_context_set_colormap (PangoContext *context,
747 GdkColormap *colormap)
749 g_return_if_fail (PANGO_IS_CONTEXT (context));
750 g_return_if_fail (colormap == NULL || GDK_IS_COLORMAP (colormap));
753 /* Gets a renderer to draw with, setting the properties of the
754 * renderer and activating it. Note that since we activate the
755 * renderer here, the implicit setting of the matrix that
756 * pango_renderer_draw_layout_[line] normally do when they
757 * activate the renderer is suppressed. */
758 static PangoRenderer *
759 get_renderer (GdkDrawable *drawable,
761 const GdkColor *foreground,
762 const GdkColor *background)
764 GdkScreen *screen = gdk_drawable_get_screen (drawable);
765 PangoRenderer *renderer = gdk_pango_renderer_get_default (screen);
766 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
768 gdk_pango_renderer_set_drawable (gdk_renderer, drawable);
769 gdk_pango_renderer_set_gc (gdk_renderer, gc);
771 gdk_pango_renderer_set_override_color (gdk_renderer,
772 PANGO_RENDER_PART_FOREGROUND,
774 gdk_pango_renderer_set_override_color (gdk_renderer,
775 PANGO_RENDER_PART_UNDERLINE,
777 gdk_pango_renderer_set_override_color (gdk_renderer,
778 PANGO_RENDER_PART_STRIKETHROUGH,
781 gdk_pango_renderer_set_override_color (gdk_renderer,
782 PANGO_RENDER_PART_BACKGROUND,
785 pango_renderer_activate (renderer);
790 /* Cleans up the renderer obtained with get_renderer() */
792 release_renderer (PangoRenderer *renderer)
794 GdkPangoRenderer *gdk_renderer = GDK_PANGO_RENDERER (renderer);
796 pango_renderer_deactivate (renderer);
798 gdk_pango_renderer_set_override_color (gdk_renderer,
799 PANGO_RENDER_PART_FOREGROUND,
801 gdk_pango_renderer_set_override_color (gdk_renderer,
802 PANGO_RENDER_PART_UNDERLINE,
804 gdk_pango_renderer_set_override_color (gdk_renderer,
805 PANGO_RENDER_PART_STRIKETHROUGH,
807 gdk_pango_renderer_set_override_color (gdk_renderer,
808 PANGO_RENDER_PART_BACKGROUND,
811 gdk_pango_renderer_set_drawable (gdk_renderer, NULL);
812 gdk_pango_renderer_set_gc (gdk_renderer, NULL);
816 * gdk_draw_layout_line_with_colors:
817 * @drawable: the drawable on which to draw the line
818 * @gc: base graphics to use
819 * @x: the x position of start of string (in pixels)
820 * @y: the y position of baseline (in pixels)
821 * @line: a #PangoLayoutLine
822 * @foreground: foreground override color, or %NULL for none
823 * @background: background override color, or %NULL for none
825 * Render a #PangoLayoutLine onto a #GdkDrawable, overriding the
826 * layout's normal colors with @foreground and/or @background.
827 * @foreground and @background need not be allocated.
829 * If the layout's #PangoContext has a transformation matrix set, then
830 * @x and @y specify the position of the left edge of the baseline
831 * (left is in before-tranform user coordinates) in after-transform
832 * device coordinates.
835 gdk_draw_layout_line_with_colors (GdkDrawable *drawable,
839 PangoLayoutLine *line,
840 const GdkColor *foreground,
841 const GdkColor *background)
843 PangoRenderer *renderer;
844 const PangoMatrix *matrix;
846 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
847 g_return_if_fail (GDK_IS_GC (gc));
848 g_return_if_fail (line != NULL);
850 renderer = get_renderer (drawable, gc, foreground, background);
852 /* When we have a matrix, we do positioning by adjusting the matrix, and
853 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
854 * a matrix when the caller didn't provide one, however, since that adds
855 * lots of floating point arithmetic for each glyph.
857 matrix = pango_context_get_matrix (pango_layout_get_context (line->layout));
860 PangoMatrix tmp_matrix;
862 tmp_matrix = *matrix;
865 pango_renderer_set_matrix (renderer, &tmp_matrix);
871 pango_renderer_set_matrix (renderer, NULL);
873 pango_renderer_draw_layout_line (renderer, line, x * PANGO_SCALE, y * PANGO_SCALE);
875 release_renderer (renderer);
878 /* Gets the bounds of a layout in device coordinates. Note cut-and-paste
879 * between here and gtklabel.c */
881 get_rotated_layout_bounds (PangoLayout *layout,
884 PangoContext *context = pango_layout_get_context (layout);
885 const PangoMatrix *matrix = pango_context_get_matrix (context);
886 gdouble x_min = 0, x_max = 0, y_min = 0, y_max = 0; /* quiet gcc */
887 PangoRectangle logical_rect;
890 pango_layout_get_extents (layout, NULL, &logical_rect);
892 for (i = 0; i < 2; i++)
894 gdouble x = (i == 0) ? logical_rect.x : logical_rect.x + logical_rect.width;
895 for (j = 0; j < 2; j++)
897 gdouble y = (j == 0) ? logical_rect.y : logical_rect.y + logical_rect.height;
899 gdouble xt = (x * matrix->xx + y * matrix->xy) / PANGO_SCALE + matrix->x0;
900 gdouble yt = (x * matrix->yx + y * matrix->yy) / PANGO_SCALE + matrix->y0;
902 if (i == 0 && j == 0)
921 rect->x = floor (x_min);
922 rect->width = ceil (x_max) - rect->x;
923 rect->y = floor (y_min);
924 rect->height = floor (y_max) - rect->y;
928 * gdk_draw_layout_with_colors:
929 * @drawable: the drawable on which to draw string
930 * @gc: base graphics context to use
931 * @x: the X position of the left of the layout (in pixels)
932 * @y: the Y position of the top of the layout (in pixels)
933 * @layout: a #PangoLayout
934 * @foreground: foreground override color, or %NULL for none
935 * @background: background override color, or %NULL for none
937 * Render a #PangoLayout onto a #GdkDrawable, overriding the
938 * layout's normal colors with @foreground and/or @background.
939 * @foreground and @background need not be allocated.
941 * If the layout's #PangoContext has a transformation matrix set, then
942 * @x and @y specify the position of the top left corner of the
943 * bounding box (in device space) of the transformed layout.
945 * If you're using GTK+, the ususal way to obtain a #PangoLayout
946 * is gtk_widget_create_pango_layout().
949 gdk_draw_layout_with_colors (GdkDrawable *drawable,
954 const GdkColor *foreground,
955 const GdkColor *background)
957 PangoRenderer *renderer;
958 const PangoMatrix *matrix;
960 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
961 g_return_if_fail (GDK_IS_GC (gc));
962 g_return_if_fail (PANGO_IS_LAYOUT (layout));
964 renderer = get_renderer (drawable, gc, foreground, background);
966 /* When we have a matrix, we do positioning by adjusting the matrix, and
967 * clamp just pass x=0, y=0 to the lower levels. We don't want to introduce
968 * a matrix when the caller didn't provide one, however, since that adds
969 * lots of floating point arithmetic for each glyph.
971 matrix = pango_context_get_matrix (pango_layout_get_context (layout));
974 PangoMatrix tmp_matrix;
977 get_rotated_layout_bounds (layout, &rect);
979 tmp_matrix = *matrix;
980 tmp_matrix.x0 += x - rect.x;
981 tmp_matrix.y0 += y - rect.y;
982 pango_renderer_set_matrix (renderer, &tmp_matrix);
988 pango_renderer_set_matrix (renderer, NULL);
990 pango_renderer_draw_layout (renderer, layout, x * PANGO_SCALE, y * PANGO_SCALE);
992 release_renderer (renderer);
996 * gdk_draw_layout_line:
997 * @drawable: the drawable on which to draw the line
998 * @gc: base graphics to use
999 * @x: the x position of start of string (in pixels)
1000 * @y: the y position of baseline (in pixels)
1001 * @line: a #PangoLayoutLine
1003 * Render a #PangoLayoutLine onto an GDK drawable
1005 * If the layout's #PangoContext has a transformation matrix set, then
1006 * @x and @y specify the position of the left edge of the baseline
1007 * (left is in before-tranform user coordinates) in after-transform
1008 * device coordinates.
1011 gdk_draw_layout_line (GdkDrawable *drawable,
1015 PangoLayoutLine *line)
1017 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1018 g_return_if_fail (GDK_IS_GC (gc));
1019 g_return_if_fail (line != NULL);
1021 gdk_draw_layout_line_with_colors (drawable, gc, x, y, line, NULL, NULL);
1026 * @drawable: the drawable on which to draw string
1027 * @gc: base graphics context to use
1028 * @x: the X position of the left of the layout (in pixels)
1029 * @y: the Y position of the top of the layout (in pixels)
1030 * @layout: a #PangoLayout
1032 * Render a #PangoLayout onto a GDK drawable
1034 * If the layout's #PangoContext has a transformation matrix set, then
1035 * @x and @y specify the position of the top left corner of the
1036 * bounding box (in device space) of the transformed layout.
1038 * If you're using GTK+, the usual way to obtain a #PangoLayout
1039 * is gtk_widget_create_pango_layout().
1042 gdk_draw_layout (GdkDrawable *drawable,
1046 PangoLayout *layout)
1048 g_return_if_fail (GDK_IS_DRAWABLE (drawable));
1049 g_return_if_fail (GDK_IS_GC (gc));
1050 g_return_if_fail (PANGO_IS_LAYOUT (layout));
1052 gdk_draw_layout_with_colors (drawable, gc, x, y, layout, NULL, NULL);
1055 static PangoAttribute *
1056 gdk_pango_attr_stipple_copy (const PangoAttribute *attr)
1058 const GdkPangoAttrStipple *src = (const GdkPangoAttrStipple*) attr;
1060 return gdk_pango_attr_stipple_new (src->stipple);
1064 gdk_pango_attr_stipple_destroy (PangoAttribute *attr)
1066 GdkPangoAttrStipple *st = (GdkPangoAttrStipple*) attr;
1069 g_object_unref (st->stipple);
1075 gdk_pango_attr_stipple_compare (const PangoAttribute *attr1,
1076 const PangoAttribute *attr2)
1078 const GdkPangoAttrStipple *a = (const GdkPangoAttrStipple*) attr1;
1079 const GdkPangoAttrStipple *b = (const GdkPangoAttrStipple*) attr2;
1081 return a->stipple == b->stipple;
1085 * gdk_pango_attr_stipple_new:
1086 * @stipple: a bitmap to be set as stipple
1088 * Creates a new attribute containing a stipple bitmap to be used when
1089 * rendering the text.
1091 * Return value: new #PangoAttribute
1095 gdk_pango_attr_stipple_new (GdkBitmap *stipple)
1097 GdkPangoAttrStipple *result;
1099 static PangoAttrClass klass = {
1101 gdk_pango_attr_stipple_copy,
1102 gdk_pango_attr_stipple_destroy,
1103 gdk_pango_attr_stipple_compare
1107 klass.type = gdk_pango_attr_stipple_type =
1108 pango_attr_type_register ("GdkPangoAttrStipple");
1110 result = g_new (GdkPangoAttrStipple, 1);
1111 result->attr.klass = &klass;
1114 g_object_ref (stipple);
1116 result->stipple = stipple;
1118 return (PangoAttribute *)result;
1121 static PangoAttribute *
1122 gdk_pango_attr_embossed_copy (const PangoAttribute *attr)
1124 const GdkPangoAttrEmbossed *e = (const GdkPangoAttrEmbossed*) attr;
1126 return gdk_pango_attr_embossed_new (e->embossed);
1130 gdk_pango_attr_embossed_destroy (PangoAttribute *attr)
1136 gdk_pango_attr_embossed_compare (const PangoAttribute *attr1,
1137 const PangoAttribute *attr2)
1139 const GdkPangoAttrEmbossed *e1 = (const GdkPangoAttrEmbossed*) attr1;
1140 const GdkPangoAttrEmbossed *e2 = (const GdkPangoAttrEmbossed*) attr2;
1142 return e1->embossed == e2->embossed;
1146 * gdk_pango_attr_embossed_new:
1147 * @embossed: a bitmap to be set as embossed
1149 * Creates a new attribute containing a embossed bitmap to be used when
1150 * rendering the text.
1152 * Return value: new #PangoAttribute
1156 gdk_pango_attr_embossed_new (gboolean embossed)
1158 GdkPangoAttrEmbossed *result;
1160 static PangoAttrClass klass = {
1162 gdk_pango_attr_embossed_copy,
1163 gdk_pango_attr_embossed_destroy,
1164 gdk_pango_attr_embossed_compare
1168 klass.type = gdk_pango_attr_embossed_type =
1169 pango_attr_type_register ("GdkPangoAttrEmbossed");
1171 result = g_new (GdkPangoAttrEmbossed, 1);
1172 result->attr.klass = &klass;
1173 result->embossed = embossed;
1175 return (PangoAttribute *)result;
1178 /* Get a clip region to draw only part of a layout. index_ranges
1179 * contains alternating range starts/stops. The region is the
1180 * region which contains the given ranges, i.e. if you draw with the
1181 * region as clip, only the given ranges are drawn.
1185 * gdk_pango_layout_line_get_clip_region:
1186 * @line: a #PangoLayoutLine
1187 * @x_origin: X pixel where you intend to draw the layout line with this clip
1188 * @y_origin: baseline pixel where you intend to draw the layout line with this clip
1189 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1190 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1192 * Obtains a clip region which contains the areas where the given
1193 * ranges of text would be drawn. @x_origin and @y_origin are the same
1194 * position you would pass to gdk_draw_layout_line(). @index_ranges
1195 * should contain ranges of bytes in the layout's text. The clip
1196 * region will include space to the left or right of the line (to the
1197 * layout bounding box) if you have indexes above or below the indexes
1198 * contained inside the line. This is to draw the selection all the way
1199 * to the side of the layout. However, the clip region is in line coordinates,
1200 * not layout coordinates.
1202 * Return value: a clip region containing the given ranges
1205 gdk_pango_layout_line_get_clip_region (PangoLayoutLine *line,
1211 GdkRegion *clip_region;
1213 PangoRectangle logical_rect;
1214 PangoLayoutIter *iter;
1217 g_return_val_if_fail (line != NULL, NULL);
1218 g_return_val_if_fail (index_ranges != NULL, NULL);
1220 clip_region = gdk_region_new ();
1222 iter = pango_layout_get_iter (line->layout);
1223 while (pango_layout_iter_get_line (iter) != line)
1224 pango_layout_iter_next_line (iter);
1226 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1227 baseline = pango_layout_iter_get_baseline (iter);
1229 pango_layout_iter_free (iter);
1232 while (i < n_ranges)
1234 gint *pixel_ranges = NULL;
1235 gint n_pixel_ranges = 0;
1238 /* Note that get_x_ranges returns layout coordinates
1240 if (index_ranges[i*2+1] >= line->start_index &&
1241 index_ranges[i*2] < line->start_index + line->length)
1242 pango_layout_line_get_x_ranges (line,
1244 index_ranges[i*2+1],
1245 &pixel_ranges, &n_pixel_ranges);
1247 for (j = 0; j < n_pixel_ranges; j++)
1251 rect.x = x_origin + pixel_ranges[2*j] / PANGO_SCALE - logical_rect.x / PANGO_SCALE;
1252 rect.y = y_origin - (baseline / PANGO_SCALE - logical_rect.y / PANGO_SCALE);
1253 rect.width = (pixel_ranges[2*j + 1] - pixel_ranges[2*j]) / PANGO_SCALE;
1254 rect.height = logical_rect.height / PANGO_SCALE;
1256 gdk_region_union_with_rect (clip_region, &rect);
1259 g_free (pixel_ranges);
1267 * gdk_pango_layout_get_clip_region:
1268 * @layout: a #PangoLayout
1269 * @x_origin: X pixel where you intend to draw the layout with this clip
1270 * @y_origin: Y pixel where you intend to draw the layout with this clip
1271 * @index_ranges: array of byte indexes into the layout, where even members of array are start indexes and odd elements are end indexes
1272 * @n_ranges: number of ranges in @index_ranges, i.e. half the size of @index_ranges
1274 * Obtains a clip region which contains the areas where the given ranges
1275 * of text would be drawn. @x_origin and @y_origin are the same position
1276 * you would pass to gdk_draw_layout_line(). @index_ranges should contain
1277 * ranges of bytes in the layout's text.
1279 * Return value: a clip region containing the given ranges
1282 gdk_pango_layout_get_clip_region (PangoLayout *layout,
1288 PangoLayoutIter *iter;
1289 GdkRegion *clip_region;
1291 g_return_val_if_fail (PANGO_IS_LAYOUT (layout), NULL);
1292 g_return_val_if_fail (index_ranges != NULL, NULL);
1294 clip_region = gdk_region_new ();
1296 iter = pango_layout_get_iter (layout);
1300 PangoRectangle logical_rect;
1301 PangoLayoutLine *line;
1302 GdkRegion *line_region;
1305 line = pango_layout_iter_get_line (iter);
1307 pango_layout_iter_get_line_extents (iter, NULL, &logical_rect);
1308 baseline = pango_layout_iter_get_baseline (iter);
1310 line_region = gdk_pango_layout_line_get_clip_region (line,
1311 x_origin + logical_rect.x / PANGO_SCALE,
1312 y_origin + baseline / PANGO_SCALE,
1316 gdk_region_union (clip_region, line_region);
1317 gdk_region_destroy (line_region);
1319 while (pango_layout_iter_next_line (iter));
1321 pango_layout_iter_free (iter);
1327 * gdk_pango_context_get:
1329 * Creates a #PangoContext for the default GDK screen.
1331 * The context must be freed when you're finished with it.
1333 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1334 * instead of this function, to get the appropriate context for
1335 * the widget you intend to render text onto.
1337 * The newly created context will have the default font options (see
1338 * #cairo_font_options_t) for the default screen; if these options
1339 * change it will not be updated. Using gtk_widget_get_pango_context()
1340 * is more convenient if you want to keep a context around and track
1341 * changes to the screen's font rendering settings.
1343 * Return value: a new #PangoContext for the default display
1346 gdk_pango_context_get (void)
1348 return gdk_pango_context_get_for_screen (gdk_screen_get_default ());
1352 * gdk_pango_context_get_for_screen:
1353 * @screen: the #GdkScreen for which the context is to be created.
1355 * Creates a #PangoContext for @screen.
1357 * The context must be freed when you're finished with it.
1359 * When using GTK+, normally you should use gtk_widget_get_pango_context()
1360 * instead of this function, to get the appropriate context for
1361 * the widget you intend to render text onto.
1363 * The newly created context will have the default font options
1364 * (see #cairo_font_options_t) for the screen; if these options
1365 * change it will not be updated. Using gtk_widget_get_pango_context()
1366 * is more convenient if you want to keep a context around and track
1367 * changes to the screen's font rendering settings.
1369 * Return value: a new #PangoContext for @screen
1374 gdk_pango_context_get_for_screen (GdkScreen *screen)
1376 PangoFontMap *fontmap;
1377 PangoContext *context;
1378 const cairo_font_options_t *options;
1381 g_return_val_if_fail (GDK_IS_SCREEN (screen), NULL);
1383 fontmap = pango_cairo_font_map_get_default ();
1385 context = pango_cairo_font_map_create_context (PANGO_CAIRO_FONT_MAP (fontmap));
1387 options = gdk_screen_get_font_options_libgtk_only (screen);
1388 pango_cairo_context_set_font_options (context, options);
1390 dpi = gdk_screen_get_resolution_libgtk_only (screen);
1391 pango_cairo_context_set_resolution (context, dpi);
1396 #define __GDK_PANGO_C__
1397 #include "gdkaliasdef.c"