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 
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 
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
gnome_canvas_text_get_type(void)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
gnome_canvas_text_class_init(GnomeCanvasTextClass * class)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
gnome_canvas_text_init(GnomeCanvasText * text)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
gnome_canvas_text_destroy(GtkObject * object)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
get_bounds(GnomeCanvasText * text,double * px1,double * py1,double * px2,double * py2)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
set_text_gc_foreground(GnomeCanvasText * text)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
set_stipple(GnomeCanvasText * text,GdkBitmap * stipple,int reconfigure)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
get_property_font_set_mask(guint prop_id)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
ensure_font(GnomeCanvasText * text)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
gnome_canvas_text_set_property(GObject * object,guint param_id,const GValue * value,GParamSpec * pspec)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
gnome_canvas_text_get_property(GObject * object,guint param_id,GValue * value,GParamSpec * pspec)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
gnome_canvas_text_apply_font_desc(GnomeCanvasText * text)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
add_attr(PangoAttrList * attr_list,PangoAttribute * attr)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
gnome_canvas_text_apply_attributes(GnomeCanvasText * text)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
gnome_canvas_text_set_font_desc(GnomeCanvasText * text,PangoFontDescription * font_desc)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
gnome_canvas_text_set_markup(GnomeCanvasText * textitem,const gchar * markup)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
gnome_canvas_text_update(GnomeCanvasItem * item,double * affine,ArtSVP * clip_path,int flags)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
gnome_canvas_text_realize(GnomeCanvasItem * item)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
gnome_canvas_text_unrealize(GnomeCanvasItem * item)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
gnome_canvas_text_draw(GnomeCanvasItem * item,GdkDrawable * drawable,int x,int y,int width,int height)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
gnome_canvas_text_render(GnomeCanvasItem * item,GnomeCanvasBuf * buf)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
gnome_canvas_text_point(GnomeCanvasItem * item,double x,double y,int cx,int cy,GnomeCanvasItem ** actual_item)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
gnome_canvas_text_bounds(GnomeCanvasItem * item,double * x1,double * y1,double * x2,double * y2)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 }
1741