remove unused and useless "src" argument for a number of Region property modifying...
[ardour.git] / libs / gnomecanvas / libgnomecanvas / gnome-canvas-text.c
1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3  * $Id$
4  * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation
5  * All rights reserved.
6  *
7  * This file is part of the Gnome Library.
8  *
9  * The Gnome Library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public License as
11  * published by the Free Software Foundation; either version 2 of the
12  * License, or (at your option) any later version.
13  *
14  * The Gnome Library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with the Gnome Library; see the file COPYING.LIB.  If not,
21  * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
22  * Boston, MA 02111-1307, USA.
23  */
24 /*
25   @NOTATION@
26  */
27 /* Text item type for GnomeCanvas widget
28  *
29  * GnomeCanvas is basically a port of the Tk toolkit's most excellent canvas
30  * widget.  Tk is copyrighted by the Regents of the University of California,
31  * Sun Microsystems, and other parties.
32  *
33  *
34  * Author: Federico Mena <federico@nuclecu.unam.mx>
35  * Port to Pango co-done by Gerg� �rdi <cactus@cactus.rulez.org>
36  */
37
38 #include <config.h>
39 #include <math.h>
40 #include <string.h>
41 #include "gnome-canvas-text.h"
42 #include <pango/pangoft2.h>
43
44 #include "libart_lgpl/art_affine.h"
45 #include "libart_lgpl/art_rgb_a_affine.h"
46 #include "libart_lgpl/art_rgb.h"
47 #include "libart_lgpl/art_rgb_bitmap_affine.h"
48 #include "gnome-canvas-util.h"
49 #include "gnome-canvas-i18n.h"
50
51 \f
52
53 /* Object argument IDs */
54 enum {
55         PROP_0,
56
57         /* Text contents */
58         PROP_TEXT,
59         PROP_MARKUP,
60
61         /* Position */
62         PROP_X,
63         PROP_Y,
64
65         /* Font */
66         PROP_FONT,
67         PROP_FONT_DESC,
68         PROP_FAMILY, PROP_FAMILY_SET,
69         
70         /* Style */
71         PROP_ATTRIBUTES,
72         PROP_STYLE,         PROP_STYLE_SET,
73         PROP_VARIANT,       PROP_VARIANT_SET,
74         PROP_WEIGHT,        PROP_WEIGHT_SET,
75         PROP_STRETCH,       PROP_STRETCH_SET,
76         PROP_SIZE,          PROP_SIZE_SET,
77         PROP_SIZE_POINTS,
78         PROP_STRIKETHROUGH, PROP_STRIKETHROUGH_SET,
79         PROP_UNDERLINE,     PROP_UNDERLINE_SET,
80         PROP_RISE,          PROP_RISE_SET,
81         PROP_SCALE,         PROP_SCALE_SET,
82
83         /* Clipping */
84         PROP_ANCHOR,
85         PROP_JUSTIFICATION,
86         PROP_CLIP_WIDTH,
87         PROP_CLIP_HEIGHT,
88         PROP_CLIP,
89         PROP_X_OFFSET,
90         PROP_Y_OFFSET,
91
92         /* Coloring */
93         PROP_FILL_COLOR,
94         PROP_FILL_COLOR_GDK,
95         PROP_FILL_COLOR_RGBA,
96         PROP_FILL_STIPPLE,
97
98         /* Rendered size accessors */
99         PROP_TEXT_WIDTH,
100         PROP_TEXT_HEIGHT
101 };
102
103 struct _GnomeCanvasTextPrivate {
104         guint render_dirty : 1;
105         FT_Bitmap bitmap;
106 };
107
108
109 static void gnome_canvas_text_class_init (GnomeCanvasTextClass *class);
110 static void gnome_canvas_text_init (GnomeCanvasText *text);
111 static void gnome_canvas_text_destroy (GtkObject *object);
112 static void gnome_canvas_text_set_property (GObject            *object,
113                                             guint               param_id,
114                                             const GValue       *value,
115                                             GParamSpec         *pspec);
116 static void gnome_canvas_text_get_property (GObject            *object,
117                                             guint               param_id,
118                                             GValue             *value,
119                                             GParamSpec         *pspec);
120
121 static void gnome_canvas_text_update (GnomeCanvasItem *item, double *affine,
122                                       ArtSVP *clip_path, int flags);
123 static void gnome_canvas_text_realize (GnomeCanvasItem *item);
124 static void gnome_canvas_text_unrealize (GnomeCanvasItem *item);
125 static void gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
126                                     int x, int y, int width, int height);
127 static double gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
128                                        GnomeCanvasItem **actual_item);
129 static void gnome_canvas_text_bounds (GnomeCanvasItem *item,
130                                       double *x1, double *y1, double *x2, double *y2);
131 static void gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
132
133 static void gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
134                                           const gchar     *markup);
135
136 static void gnome_canvas_text_set_font_desc    (GnomeCanvasText *textitem,
137                                                 PangoFontDescription *font_desc);
138
139 static void gnome_canvas_text_apply_font_desc  (GnomeCanvasText *textitem);
140 static void gnome_canvas_text_apply_attributes (GnomeCanvasText *textitem);
141
142 static void add_attr (PangoAttrList  *attr_list,
143                       PangoAttribute *attr);
144
145 static GnomeCanvasItemClass *parent_class;
146
147 \f
148
149 /**
150  * gnome_canvas_text_get_type:
151  * @void: 
152  * 
153  * Registers the &GnomeCanvasText class if necessary, and returns the type ID
154  * associated to it.
155  * 
156  * Return value: The type ID of the &GnomeCanvasText class.
157  **/
158 GType
159 gnome_canvas_text_get_type (void)
160 {
161         static GType text_type;
162
163         if (!text_type) {
164                 const GTypeInfo object_info = {
165                         sizeof (GnomeCanvasTextClass),
166                         (GBaseInitFunc) NULL,
167                         (GBaseFinalizeFunc) NULL,
168                         (GClassInitFunc) gnome_canvas_text_class_init,
169                         (GClassFinalizeFunc) NULL,
170                         NULL,                   /* class_data */
171                         sizeof (GnomeCanvasText),
172                         0,                      /* n_preallocs */
173                         (GInstanceInitFunc) gnome_canvas_text_init,
174                         NULL                    /* value_table */
175                 };
176
177                 text_type = g_type_register_static (GNOME_TYPE_CANVAS_ITEM, "GnomeCanvasText",
178                                                     &object_info, 0);
179         }
180
181         return text_type;
182 }
183
184 /* Class initialization function for the text item */
185 static void
186 gnome_canvas_text_class_init (GnomeCanvasTextClass *class)
187 {
188         GObjectClass *gobject_class;
189         GtkObjectClass *object_class;
190         GnomeCanvasItemClass *item_class;
191
192         gobject_class = (GObjectClass *) class;
193         object_class = (GtkObjectClass *) class;
194         item_class = (GnomeCanvasItemClass *) class;
195
196         parent_class = g_type_class_peek_parent (class);
197
198         gobject_class->set_property = gnome_canvas_text_set_property;
199         gobject_class->get_property = gnome_canvas_text_get_property;
200
201         /* Text */
202         g_object_class_install_property
203                 (gobject_class,
204                  PROP_TEXT,
205                  g_param_spec_string ("text",
206                                       _("Text"),
207                                       _("Text to render"),
208                                       NULL,
209                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
210
211         g_object_class_install_property
212                 (gobject_class,
213                  PROP_MARKUP,
214                  g_param_spec_string ("markup",
215                                       _("Markup"),
216                                       _("Marked up text to render"),
217                                       NULL,
218                                       (G_PARAM_WRITABLE)));
219
220         /* Position */
221         g_object_class_install_property
222                 (gobject_class,
223                  PROP_X,
224                  g_param_spec_double ("x", NULL, NULL,
225                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
226                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
227
228         g_object_class_install_property
229                 (gobject_class,
230                  PROP_Y,
231                  g_param_spec_double ("y", NULL, NULL,
232                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
233                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
234
235
236         /* Font */
237         g_object_class_install_property
238                 (gobject_class,
239                  PROP_FONT,
240                  g_param_spec_string ("font",
241                                       _("Font"),
242                                       _("Font description as a string"),
243                                       NULL,
244                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
245         
246         g_object_class_install_property
247                 (gobject_class,
248                  PROP_FONT_DESC,
249                  g_param_spec_boxed ("font_desc",
250                                      _("Font description"),
251                                      _("Font description as a PangoFontDescription struct"),
252                                      PANGO_TYPE_FONT_DESCRIPTION,
253                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
254
255         g_object_class_install_property
256                 (gobject_class,
257                  PROP_FAMILY,
258                  g_param_spec_string ("family",
259                                       _("Font family"),
260                                       _("Name of the font family, e.g. Sans, Helvetica, Times, Monospace"),
261                                       NULL,
262                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
263         
264         /* Style */
265         g_object_class_install_property
266                 (gobject_class,
267                  PROP_ATTRIBUTES,
268                  g_param_spec_boxed ("attributes", NULL, NULL,
269                                      PANGO_TYPE_ATTR_LIST,
270                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
271         
272         g_object_class_install_property
273                 (gobject_class,
274                  PROP_STYLE,
275                  g_param_spec_enum ("style",
276                                     _("Font style"),
277                                     _("Font style"),
278                                     PANGO_TYPE_STYLE,
279                                     PANGO_STYLE_NORMAL,
280                                     G_PARAM_READABLE | G_PARAM_WRITABLE));
281         
282         g_object_class_install_property
283                 (gobject_class,
284                  PROP_VARIANT,
285                  g_param_spec_enum ("variant",
286                                     _("Font variant"),
287                                     _("Font variant"),
288                                     PANGO_TYPE_VARIANT,
289                                     PANGO_VARIANT_NORMAL,
290                                     G_PARAM_READABLE | G_PARAM_WRITABLE));
291         
292         g_object_class_install_property
293                 (gobject_class,
294                  PROP_WEIGHT,
295                  g_param_spec_int ("weight",
296                                    _("Font weight"),
297                                    _("Font weight"),
298                                    0,
299                                    G_MAXINT,
300                                    PANGO_WEIGHT_NORMAL,
301                                    G_PARAM_READABLE | G_PARAM_WRITABLE));
302         
303         
304         g_object_class_install_property
305                 (gobject_class,
306                  PROP_STRETCH,
307                  g_param_spec_enum ("stretch",
308                                     _("Font stretch"),
309                                     _("Font stretch"),
310                                     PANGO_TYPE_STRETCH,
311                                     PANGO_STRETCH_NORMAL,
312                                     G_PARAM_READABLE | G_PARAM_WRITABLE));
313         
314         g_object_class_install_property
315                 (gobject_class,
316                  PROP_SIZE,
317                  g_param_spec_int ("size",
318                                    _("Font size"),
319                                    _("Font size (as a multiple of PANGO_SCALE, eg. 12*PANGO_SCALE for a 12pt font size)"),
320                                    0,
321                                    G_MAXINT,
322                                    0,
323                                    G_PARAM_READABLE | G_PARAM_WRITABLE));
324         
325         g_object_class_install_property
326                 (gobject_class,
327                 PROP_SIZE_POINTS,
328                 g_param_spec_double ("size_points",
329                                      _("Font points"),
330                                      _("Font size in points (eg. 12 for a 12pt font size)"),
331                                      0.0,
332                                      G_MAXDOUBLE,
333                                      0.0,
334                                      G_PARAM_READABLE | G_PARAM_WRITABLE));  
335         
336         g_object_class_install_property
337                 (gobject_class,
338                  PROP_RISE,
339                  g_param_spec_int ("rise",
340                                    _("Rise"),
341                                    _("Offset of text above the baseline (below the baseline if rise is negative)"),
342                                    -G_MAXINT,
343                                    G_MAXINT,
344                                    0,
345                                    G_PARAM_READABLE | G_PARAM_WRITABLE));
346         
347         g_object_class_install_property
348                 (gobject_class,
349                  PROP_STRIKETHROUGH,
350                  g_param_spec_boolean ("strikethrough",
351                                        _("Strikethrough"),
352                                        _("Whether to strike through the text"),
353                                        FALSE,
354                                        G_PARAM_READABLE | G_PARAM_WRITABLE));
355         
356         g_object_class_install_property
357                 (gobject_class,
358                  PROP_UNDERLINE,
359                  g_param_spec_enum ("underline",
360                                     _("Underline"),
361                                     _("Style of underline for this text"),
362                                     PANGO_TYPE_UNDERLINE,
363                                     PANGO_UNDERLINE_NONE,
364                                     G_PARAM_READABLE | G_PARAM_WRITABLE));
365
366         g_object_class_install_property
367                 (gobject_class,
368                  PROP_SCALE,
369                  g_param_spec_double ("scale",
370                                       _("Scale"),
371                                       _("Size of font, relative to default size"),
372                                       0.0,
373                                       G_MAXDOUBLE,
374                                       1.0,
375                                       G_PARAM_READABLE | G_PARAM_WRITABLE));  
376         
377         g_object_class_install_property
378                 (gobject_class,
379                  PROP_ANCHOR,
380                  g_param_spec_enum ("anchor", NULL, NULL,
381                                     GTK_TYPE_ANCHOR_TYPE,
382                                     GTK_ANCHOR_CENTER,
383                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
384         g_object_class_install_property
385                 (gobject_class,
386                  PROP_JUSTIFICATION,
387                  g_param_spec_enum ("justification", NULL, NULL,
388                                     GTK_TYPE_JUSTIFICATION,
389                                     GTK_JUSTIFY_LEFT,
390                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
391         g_object_class_install_property
392                 (gobject_class,
393                  PROP_CLIP_WIDTH,
394                  g_param_spec_double ("clip_width", NULL, NULL,
395                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
396                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
397         g_object_class_install_property
398                 (gobject_class,
399                  PROP_CLIP_HEIGHT,
400                  g_param_spec_double ("clip_height", NULL, NULL,
401                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
402                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
403         g_object_class_install_property
404                 (gobject_class,
405                  PROP_CLIP,
406                  g_param_spec_boolean ("clip", NULL, NULL,
407                                        FALSE,
408                                        (G_PARAM_READABLE | G_PARAM_WRITABLE)));
409         g_object_class_install_property
410                 (gobject_class,
411                  PROP_X_OFFSET,
412                  g_param_spec_double ("x_offset", NULL, NULL,
413                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
414                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
415         g_object_class_install_property
416                 (gobject_class,
417                  PROP_Y_OFFSET,
418                  g_param_spec_double ("y_offset", NULL, NULL,
419                                       -G_MAXDOUBLE, G_MAXDOUBLE, 0.0,
420                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
421         g_object_class_install_property
422                 (gobject_class,
423                  PROP_FILL_COLOR,
424                  g_param_spec_string ("fill_color",
425                                       _("Color"),
426                                       _("Text color, as string"),
427                                       NULL,
428                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
429         g_object_class_install_property
430                 (gobject_class,
431                  PROP_FILL_COLOR_GDK,
432                  g_param_spec_boxed ("fill_color_gdk",
433                                      _("Color"),
434                                      _("Text color, as a GdkColor"),
435                                      GDK_TYPE_COLOR,
436                                      (G_PARAM_READABLE | G_PARAM_WRITABLE)));
437         g_object_class_install_property
438                 (gobject_class,
439                  PROP_FILL_COLOR_RGBA,
440                  g_param_spec_uint ("fill_color_rgba",
441                                     _("Color"),
442                                     _("Text color, as an R/G/B/A combined integer"),
443                                     0, G_MAXUINT, 0,
444                                     (G_PARAM_READABLE | G_PARAM_WRITABLE)));
445         g_object_class_install_property
446                 (gobject_class,
447                  PROP_FILL_STIPPLE,
448                  g_param_spec_object ("fill_stipple", NULL, NULL,
449                                       GDK_TYPE_DRAWABLE,
450                                       (G_PARAM_READABLE | G_PARAM_WRITABLE)));
451         g_object_class_install_property
452                 (gobject_class,
453                  PROP_TEXT_WIDTH,
454                  g_param_spec_double ("text_width",
455                                       _("Text width"),
456                                       _("Width of the rendered text"),
457                                       0.0, G_MAXDOUBLE, 0.0,
458                                       G_PARAM_READABLE));
459         g_object_class_install_property
460                 (gobject_class,
461                  PROP_TEXT_HEIGHT,
462                  g_param_spec_double ("text_height",
463                                       _("Text height"),
464                                       _("Height of the rendered text"),
465                                       0.0, G_MAXDOUBLE, 0.0,
466                                       G_PARAM_READABLE));
467
468         /* Style props are set (explicitly applied) or not */
469 #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))
470
471         ADD_SET_PROP ("family_set", PROP_FAMILY_SET,
472                       _("Font family set"),
473                       _("Whether this tag affects the font family"));  
474         
475         ADD_SET_PROP ("style_set", PROP_STYLE_SET,
476                       _("Font style set"),
477                       _("Whether this tag affects the font style"));
478         
479         ADD_SET_PROP ("variant_set", PROP_VARIANT_SET,
480                       _("Font variant set"),
481                       _("Whether this tag affects the font variant"));
482         
483         ADD_SET_PROP ("weight_set", PROP_WEIGHT_SET,
484                       _("Font weight set"),
485                       _("Whether this tag affects the font weight"));
486         
487         ADD_SET_PROP ("stretch_set", PROP_STRETCH_SET,
488                       _("Font stretch set"),
489                       _("Whether this tag affects the font stretch"));
490         
491         ADD_SET_PROP ("size_set", PROP_SIZE_SET,
492                       _("Font size set"),
493                       _("Whether this tag affects the font size"));
494         
495         ADD_SET_PROP ("rise_set", PROP_RISE_SET,
496                       _("Rise set"),
497                       _("Whether this tag affects the rise"));
498         
499         ADD_SET_PROP ("strikethrough_set", PROP_STRIKETHROUGH_SET,
500                       _("Strikethrough set"),
501                       _("Whether this tag affects strikethrough"));
502         
503         ADD_SET_PROP ("underline_set", PROP_UNDERLINE_SET,
504                       _("Underline set"),
505                       _("Whether this tag affects underlining"));
506
507         ADD_SET_PROP ("scale_set", PROP_SCALE_SET,
508                       _("Scale set"),
509                       _("Whether this tag affects font scaling"));
510 #undef ADD_SET_PROP
511         
512         object_class->destroy = gnome_canvas_text_destroy;
513
514         item_class->update = gnome_canvas_text_update;
515         item_class->realize = gnome_canvas_text_realize;
516         item_class->unrealize = gnome_canvas_text_unrealize;
517         item_class->draw = gnome_canvas_text_draw;
518         item_class->point = gnome_canvas_text_point;
519         item_class->bounds = gnome_canvas_text_bounds;
520         item_class->render = gnome_canvas_text_render;
521 }
522
523 /* Object initialization function for the text item */
524 static void
525 gnome_canvas_text_init (GnomeCanvasText *text)
526 {
527         text->x = 0.0;
528         text->y = 0.0;
529         text->anchor = GTK_ANCHOR_CENTER;
530         text->justification = GTK_JUSTIFY_LEFT;
531         text->clip_width = 0.0;
532         text->clip_height = 0.0;
533         text->xofs = 0.0;
534         text->yofs = 0.0;
535         text->layout = NULL;
536
537         text->font_desc = NULL;
538         
539         text->underline     = PANGO_UNDERLINE_NONE;
540         text->strikethrough = FALSE;
541         text->rise          = 0;
542         
543         text->underline_set = FALSE;
544         text->strike_set    = FALSE;
545         text->rise_set      = FALSE;
546         
547         text->priv = g_new (GnomeCanvasTextPrivate, 1);
548         text->priv->bitmap.buffer = NULL;
549         text->priv->render_dirty = 1;
550 }
551
552 /* Destroy handler for the text item */
553 static void
554 gnome_canvas_text_destroy (GtkObject *object)
555 {
556         GnomeCanvasText *text;
557
558         g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
559
560         text = GNOME_CANVAS_TEXT (object);
561
562         /* remember, destroy can be run multiple times! */
563
564         g_free (text->text);
565         text->text = NULL;
566
567         if (text->layout)
568             g_object_unref (G_OBJECT (text->layout));
569         text->layout = NULL;
570         
571         if (text->font_desc) {
572                 pango_font_description_free (text->font_desc);
573                 text->font_desc = NULL;
574         }
575
576         if (text->attr_list)
577                 pango_attr_list_unref (text->attr_list);
578         text->attr_list = NULL;
579         
580         if (text->stipple)
581                 g_object_unref (text->stipple);
582         text->stipple = NULL;
583
584         if (text->priv && text->priv->bitmap.buffer) {
585                 g_free (text->priv->bitmap.buffer);             
586         }
587         g_free (text->priv);
588         text->priv = NULL;
589         
590         if (GTK_OBJECT_CLASS (parent_class)->destroy)
591                 (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
592 }
593
594 static void
595 get_bounds (GnomeCanvasText *text, double *px1, double *py1, double *px2, double *py2)
596 {
597         GnomeCanvasItem *item;
598         double wx, wy;
599
600         item = GNOME_CANVAS_ITEM (text);
601
602         /* Get canvas pixel coordinates for text position */
603
604         
605         wx = text->x;
606         wy = text->y;
607         gnome_canvas_item_i2w (item, &wx, &wy);
608         gnome_canvas_w2c (item->canvas, wx + text->xofs, wy + text->yofs, &text->cx, &text->cy);
609
610         /* Get canvas pixel coordinates for clip rectangle position */
611
612         gnome_canvas_w2c (item->canvas, wx, wy, &text->clip_cx, &text->clip_cy);
613         text->clip_cwidth = text->clip_width * item->canvas->pixels_per_unit;
614         text->clip_cheight = text->clip_height * item->canvas->pixels_per_unit;
615
616         /* Anchor text */
617
618         switch (text->anchor) {
619         case GTK_ANCHOR_NW:
620         case GTK_ANCHOR_W:
621         case GTK_ANCHOR_SW:
622                 break;
623
624         case GTK_ANCHOR_N:
625         case GTK_ANCHOR_CENTER:
626         case GTK_ANCHOR_S:
627                 text->cx -= text->max_width / 2;
628                 text->clip_cx -= text->clip_cwidth / 2;
629                 break;
630
631         case GTK_ANCHOR_NE:
632         case GTK_ANCHOR_E:
633         case GTK_ANCHOR_SE:
634                 text->cx -= text->max_width;
635                 text->clip_cx -= text->clip_cwidth;
636                 break;
637
638         default:
639                 break;
640         }
641
642         switch (text->anchor) {
643         case GTK_ANCHOR_NW:
644         case GTK_ANCHOR_N:
645         case GTK_ANCHOR_NE:
646                 break;
647
648         case GTK_ANCHOR_W:
649         case GTK_ANCHOR_CENTER:
650         case GTK_ANCHOR_E:
651                 text->cy -= text->height / 2;
652                 text->clip_cy -= text->clip_cheight / 2;
653                 break;
654
655         case GTK_ANCHOR_SW:
656         case GTK_ANCHOR_S:
657         case GTK_ANCHOR_SE:
658                 text->cy -= text->height;
659                 text->clip_cy -= text->clip_cheight;
660                 break;
661
662         default:
663                 break;
664         }
665
666         /* Bounds */
667
668         if (text->clip) {
669                 *px1 = text->clip_cx;
670                 *py1 = text->clip_cy;
671                 *px2 = text->clip_cx + text->clip_cwidth;
672                 *py2 = text->clip_cy + text->clip_cheight;
673         } else {
674                 *px1 = text->cx;
675                 *py1 = text->cy;
676                 *px2 = text->cx + text->max_width;
677                 *py2 = text->cy + text->height;
678         }
679 }
680
681 /* Convenience function to set the text's GC's foreground color */
682 static void
683 set_text_gc_foreground (GnomeCanvasText *text)
684 {
685         GdkColor c;
686
687         if (!text->gc)
688                 return;
689
690         c.pixel = text->pixel;
691         gdk_gc_set_foreground (text->gc, &c);
692 }
693
694 /* Sets the stipple pattern for the text */
695 static void
696 set_stipple (GnomeCanvasText *text, GdkBitmap *stipple, int reconfigure)
697 {
698         if (text->stipple && !reconfigure)
699                 g_object_unref (text->stipple);
700
701         text->stipple = stipple;
702         if (stipple && !reconfigure)
703                 g_object_ref (stipple);
704
705         if (text->gc) {
706                 if (stipple) {
707                         gdk_gc_set_stipple (text->gc, stipple);
708                         gdk_gc_set_fill (text->gc, GDK_STIPPLED);
709                 } else
710                         gdk_gc_set_fill (text->gc, GDK_SOLID);
711         }
712 }
713
714 static PangoFontMask
715 get_property_font_set_mask (guint prop_id)
716 {
717   switch (prop_id)
718     {
719     case PROP_FAMILY_SET:
720       return PANGO_FONT_MASK_FAMILY;
721     case PROP_STYLE_SET:
722       return PANGO_FONT_MASK_STYLE;
723     case PROP_VARIANT_SET:
724       return PANGO_FONT_MASK_VARIANT;
725     case PROP_WEIGHT_SET:
726       return PANGO_FONT_MASK_WEIGHT;
727     case PROP_STRETCH_SET:
728       return PANGO_FONT_MASK_STRETCH;
729     case PROP_SIZE_SET:
730       return PANGO_FONT_MASK_SIZE;
731     }
732
733   return 0;
734 }
735
736 static void
737 ensure_font (GnomeCanvasText *text)
738 {
739         if (!text->font_desc)
740                 text->font_desc = pango_font_description_new ();
741 }
742
743 /* Set_arg handler for the text item */
744 static void
745 gnome_canvas_text_set_property (GObject            *object,
746                                 guint               param_id,
747                                 const GValue       *value,
748                                 GParamSpec         *pspec)
749 {
750         GnomeCanvasItem *item;
751         GnomeCanvasText *text;
752         GdkColor color = { 0, 0, 0, 0, };
753         GdkColor *pcolor;
754         gboolean color_changed;
755         int have_pixel;
756         PangoAlignment align;
757
758         g_return_if_fail (object != NULL);
759         g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
760
761         item = GNOME_CANVAS_ITEM (object);
762         text = GNOME_CANVAS_TEXT (object);
763
764         color_changed = FALSE;
765         have_pixel = FALSE;
766         
767
768         if (!text->layout) {
769
770                 PangoContext *gtk_context, *context;
771                 gtk_context = gtk_widget_get_pango_context (GTK_WIDGET (item->canvas));
772                 
773                 if (item->canvas->aa)  {
774                         PangoLanguage *language;
775                         gint    pixels, mm;
776                         double  dpi_x;
777                         double  dpi_y;
778                         
779                         pixels = gdk_screen_width ();
780                         mm = gdk_screen_width_mm ();
781                         dpi_x = (((double) pixels * 25.4) / (double) mm);
782                         
783                         pixels = gdk_screen_height ();
784                         mm = gdk_screen_height_mm ();
785                         dpi_y = (((double) pixels * 25.4) / (double) mm);
786                         
787                         context = pango_ft2_get_context (dpi_x, dpi_y);
788                         language = pango_context_get_language (gtk_context);
789                         pango_context_set_language (context, language);
790                         pango_context_set_base_dir (context,
791                                                     pango_context_get_base_dir (gtk_context));
792                         pango_context_set_font_description (context,
793                                                             pango_context_get_font_description (gtk_context));
794                         
795                 } else
796                         context = gtk_context;
797                         
798
799                 text->layout = pango_layout_new (context);
800                 
801                 if (item->canvas->aa)
802                         g_object_unref (G_OBJECT (context));
803         }
804
805         switch (param_id) {
806         case PROP_TEXT:
807                 g_free (text->text);
808
809                 text->text = g_value_dup_string (value);
810                 pango_layout_set_text (text->layout, text->text, -1);
811
812                 text->priv->render_dirty = 1;
813                 break;
814
815         case PROP_MARKUP:
816                 gnome_canvas_text_set_markup (text,
817                                               g_value_get_string (value));
818                 text->priv->render_dirty = 1;
819                 break;
820
821         case PROP_X:
822                 text->x = g_value_get_double (value);
823                 break;
824
825         case PROP_Y:
826                 text->y = g_value_get_double (value);
827                 break;
828
829         case PROP_FONT: {
830                 const char *font_name;
831                 PangoFontDescription *font_desc;
832
833                 font_name = g_value_get_string (value);
834                 if (font_name)
835                         font_desc = pango_font_description_from_string (font_name);
836                 else
837                         font_desc = NULL;
838                 
839                 gnome_canvas_text_set_font_desc (text, font_desc);
840                 if (font_desc)
841                         pango_font_description_free (font_desc);
842
843                 break;
844         }
845
846         case PROP_FONT_DESC:
847                 gnome_canvas_text_set_font_desc (text, g_value_peek_pointer (value));
848                 break;
849
850         case PROP_FAMILY:
851         case PROP_STYLE:
852         case PROP_VARIANT:
853         case PROP_WEIGHT:
854         case PROP_STRETCH:
855         case PROP_SIZE:
856         case PROP_SIZE_POINTS:
857                 ensure_font (text);
858
859                 switch (param_id) {
860                 case PROP_FAMILY:
861                         pango_font_description_set_family (text->font_desc,
862                                                            g_value_get_string (value));
863                         break;
864                 case PROP_STYLE:
865                         pango_font_description_set_style (text->font_desc,
866                                                           g_value_get_enum (value));
867                         break;
868                 case PROP_VARIANT:
869                         pango_font_description_set_variant (text->font_desc,
870                                                             g_value_get_enum (value));
871                         break;
872                 case PROP_WEIGHT:
873                         pango_font_description_set_weight (text->font_desc,
874                                                            g_value_get_int (value));
875                         break;
876                 case PROP_STRETCH:
877                         pango_font_description_set_stretch (text->font_desc,
878                                                             g_value_get_enum (value));
879                         break;
880                 case PROP_SIZE:
881                         /* FIXME: This is bogus! It should be pixels, not points/PANGO_SCALE! */
882                         pango_font_description_set_size (text->font_desc,
883                                                          g_value_get_int (value));
884                         break;
885                 case PROP_SIZE_POINTS:
886                         pango_font_description_set_size (text->font_desc,
887                                                          g_value_get_double (value) * PANGO_SCALE);
888                         break;
889                 }
890                 
891                 gnome_canvas_text_apply_font_desc (text);
892                 text->priv->render_dirty = 1;
893                 break;
894
895         case PROP_FAMILY_SET:
896         case PROP_STYLE_SET:
897         case PROP_VARIANT_SET:
898         case PROP_WEIGHT_SET:
899         case PROP_STRETCH_SET:
900         case PROP_SIZE_SET:
901                 if (!g_value_get_boolean (value) && text->font_desc)
902                         pango_font_description_unset_fields (text->font_desc,
903                                                              get_property_font_set_mask (param_id));
904                 break;
905
906         case PROP_SCALE:
907                 text->scale = g_value_get_double (value);
908                 text->scale_set = TRUE;
909                 
910                 gnome_canvas_text_apply_font_desc (text);
911                 text->priv->render_dirty = 1;
912                 break;
913                 
914         case PROP_SCALE_SET:
915                 text->scale_set = g_value_get_boolean (value);
916                 
917                 gnome_canvas_text_apply_font_desc (text);
918                 text->priv->render_dirty = 1;
919                 break;          
920                 
921         case PROP_UNDERLINE:
922                 text->underline = g_value_get_enum (value);
923                 text->underline_set = TRUE;
924                 
925                 gnome_canvas_text_apply_attributes (text);
926                 text->priv->render_dirty = 1;
927                 break;
928
929         case PROP_UNDERLINE_SET:
930                 text->underline_set = g_value_get_boolean (value);
931                 
932                 gnome_canvas_text_apply_attributes (text);
933                 text->priv->render_dirty = 1;
934                 break;
935
936         case PROP_STRIKETHROUGH:
937                 text->strikethrough = g_value_get_boolean (value);
938                 text->strike_set = TRUE;
939                 
940                 gnome_canvas_text_apply_attributes (text);
941                 text->priv->render_dirty = 1;
942                 break;
943
944         case PROP_STRIKETHROUGH_SET:
945                 text->strike_set = g_value_get_boolean (value);
946                 
947                 gnome_canvas_text_apply_attributes (text);
948                 text->priv->render_dirty = 1;
949                 break;
950
951         case PROP_RISE:
952                 text->rise = g_value_get_int (value);
953                 text->rise_set = TRUE;
954                 
955                 gnome_canvas_text_apply_attributes (text);
956                 text->priv->render_dirty = 1;
957                 break;
958
959         case PROP_RISE_SET:
960                 text->rise_set = TRUE;
961                 
962                 gnome_canvas_text_apply_attributes (text);
963                 text->priv->render_dirty = 1;
964                 break;
965
966         case PROP_ATTRIBUTES:
967                 if (text->attr_list)
968                         pango_attr_list_unref (text->attr_list);
969
970                 text->attr_list = g_value_peek_pointer (value);
971                 pango_attr_list_ref (text->attr_list);
972                 
973                 gnome_canvas_text_apply_attributes (text);
974                 text->priv->render_dirty = 1;
975                 break;
976
977         case PROP_ANCHOR:
978                 text->anchor = g_value_get_enum (value);
979                 break;
980
981         case PROP_JUSTIFICATION:
982                 text->justification = g_value_get_enum (value);
983
984                 switch (text->justification) {
985                 case GTK_JUSTIFY_LEFT:
986                         align = PANGO_ALIGN_LEFT;
987                         break;
988                 case GTK_JUSTIFY_CENTER:
989                         align = PANGO_ALIGN_CENTER;
990                         break;
991                 case GTK_JUSTIFY_RIGHT:
992                         align = PANGO_ALIGN_RIGHT;
993                         break;
994                 default:
995                         /* GTK_JUSTIFY_FILL isn't supported yet. */
996                         align = PANGO_ALIGN_LEFT;
997                         break;
998                 }                 
999                 pango_layout_set_alignment (text->layout, align);
1000                 text->priv->render_dirty = 1;                           
1001                 break;
1002
1003         case PROP_CLIP_WIDTH:
1004                 text->clip_width = fabs (g_value_get_double (value));
1005                 text->priv->render_dirty = 1;                           
1006                 break;
1007
1008         case PROP_CLIP_HEIGHT:
1009                 text->clip_height = fabs (g_value_get_double (value));
1010                 text->priv->render_dirty = 1;                           
1011                 break;
1012
1013         case PROP_CLIP:
1014                 text->clip = g_value_get_boolean (value);
1015                 text->priv->render_dirty = 1;
1016                 break;
1017
1018         case PROP_X_OFFSET:
1019                 text->xofs = g_value_get_double (value);
1020                 break;
1021
1022         case PROP_Y_OFFSET:
1023                 text->yofs = g_value_get_double (value);
1024                 break;
1025
1026         case PROP_FILL_COLOR: {
1027                 const char *color_name;
1028
1029                 color_name = g_value_get_string (value);
1030                 if (color_name) {
1031                         gdk_color_parse (color_name, &color);
1032
1033                         text->rgba = ((color.red & 0xff00) << 16 |
1034                                       (color.green & 0xff00) << 8 |
1035                                       (color.blue & 0xff00) |
1036                                       0xff);
1037                         color_changed = TRUE;
1038                 }
1039                 text->priv->render_dirty = 1;
1040                 break;
1041         }
1042
1043         case PROP_FILL_COLOR_GDK:
1044                 pcolor = g_value_get_boxed (value);
1045                 if (pcolor) {
1046                     GdkColormap *colormap;
1047
1048                     color = *pcolor;
1049                     colormap = gtk_widget_get_colormap (GTK_WIDGET (item->canvas));
1050                     gdk_rgb_find_color (colormap, &color);
1051                     have_pixel = TRUE;
1052                 }
1053
1054                 text->rgba = ((color.red & 0xff00) << 16 |
1055                               (color.green & 0xff00) << 8|
1056                               (color.blue & 0xff00) |
1057                               0xff);
1058                 color_changed = TRUE;
1059                 break;
1060
1061         case PROP_FILL_COLOR_RGBA:
1062                 text->rgba = g_value_get_uint (value);
1063                 color_changed = TRUE;
1064                 text->priv->render_dirty = 1;
1065                 break;
1066
1067         case PROP_FILL_STIPPLE:
1068                 set_stipple (text, (GdkBitmap *)g_value_get_object (value), FALSE);
1069                 break;
1070
1071         default:
1072                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1073                 break;
1074         }
1075
1076         if (color_changed) {
1077                 if (have_pixel)
1078                         text->pixel = color.pixel;
1079                 else
1080                         text->pixel = gnome_canvas_get_color_pixel (item->canvas, text->rgba);
1081
1082                 if (!item->canvas->aa)
1083                         set_text_gc_foreground (text);
1084         }
1085
1086         /* Calculate text dimensions */
1087
1088         if (text->layout)
1089                 pango_layout_get_pixel_size (text->layout,
1090                                              &text->max_width,
1091                                              &text->height);
1092         else {
1093                 text->max_width = 0;
1094                 text->height = 0;
1095         }
1096         
1097         gnome_canvas_item_request_update (item);
1098 }
1099
1100 /* Get_arg handler for the text item */
1101 static void
1102 gnome_canvas_text_get_property (GObject            *object,
1103                                 guint               param_id,
1104                                 GValue             *value,
1105                                 GParamSpec         *pspec)
1106 {
1107         GnomeCanvasText *text;
1108
1109         g_return_if_fail (object != NULL);
1110         g_return_if_fail (GNOME_IS_CANVAS_TEXT (object));
1111
1112         text = GNOME_CANVAS_TEXT (object);
1113
1114         switch (param_id) {
1115         case PROP_TEXT:
1116                 g_value_set_string (value, text->text);
1117                 break;
1118
1119         case PROP_X:
1120                 g_value_set_double (value, text->x);
1121                 break;
1122
1123         case PROP_Y:
1124                 g_value_set_double (value, text->y);
1125                 break;
1126
1127         case PROP_FONT:
1128         case PROP_FONT_DESC:
1129         case PROP_FAMILY:
1130         case PROP_STYLE:
1131         case PROP_VARIANT:
1132         case PROP_WEIGHT:
1133         case PROP_STRETCH:
1134         case PROP_SIZE:
1135         case PROP_SIZE_POINTS:
1136                 ensure_font (text);
1137                 
1138                 switch (param_id) {
1139                 case PROP_FONT:
1140                 {
1141                         /* FIXME GValue imposes a totally gratuitous string copy
1142                          * here, we could just hand off string ownership
1143                          */
1144                         gchar *str;
1145                         
1146                         str = pango_font_description_to_string (text->font_desc);
1147                         g_value_set_string (value, str);
1148                         g_free (str);
1149
1150                         break;
1151                 }
1152                         
1153                 case PROP_FONT_DESC:
1154                         g_value_set_boxed (value, text->font_desc);
1155                         break;
1156
1157                 case PROP_FAMILY:
1158                         g_value_set_string (value, pango_font_description_get_family (text->font_desc));
1159                         break;
1160                         
1161                 case PROP_STYLE:
1162                         g_value_set_enum (value, pango_font_description_get_style (text->font_desc));
1163                         break;
1164                         
1165                 case PROP_VARIANT:
1166                         g_value_set_enum (value, pango_font_description_get_variant (text->font_desc));
1167                         break;
1168                         
1169                 case PROP_WEIGHT:
1170                         g_value_set_int (value, pango_font_description_get_weight (text->font_desc));
1171                         break;
1172                         
1173                 case PROP_STRETCH:
1174                         g_value_set_enum (value, pango_font_description_get_stretch (text->font_desc));
1175                         break;
1176                         
1177                 case PROP_SIZE:
1178                         g_value_set_int (value, pango_font_description_get_size (text->font_desc));
1179                         break;
1180                         
1181                 case PROP_SIZE_POINTS:
1182                         g_value_set_double (value, ((double)pango_font_description_get_size (text->font_desc)) / (double)PANGO_SCALE);
1183                         break;
1184                 }
1185                 break;
1186
1187         case PROP_FAMILY_SET:
1188         case PROP_STYLE_SET:
1189         case PROP_VARIANT_SET:
1190         case PROP_WEIGHT_SET:
1191         case PROP_STRETCH_SET:
1192         case PROP_SIZE_SET:
1193         {
1194                 PangoFontMask set_mask = text->font_desc ? pango_font_description_get_set_fields (text->font_desc) : 0;
1195                 PangoFontMask test_mask = get_property_font_set_mask (param_id);
1196                 g_value_set_boolean (value, (set_mask & test_mask) != 0);
1197
1198                 break;
1199         }
1200
1201         case PROP_SCALE:
1202                 g_value_set_double (value, text->scale);
1203                 break;
1204         case PROP_SCALE_SET:
1205                 g_value_set_boolean (value, text->scale_set);
1206                 break;
1207                 
1208         case PROP_UNDERLINE:
1209                 g_value_set_enum (value, text->underline);
1210                 break;
1211         case PROP_UNDERLINE_SET:
1212                 g_value_set_boolean (value, text->underline_set);
1213                 break;
1214                 
1215         case PROP_STRIKETHROUGH:
1216                 g_value_set_boolean (value, text->strikethrough);
1217                 break;
1218         case PROP_STRIKETHROUGH_SET:
1219                 g_value_set_boolean (value, text->strike_set);
1220                 break;
1221                 
1222         case PROP_RISE:
1223                 g_value_set_int (value, text->rise);
1224                 break;
1225         case PROP_RISE_SET:
1226                 g_value_set_boolean (value, text->rise_set);
1227                 break;
1228                 
1229         case PROP_ATTRIBUTES:
1230                 g_value_set_boxed (value, text->attr_list);
1231                 break;
1232
1233         case PROP_ANCHOR:
1234                 g_value_set_enum (value, text->anchor);
1235                 break;
1236
1237         case PROP_JUSTIFICATION:
1238                 g_value_set_enum (value, text->justification);
1239                 break;
1240
1241         case PROP_CLIP_WIDTH:
1242                 g_value_set_double (value, text->clip_width);
1243                 break;
1244
1245         case PROP_CLIP_HEIGHT:
1246                 g_value_set_double (value, text->clip_height);
1247                 break;
1248
1249         case PROP_CLIP:
1250                 g_value_set_boolean (value, text->clip);
1251                 break;
1252
1253         case PROP_X_OFFSET:
1254                 g_value_set_double (value, text->xofs);
1255                 break;
1256
1257         case PROP_Y_OFFSET:
1258                 g_value_set_double (value, text->yofs);
1259                 break;
1260
1261         case PROP_FILL_COLOR:
1262                 g_value_take_string (value,
1263                                      g_strdup_printf ("#%02x%02x%02x",
1264                                      text->rgba >> 24,
1265                                      (text->rgba >> 16) & 0xff,
1266                                      (text->rgba >> 8) & 0xff));
1267                 break;
1268
1269         case PROP_FILL_COLOR_GDK: {
1270                 GnomeCanvas *canvas = GNOME_CANVAS_ITEM (text)->canvas;
1271                 GdkColormap *colormap = gtk_widget_get_colormap (GTK_WIDGET (canvas));
1272                 GdkColor color;
1273
1274                 gdk_colormap_query_color (colormap, text->pixel, &color);
1275                 g_value_set_boxed (value, &color);
1276                 break;
1277         }
1278         case PROP_FILL_COLOR_RGBA:
1279                 g_value_set_uint (value, text->rgba);
1280                 break;
1281
1282         case PROP_FILL_STIPPLE:
1283                 g_value_set_object (value, text->stipple);
1284                 break;
1285
1286         case PROP_TEXT_WIDTH:
1287                 g_value_set_double (value, text->max_width / text->item.canvas->pixels_per_unit);
1288                 break;
1289
1290         case PROP_TEXT_HEIGHT:
1291                 g_value_set_double (value, text->height / text->item.canvas->pixels_per_unit);
1292                 break;
1293
1294         default:
1295                 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
1296                 break;
1297         }
1298 }
1299
1300 /* */
1301 static void
1302 gnome_canvas_text_apply_font_desc (GnomeCanvasText *text)
1303 {
1304         PangoFontDescription *font_desc =
1305                 pango_font_description_copy (
1306                         GTK_WIDGET (GNOME_CANVAS_ITEM (text)->canvas)->style->font_desc);
1307
1308         if (text->font_desc)
1309                 pango_font_description_merge (font_desc, text->font_desc, TRUE);
1310
1311         pango_layout_set_font_description (text->layout, font_desc);
1312         pango_font_description_free (font_desc);
1313 }
1314
1315 static void
1316 add_attr (PangoAttrList  *attr_list,
1317           PangoAttribute *attr)
1318 {
1319         attr->start_index = 0;
1320         attr->end_index = G_MAXINT;
1321
1322         pango_attr_list_insert (attr_list, attr);
1323 }
1324
1325 /* */
1326 static void
1327 gnome_canvas_text_apply_attributes (GnomeCanvasText *text)
1328 {
1329         PangoAttrList *attr_list;
1330
1331         if (text->attr_list)
1332                 attr_list = pango_attr_list_copy (text->attr_list);
1333         else
1334                 attr_list = pango_attr_list_new ();
1335         
1336         if (text->underline_set)
1337                 add_attr (attr_list, pango_attr_underline_new (text->underline));
1338         if (text->strike_set)
1339                 add_attr (attr_list, pango_attr_strikethrough_new (text->strikethrough));
1340         if (text->rise_set)
1341                 add_attr (attr_list, pango_attr_rise_new (text->rise));
1342         
1343         pango_layout_set_attributes (text->layout, attr_list);
1344         pango_attr_list_unref (attr_list);
1345 }
1346
1347 static void
1348 gnome_canvas_text_set_font_desc (GnomeCanvasText      *text,
1349                                  PangoFontDescription *font_desc)
1350 {
1351         if (text->font_desc)
1352                 pango_font_description_free (text->font_desc);
1353
1354         if (font_desc)
1355                 text->font_desc = pango_font_description_copy (font_desc);
1356         else
1357                 text->font_desc = NULL;
1358
1359         gnome_canvas_text_apply_font_desc (text);
1360         text->priv->render_dirty = 1;
1361 }
1362
1363 /* Setting the text from a Pango markup string */
1364 static void
1365 gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
1366                               const gchar     *markup)
1367 {
1368         PangoAttrList *attr_list = NULL;
1369         gchar         *text = NULL;
1370         GError        *error = NULL;
1371
1372         if (markup && !pango_parse_markup (markup, -1,
1373                                            0,
1374                                            &attr_list, &text, NULL,
1375                                            &error))
1376         {
1377                 g_warning ("Failed to set cell text from markup due to error parsing markup: %s",
1378                            error->message);
1379                 g_error_free (error);
1380                 return;
1381         }
1382
1383         g_free (textitem->text);
1384         if (textitem->attr_list)
1385                 pango_attr_list_unref (textitem->attr_list);
1386
1387         textitem->text = text;
1388         textitem->attr_list = attr_list;
1389
1390         pango_layout_set_text (textitem->layout, text, -1);
1391
1392         gnome_canvas_text_apply_attributes (textitem);
1393 }
1394
1395 /* Update handler for the text item */
1396 static void
1397 gnome_canvas_text_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
1398 {
1399         GnomeCanvasText *text;
1400         double x1, y1, x2, y2;
1401
1402         text = GNOME_CANVAS_TEXT (item);
1403
1404         if (parent_class->update)
1405                 (* parent_class->update) (item, affine, clip_path, flags);
1406
1407         set_text_gc_foreground (text);
1408         set_stipple (text, text->stipple, TRUE);
1409         get_bounds (text, &x1, &y1, &x2, &y2);
1410
1411         gnome_canvas_update_bbox (item,
1412                                   floor (x1), floor (y1),
1413                                   ceil (x2), ceil (y2));
1414 }
1415
1416 /* Realize handler for the text item */
1417 static void
1418 gnome_canvas_text_realize (GnomeCanvasItem *item)
1419 {
1420         GnomeCanvasText *text;
1421
1422         text = GNOME_CANVAS_TEXT (item);
1423
1424         if (parent_class->realize)
1425                 (* parent_class->realize) (item);
1426
1427         text->gc = gdk_gc_new (item->canvas->layout.bin_window);
1428 }
1429
1430 /* Unrealize handler for the text item */
1431 static void
1432 gnome_canvas_text_unrealize (GnomeCanvasItem *item)
1433 {
1434         GnomeCanvasText *text;
1435
1436         text = GNOME_CANVAS_TEXT (item);
1437
1438         g_object_unref (text->gc);
1439         text->gc = NULL;
1440
1441         if (parent_class->unrealize)
1442                 (* parent_class->unrealize) (item);
1443 }
1444
1445 /* Draw handler for the text item */
1446 static void
1447 gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
1448                         int x, int y, int width, int height)
1449 {
1450         GnomeCanvasText *text;
1451         GdkRectangle rect;
1452
1453         text = GNOME_CANVAS_TEXT (item);
1454
1455         if (!text->text)
1456                 return;
1457
1458         if (text->clip) {
1459                 rect.x = text->clip_cx - x;
1460                 rect.y = text->clip_cy - y;
1461                 rect.width = text->clip_cwidth;
1462                 rect.height = text->clip_cheight;
1463
1464                 gdk_gc_set_clip_rectangle (text->gc, &rect);
1465         }
1466
1467         if (text->stipple)
1468                 gnome_canvas_set_stipple_origin (item->canvas, text->gc);
1469
1470
1471         gdk_draw_layout (drawable, text->gc, text->cx - x, text->cy - y, text->layout);
1472
1473         if (text->clip)
1474                 gdk_gc_set_clip_rectangle (text->gc, NULL);
1475 }
1476
1477
1478 /* Render handler for the text item */
1479 static void
1480 gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
1481 {
1482         GnomeCanvasText *text;
1483         guint32 fg_color;
1484         int render_x = 0, render_y = 0; /* offsets for text rendering,
1485                                          * for clipping rectangles */
1486         int x, y;
1487         int w, h;
1488         guchar *dst, *src;
1489         int src_dx, src_dy;
1490         int i, alpha;
1491         int bm_rows, bm_width;
1492         
1493         text = GNOME_CANVAS_TEXT (item);
1494
1495         if (!text->text)
1496                 return;
1497
1498         fg_color = text->rgba;
1499
1500         gnome_canvas_buf_ensure_buf (buf);
1501
1502         bm_rows = (text->clip) ? text->clip_cheight : text->height;
1503         bm_width = (text->clip) ? text->clip_cwidth : text->max_width;
1504         if(text->priv->render_dirty ||
1505            bm_rows != text->priv->bitmap.rows ||
1506            bm_width != text->priv->bitmap.width) {              
1507                 if(text->priv->bitmap.buffer) {
1508                         g_free(text->priv->bitmap.buffer);
1509                 }
1510                 text->priv->bitmap.rows =  bm_rows;
1511                 text->priv->bitmap.width = bm_width;
1512                 text->priv->bitmap.pitch = (text->priv->bitmap.width+3)&~3;
1513                 text->priv->bitmap.buffer = g_malloc0 (text->priv->bitmap.rows * text->priv->bitmap.pitch);
1514                 text->priv->bitmap.num_grays = 256;
1515                 text->priv->bitmap.pixel_mode = ft_pixel_mode_grays;
1516
1517                 /* What this does is when a clipping rectangle is
1518                    being used shift the rendering of the text by the
1519                    correct amount so that the correct result is
1520                    obtained as if all text was rendered, then clipped.
1521                    In this sense we can use smaller buffers and less
1522                    rendeirng since hopefully FreeType2 checks to see
1523                    if the glyph falls in the bounding box before
1524                    rasterizing it. */
1525
1526                 if(text->clip) {
1527                         render_x = text->cx - text->clip_cx;
1528                         render_y = text->cy - text->clip_cy;
1529                 }
1530
1531                 pango_ft2_render_layout (&text->priv->bitmap, text->layout, render_x, render_y);
1532
1533                 text->priv->render_dirty = 0;
1534         }
1535
1536         if (text->clip) {
1537                 x = text->clip_cx - buf->rect.x0;
1538                 y = text->clip_cy - buf->rect.y0;
1539         } else {
1540                 x = text->cx - buf->rect.x0;
1541                 y = text->cy - buf->rect.y0;
1542         }
1543                 
1544         w = text->priv->bitmap.width;
1545         h = text->priv->bitmap.rows;
1546
1547         src_dx = src_dy = 0;
1548         
1549         if (x + w > buf->rect.x1 - buf->rect.x0) {
1550                 w = buf->rect.x1 - buf->rect.x0 - x;
1551         }
1552         
1553         if (y + h > buf->rect.y1 - buf->rect.y0) {
1554                 h = buf->rect.y1 - buf->rect.y0 - y;
1555         }
1556
1557         if (x < 0) {
1558                 w -= - x;
1559                 src_dx += - x;
1560                 x = 0;
1561         }
1562         
1563         if (y < 0) {
1564                 h -= -y;
1565                 src_dy += - y;
1566                 y = 0;
1567         }
1568         
1569         dst = buf->buf + y * buf->buf_rowstride + x * 3;
1570         src = text->priv->bitmap.buffer +
1571                 src_dy * text->priv->bitmap.pitch + src_dx;
1572         while (h-- > 0) {
1573                 i = w;
1574                 while (i-- > 0) {
1575                         /* FIXME: Do the libart thing instead of divide by 255 */
1576                         alpha = ((fg_color & 0xff) * (*src)) / 255;
1577                         dst[0] = (dst[0] * (255 - alpha) + ((fg_color >> 24) & 0xff) * alpha) / 255;
1578                         dst[1] = (dst[1] * (255 - alpha) + ((fg_color >> 16) & 0xff) * alpha) / 255;
1579                         dst[2] = (dst[2] * (255 - alpha) + ((fg_color >> 8) & 0xff) * alpha) / 255;
1580                         dst += 3;
1581                         src += 1;
1582                 }
1583                 dst += buf->buf_rowstride - w*3;
1584                 src += text->priv->bitmap.pitch - w;
1585         }
1586         
1587         buf->is_bg = 0;
1588         return;
1589 }
1590
1591 /* Point handler for the text item */
1592 static double
1593 gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y,
1594                          int cx, int cy, GnomeCanvasItem **actual_item)
1595 {
1596         GnomeCanvasText *text;
1597         PangoLayoutIter *iter;
1598         int x1, y1, x2, y2;
1599         int dx, dy;
1600         double dist, best;
1601
1602         text = GNOME_CANVAS_TEXT (item);
1603
1604         *actual_item = item;
1605
1606         /* The idea is to build bounding rectangles for each of the lines of
1607          * text (clipped by the clipping rectangle, if it is activated) and see
1608          * whether the point is inside any of these.  If it is, we are done.
1609          * Otherwise, calculate the distance to the nearest rectangle.
1610          */
1611
1612         best = 1.0e36;
1613
1614         iter = pango_layout_get_iter (text->layout);
1615         do {
1616                 PangoRectangle log_rect;
1617
1618                 pango_layout_iter_get_line_extents (iter, NULL, &log_rect);
1619                                 
1620                 x1 = text->cx + PANGO_PIXELS (log_rect.x);
1621                 y1 = text->cy + PANGO_PIXELS (log_rect.y);
1622                 x2 = x1 + PANGO_PIXELS (log_rect.width);
1623                 y2 = y1 + PANGO_PIXELS (log_rect.height);
1624
1625                 if (text->clip) {
1626                         if (x1 < text->clip_cx)
1627                                 x1 = text->clip_cx;
1628
1629                         if (y1 < text->clip_cy)
1630                                 y1 = text->clip_cy;
1631
1632                         if (x2 > (text->clip_cx + text->clip_width))
1633                                 x2 = text->clip_cx + text->clip_width;
1634
1635                         if (y2 > (text->clip_cy + text->clip_height))
1636                                 y2 = text->clip_cy + text->clip_height;
1637
1638                         if ((x1 >= x2) || (y1 >= y2))
1639                                 continue;
1640                 }
1641
1642                 /* Calculate distance from point to rectangle */
1643
1644                 if (cx < x1)
1645                         dx = x1 - cx;
1646                 else if (cx >= x2)
1647                         dx = cx - x2 + 1;
1648                 else
1649                         dx = 0;
1650
1651                 if (cy < y1)
1652                         dy = y1 - cy;
1653                 else if (cy >= y2)
1654                         dy = cy - y2 + 1;
1655                 else
1656                         dy = 0;
1657
1658                 if ((dx == 0) && (dy == 0)) {
1659                         pango_layout_iter_free(iter);
1660                         return 0.0;
1661                 }
1662
1663                 dist = sqrt (dx * dx + dy * dy);
1664                 if (dist < best)
1665                         best = dist;
1666                 
1667         } while (pango_layout_iter_next_line(iter));
1668
1669         pango_layout_iter_free(iter);
1670         
1671         return best / item->canvas->pixels_per_unit;
1672 }
1673
1674 /* Bounds handler for the text item */
1675 static void
1676 gnome_canvas_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1677 {
1678         GnomeCanvasText *text;
1679         double width, height;
1680
1681         text = GNOME_CANVAS_TEXT (item);
1682
1683         *x1 = text->x;
1684         *y1 = text->y;
1685
1686         if (text->clip) {
1687                 width = text->clip_width;
1688                 height = text->clip_height;
1689         } else {
1690                 width = text->max_width / item->canvas->pixels_per_unit;
1691                 height = text->height / item->canvas->pixels_per_unit;
1692         }
1693
1694         switch (text->anchor) {
1695         case GTK_ANCHOR_NW:
1696         case GTK_ANCHOR_W:
1697         case GTK_ANCHOR_SW:
1698                 break;
1699
1700         case GTK_ANCHOR_N:
1701         case GTK_ANCHOR_CENTER:
1702         case GTK_ANCHOR_S:
1703                 *x1 -= width / 2.0;
1704                 break;
1705
1706         case GTK_ANCHOR_NE:
1707         case GTK_ANCHOR_E:
1708         case GTK_ANCHOR_SE:
1709                 *x1 -= width;
1710                 break;
1711
1712         default:
1713                 break;
1714         }
1715
1716         switch (text->anchor) {
1717         case GTK_ANCHOR_NW:
1718         case GTK_ANCHOR_N:
1719         case GTK_ANCHOR_NE:
1720                 break;
1721
1722         case GTK_ANCHOR_W:
1723         case GTK_ANCHOR_CENTER:
1724         case GTK_ANCHOR_E:
1725                 *y1 -= height / 2.0;
1726                 break;
1727
1728         case GTK_ANCHOR_SW:
1729         case GTK_ANCHOR_S:
1730         case GTK_ANCHOR_SE:
1731                 *y1 -= height;
1732                 break;
1733
1734         default:
1735                 break;
1736         }
1737
1738         *x2 = *x1 + width;
1739         *y2 = *y1 + height;     
1740 }