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