aboutsummaryrefslogtreecommitdiffstats
path: root/libgnomecanvas/gnome-canvas-text.c
diff options
context:
space:
mode:
Diffstat (limited to 'libgnomecanvas/gnome-canvas-text.c')
-rw-r--r--libgnomecanvas/gnome-canvas-text.c1746
1 files changed, 1746 insertions, 0 deletions
diff --git a/libgnomecanvas/gnome-canvas-text.c b/libgnomecanvas/gnome-canvas-text.c
new file mode 100644
index 0000000000..81cc357e41
--- /dev/null
+++ b/libgnomecanvas/gnome-canvas-text.c
@@ -0,0 +1,1746 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * $Id$
+ * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
+ * All rights reserved.
+ *
+ * This file is part of the Gnome Library.
+ *
+ * The Gnome Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * The Gnome Library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Gnome Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+/* Text item type for GnomeCanvas widget
+ *
+ * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
+ * widget. Tk is copyrighted by the Regents of the University of California,
+ * Sun Microsystems, and other parties.
+ *
+ *
+ * Author: Federico Mena <federico@nuclecu.unam.mx>
+ * Port to Pango co-done by Gergõ Érdi <cactus@cactus.rulez.org>
+ */
+
+#include <config.h>
+#include <math.h>
+#include <string.h>
+#include "gnome-canvas-text.h"
+#include <pango/pangoft2.h>
+
+#include <libart_lgpl/art_affine.h>
+#include <libart_lgpl/art_rgb_a_affine.h>
+#include <libart_lgpl/art_rgb.h>
+#include <libart_lgpl/art_rgb_bitmap_affine.h>
+#include "gnome-canvas-util.h"
+#include "gnome-canvas-i18n.h"
+
+
+
+/* Object argument IDs */
+enum {
+ PROP_0,
+
+ /* Text contents */
+ PROP_TEXT,
+ PROP_MARKUP,
+
+ /* Position */
+ PROP_X,
+ PROP_Y,
+
+ /* Font */
+ PROP_FONT,
+ PROP_FONT_DESC,
+ PROP_FAMILY, PROP_FAMILY_SET,
+
+ /* Style */
+ PROP_ATTRIBUTES,
+ PROP_STYLE, PROP_STYLE_SET,
+ PROP_VARIANT, PROP_VARIANT_SET,
+ PROP_WEIGHT, PROP_WEIGHT_SET,
+ PROP_STRETCH, PROP_STRETCH_SET,
+ PROP_SIZE, PROP_SIZE_SET,
+ PROP_SIZE_POINTS,
+ PROP_STRIKETHROUGH, PROP_STRIKETHROUGH_SET,
+ PROP_UNDERLINE, PROP_UNDERLINE_SET,
+ PROP_RISE, PROP_RISE_SET,
+ PROP_SCALE, PROP_SCALE_SET,
+
+ /* Clipping */
+ PROP_ANCHOR,
+ PROP_JUSTIFICATION,
+ PROP_CLIP_WIDTH,
+ PROP_CLIP_HEIGHT,
+ PROP_CLIP,
+ PROP_X_OFFSET,
+ PROP_Y_OFFSET,
+
+ /* Coloring */
+ PROP_FILL_COLOR,
+ PROP_FILL_COLOR_GDK,
+ PROP_FILL_COLOR_RGBA,
+ PROP_FILL_STIPPLE,
+
+ /* Rendered size accessors */
+ PROP_TEXT_WIDTH,
+ PROP_TEXT_HEIGHT
+};
+
+struct _GnomeCanvasTextPrivate {
+ guint render_dirty : 1;
+ FT_Bitmap bitmap;
+};
+
+
+static void gnome_canvas_text_class_init (GnomeCanvasTextClass *class);
+static void gnome_canvas_text_init (GnomeCanvasText *text);
+static void gnome_canvas_text_destroy (GtkObject *object);
+static void gnome_canvas_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void gnome_canvas_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec);
+
+static void gnome_canvas_text_update (GnomeCanvasItem *item, double *affine,
+ ArtSVP *clip_path, int flags);
+static void gnome_canvas_text_realize (GnomeCanvasItem *item);
+static void gnome_canvas_text_unrealize (GnomeCanvasItem *item);
+static void gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height);
+static double gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
+ GnomeCanvasItem **actual_item);
+static void gnome_canvas_text_bounds (GnomeCanvasItem *item,
+ double *x1, double *y1, double *x2, double *y2);
+static void gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
+
+static void gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
+ const gchar *markup);
+
+static void gnome_canvas_text_set_font_desc (GnomeCanvasText *textitem,
+ PangoFontDescription *font_desc);
+
+static void gnome_canvas_text_apply_font_desc (GnomeCanvasText *textitem);
+static void gnome_canvas_text_apply_attributes (GnomeCanvasText *textitem);
+
+static void add_attr (PangoAttrList *attr_list,
+ PangoAttribute *attr);
+
+static GnomeCanvasItemClass *parent_class;
+
+
+
+/**
+ * gnome_canvas_text_get_type:
+ * @void:
+ *
+ * Registers the &GnomeCanvasText class if necessary, and returns the type ID
+ * associated to it.
+ *
+ * Return value: The type ID of the &GnomeCanvasText class.
+ **/
+GType
+gnome_canvas_text_get_type (void)
+{
+ static GType text_type;
+
+ if (!text_type) {
+ const GTypeInfo object_info = {
+ sizeof (GnomeCanvasTextClass),
+ (GBaseInitFunc) NULL,
+ (GBaseFinalizeFunc) NULL,
+ (GClassInitFunc) gnome_canvas_text_class_init,
+ (GClassFinalizeFunc) NULL,
+ NULL, /* class_data */
+ sizeof (GnomeCanvasText),
+ 0, /* n_preallocs */
+ (GInstanceInitFunc) gnome_canvas_text_init,
+ NULL /* value_table */
+ };
+
+ text_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasText",
+ &object_info, 0);
+ }
+
+ return text_type;
+}
+
+/* Class initialization function for the text item */
+static void
+gnome_canvas_text_class_init (GnomeCanvasTextClass *class)
+{
+ GObjectClass *gobject_class;
+ GtkObjectClass *object_class;
+ GnomeCanvasItemClass *item_class;
+
+ gobject_class = (GObjectClass *) class;
+ object_class = (GtkObjectClass *) class;
+ item_class = (GnomeCanvasItemClass *) class;
+
+ parent_class = g_type_class_peek_parent (class);
+
+ gobject_class->set_property = gnome_canvas_text_set_property;
+ gobject_class->get_property = gnome_canvas_text_get_property;
+
+ /* Text */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_TEXT,
+ g_param_spec_string ("text",
+ _("Text"),
+ _("Text to render"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_MARKUP,
+ g_param_spec_string ("markup",
+ _("Markup"),
+ _("Marked up text to render"),
+ NULL,
+ (G_PARAM_WRITABLE)));
+
+ /* Position */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X,
+ g_param_spec_double ("x", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y,
+ g_param_spec_double ("y", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+
+ /* Font */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FONT,
+ g_param_spec_string ("font",
+ _("Font"),
+ _("Font description as a string"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FONT_DESC,
+ g_param_spec_boxed ("font_desc",
+ _("Font description"),
+ _("Font description as a PangoFontDescription struct"),
+ PANGO_TYPE_FONT_DESCRIPTION,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FAMILY,
+ g_param_spec_string ("family",
+ _("Font family"),
+ _("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ /* Style */
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ATTRIBUTES,
+ g_param_spec_boxed ("attributes", NULL, NULL,
+ PANGO_TYPE_ATTR_LIST,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_STYLE,
+ g_param_spec_enum ("style",
+ _("Font style"),
+ _("Font style"),
+ PANGO_TYPE_STYLE,
+ PANGO_STYLE_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_VARIANT,
+ g_param_spec_enum ("variant",
+ _("Font variant"),
+ _("Font variant"),
+ PANGO_TYPE_VARIANT,
+ PANGO_VARIANT_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WEIGHT,
+ g_param_spec_int ("weight",
+ _("Font weight"),
+ _("Font weight"),
+ 0,
+ G_MAXINT,
+ PANGO_WEIGHT_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_STRETCH,
+ g_param_spec_enum ("stretch",
+ _("Font stretch"),
+ _("Font stretch"),
+ PANGO_TYPE_STRETCH,
+ PANGO_STRETCH_NORMAL,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SIZE,
+ g_param_spec_int ("size",
+ _("Font size"),
+ _("Font size (as a multiple of PANGO_SCALE, eg. 12*PANGO_SCALE for a 12pt font size)"),
+ 0,
+ G_MAXINT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SIZE_POINTS,
+ g_param_spec_double ("size_points",
+ _("Font points"),
+ _("Font size in points (eg. 12 for a 12pt font size)"),
+ 0.0,
+ G_MAXDOUBLE,
+ 0.0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_RISE,
+ g_param_spec_int ("rise",
+ _("Rise"),
+ _("Offset of text above the baseline (below the baseline if rise is negative)"),
+ -G_MAXINT,
+ G_MAXINT,
+ 0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_STRIKETHROUGH,
+ g_param_spec_boolean ("strikethrough",
+ _("Strikethrough"),
+ _("Whether to strike through the text"),
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_UNDERLINE,
+ g_param_spec_enum ("underline",
+ _("Underline"),
+ _("Style of underline for this text"),
+ PANGO_TYPE_UNDERLINE,
+ PANGO_UNDERLINE_NONE,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_SCALE,
+ g_param_spec_double ("scale",
+ _("Scale"),
+ _("Size of font, relative to default size"),
+ 0.0,
+ G_MAXDOUBLE,
+ 1.0,
+ G_PARAM_READABLE | G_PARAM_WRITABLE));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_ANCHOR,
+ g_param_spec_enum ("anchor", NULL, NULL,
+ GTK_TYPE_ANCHOR_TYPE,
+ GTK_ANCHOR_CENTER,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_JUSTIFICATION,
+ g_param_spec_enum ("justification", NULL, NULL,
+ GTK_TYPE_JUSTIFICATION,
+ GTK_JUSTIFY_LEFT,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_CLIP_WIDTH,
+ g_param_spec_double ("clip_width", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_CLIP_HEIGHT,
+ g_param_spec_double ("clip_height", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_CLIP,
+ g_param_spec_boolean ("clip", NULL, NULL,
+ FALSE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_X_OFFSET,
+ g_param_spec_double ("x_offset", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_Y_OFFSET,
+ g_param_spec_double ("y_offset", NULL, NULL,
+ -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR,
+ g_param_spec_string ("fill_color",
+ _("Color"),
+ _("Text color, as string"),
+ NULL,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR_GDK,
+ g_param_spec_boxed ("fill_color_gdk",
+ _("Color"),
+ _("Text color, as a GdkColor"),
+ GDK_TYPE_COLOR,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_COLOR_RGBA,
+ g_param_spec_uint ("fill_color_rgba",
+ _("Color"),
+ _("Text color, as an R/G/B/A combined integer"),
+ 0, G_MAXUINT, 0,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_FILL_STIPPLE,
+ g_param_spec_object ("fill_stipple", NULL, NULL,
+ GDK_TYPE_DRAWABLE,
+ (G_PARAM_READABLE | G_PARAM_WRITABLE)));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_TEXT_WIDTH,
+ g_param_spec_double ("text_width",
+ _("Text width"),
+ _("Width of the rendered text"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE));
+ g_object_class_install_property
+ (gobject_class,
+ PROP_TEXT_HEIGHT,
+ g_param_spec_double ("text_height",
+ _("Text height"),
+ _("Height of the rendered text"),
+ 0.0, G_MAXDOUBLE, 0.0,
+ G_PARAM_READABLE));
+
+ /* Style props are set (explicitly applied) or not */
+#define ADD_SET_PROP(propname, propval, nick, blurb) g_object_class_install_property (gobject_class, propval, g_param_spec_boolean (propname, nick, blurb, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE))
+
+ ADD_SET_PROP ("family_set", PROP_FAMILY_SET,
+ _("Font family set"),
+ _("Whether this tag affects the font family"));
+
+ ADD_SET_PROP ("style_set", PROP_STYLE_SET,
+ _("Font style set"),
+ _("Whether this tag affects the font style"));
+
+ ADD_SET_PROP ("variant_set", PROP_VARIANT_SET,
+ _("Font variant set"),
+ _("Whether this tag affects the font variant"));
+
+ ADD_SET_PROP ("weight_set", PROP_WEIGHT_SET,
+ _("Font weight set"),
+ _("Whether this tag affects the font weight"));
+
+ ADD_SET_PROP ("stretch_set", PROP_STRETCH_SET,
+ _("Font stretch set"),
+ _("Whether this tag affects the font stretch"));
+
+ ADD_SET_PROP ("size_set", PROP_SIZE_SET,
+ _("Font size set"),
+ _("Whether this tag affects the font size"));
+
+ ADD_SET_PROP ("rise_set", PROP_RISE_SET,
+ _("Rise set"),
+ _("Whether this tag affects the rise"));
+
+ ADD_SET_PROP ("strikethrough_set", PROP_STRIKETHROUGH_SET,
+ _("Strikethrough set"),
+ _("Whether this tag affects strikethrough"));
+
+ ADD_SET_PROP ("underline_set", PROP_UNDERLINE_SET,
+ _("Underline set"),
+ _("Whether this tag affects underlining"));
+
+ ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
+ _("Scale set"),
+ _("Whether this tag affects font scaling"));
+#undef ADD_SET_PROP
+
+ object_class->destroy = gnome_canvas_text_destroy;
+
+ item_class->update = gnome_canvas_text_update;
+ item_class->realize = gnome_canvas_text_realize;
+ item_class->unrealize = gnome_canvas_text_unrealize;
+ item_class->draw = gnome_canvas_text_draw;
+ item_class->point = gnome_canvas_text_point;
+ item_class->bounds = gnome_canvas_text_bounds;
+ item_class->render = gnome_canvas_text_render;
+}
+
+/* Object initialization function for the text item */
+static void
+gnome_canvas_text_init (GnomeCanvasText *text)
+{
+ text->x = 0.0;
+ text->y = 0.0;
+ text->anchor = GTK_ANCHOR_CENTER;
+ text->justification = GTK_JUSTIFY_LEFT;
+ text->clip_width = 0.0;
+ text->clip_height = 0.0;
+ text->xofs = 0.0;
+ text->yofs = 0.0;
+ text->layout = NULL;
+
+ text->font_desc = NULL;
+
+ text->underline = PANGO_UNDERLINE_NONE;
+ text->strikethrough = FALSE;
+ text->rise = 0;
+
+ text->underline_set = FALSE;
+ text->strike_set = FALSE;
+ text->rise_set = FALSE;
+
+ text->priv = g_new (GnomeCanvasTextPrivate, 1);
+ text->priv->bitmap.buffer = NULL;
+ text->priv->render_dirty = 1;
+}
+
+/* Destroy handler for the text item */
+static void
+gnome_canvas_text_destroy (GtkObject *object)
+{
+ GnomeCanvasText *text;
+
+ g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
+
+ text = GNOME_CANVAS_TEXT (object);
+
+ /* remember, destroy can be run multiple times! */
+
+ g_free (text->text);
+ text->text = NULL;
+
+ if (text->layout)
+ g_object_unref (G_OBJECT (text->layout));
+ text->layout = NULL;
+
+ if (text->font_desc) {
+ pango_font_description_free (text->font_desc);
+ text->font_desc = NULL;
+ }
+
+ if (text->attr_list)
+ pango_attr_list_unref (text->attr_list);
+ text->attr_list = NULL;
+
+ if (text->stipple)
+ g_object_unref (text->stipple);
+ text->stipple = NULL;
+
+ if (text->priv && text->priv->bitmap.buffer) {
+ g_free (text->priv->bitmap.buffer);
+ }
+ g_free (text->priv);
+ text->priv = NULL;
+
+ if (GTK_OBJECT_CLASS (parent_class)->destroy)
+ (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
+}
+
+static void
+get_bounds (GnomeCanvasText *text, double *px1, double *py1, double *px2, double *py2)
+{
+ GnomeCanvasItem *item;
+ double wx, wy;
+
+ item = GNOME_CANVAS_ITEM (text);
+
+ /* Get canvas pixel coordinates for text position */
+
+
+ wx = text->x;
+ wy = text->y;
+ gnome_canvas_item_i2w (item, &wx, &wy);
+ gnome_canvas_w2c (item->canvas, wx + text->xofs, wy + text->yofs, &text->cx, &text->cy);
+
+ /* Get canvas pixel coordinates for clip rectangle position */
+
+ gnome_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy);
+ text->clip_cwidth = text->clip_width * item->canvas->pixels_per_unit;
+ text->clip_cheight = text->clip_height * item->canvas->pixels_per_unit;
+
+ /* Anchor text */
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ text->cx -= text->max_width / 2;
+ text->clip_cx -= text->clip_cwidth / 2;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ text->cx -= text->max_width;
+ text->clip_cx -= text->clip_cwidth;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ text->cy -= text->height / 2;
+ text->clip_cy -= text->clip_cheight / 2;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ text->cy -= text->height;
+ text->clip_cy -= text->clip_cheight;
+ break;
+
+ default:
+ break;
+ }
+
+ /* Bounds */
+
+ if (text->clip) {
+ *px1 = text->clip_cx;
+ *py1 = text->clip_cy;
+ *px2 = text->clip_cx + text->clip_cwidth;
+ *py2 = text->clip_cy + text->clip_cheight;
+ } else {
+ *px1 = text->cx;
+ *py1 = text->cy;
+ *px2 = text->cx + text->max_width;
+ *py2 = text->cy + text->height;
+ }
+}
+
+/* Convenience function to set the text's GC's foreground color */
+static void
+set_text_gc_foreground (GnomeCanvasText *text)
+{
+ GdkColor c;
+
+ if (!text->gc)
+ return;
+
+ c.pixel = text->pixel;
+ gdk_gc_set_foreground (text->gc, &c);
+}
+
+/* Sets the stipple pattern for the text */
+static void
+set_stipple (GnomeCanvasText *text, GdkBitmap *stipple, int reconfigure)
+{
+ if (text->stipple && !reconfigure)
+ g_object_unref (text->stipple);
+
+ text->stipple = stipple;
+ if (stipple && !reconfigure)
+ g_object_ref (stipple);
+
+ if (text->gc) {
+ if (stipple) {
+ gdk_gc_set_stipple (text->gc, stipple);
+ gdk_gc_set_fill (text->gc, GDK_STIPPLED);
+ } else
+ gdk_gc_set_fill (text->gc, GDK_SOLID);
+ }
+}
+
+static PangoFontMask
+get_property_font_set_mask (guint prop_id)
+{
+ switch (prop_id)
+ {
+ case PROP_FAMILY_SET:
+ return PANGO_FONT_MASK_FAMILY;
+ case PROP_STYLE_SET:
+ return PANGO_FONT_MASK_STYLE;
+ case PROP_VARIANT_SET:
+ return PANGO_FONT_MASK_VARIANT;
+ case PROP_WEIGHT_SET:
+ return PANGO_FONT_MASK_WEIGHT;
+ case PROP_STRETCH_SET:
+ return PANGO_FONT_MASK_STRETCH;
+ case PROP_SIZE_SET:
+ return PANGO_FONT_MASK_SIZE;
+ }
+
+ return 0;
+}
+
+static void
+ensure_font (GnomeCanvasText *text)
+{
+ if (!text->font_desc)
+ text->font_desc = pango_font_description_new ();
+}
+
+/* Set_arg handler for the text item */
+static void
+gnome_canvas_text_set_property (GObject *object,
+ guint param_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasItem *item;
+ GnomeCanvasText *text;
+ GdkColor color = { 0, 0, 0, 0, };
+ GdkColor *pcolor;
+ gboolean color_changed;
+ int have_pixel;
+ PangoAlignment align;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
+
+ item = GNOME_CANVAS_ITEM (object);
+ text = GNOME_CANVAS_TEXT (object);
+
+ color_changed = FALSE;
+ have_pixel = FALSE;
+
+
+ if (!text->layout) {
+
+ PangoContext *gtk_context, *context;
+ gtk_context = gtk_widget_get_pango_context (GTK_WIDGET (item->canvas));
+
+ if (item->canvas->aa) {
+ PangoFontMap *fontmap;
+ PangoLanguage *language;
+ gint pixels, mm;
+ double dpi_x;
+ double dpi_y;
+
+ pixels = gdk_screen_width ();
+ mm = gdk_screen_width_mm ();
+ dpi_x = (((double) pixels * 25.4) / (double) mm);
+
+ pixels = gdk_screen_height ();
+ mm = gdk_screen_height_mm ();
+ dpi_y = (((double) pixels * 25.4) / (double) mm);
+
+ /* XXX This used to call pango_ft2_get_context().
+ * Is there a better way to do this? */
+ fontmap = pango_ft2_font_map_new ();
+ pango_ft2_font_map_set_resolution (PANGO_FT2_FONT_MAP (fontmap), dpi_x, dpi_y);
+ context = pango_font_map_create_context (fontmap);
+
+ language = pango_context_get_language (gtk_context);
+ pango_context_set_language (context, language);
+ pango_context_set_base_dir (context,
+ pango_context_get_base_dir (gtk_context));
+ pango_context_set_font_description (context,
+ pango_context_get_font_description (gtk_context));
+
+ } else
+ context = gtk_context;
+
+
+ text->layout = pango_layout_new (context);
+
+ if (item->canvas->aa)
+ g_object_unref (G_OBJECT (context));
+ }
+
+ switch (param_id) {
+ case PROP_TEXT:
+ g_free (text->text);
+
+ text->text = g_value_dup_string (value);
+ pango_layout_set_text (text->layout, text->text, -1);
+
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_MARKUP:
+ gnome_canvas_text_set_markup (text,
+ g_value_get_string (value));
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_X:
+ text->x = g_value_get_double (value);
+ break;
+
+ case PROP_Y:
+ text->y = g_value_get_double (value);
+ break;
+
+ case PROP_FONT: {
+ const char *font_name;
+ PangoFontDescription *font_desc;
+
+ font_name = g_value_get_string (value);
+ if (font_name)
+ font_desc = pango_font_description_from_string (font_name);
+ else
+ font_desc = NULL;
+
+ gnome_canvas_text_set_font_desc (text, font_desc);
+ if (font_desc)
+ pango_font_description_free (font_desc);
+
+ break;
+ }
+
+ case PROP_FONT_DESC:
+ gnome_canvas_text_set_font_desc (text, g_value_peek_pointer (value));
+ break;
+
+ case PROP_FAMILY:
+ case PROP_STYLE:
+ case PROP_VARIANT:
+ case PROP_WEIGHT:
+ case PROP_STRETCH:
+ case PROP_SIZE:
+ case PROP_SIZE_POINTS:
+ ensure_font (text);
+
+ switch (param_id) {
+ case PROP_FAMILY:
+ pango_font_description_set_family (text->font_desc,
+ g_value_get_string (value));
+ break;
+ case PROP_STYLE:
+ pango_font_description_set_style (text->font_desc,
+ g_value_get_enum (value));
+ break;
+ case PROP_VARIANT:
+ pango_font_description_set_variant (text->font_desc,
+ g_value_get_enum (value));
+ break;
+ case PROP_WEIGHT:
+ pango_font_description_set_weight (text->font_desc,
+ g_value_get_int (value));
+ break;
+ case PROP_STRETCH:
+ pango_font_description_set_stretch (text->font_desc,
+ g_value_get_enum (value));
+ break;
+ case PROP_SIZE:
+ /* FIXME: This is bogus! It should be pixels, not points/PANGO_SCALE! */
+ pango_font_description_set_size (text->font_desc,
+ g_value_get_int (value));
+ break;
+ case PROP_SIZE_POINTS:
+ pango_font_description_set_size (text->font_desc,
+ g_value_get_double (value) * PANGO_SCALE);
+ break;
+ }
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_FAMILY_SET:
+ case PROP_STYLE_SET:
+ case PROP_VARIANT_SET:
+ case PROP_WEIGHT_SET:
+ case PROP_STRETCH_SET:
+ case PROP_SIZE_SET:
+ if (!g_value_get_boolean (value) && text->font_desc)
+ pango_font_description_unset_fields (text->font_desc,
+ get_property_font_set_mask (param_id));
+ break;
+
+ case PROP_SCALE:
+ text->scale = g_value_get_double (value);
+ text->scale_set = TRUE;
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_SCALE_SET:
+ text->scale_set = g_value_get_boolean (value);
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_UNDERLINE:
+ text->underline = g_value_get_enum (value);
+ text->underline_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_UNDERLINE_SET:
+ text->underline_set = g_value_get_boolean (value);
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_STRIKETHROUGH:
+ text->strikethrough = g_value_get_boolean (value);
+ text->strike_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_STRIKETHROUGH_SET:
+ text->strike_set = g_value_get_boolean (value);
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_RISE:
+ text->rise = g_value_get_int (value);
+ text->rise_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_RISE_SET:
+ text->rise_set = TRUE;
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_ATTRIBUTES:
+ if (text->attr_list)
+ pango_attr_list_unref (text->attr_list);
+
+ text->attr_list = g_value_peek_pointer (value);
+ pango_attr_list_ref (text->attr_list);
+
+ gnome_canvas_text_apply_attributes (text);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_ANCHOR:
+ text->anchor = g_value_get_enum (value);
+ break;
+
+ case PROP_JUSTIFICATION:
+ text->justification = g_value_get_enum (value);
+
+ switch (text->justification) {
+ case GTK_JUSTIFY_LEFT:
+ align = PANGO_ALIGN_LEFT;
+ break;
+ case GTK_JUSTIFY_CENTER:
+ align = PANGO_ALIGN_CENTER;
+ break;
+ case GTK_JUSTIFY_RIGHT:
+ align = PANGO_ALIGN_RIGHT;
+ break;
+ default:
+ /* GTK_JUSTIFY_FILL isn't supported yet. */
+ align = PANGO_ALIGN_LEFT;
+ break;
+ }
+ pango_layout_set_alignment (text->layout, align);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_CLIP_WIDTH:
+ text->clip_width = fabs (g_value_get_double (value));
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_CLIP_HEIGHT:
+ text->clip_height = fabs (g_value_get_double (value));
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_CLIP:
+ text->clip = g_value_get_boolean (value);
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_X_OFFSET:
+ text->xofs = g_value_get_double (value);
+ break;
+
+ case PROP_Y_OFFSET:
+ text->yofs = g_value_get_double (value);
+ break;
+
+ case PROP_FILL_COLOR: {
+ const char *color_name;
+
+ color_name = g_value_get_string (value);
+ if (color_name) {
+ gdk_color_parse (color_name, &color);
+
+ text->rgba = ((color.red & 0xff00) << 16 |
+ (color.green & 0xff00) << 8 |
+ (color.blue & 0xff00) |
+ 0xff);
+ color_changed = TRUE;
+ }
+ text->priv->render_dirty = 1;
+ break;
+ }
+
+ case PROP_FILL_COLOR_GDK:
+ pcolor = g_value_get_boxed (value);
+ if (pcolor) {
+ GdkColormap *colormap;
+
+ color = *pcolor;
+ colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
+ gdk_rgb_find_color (colormap, &color);
+ have_pixel = TRUE;
+ }
+
+ text->rgba = ((color.red & 0xff00) << 16 |
+ (color.green & 0xff00) << 8|
+ (color.blue & 0xff00) |
+ 0xff);
+ color_changed = TRUE;
+ break;
+
+ case PROP_FILL_COLOR_RGBA:
+ text->rgba = g_value_get_uint (value);
+ color_changed = TRUE;
+ text->priv->render_dirty = 1;
+ break;
+
+ case PROP_FILL_STIPPLE:
+ set_stipple (text, (GdkBitmap *)g_value_get_object (value), FALSE);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+
+ if (color_changed) {
+ if (have_pixel)
+ text->pixel = color.pixel;
+ else
+ text->pixel = gnome_canvas_get_color_pixel (item->canvas, text->rgba);
+
+ if (!item->canvas->aa)
+ set_text_gc_foreground (text);
+ }
+
+ /* Calculate text dimensions */
+
+ if (text->layout)
+ pango_layout_get_pixel_size (text->layout,
+ &text->max_width,
+ &text->height);
+ else {
+ text->max_width = 0;
+ text->height = 0;
+ }
+
+ gnome_canvas_item_request_update (item);
+}
+
+/* Get_arg handler for the text item */
+static void
+gnome_canvas_text_get_property (GObject *object,
+ guint param_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GnomeCanvasText *text;
+
+ g_return_if_fail (object != NULL);
+ g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
+
+ text = GNOME_CANVAS_TEXT (object);
+
+ switch (param_id) {
+ case PROP_TEXT:
+ g_value_set_string (value, text->text);
+ break;
+
+ case PROP_X:
+ g_value_set_double (value, text->x);
+ break;
+
+ case PROP_Y:
+ g_value_set_double (value, text->y);
+ break;
+
+ case PROP_FONT:
+ case PROP_FONT_DESC:
+ case PROP_FAMILY:
+ case PROP_STYLE:
+ case PROP_VARIANT:
+ case PROP_WEIGHT:
+ case PROP_STRETCH:
+ case PROP_SIZE:
+ case PROP_SIZE_POINTS:
+ ensure_font (text);
+
+ switch (param_id) {
+ case PROP_FONT:
+ {
+ /* FIXME GValue imposes a totally gratuitous string copy
+ * here, we could just hand off string ownership
+ */
+ gchar *str;
+
+ str = pango_font_description_to_string (text->font_desc);
+ g_value_set_string (value, str);
+ g_free (str);
+
+ break;
+ }
+
+ case PROP_FONT_DESC:
+ g_value_set_boxed (value, text->font_desc);
+ break;
+
+ case PROP_FAMILY:
+ g_value_set_string (value, pango_font_description_get_family (text->font_desc));
+ break;
+
+ case PROP_STYLE:
+ g_value_set_enum (value, pango_font_description_get_style (text->font_desc));
+ break;
+
+ case PROP_VARIANT:
+ g_value_set_enum (value, pango_font_description_get_variant (text->font_desc));
+ break;
+
+ case PROP_WEIGHT:
+ g_value_set_int (value, pango_font_description_get_weight (text->font_desc));
+ break;
+
+ case PROP_STRETCH:
+ g_value_set_enum (value, pango_font_description_get_stretch (text->font_desc));
+ break;
+
+ case PROP_SIZE:
+ g_value_set_int (value, pango_font_description_get_size (text->font_desc));
+ break;
+
+ case PROP_SIZE_POINTS:
+ g_value_set_double (value, ((double)pango_font_description_get_size (text->font_desc)) / (double)PANGO_SCALE);
+ break;
+ }
+ break;
+
+ case PROP_FAMILY_SET:
+ case PROP_STYLE_SET:
+ case PROP_VARIANT_SET:
+ case PROP_WEIGHT_SET:
+ case PROP_STRETCH_SET:
+ case PROP_SIZE_SET:
+ {
+ PangoFontMask set_mask = text->font_desc ? pango_font_description_get_set_fields (text->font_desc) : 0;
+ PangoFontMask test_mask = get_property_font_set_mask (param_id);
+ g_value_set_boolean (value, (set_mask & test_mask) != 0);
+
+ break;
+ }
+
+ case PROP_SCALE:
+ g_value_set_double (value, text->scale);
+ break;
+ case PROP_SCALE_SET:
+ g_value_set_boolean (value, text->scale_set);
+ break;
+
+ case PROP_UNDERLINE:
+ g_value_set_enum (value, text->underline);
+ break;
+ case PROP_UNDERLINE_SET:
+ g_value_set_boolean (value, text->underline_set);
+ break;
+
+ case PROP_STRIKETHROUGH:
+ g_value_set_boolean (value, text->strikethrough);
+ break;
+ case PROP_STRIKETHROUGH_SET:
+ g_value_set_boolean (value, text->strike_set);
+ break;
+
+ case PROP_RISE:
+ g_value_set_int (value, text->rise);
+ break;
+ case PROP_RISE_SET:
+ g_value_set_boolean (value, text->rise_set);
+ break;
+
+ case PROP_ATTRIBUTES:
+ g_value_set_boxed (value, text->attr_list);
+ break;
+
+ case PROP_ANCHOR:
+ g_value_set_enum (value, text->anchor);
+ break;
+
+ case PROP_JUSTIFICATION:
+ g_value_set_enum (value, text->justification);
+ break;
+
+ case PROP_CLIP_WIDTH:
+ g_value_set_double (value, text->clip_width);
+ break;
+
+ case PROP_CLIP_HEIGHT:
+ g_value_set_double (value, text->clip_height);
+ break;
+
+ case PROP_CLIP:
+ g_value_set_boolean (value, text->clip);
+ break;
+
+ case PROP_X_OFFSET:
+ g_value_set_double (value, text->xofs);
+ break;
+
+ case PROP_Y_OFFSET:
+ g_value_set_double (value, text->yofs);
+ break;
+
+ case PROP_FILL_COLOR:
+ g_value_take_string (value,
+ g_strdup_printf ("#%02x%02x%02x",
+ text->rgba >> 24,
+ (text->rgba >> 16) & 0xff,
+ (text->rgba >> 8) & 0xff));
+ break;
+
+ case PROP_FILL_COLOR_GDK: {
+ GnomeCanvas *canvas = GNOME_CANVAS_ITEM (text)->canvas;
+ GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
+ GdkColor color;
+
+ gdk_colormap_query_color (colormap, text->pixel, &color);
+ g_value_set_boxed (value, &color);
+ break;
+ }
+ case PROP_FILL_COLOR_RGBA:
+ g_value_set_uint (value, text->rgba);
+ break;
+
+ case PROP_FILL_STIPPLE:
+ g_value_set_object (value, text->stipple);
+ break;
+
+ case PROP_TEXT_WIDTH:
+ g_value_set_double (value, text->max_width / text->item.canvas->pixels_per_unit);
+ break;
+
+ case PROP_TEXT_HEIGHT:
+ g_value_set_double (value, text->height / text->item.canvas->pixels_per_unit);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
+ break;
+ }
+}
+
+/* */
+static void
+gnome_canvas_text_apply_font_desc (GnomeCanvasText *text)
+{
+ PangoFontDescription *font_desc =
+ pango_font_description_copy (
+ GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas)->style->font_desc);
+
+ if (text->font_desc)
+ pango_font_description_merge (font_desc, text->font_desc, TRUE);
+
+ pango_layout_set_font_description (text->layout, font_desc);
+ pango_font_description_free (font_desc);
+}
+
+static void
+add_attr (PangoAttrList *attr_list,
+ PangoAttribute *attr)
+{
+ attr->start_index = 0;
+ attr->end_index = G_MAXINT;
+
+ pango_attr_list_insert (attr_list, attr);
+}
+
+/* */
+static void
+gnome_canvas_text_apply_attributes (GnomeCanvasText *text)
+{
+ PangoAttrList *attr_list;
+
+ if (text->attr_list)
+ attr_list = pango_attr_list_copy (text->attr_list);
+ else
+ attr_list = pango_attr_list_new ();
+
+ if (text->underline_set)
+ add_attr (attr_list, pango_attr_underline_new (text->underline));
+ if (text->strike_set)
+ add_attr (attr_list, pango_attr_strikethrough_new (text->strikethrough));
+ if (text->rise_set)
+ add_attr (attr_list, pango_attr_rise_new (text->rise));
+
+ pango_layout_set_attributes (text->layout, attr_list);
+ pango_attr_list_unref (attr_list);
+}
+
+static void
+gnome_canvas_text_set_font_desc (GnomeCanvasText *text,
+ PangoFontDescription *font_desc)
+{
+ if (text->font_desc)
+ pango_font_description_free (text->font_desc);
+
+ if (font_desc)
+ text->font_desc = pango_font_description_copy (font_desc);
+ else
+ text->font_desc = NULL;
+
+ gnome_canvas_text_apply_font_desc (text);
+ text->priv->render_dirty = 1;
+}
+
+/* Setting the text from a Pango markup string */
+static void
+gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
+ const gchar *markup)
+{
+ PangoAttrList *attr_list = NULL;
+ gchar *text = NULL;
+ GError *error = NULL;
+
+ if (markup && !pango_parse_markup (markup, -1,
+ 0,
+ &attr_list, &text, NULL,
+ &error))
+ {
+ g_warning ("Failed to set cell text from markup due to error parsing markup: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ g_free (textitem->text);
+ if (textitem->attr_list)
+ pango_attr_list_unref (textitem->attr_list);
+
+ textitem->text = text;
+ textitem->attr_list = attr_list;
+
+ pango_layout_set_text (textitem->layout, text, -1);
+
+ gnome_canvas_text_apply_attributes (textitem);
+}
+
+/* Update handler for the text item */
+static void
+gnome_canvas_text_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
+{
+ GnomeCanvasText *text;
+ double x1, y1, x2, y2;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (parent_class->update)
+ (* parent_class->update) (item, affine, clip_path, flags);
+
+ set_text_gc_foreground (text);
+ set_stipple (text, text->stipple, TRUE);
+ get_bounds (text, &x1, &y1, &x2, &y2);
+
+ gnome_canvas_update_bbox (item,
+ floor (x1), floor (y1),
+ ceil (x2), ceil (y2));
+}
+
+/* Realize handler for the text item */
+static void
+gnome_canvas_text_realize (GnomeCanvasItem *item)
+{
+ GnomeCanvasText *text;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (parent_class->realize)
+ (* parent_class->realize) (item);
+
+ text->gc = gdk_gc_new (item->canvas->layout.bin_window);
+}
+
+/* Unrealize handler for the text item */
+static void
+gnome_canvas_text_unrealize (GnomeCanvasItem *item)
+{
+ GnomeCanvasText *text;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ g_object_unref (text->gc);
+ text->gc = NULL;
+
+ if (parent_class->unrealize)
+ (* parent_class->unrealize) (item);
+}
+
+/* Draw handler for the text item */
+static void
+gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
+ int x, int y, int width, int height)
+{
+ GnomeCanvasText *text;
+ GdkRectangle rect;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (!text->text)
+ return;
+
+ if (text->clip) {
+ rect.x = text->clip_cx - x;
+ rect.y = text->clip_cy - y;
+ rect.width = text->clip_cwidth;
+ rect.height = text->clip_cheight;
+
+ gdk_gc_set_clip_rectangle (text->gc, &rect);
+ }
+
+ if (text->stipple)
+ gnome_canvas_set_stipple_origin (item->canvas, text->gc);
+
+
+ gdk_draw_layout (drawable, text->gc, text->cx - x, text->cy - y, text->layout);
+
+ if (text->clip)
+ gdk_gc_set_clip_rectangle (text->gc, NULL);
+}
+
+
+/* Render handler for the text item */
+static void
+gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
+{
+ GnomeCanvasText *text;
+ guint32 fg_color;
+ int render_x = 0, render_y = 0; /* offsets for text rendering,
+ * for clipping rectangles */
+ int x, y;
+ int w, h;
+ guchar *dst, *src;
+ int src_dx, src_dy;
+ int i, alpha;
+ int bm_rows, bm_width;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ if (!text->text)
+ return;
+
+ fg_color = text->rgba;
+
+ gnome_canvas_buf_ensure_buf (buf);
+
+ bm_rows = (text->clip) ? text->clip_cheight : text->height;
+ bm_width = (text->clip) ? text->clip_cwidth : text->max_width;
+ if(text->priv->render_dirty ||
+ bm_rows != text->priv->bitmap.rows ||
+ bm_width != text->priv->bitmap.width) {
+ if(text->priv->bitmap.buffer) {
+ g_free(text->priv->bitmap.buffer);
+ }
+ text->priv->bitmap.rows = bm_rows;
+ text->priv->bitmap.width = bm_width;
+ text->priv->bitmap.pitch = (text->priv->bitmap.width+3)&~3;
+ text->priv->bitmap.buffer = g_malloc0 (text->priv->bitmap.rows * text->priv->bitmap.pitch);
+ text->priv->bitmap.num_grays = 256;
+ text->priv->bitmap.pixel_mode = ft_pixel_mode_grays;
+
+ /* What this does is when a clipping rectangle is
+ being used shift the rendering of the text by the
+ correct amount so that the correct result is
+ obtained as if all text was rendered, then clipped.
+ In this sense we can use smaller buffers and less
+ rendeirng since hopefully FreeType2 checks to see
+ if the glyph falls in the bounding box before
+ rasterizing it. */
+
+ if(text->clip) {
+ render_x = text->cx - text->clip_cx;
+ render_y = text->cy - text->clip_cy;
+ }
+
+ pango_ft2_render_layout (&text->priv->bitmap, text->layout, render_x, render_y);
+
+ text->priv->render_dirty = 0;
+ }
+
+ if (text->clip) {
+ x = text->clip_cx - buf->rect.x0;
+ y = text->clip_cy - buf->rect.y0;
+ } else {
+ x = text->cx - buf->rect.x0;
+ y = text->cy - buf->rect.y0;
+ }
+
+ w = text->priv->bitmap.width;
+ h = text->priv->bitmap.rows;
+
+ src_dx = src_dy = 0;
+
+ if (x + w > buf->rect.x1 - buf->rect.x0) {
+ w = buf->rect.x1 - buf->rect.x0 - x;
+ }
+
+ if (y + h > buf->rect.y1 - buf->rect.y0) {
+ h = buf->rect.y1 - buf->rect.y0 - y;
+ }
+
+ if (x < 0) {
+ w -= - x;
+ src_dx += - x;
+ x = 0;
+ }
+
+ if (y < 0) {
+ h -= -y;
+ src_dy += - y;
+ y = 0;
+ }
+
+ dst = buf->buf + y * buf->buf_rowstride + x * 3;
+ src = text->priv->bitmap.buffer +
+ src_dy * text->priv->bitmap.pitch + src_dx;
+ while (h-- > 0) {
+ i = w;
+ while (i-- > 0) {
+ /* FIXME: Do the libart thing instead of divide by 255 */
+ alpha = ((fg_color & 0xff) * (*src)) / 255;
+ dst[0] = (dst[0] * (255 - alpha) + ((fg_color >> 24) & 0xff) * alpha) / 255;
+ dst[1] = (dst[1] * (255 - alpha) + ((fg_color >> 16) & 0xff) * alpha) / 255;
+ dst[2] = (dst[2] * (255 - alpha) + ((fg_color >> 8) & 0xff) * alpha) / 255;
+ dst += 3;
+ src += 1;
+ }
+ dst += buf->buf_rowstride - w*3;
+ src += text->priv->bitmap.pitch - w;
+ }
+
+ buf->is_bg = 0;
+ return;
+}
+
+/* Point handler for the text item */
+static double
+gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y,
+ int cx, int cy, GnomeCanvasItem **actual_item)
+{
+ GnomeCanvasText *text;
+ PangoLayoutIter *iter;
+ int x1, y1, x2, y2;
+ int dx, dy;
+ double dist, best;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ *actual_item = item;
+
+ /* The idea is to build bounding rectangles for each of the lines of
+ * text (clipped by the clipping rectangle, if it is activated) and see
+ * whether the point is inside any of these. If it is, we are done.
+ * Otherwise, calculate the distance to the nearest rectangle.
+ */
+
+ best = 1.0e36;
+
+ iter = pango_layout_get_iter (text->layout);
+ do {
+ PangoRectangle log_rect;
+
+ pango_layout_iter_get_line_extents (iter, NULL, &log_rect);
+
+ x1 = text->cx + PANGO_PIXELS (log_rect.x);
+ y1 = text->cy + PANGO_PIXELS (log_rect.y);
+ x2 = x1 + PANGO_PIXELS (log_rect.width);
+ y2 = y1 + PANGO_PIXELS (log_rect.height);
+
+ if (text->clip) {
+ if (x1 < text->clip_cx)
+ x1 = text->clip_cx;
+
+ if (y1 < text->clip_cy)
+ y1 = text->clip_cy;
+
+ if (x2 > (text->clip_cx + text->clip_width))
+ x2 = text->clip_cx + text->clip_width;
+
+ if (y2 > (text->clip_cy + text->clip_height))
+ y2 = text->clip_cy + text->clip_height;
+
+ if ((x1 >= x2) || (y1 >= y2))
+ continue;
+ }
+
+ /* Calculate distance from point to rectangle */
+
+ if (cx < x1)
+ dx = x1 - cx;
+ else if (cx >= x2)
+ dx = cx - x2 + 1;
+ else
+ dx = 0;
+
+ if (cy < y1)
+ dy = y1 - cy;
+ else if (cy >= y2)
+ dy = cy - y2 + 1;
+ else
+ dy = 0;
+
+ if ((dx == 0) && (dy == 0)) {
+ pango_layout_iter_free(iter);
+ return 0.0;
+ }
+
+ dist = sqrt (dx * dx + dy * dy);
+ if (dist < best)
+ best = dist;
+
+ } while (pango_layout_iter_next_line(iter));
+
+ pango_layout_iter_free(iter);
+
+ return best / item->canvas->pixels_per_unit;
+}
+
+/* Bounds handler for the text item */
+static void
+gnome_canvas_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
+{
+ GnomeCanvasText *text;
+ double width, height;
+
+ text = GNOME_CANVAS_TEXT (item);
+
+ *x1 = text->x;
+ *y1 = text->y;
+
+ if (text->clip) {
+ width = text->clip_width;
+ height = text->clip_height;
+ } else {
+ width = text->max_width / item->canvas->pixels_per_unit;
+ height = text->height / item->canvas->pixels_per_unit;
+ }
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_SW:
+ break;
+
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_S:
+ *x1 -= width / 2.0;
+ break;
+
+ case GTK_ANCHOR_NE:
+ case GTK_ANCHOR_E:
+ case GTK_ANCHOR_SE:
+ *x1 -= width;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (text->anchor) {
+ case GTK_ANCHOR_NW:
+ case GTK_ANCHOR_N:
+ case GTK_ANCHOR_NE:
+ break;
+
+ case GTK_ANCHOR_W:
+ case GTK_ANCHOR_CENTER:
+ case GTK_ANCHOR_E:
+ *y1 -= height / 2.0;
+ break;
+
+ case GTK_ANCHOR_SW:
+ case GTK_ANCHOR_S:
+ case GTK_ANCHOR_SE:
+ *y1 -= height;
+ break;
+
+ default:
+ break;
+ }
+
+ *x2 = *x1 + width;
+ *y2 = *y1 + height;
+}