source: trunk/third/libgnomecanvas/libgnomecanvas/gnome-canvas-text.c @ 18323

Revision 18323, 44.0 KB checked in by ghudson, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18322, which included commits to RCS files with non-trunk default branches.
Line 
1/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2/*
3 * $Id: gnome-canvas-text.c,v 1.1.1.1 2003-01-04 19:43:26 ghudson Exp $
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
52
53/* Object argument IDs */
54enum {
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
103struct _GnomeCanvasTextPrivate {
104        guint render_dirty : 1;
105        FT_Bitmap bitmap;
106};
107
108
109static void gnome_canvas_text_class_init (GnomeCanvasTextClass *class);
110static void gnome_canvas_text_init (GnomeCanvasText *text);
111static void gnome_canvas_text_destroy (GtkObject *object);
112static void gnome_canvas_text_set_property (GObject            *object,
113                                            guint               param_id,
114                                            const GValue       *value,
115                                            GParamSpec         *pspec);
116static void gnome_canvas_text_get_property (GObject            *object,
117                                            guint               param_id,
118                                            GValue             *value,
119                                            GParamSpec         *pspec);
120
121static void gnome_canvas_text_update (GnomeCanvasItem *item, double *affine,
122                                      ArtSVP *clip_path, int flags);
123static void gnome_canvas_text_realize (GnomeCanvasItem *item);
124static void gnome_canvas_text_unrealize (GnomeCanvasItem *item);
125static void gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
126                                    int x, int y, int width, int height);
127static double gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y, int cx, int cy,
128                                       GnomeCanvasItem **actual_item);
129static void gnome_canvas_text_bounds (GnomeCanvasItem *item,
130                                      double *x1, double *y1, double *x2, double *y2);
131static void gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf);
132
133static void gnome_canvas_text_set_markup (GnomeCanvasText *textitem,
134                                          const gchar     *markup);
135
136static void gnome_canvas_text_set_font_desc    (GnomeCanvasText *textitem,
137                                                PangoFontDescription *font_desc);
138
139static void gnome_canvas_text_apply_font_desc  (GnomeCanvasText *textitem);
140static void gnome_canvas_text_apply_attributes (GnomeCanvasText *textitem);
141
142static void add_attr (PangoAttrList  *attr_list,
143                      PangoAttribute *attr);
144
145static GnomeCanvasItemClass *parent_class;
146
147
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 **/
158GType
159gnome_canvas_text_get_type (void)
160{
161        static GType text_type;
162
163        if (!text_type) {
164                static 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 */
185static void
186gnome_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"),
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"),
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 | G_PARAM_WRITABLE)));
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 | G_PARAM_WRITABLE)));
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 */
524static void
525gnome_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 */
553static void
554gnome_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                gdk_bitmap_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
594static void
595get_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 */
682static void
683set_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 */
695static void
696set_stipple (GnomeCanvasText *text, GdkBitmap *stipple, int reconfigure)
697{
698        if (text->stipple && !reconfigure)
699                gdk_bitmap_unref (text->stipple);
700
701        text->stipple = stipple;
702        if (stipple && !reconfigure)
703                gdk_bitmap_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
714static PangoFontMask
715get_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
736static void
737ensure_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 */
744static void
745gnome_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                if (text->text)
808                        g_free (text->text);
809
810                text->text = g_value_dup_string (value);
811                pango_layout_set_text (text->layout, text->text, -1);
812
813                text->priv->render_dirty = 1;
814                break;
815
816        case PROP_MARKUP:
817                gnome_canvas_text_set_markup (text,
818                                              g_value_get_string (value));
819                text->priv->render_dirty = 1;
820                break;
821
822        case PROP_X:
823                text->x = g_value_get_double (value);
824                break;
825
826        case PROP_Y:
827                text->y = g_value_get_double (value);
828                break;
829
830        case PROP_FONT: {
831                const char *font_name;
832                PangoFontDescription *font_desc;
833
834                font_name = g_value_get_string (value);
835                if (font_name)
836                        font_desc = pango_font_description_from_string (font_name);
837                else
838                        font_desc = NULL;
839               
840                gnome_canvas_text_set_font_desc (text, font_desc);
841                if (font_desc)
842                        pango_font_description_free (font_desc);
843
844                break;
845        }
846
847        case PROP_FONT_DESC:
848                gnome_canvas_text_set_font_desc (text, g_value_peek_pointer (value));
849                break;
850
851        case PROP_FAMILY:
852        case PROP_STYLE:
853        case PROP_VARIANT:
854        case PROP_WEIGHT:
855        case PROP_STRETCH:
856        case PROP_SIZE:
857        case PROP_SIZE_POINTS:
858                ensure_font (text);
859
860                switch (param_id) {
861                case PROP_FAMILY:
862                        pango_font_description_set_family (text->font_desc,
863                                                           g_value_get_string (value));
864                        break;
865                case PROP_STYLE:
866                        pango_font_description_set_style (text->font_desc,
867                                                          g_value_get_enum (value));
868                        break;
869                case PROP_VARIANT:
870                        pango_font_description_set_variant (text->font_desc,
871                                                            g_value_get_enum (value));
872                        break;
873                case PROP_WEIGHT:
874                        pango_font_description_set_weight (text->font_desc,
875                                                           g_value_get_int (value));
876                        break;
877                case PROP_STRETCH:
878                        pango_font_description_set_stretch (text->font_desc,
879                                                            g_value_get_enum (value));
880                        break;
881                case PROP_SIZE:
882                        /* FIXME: This is bogus! It should be pixels, not points/PANGO_SCALE! */
883                        pango_font_description_set_size (text->font_desc,
884                                                         g_value_get_int (value));
885                        break;
886                case PROP_SIZE_POINTS:
887                        pango_font_description_set_size (text->font_desc,
888                                                         g_value_get_double (value) * PANGO_SCALE);
889                        break;
890                }
891               
892                gnome_canvas_text_apply_font_desc (text);
893                text->priv->render_dirty = 1;
894                break;
895
896        case PROP_FAMILY_SET:
897        case PROP_STYLE_SET:
898        case PROP_VARIANT_SET:
899        case PROP_WEIGHT_SET:
900        case PROP_STRETCH_SET:
901        case PROP_SIZE_SET:
902                if (!g_value_get_boolean (value) && text->font_desc)
903                        pango_font_description_unset_fields (text->font_desc,
904                                                             get_property_font_set_mask (param_id));
905                break;
906
907        case PROP_SCALE:
908                text->scale = g_value_get_double (value);
909                text->scale_set = TRUE;
910               
911                gnome_canvas_text_apply_font_desc (text);
912                text->priv->render_dirty = 1;
913                break;
914               
915        case PROP_SCALE_SET:
916                text->scale_set = g_value_get_boolean (value);
917               
918                gnome_canvas_text_apply_font_desc (text);
919                text->priv->render_dirty = 1;
920                break;         
921               
922        case PROP_UNDERLINE:
923                text->underline = g_value_get_enum (value);
924                text->underline_set = TRUE;
925               
926                gnome_canvas_text_apply_attributes (text);
927                text->priv->render_dirty = 1;
928                break;
929
930        case PROP_UNDERLINE_SET:
931                text->underline_set = g_value_get_boolean (value);
932               
933                gnome_canvas_text_apply_attributes (text);
934                text->priv->render_dirty = 1;
935                break;
936
937        case PROP_STRIKETHROUGH:
938                text->strikethrough = g_value_get_boolean (value);
939                text->strike_set = TRUE;
940               
941                gnome_canvas_text_apply_attributes (text);
942                text->priv->render_dirty = 1;
943                break;
944
945        case PROP_STRIKETHROUGH_SET:
946                text->strike_set = g_value_get_boolean (value);
947               
948                gnome_canvas_text_apply_attributes (text);
949                text->priv->render_dirty = 1;
950                break;
951
952        case PROP_RISE:
953                text->rise = g_value_get_int (value);
954                text->rise_set = TRUE;
955               
956                gnome_canvas_text_apply_attributes (text);
957                text->priv->render_dirty = 1;
958                break;
959
960        case PROP_RISE_SET:
961                text->rise_set = TRUE;
962               
963                gnome_canvas_text_apply_attributes (text);
964                text->priv->render_dirty = 1;
965                break;
966
967        case PROP_ATTRIBUTES:
968                if (text->attr_list)
969                        pango_attr_list_unref (text->attr_list);
970
971                text->attr_list = g_value_peek_pointer (value);
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 */
1101static void
1102gnome_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_set_string_take_ownership (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/* */
1301static void
1302gnome_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
1315static void
1316add_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/* */
1326static void
1327gnome_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
1347static void
1348gnome_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 */
1364static void
1365gnome_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 (textitem->text)
1373                g_free (textitem->text);
1374        if (textitem->attr_list)
1375                pango_attr_list_unref (textitem->attr_list);
1376
1377        if (markup && !pango_parse_markup (markup, -1,
1378                                           0,
1379                                           &attr_list, &text, NULL,
1380                                           &error))
1381        {
1382                g_warning ("Failed to set cell text from markup due to error parsing markup: %s",
1383                           error->message);
1384                g_error_free (error);
1385                return;
1386        }
1387
1388        textitem->text = text;
1389        textitem->attr_list = attr_list;
1390
1391        pango_layout_set_text (textitem->layout, text, -1);
1392
1393        gnome_canvas_text_apply_attributes (textitem);
1394}
1395
1396/* Update handler for the text item */
1397static void
1398gnome_canvas_text_update (GnomeCanvasItem *item, double *affine, ArtSVP *clip_path, int flags)
1399{
1400        GnomeCanvasText *text;
1401        double x1, y1, x2, y2;
1402
1403        text = GNOME_CANVAS_TEXT (item);
1404
1405        if (parent_class->update)
1406                (* parent_class->update) (item, affine, clip_path, flags);
1407
1408        set_text_gc_foreground (text);
1409        set_stipple (text, text->stipple, TRUE);
1410        get_bounds (text, &x1, &y1, &x2, &y2);
1411
1412        gnome_canvas_update_bbox (item,
1413                                  floor (x1), floor (y1),
1414                                  ceil (x2), ceil (y2));
1415}
1416
1417/* Realize handler for the text item */
1418static void
1419gnome_canvas_text_realize (GnomeCanvasItem *item)
1420{
1421        GnomeCanvasText *text;
1422
1423        text = GNOME_CANVAS_TEXT (item);
1424
1425        if (parent_class->realize)
1426                (* parent_class->realize) (item);
1427
1428        text->gc = gdk_gc_new (item->canvas->layout.bin_window);
1429}
1430
1431/* Unrealize handler for the text item */
1432static void
1433gnome_canvas_text_unrealize (GnomeCanvasItem *item)
1434{
1435        GnomeCanvasText *text;
1436
1437        text = GNOME_CANVAS_TEXT (item);
1438
1439        gdk_gc_unref (text->gc);
1440        text->gc = NULL;
1441
1442        if (parent_class->unrealize)
1443                (* parent_class->unrealize) (item);
1444}
1445
1446/* Draw handler for the text item */
1447static void
1448gnome_canvas_text_draw (GnomeCanvasItem *item, GdkDrawable *drawable,
1449                        int x, int y, int width, int height)
1450{
1451        GnomeCanvasText *text;
1452        GdkRectangle rect;
1453
1454        text = GNOME_CANVAS_TEXT (item);
1455
1456        if (!text->text)
1457                return;
1458
1459        if (text->clip) {
1460                rect.x = text->clip_cx - x;
1461                rect.y = text->clip_cy - y;
1462                rect.width = text->clip_cwidth;
1463                rect.height = text->clip_cheight;
1464
1465                gdk_gc_set_clip_rectangle (text->gc, &rect);
1466        }
1467
1468        if (text->stipple)
1469                gnome_canvas_set_stipple_origin (item->canvas, text->gc);
1470
1471
1472        gdk_draw_layout (drawable, text->gc, text->cx - x, text->cy - y, text->layout);
1473
1474        if (text->clip)
1475                gdk_gc_set_clip_rectangle (text->gc, NULL);
1476}
1477
1478
1479/* Render handler for the text item */
1480static void
1481gnome_canvas_text_render (GnomeCanvasItem *item, GnomeCanvasBuf *buf)
1482{
1483        GnomeCanvasText *text;
1484        guint32 fg_color;
1485        int render_x = 0, render_y = 0; /* offsets for text rendering,
1486                                         * for clipping rectangles */
1487        int x, y;
1488        int w, h;
1489        guchar *dst, *src;
1490        int src_dx, src_dy;
1491        int i, alpha;
1492        int bm_rows, bm_width;
1493       
1494        text = GNOME_CANVAS_TEXT (item);
1495
1496        if (!text->text)
1497                return;
1498
1499        fg_color = text->rgba;
1500
1501        gnome_canvas_buf_ensure_buf (buf);
1502
1503        bm_rows = (text->clip) ? text->clip_cheight : text->height;
1504        bm_width = (text->clip) ? text->clip_cwidth : text->max_width;
1505        if(text->priv->render_dirty ||
1506           bm_rows != text->priv->bitmap.rows ||
1507           bm_width != text->priv->bitmap.width) {             
1508                if(text->priv->bitmap.buffer) {
1509                        g_free(text->priv->bitmap.buffer);
1510                }
1511                text->priv->bitmap.rows =  bm_rows;
1512                text->priv->bitmap.width = bm_width;
1513                text->priv->bitmap.pitch = (text->priv->bitmap.width+3)&~3;
1514                text->priv->bitmap.buffer = g_malloc0 (text->priv->bitmap.rows * text->priv->bitmap.pitch);
1515                text->priv->bitmap.num_grays = 256;
1516                text->priv->bitmap.pixel_mode = ft_pixel_mode_grays;
1517
1518                /* What this does is when a clipping rectangle is
1519                   being used shift the rendering of the text by the
1520                   correct amount so that the correct result is
1521                   obtained as if all text was rendered, then clipped.
1522                   In this sense we can use smaller buffers and less
1523                   rendeirng since hopefully FreeType2 checks to see
1524                   if the glyph falls in the bounding box before
1525                   rasterizing it. */
1526
1527                if(text->clip) {
1528                        render_x = text->cx - text->clip_cx;
1529                        render_y = text->cy - text->clip_cy;
1530                }
1531
1532                pango_ft2_render_layout (&text->priv->bitmap, text->layout, render_x, render_y);
1533
1534                text->priv->render_dirty = 0;
1535        }
1536
1537        if (text->clip) {
1538                x = text->clip_cx - buf->rect.x0;
1539                y = text->clip_cy - buf->rect.y0;
1540        } else {
1541                x = text->cx - buf->rect.x0;
1542                y = text->cy - buf->rect.y0;
1543        }
1544               
1545        w = text->priv->bitmap.width;
1546        h = text->priv->bitmap.rows;
1547
1548        src_dx = src_dy = 0;
1549       
1550        if (x + w > buf->rect.x1 - buf->rect.x0) {
1551                w = buf->rect.x1 - buf->rect.x0 - x;
1552        }
1553       
1554        if (y + h > buf->rect.y1 - buf->rect.y0) {
1555                h = buf->rect.y1 - buf->rect.y0 - y;
1556        }
1557
1558        if (x < 0) {
1559                w -= - x;
1560                src_dx += - x;
1561                x = 0;
1562        }
1563       
1564        if (y < 0) {
1565                h -= -y;
1566                src_dy += - y;
1567                y = 0;
1568        }
1569       
1570        dst = buf->buf + y * buf->buf_rowstride + x * 3;
1571        src = text->priv->bitmap.buffer +
1572                src_dy * text->priv->bitmap.pitch + src_dx;
1573        while (h-- > 0) {
1574                i = w;
1575                while (i-- > 0) {
1576                        /* FIXME: Do the libart thing instead of divide by 255 */
1577                        alpha = ((fg_color & 0xff) * (*src)) / 255;
1578                        dst[0] = (dst[0] * (255 - alpha) + ((fg_color >> 24) & 0xff) * alpha) / 255;
1579                        dst[1] = (dst[1] * (255 - alpha) + ((fg_color >> 16) & 0xff) * alpha) / 255;
1580                        dst[2] = (dst[2] * (255 - alpha) + ((fg_color >> 8) & 0xff) * alpha) / 255;
1581                        dst += 3;
1582                        src += 1;
1583                }
1584                dst += buf->buf_rowstride - w*3;
1585                src += text->priv->bitmap.pitch - w;
1586        }
1587       
1588        buf->is_bg = 0;
1589        return;
1590}
1591
1592/* Point handler for the text item */
1593static double
1594gnome_canvas_text_point (GnomeCanvasItem *item, double x, double y,
1595                         int cx, int cy, GnomeCanvasItem **actual_item)
1596{
1597        GnomeCanvasText *text;
1598        PangoLayoutIter *iter;
1599        int x1, y1, x2, y2;
1600        int dx, dy;
1601        double dist, best;
1602
1603        text = GNOME_CANVAS_TEXT (item);
1604
1605        *actual_item = item;
1606
1607        /* The idea is to build bounding rectangles for each of the lines of
1608         * text (clipped by the clipping rectangle, if it is activated) and see
1609         * whether the point is inside any of these.  If it is, we are done.
1610         * Otherwise, calculate the distance to the nearest rectangle.
1611         */
1612
1613        best = 1.0e36;
1614
1615        iter = pango_layout_get_iter (text->layout);
1616        do {
1617                PangoRectangle log_rect;
1618
1619                pango_layout_iter_get_line_extents (iter, NULL, &log_rect);
1620                               
1621                if (text->clip) {
1622                        x1 = PANGO_PIXELS (log_rect.x);
1623                        y1 = PANGO_PIXELS (log_rect.y);
1624                        x2 = PANGO_PIXELS (log_rect.x+log_rect.width);
1625                        y2 = PANGO_PIXELS (log_rect.y+log_rect.height);
1626
1627
1628                        if (x1 < text->clip_cx)
1629                                x1 = text->clip_cx;
1630
1631                        if (y1 < text->clip_cy)
1632                                y1 = text->clip_cy;
1633
1634                        if (x2 > (text->clip_cx + text->clip_width))
1635                                x2 = text->clip_cx + text->clip_width;
1636
1637                        if (y2 > (text->clip_cy + text->clip_height))
1638                                y2 = text->clip_cy + text->clip_height;
1639
1640                        if ((x1 >= x2) || (y1 >= y2))
1641                                continue;
1642                } else {
1643                        x1 = text->x;
1644                        y1 = text->y;
1645                        x2 = log_rect.width;
1646                        y2 = log_rect.height;                   
1647                }
1648
1649                /* Calculate distance from point to rectangle */
1650
1651                if (cx < x1)
1652                        dx = x1 - cx;
1653                else if (cx >= x2)
1654                        dx = cx - x2 + 1;
1655                else
1656                        dx = 0;
1657
1658                if (cy < y1)
1659                        dy = y1 - cy;
1660                else if (cy >= y2)
1661                        dy = cy - y2 + 1;
1662                else
1663                        dy = 0;
1664
1665                if ((dx == 0) && (dy == 0)) {
1666                        pango_layout_iter_free(iter);
1667                        return 0.0;
1668                }
1669
1670                dist = sqrt (dx * dx + dy * dy);
1671                if (dist < best)
1672                        best = dist;
1673               
1674        } while (pango_layout_iter_next_line(iter));
1675
1676        pango_layout_iter_free(iter);
1677       
1678        return best / item->canvas->pixels_per_unit;
1679}
1680
1681/* Bounds handler for the text item */
1682static void
1683gnome_canvas_text_bounds (GnomeCanvasItem *item, double *x1, double *y1, double *x2, double *y2)
1684{
1685        GnomeCanvasText *text;
1686        double width, height;
1687
1688        text = GNOME_CANVAS_TEXT (item);
1689
1690        *x1 = text->x;
1691        *y1 = text->y;
1692
1693        if (text->clip) {
1694                width = text->clip_width;
1695                height = text->clip_height;
1696        } else {
1697                width = text->max_width / item->canvas->pixels_per_unit;
1698                height = text->height / item->canvas->pixels_per_unit;
1699        }
1700
1701        switch (text->anchor) {
1702        case GTK_ANCHOR_NW:
1703        case GTK_ANCHOR_W:
1704        case GTK_ANCHOR_SW:
1705                break;
1706
1707        case GTK_ANCHOR_N:
1708        case GTK_ANCHOR_CENTER:
1709        case GTK_ANCHOR_S:
1710                *x1 -= width / 2.0;
1711                break;
1712
1713        case GTK_ANCHOR_NE:
1714        case GTK_ANCHOR_E:
1715        case GTK_ANCHOR_SE:
1716                *x1 -= width;
1717                break;
1718
1719        default:
1720                break;
1721        }
1722
1723        switch (text->anchor) {
1724        case GTK_ANCHOR_NW:
1725        case GTK_ANCHOR_N:
1726        case GTK_ANCHOR_NE:
1727                break;
1728
1729        case GTK_ANCHOR_W:
1730        case GTK_ANCHOR_CENTER:
1731        case GTK_ANCHOR_E:
1732                *y1 -= height / 2.0;
1733                break;
1734
1735        case GTK_ANCHOR_SW:
1736        case GTK_ANCHOR_S:
1737        case GTK_ANCHOR_SE:
1738                *y1 -= height;
1739                break;
1740
1741        default:
1742                break;
1743        }
1744
1745        *x2 = *x1 + width;
1746        *y2 = *y1 + height;     
1747}
Note: See TracBrowser for help on using the repository browser.