[goffice] Use pango attributes for formatting.



commit 2c5547c8901ce9ed0c649c09bbc947c4ae662055
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Mon Aug 1 21:05:30 2011 -0600

    Use pango attributes for formatting.
    
    2011-08-01  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* configure.in: disable gtk depreciation check
    	* goffice/graph/gog-axis-line.c: replace ticks.labels with ticks.str
    	throughout;
    	gog_renderer_get_text_OBR with gog_renderer_get_gostring_OBR, and
    	gog_renderer_draw_text with gog_renderer_draw_gostring as required
    	byt he ticks change
    	* goffice/graph/gog-axis.c replace ticks.labels with ticks.str
    	throughout and use gog_axis_ticks_set_text to initialize
    	(gog_get_layout): new
    	(gog_axis_ticks_set_text): new
    	(axis_format_value): add GOString argument and change all callers
    	* goffice/graph/gog-axis.h: replace ticks.labels with ticks.str
    	* goffice/graph/gog-renderer.c (gog_renderer_draw_gostring): new
    	(gog_renderer_draw_text): use gog_renderer_draw_gostring
    	(gog_renderer_get_gostring_OBR): new
    	(gog_renderer_get_text_OBR): use gog_renderer_get_gostring_OBR
    	(gog_renderer_get_gostring_OBR): new
    	* goffice/graph/gog-renderer.h (gog_renderer_draw_gostring): new
    	* goffice/gtk/go-format-sel.c (generate_preview): use PangoAttrList
    	(draw_format_preview): ditto
    	(nfs_init): create buffer tags
    	* goffice/utils/go-format.c (go_format_parse_number_E): use attributes
    	(go_format_execute): use attributes
    	(go_format_value_gstring): use attributes instead of passing colour
    	* goffice/utils/go-pango-extras.c
    	(go_load_pango_attributes_into_buffer_filter): new
    	(go_load_pango_attributes_into_buffer_named_filter): new
    	(go_create_std_tags_for_buffer): new
    	(go_load_pango_byte_to_char): new
    	(go_load_pango_attributes_into_buffer): new
    	* goffice/utils/go-pango-extras.h (go_create_std_tags_for_buffer): new
    	(go_load_pango_attributes_into_buffer): new
    	* goffice/utils/go-string.c (go_string_new_rich): ensure we have determined
    	the byte_len (if it was negative or zero)

 ChangeLog                       |   37 ++++++
 NEWS                            |    3 +
 configure.in                    |    2 +-
 goffice/canvas/goc-graph.c      |    3 +-
 goffice/graph/gog-axis-line.c   |   38 ++++---
 goffice/graph/gog-axis.c        |   89 ++++++++++-----
 goffice/graph/gog-axis.h        |    4 +-
 goffice/graph/gog-renderer.c    |  143 ++++++++++++++++++------
 goffice/graph/gog-renderer.h    |   10 ++-
 goffice/gtk/go-format-sel.c     |   25 ++--
 goffice/utils/go-format.c       |  161 ++++++++++++++++++++++-----
 goffice/utils/go-pango-extras.c |  233 +++++++++++++++++++++++++++++++++++++++
 goffice/utils/go-pango-extras.h |    6 +
 goffice/utils/go-string.c       |    4 +-
 14 files changed, 632 insertions(+), 126 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 1f791ee..fbe616c 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,40 @@
+2011-08-01  Andreas J. Guelzow <aguelzow pyrshep ca>
+
+	* configure.in: disable gtk depreciation check
+	* goffice/graph/gog-axis-line.c: replace ticks.labels with ticks.str
+	throughout;
+	gog_renderer_get_text_OBR with gog_renderer_get_gostring_OBR, and
+	gog_renderer_draw_text with gog_renderer_draw_gostring as required
+	byt he ticks change
+	* goffice/graph/gog-axis.c replace ticks.labels with ticks.str
+	throughout and use gog_axis_ticks_set_text to initialize
+	(gog_get_layout): new
+	(gog_axis_ticks_set_text): new
+	(axis_format_value): add GOString argument and change all callers
+	* goffice/graph/gog-axis.h: replace ticks.labels with ticks.str
+	* goffice/graph/gog-renderer.c (gog_renderer_draw_gostring): new
+	(gog_renderer_draw_text): use gog_renderer_draw_gostring
+	(gog_renderer_get_gostring_OBR): new
+	(gog_renderer_get_text_OBR): use gog_renderer_get_gostring_OBR
+	(gog_renderer_get_gostring_OBR): new
+	* goffice/graph/gog-renderer.h (gog_renderer_draw_gostring): new
+	* goffice/gtk/go-format-sel.c (generate_preview): use PangoAttrList
+	(draw_format_preview): ditto
+	(nfs_init): create buffer tags
+	* goffice/utils/go-format.c (go_format_parse_number_E): use attributes
+	(go_format_execute): use attributes
+	(go_format_value_gstring): use attributes instead of passing colour
+	* goffice/utils/go-pango-extras.c
+	(go_load_pango_attributes_into_buffer_filter): new
+	(go_load_pango_attributes_into_buffer_named_filter): new
+	(go_create_std_tags_for_buffer): new
+	(go_load_pango_byte_to_char): new
+	(go_load_pango_attributes_into_buffer): new
+	* goffice/utils/go-pango-extras.h (go_create_std_tags_for_buffer): new
+	(go_load_pango_attributes_into_buffer): new
+	* goffice/utils/go-string.c (go_string_new_rich): ensure we have determined
+	the byte_len (if it was negative or zero)
+
 2011-08-01  Morten Welinder <terra gnome org>
 
 	* configure.in: Branch to 0.9.0.
diff --git a/NEWS b/NEWS
index f54d893..00b1d06 100644
--- a/NEWS
+++ b/NEWS
@@ -1,5 +1,8 @@
 goffice 0.9.0:
 
+Andreas:
+	* Use pango attributes for formatting.
+
 --------------------------------------------------------------------------
 goffice 0.8.17:
 
diff --git a/configure.in b/configure.in
index 12eaf5c..d71b962 100644
--- a/configure.in
+++ b/configure.in
@@ -306,7 +306,7 @@ fi
 
 dnl disable for in stable release, re-enable for development series
 gtk_disable_deprecated=no
-if test $goffice_devel = yes; then
+if test XXX$goffice_devel = yes; then
 	CFLAGS="$CFLAGS -DG_DISABLE_DEPRECATED"
 	CFLAGS="$CFLAGS -DPANGO_DISABLE_DEPRECATED"
 	if test "x$goffice_with_gtk" = "xtrue"; then
diff --git a/goffice/canvas/goc-graph.c b/goffice/canvas/goc-graph.c
index ed84eb6..163b87d 100644
--- a/goffice/canvas/goc-graph.c
+++ b/goffice/canvas/goc-graph.c
@@ -235,8 +235,7 @@ format_coordinate (GogAxis *axis, GOFormat *fmt, double x)
 		 go_format_measure_strlen,
 		 go_font_metrics_unit,
 		 fmt,
-		 x, 'F', NULL,
-		 NULL,
+		 x, 'F', NULL, NULL,
 		 width, date_conv, TRUE);
 	if (err) {
 		/* Invalid number for format.  */
diff --git a/goffice/graph/gog-axis-line.c b/goffice/graph/gog-axis-line.c
index da30abc..26ffcfa 100644
--- a/goffice/graph/gog-axis-line.c
+++ b/goffice/graph/gog-axis-line.c
@@ -1054,9 +1054,9 @@ axis_line_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
 
 	obrs = g_new0 (GOGeometryOBR, tick_nbr);
 	for (i = 0; i < tick_nbr; i++) {
-		if (ticks[i].label != NULL) {
+		if (ticks[i].str != NULL) {
 			GOGeometryOBR *obr = obrs + i;
-			gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, obr);
+			gog_renderer_get_gostring_OBR (renderer, ticks[i].str, obr);
 			if (obr->w > label_size_max
 			    || obr->h > label_size_max) {
 				label_size_max = MAX (obr->w, obr->h);
@@ -1066,7 +1066,7 @@ axis_line_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
 	}
 
 	for (i = 0; i < tick_nbr; i++) {
-		if (ticks[i].label != NULL) {
+		if (ticks[i].str != NULL) {
 			GOGeometryOBR *obr = obrs + i;
 			pos = gog_axis_map_to_view (map, ticks[i].position);
 			obr->w += label_padding;
@@ -1166,9 +1166,9 @@ axis_line_render (GogAxisBase *axis_base,
 		obrs = g_new0 (GOGeometryOBR, tick_nbr);
 		indexmap = g_new0 (unsigned int, tick_nbr);
 		for (i = 0; i < tick_nbr; i++) {
-			if (ticks[i].label != NULL) {
+			if (ticks[i].str != NULL) {
 				GOGeometryOBR *obr = obrs + i;
-				gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, obr);
+				gog_renderer_get_gostring_OBR (renderer, ticks[i].str, obr);
 				if (obr->w > label_size_max
 				    || obr->h > label_size_max) {
 					label_size_max = MAX (obr->w, obr->h);
@@ -1216,7 +1216,7 @@ axis_line_render (GogAxisBase *axis_base,
 			}
 		}
 
-		if (ticks[i].label != NULL && draw_labels) {
+		if (ticks[i].str != NULL && draw_labels) {
 			GOGeometryOBR *obr = obrs + i;
 			obr->w += label_padding;
 			go_geometry_calc_label_position (obr, axis_angle, tick_len,
@@ -1267,9 +1267,8 @@ axis_line_render (GogAxisBase *axis_base,
 			GogViewAllocation label_pos;
 			label_pos.x = obrs[j].x;
 			label_pos.y = obrs[j].y;
-			gog_renderer_draw_text (renderer, ticks[j].label,
-						&label_pos, GTK_ANCHOR_CENTER,
-						TRUE);
+			gog_renderer_draw_gostring (renderer, ticks[j].str,
+						    &label_pos, GTK_ANCHOR_CENTER);
 		}
 	}
 	g_free (obrs);
@@ -1338,8 +1337,8 @@ axis_circle_get_bbox (GogAxisBase *axis_base, GogRenderer *renderer,
 		angle = gog_axis_map_to_view (map, ticks[i].position);
 		gog_chart_map_2D_to_view (c_map, ticks[i].position, position, &x, &y);
 
-		if (ticks[i].label != NULL && draw_labels) {
-			gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, &txt_obr);
+		if (ticks[i].str != NULL && draw_labels) {
+			gog_renderer_get_gostring_OBR (renderer, ticks[i].str, &txt_obr);
 			txt_obr.w += label_padding;
 			go_geometry_calc_label_position (&txt_obr, angle + M_PI / 2.0, tick_len,
 							 GO_SIDE_LEFT, GO_SIDE_AUTO);
@@ -1460,10 +1459,10 @@ axis_circle_render (GogAxisBase *axis_base, GogRenderer *renderer,
 			}
 		}
 
-		if (ticks[i].label != NULL && draw_labels) {
+		if (ticks[i].str != NULL && draw_labels) {
 			gog_chart_map_2D_to_view (c_map, ticks[i].position, position,
 						  &label_pos.x, &label_pos.y);
-			gog_renderer_get_text_OBR (renderer, ticks[i].label, TRUE, &txt_obr);
+			gog_renderer_get_gostring_OBR (renderer, ticks[i].str, &txt_obr);
 			txt_obr.w += label_padding;
 			go_geometry_calc_label_position (&txt_obr, angle + M_PI / 2.0, tick_len,
 							 GO_SIDE_LEFT, GO_SIDE_AUTO);
@@ -1474,8 +1473,9 @@ axis_circle_render (GogAxisBase *axis_base, GogRenderer *renderer,
 			if (!first_label_done ||
 			    (!go_geometry_test_OBR_overlap (&txt_obr, &txt_obr_old) &&
 			     !go_geometry_test_OBR_overlap (&txt_obr, &txt_obr_first))) {
-				gog_renderer_draw_text (renderer, ticks[i].label,
-							&label_pos, GTK_ANCHOR_CENTER, TRUE);
+				gog_renderer_draw_gostring 
+					(renderer, ticks[i].str,
+					 &label_pos, GTK_ANCHOR_CENTER);
 				txt_obr_old = txt_obr;
 			}
 			if (!first_label_done) {
@@ -2061,10 +2061,12 @@ xyz_process (GogAxisBaseAction action, GogView *view, GogViewPadding *padding,
 			if (axis_base->major_tick_labeled) {
 				label_w = label_h = 0;
 				for (i = 0; i < tick_nbr; i++) {
-					if (ticks[i].label == NULL)
+					if (ticks[i].str == NULL)
 						continue;
-					gog_renderer_get_text_OBR (view->renderer,
-						ticks[i].label, TRUE, &obr);
+					gog_renderer_get_text_OBR 
+						(view->renderer,
+						 ticks[i].str->str, 
+						 FALSE, &obr);
 					if (obr.w > label_w)
 						label_w = obr.w;
 					if (obr.h > label_h)
diff --git a/goffice/graph/gog-axis.c b/goffice/graph/gog-axis.c
index 4762c67..79bbe17 100644
--- a/goffice/graph/gog-axis.c
+++ b/goffice/graph/gog-axis.c
@@ -105,6 +105,22 @@ struct _GogAxis {
 
 static void gog_axis_set_ticks (GogAxis *axis,int tick_nbr, GogAxisTick *ticks);
 
+static PangoLayout *
+gog_get_layout (void)
+{
+	PangoContext *context = pango_context_new ();
+	PangoLayout *layout = pango_layout_new (context);
+	g_object_unref (context);
+	return layout;
+}
+
+static void
+gog_axis_ticks_set_text (GogAxisTick *ticks, char const *str)
+{
+	go_string_unref (ticks->str);
+	ticks->str = go_string_new (str);
+}
+
 static GogAxisTick *
 create_invalid_axis_ticks (double min, double max)
 {
@@ -114,8 +130,9 @@ create_invalid_axis_ticks (double min, double max)
 	ticks[0].position = min;
 	ticks[1].position = max;
 	ticks[0].type = ticks[1].type = GOG_AXIS_TICK_MAJOR;
-	ticks[0].label = g_strdup ("##");
-	ticks[1].label = g_strdup ("##");
+	ticks[0].str = ticks[1].str = NULL;
+	gog_axis_ticks_set_text (&ticks[0], "##");
+	gog_axis_ticks_set_text (&ticks[1], "##");
 
 	return ticks;
 }
@@ -139,26 +156,36 @@ gog_axis_get_effective_format (GogAxis const *axis)
 	return axis->format;
 }
 
-static char *
-axis_format_value (GogAxis *axis, double val)
+static void
+axis_format_value (GogAxis *axis, double val, GOString **str)
 {
 	GOFormat *fmt = gog_axis_get_effective_format (axis);
-	GString *res = g_string_sized_new (20);
 	const GODateConventions *date_conv = axis->date_conv;
-	GOFormatNumberError err = go_format_value_gstring
-		(NULL, res,
+	GOFormatNumberError err;
+	PangoLayout *layout = gog_get_layout ();
+
+	g_return_if_fail (layout != NULL);
+
+	go_string_unref (*str);
+
+	err = go_format_value_gstring
+		(layout, NULL,
 		 go_format_measure_strlen,
 		 go_font_metrics_unit,
 		 fmt,
-		 val, 'F', NULL,
-		 NULL,
+		 val, 'F', NULL, NULL,
 		 -1, date_conv, TRUE);
-	if (err) {
-		/* Invalid number for format.  */
-		g_string_assign (res, "#####");
-	}
-
-	return g_string_free (res, FALSE);
+	if (err)
+		*str = go_string_new ("#####");
+	else
+		*str = go_string_new_rich 
+			(g_strdup (pango_layout_get_text (layout)),
+			 -1,
+			 FALSE,
+			 pango_attr_list_ref (pango_layout_get_attributes (layout)),
+			 NULL);
+	
+	g_object_unref (layout);
 }
 
 static gboolean
@@ -345,22 +372,25 @@ map_discrete_calc_ticks (GogAxis *axis)
 	for (i = 0; i < tick_nbr; i++) {
 		ticks[i].position = tick_start + (double) (i) * major_tick;
 		ticks[i].type = GOG_AXIS_TICK_MAJOR;
-		ticks[i].label = NULL;
+		ticks[i].str = NULL;
 	}
 	for (i = 0, j = tick_nbr; i < label_nbr; i++, j++) {
+		char *label;
 		ticks[j].position = go_rint (label_start + (double) (i) * major_label);
 		index = ticks[j].position - 1;
 		ticks[j].type = GOG_AXIS_TICK_NONE;
+		ticks[j].str = NULL;
 		if (axis->labels != NULL) {
 			if (index < (int) go_data_get_vector_size (axis->labels) && index >= 0) {
-				char *label = go_data_get_vector_string (axis->labels, index);
-				ticks[j].label = g_markup_escape_text (label, -1);
+				label = go_data_get_vector_string (axis->labels, index);
+				gog_axis_ticks_set_text(&ticks[j], label);
 				g_free (label);
-			} else
-				ticks[j].label = NULL;
+			}
+		} else {
+			label = g_strdup_printf ("%d", index + 1);
+			gog_axis_ticks_set_text (&ticks[j], label);
+			g_free (label);
 		}
-		else
-			ticks[j].label = g_strdup_printf ("%d", index + 1);
 	}
 
 	gog_axis_set_ticks (axis, tick_nbr + label_nbr, ticks);
@@ -761,7 +791,7 @@ map_linear_calc_ticks (GogAxis *axis)
 			g_assert (t < N);
 			ticks[t].position = maj_pos;
 			ticks[t].type = GOG_AXIS_TICK_MAJOR;
-			ticks[t].label = axis_format_value (axis, maj_pos);
+			axis_format_value (axis, maj_pos, &ticks[t].str);
 			t++;
 		}
 
@@ -775,7 +805,7 @@ map_linear_calc_ticks (GogAxis *axis)
 			g_assert (t < N);
 			ticks[t].position = min_pos;
 			ticks[t].type = GOG_AXIS_TICK_MINOR;
-			ticks[t].label = NULL;
+			ticks[t].str = NULL;
 			t++;
 		}
 	}
@@ -985,7 +1015,7 @@ map_date_calc_ticks (GogAxis *axis)
 
 		ticks[t].position = maj_pos;
 		ticks[t].type = GOG_AXIS_TICK_MAJOR;
-		ticks[t].label = axis_format_value (axis, maj_pos);
+		axis_format_value (axis, maj_pos, &ticks[t].str);
 		t++;
 
 		/* Calculate next major so we know when to stop minors.  */
@@ -1007,7 +1037,7 @@ map_date_calc_ticks (GogAxis *axis)
 
 			ticks[t].position = min_pos;
 			ticks[t].type = GOG_AXIS_TICK_MINOR;
-			ticks[t].label = NULL;
+			ticks[t].str = NULL;
 			t++;
 		}
 	}
@@ -1035,6 +1065,7 @@ map_date_get_dim_format (GogAxis *axis, unsigned dim)
 {
 	switch (dim) {
 	case GOG_AXIS_ELEM_MIN:
+
 	case GOG_AXIS_ELEM_MAX: {
 		GOFormat *fmt = gog_axis_get_effective_format (axis);
 		/*
@@ -1349,7 +1380,7 @@ map_log_calc_ticks (GogAxis *axis)
 			g_assert (t < N);
 			ticks[t].position = maj_pos;
 			ticks[t].type = GOG_AXIS_TICK_MAJOR;
-			ticks[t].label = axis_format_value (axis, maj_pos);
+		        axis_format_value (axis, maj_pos, &ticks[t].str);
 			t++;
 		}
 
@@ -1373,7 +1404,7 @@ map_log_calc_ticks (GogAxis *axis)
 			g_assert (t < N);
 			ticks[t].position = min_pos;
 			ticks[t].type = GOG_AXIS_TICK_MINOR;
-			ticks[t].label = NULL;
+			ticks[t].str = NULL;
 			t++;
 		}
 	}
@@ -1778,7 +1809,7 @@ gog_axis_set_ticks (GogAxis *axis, int tick_nbr, GogAxisTick *ticks)
 
 	if (axis->ticks != NULL) {
 		for (i = 0; i < axis->tick_nbr; i++)
-			g_free (axis->ticks[i].label);
+			go_string_unref (axis->ticks[i].str);
 
 		g_free (axis->ticks);
 	}
diff --git a/goffice/graph/gog-axis.h b/goffice/graph/gog-axis.h
index 75c5b6e..8e531ee 100644
--- a/goffice/graph/gog-axis.h
+++ b/goffice/graph/gog-axis.h
@@ -44,8 +44,8 @@ typedef enum {
 
 typedef struct {
 	double		 position;
-	GogAxisTickTypes	 type;
-	char 		*label;
+	GogAxisTickTypes type;
+	GOString        *str;
 } GogAxisTick;
 
 typedef struct _GogAxisMap GogAxisMap;
diff --git a/goffice/graph/gog-renderer.c b/goffice/graph/gog-renderer.c
index 17a32ee..b77a681 100644
--- a/goffice/graph/gog-renderer.c
+++ b/goffice/graph/gog-renderer.c
@@ -777,51 +777,51 @@ gog_renderer_draw_marker (GogRenderer *rend, double x, double y)
 }
 
 /**
- * gog_renderer_draw_text :
+ * gog_renderer_draw_layout :
  * @rend   : #GogRenderer
- * @text   : the string to draw
+ * @gostring : the #GOString to draw
  * @pos    : #GogViewAllocation
  * @anchor : #GtkAnchorType how to draw relative to @pos
- * @use_markup: wether to use pango markup
  *
- * Have @rend draw @text in the at @pos.{x,y} anchored by the @anchor corner.
+ * Have @rend draw @layout in the at @pos.{x,y} anchored by the @anchor corner.
  * If @pos.w or @pos.h are >= 0 then clip the results to less than that size.
  **/
 
 void
-gog_renderer_draw_text (GogRenderer *rend, char const *text,
-			GogViewAllocation const *pos, GtkAnchorType anchor,
-			gboolean use_markup)
+gog_renderer_draw_gostring (GogRenderer *rend, GOString *str,
+			GogViewAllocation const *pos, GtkAnchorType anchor)
 {
 	PangoLayout *layout;
 	PangoContext *context;
-	cairo_t *cairo = rend->cairo;
+	cairo_t *cairo;
 	GOGeometryOBR obr;
 	GOGeometryAABR aabr;
 	GOStyle const *style;
 	int iw, ih;
+	PangoAttrList *attr;
 
+	g_return_if_fail (str != NULL);
 	g_return_if_fail (GOG_IS_RENDERER (rend));
 	g_return_if_fail (rend->cur_style != NULL);
-	g_return_if_fail (text != NULL);
-
-	if (*text == '\0')
-		return;
 
+	cairo = rend->cairo;
 	style = rend->cur_style;
 
+	/* Note: orig layout may not have been created using cairo! */
 	layout = pango_cairo_create_layout (cairo);
 	context = pango_layout_get_context (layout);
+	pango_layout_set_text (layout, str->str, -1);
+	attr = go_string_get_markup (str);
+	if (attr)
+		pango_layout_set_attributes (layout, attr);
 	pango_cairo_context_set_resolution (context, 72.0);
-	if (use_markup)
-		pango_layout_set_markup (layout, text, -1);
-	else
-		pango_layout_set_text (layout, text, -1);
 	pango_layout_set_font_description (layout, style->font.font->desc);
 	pango_layout_get_size (layout, &iw, &ih);
 
-	obr.w = rend->scale * ((double) iw + (double) PANGO_SCALE / 2.0) / (double) PANGO_SCALE;
-	obr.h = rend->scale * ((double) ih + (double) PANGO_SCALE / 2.0) /(double) PANGO_SCALE;
+	obr.w = rend->scale * ((double) iw + (double) PANGO_SCALE / 2.0) 
+		/ (double) PANGO_SCALE;
+	obr.h = rend->scale * ((double) ih + (double) PANGO_SCALE / 2.0) 
+		/(double) PANGO_SCALE;
 	obr.alpha = -style->text_layout.angle * M_PI / 180.0;
 	obr.x = pos->x;
 	obr.y = pos->y;
@@ -849,8 +849,10 @@ gog_renderer_draw_text (GogRenderer *rend, char const *text,
 
 	cairo_save (cairo);
 	cairo_set_source_rgba (cairo, GO_COLOR_TO_CAIRO (style->font.color));
-	cairo_move_to (cairo, obr.x - (obr.w / 2.0) * cos (obr.alpha) + (obr.h / 2.0) * sin (obr.alpha),
-		       obr.y - (obr.w / 2.0) * sin (obr.alpha) - (obr.h / 2.0) * cos (obr.alpha));
+	cairo_move_to (cairo, obr.x - (obr.w / 2.0) * cos (obr.alpha) + 
+		       (obr.h / 2.0) * sin (obr.alpha),
+		       obr.y - (obr.w / 2.0) * sin (obr.alpha) - 
+		       (obr.h / 2.0) * cos (obr.alpha));
 	cairo_rotate (cairo, obr.alpha);
 	cairo_scale (cairo, rend->scale, rend->scale);
 	pango_cairo_show_layout (cairo, layout);
@@ -858,30 +860,69 @@ gog_renderer_draw_text (GogRenderer *rend, char const *text,
 	g_object_unref (layout);
 }
 
+
+/**
+ * gog_renderer_draw_text :
+ * @rend   : #GogRenderer
+ * @text   : the string to draw
+ * @pos    : #GogViewAllocation
+ * @anchor : #GtkAnchorType how to draw relative to @pos
+ * @use_markup: wether to use pango markup
+ *
+ * Have @rend draw @text in the at @pos.{x,y} anchored by the @anchor corner.
+ * If @pos.w or @pos.h are >= 0 then clip the results to less than that size.
+ **/
+
+void
+gog_renderer_draw_text (GogRenderer *rend, char const *text,
+			GogViewAllocation const *pos, GtkAnchorType anchor,
+			gboolean use_markup)
+{
+	cairo_t *cairo;
+	GOString *str;
+	PangoAttrList *attr_list = NULL;
+	char *m_text = NULL;
+
+	g_return_if_fail (GOG_IS_RENDERER (rend));
+	g_return_if_fail (text != NULL);
+
+	if (*text == '\0')
+		return;
+
+	cairo = rend->cairo;
+	if (use_markup && pango_parse_markup  (text, -1, 0,
+					       &attr_list, &m_text,
+					       NULL, NULL))
+		str = go_string_new_rich (m_text, -1, FALSE, attr_list, NULL);
+	else
+		str = go_string_new (text);
+	gog_renderer_draw_gostring (rend, str, pos, anchor);
+	go_string_unref (str);
+}
+
 /**
  * gog_renderer_get_text_OBR :
  * @rend: #GogRenderer
- * @text: the string to draw
- * @use_markup: wether to use pango markup
+ * @gostring: the string to draw
  * @obr: #GOGeometryOBR to store the Object Bounding Rectangle of @text.
  **/
 void
-gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
-			   gboolean use_markup, GOGeometryOBR *obr)
+gog_renderer_get_gostring_OBR (GogRenderer *rend, GOString *str, GOGeometryOBR *obr)
 {
 	GOStyle const *style;
 	PangoLayout *layout;
 	PangoContext *context;
 	PangoRectangle logical;
-	cairo_t *cairo = rend->cairo;
+	cairo_t *cairo;
+	PangoAttrList *attr;
 
 	g_return_if_fail (GOG_IS_RENDERER (rend));
 	g_return_if_fail (rend->cur_style != NULL);
-	g_return_if_fail (text != NULL);
 	g_return_if_fail (obr != NULL);
 
+	cairo = rend->cairo;
 	obr->x = obr->y = 0;
-	if (*text == '\0') {
+	if (str->str == NULL || *(str->str) == '\0') {
 		/* Make sure invisible things don't skew size */
 		obr->w = obr->h = 0;
 		obr->alpha = 0;
@@ -889,20 +930,21 @@ gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
 	}
 
 	style = rend->cur_style;
-
 	layout = pango_cairo_create_layout (cairo);
 	context = pango_layout_get_context (layout);
+	pango_layout_set_text (layout, str->str, -1);
+	attr = go_string_get_markup (str);
+	if (attr)
+		pango_layout_set_attributes (layout, attr);
 	pango_cairo_context_set_resolution (context, 72.0);
-	if (use_markup)
-		pango_layout_set_markup (layout, text, -1);
-	else
-		pango_layout_set_text (layout, text, -1);
 	pango_layout_set_font_description (layout, style->font.font->desc);
 	pango_layout_get_extents (layout, NULL, &logical);
 	g_object_unref (layout);
 
-	obr->w = rend->scale * ((double) logical.width + (double) PANGO_SCALE / 2.0) / (double) PANGO_SCALE;
-	obr->h = rend->scale * ((double) logical.height + (double) PANGO_SCALE / 2.0) /(double) PANGO_SCALE;
+	obr->w = rend->scale * ((double) logical.width + (double) PANGO_SCALE / 2.0) 
+		/ (double) PANGO_SCALE;
+	obr->h = rend->scale * ((double) logical.height + (double) PANGO_SCALE / 2.0) 
+		/(double) PANGO_SCALE;
 
 	/* Make sure invisible things don't skew size */
 	if (obr->w == 0)
@@ -913,6 +955,39 @@ gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
 	obr->alpha = - style->text_layout.angle * M_PI / 180.0;
 }
 
+
+/**
+ * gog_renderer_get_text_OBR :
+ * @rend: #GogRenderer
+ * @text: the string to draw
+ * @use_markup: wether to use pango markup
+ * @obr: #GOGeometryOBR to store the Object Bounding Rectangle of @text.
+ **/
+void
+gog_renderer_get_text_OBR (GogRenderer *rend, char const *text,
+			   gboolean use_markup, GOGeometryOBR *obr)
+{
+	cairo_t *cairo;
+	GOString *str;
+	PangoAttrList *attr_list = NULL;
+	char *m_text = NULL;
+
+	g_return_if_fail (GOG_IS_RENDERER (rend));
+	g_return_if_fail (text != NULL);
+
+	cairo = rend->cairo;
+
+	if (use_markup && pango_parse_markup  (text, -1, 0,
+					       &attr_list, &m_text,
+					       NULL, NULL))
+		str = go_string_new_rich (m_text, -1, FALSE, attr_list, NULL);
+	else
+		str = go_string_new (text);
+	gog_renderer_get_gostring_OBR (rend, str, obr);
+	go_string_unref (str);
+
+}
+
 /**
  * gog_renderer_get_text_AABR :
  * @rend: #GogRenderer
diff --git a/goffice/graph/gog-renderer.h b/goffice/graph/gog-renderer.h
index 3c0dc5e..7db1410 100644
--- a/goffice/graph/gog-renderer.h
+++ b/goffice/graph/gog-renderer.h
@@ -115,9 +115,17 @@ void  gog_renderer_draw_selection_rectangle	(GogRenderer *renderer, GogViewAlloc
 void  gog_renderer_draw_marker	  (GogRenderer *rend, double x, double y);
 
 void  gog_renderer_draw_text	  (GogRenderer *rend, char const *text,
-				   GogViewAllocation const *pos, GtkAnchorType anchor,
+				   GogViewAllocation const *pos, 
+				   GtkAnchorType anchor,
 				   gboolean use_markup);
 
+void  gog_renderer_draw_gostring  (GogRenderer *rend,
+				   GOString *str,
+				   GogViewAllocation const *pos, 
+				   GtkAnchorType anchor);
+
+void  gog_renderer_get_gostring_OBR   (GogRenderer *rend, GOString *str,
+				       GOGeometryOBR *obr);
 void  gog_renderer_get_text_OBR   (GogRenderer *rend, char const *text,
 				   gboolean use_markup, GOGeometryOBR *obr);
 void  gog_renderer_get_text_AABR  (GogRenderer *rend, char const *text,
diff --git a/goffice/gtk/go-format-sel.c b/goffice/gtk/go-format-sel.c
index c0c4224..2b7b9d7 100644
--- a/goffice/gtk/go-format-sel.c
+++ b/goffice/gtk/go-format-sel.c
@@ -160,12 +160,12 @@ static guint go_format_sel_signals [LAST_SIGNAL] = { 0 };
 static void format_entry_set_text (GOFormatSel *gfs, const gchar *text);
 
 static char *
-generate_preview (GOFormatSel *gfs, GOColor *c)
+generate_preview (GOFormatSel *gfs, PangoAttrList **attrs)
 {
 	char *res = NULL;
 	g_signal_emit (G_OBJECT (gfs),
 		       go_format_sel_signals [GENERATE_PREVIEW], 0,
-		       c, &res);
+		       attrs, &res);
 	return res;
 }
 
@@ -174,8 +174,7 @@ draw_format_preview (GOFormatSel *gfs, gboolean regen_format)
 {
 	char *preview;
 	GOFormat const *sf = NULL;
-	GOColor c = 0;
-	GdkColor gdk_color;
+	PangoAttrList *attrs = NULL;
 	gsize len;
 
 	if (regen_format) {
@@ -196,22 +195,23 @@ draw_format_preview (GOFormatSel *gfs, gboolean regen_format)
 	if (NULL == (sf = gfs->format.spec))
 		return;
 
-	if (NULL == (preview = generate_preview (gfs, &c)))
+	if (NULL == (preview = generate_preview (gfs, &attrs)))
 		return;
 
 	len = g_utf8_strlen (preview, -1);
 	if (len > FORMAT_PREVIEW_MAX)
-		strcpy (g_utf8_offset_to_pointer (preview, FORMAT_PREVIEW_MAX - 5),
+		strcpy (g_utf8_offset_to_pointer (preview, 
+						  FORMAT_PREVIEW_MAX - 5),
 			"...");
 
 	gtk_text_buffer_set_text (gfs->format.preview_buffer, preview, -1);
-	if (c != 0)
-		go_color_to_gdk (c, &gdk_color);
-	else
-		gdk_color_parse ("black", &gdk_color);
 
-	gtk_widget_modify_text (GTK_WIDGET (gfs->format.preview),
-				GTK_STATE_NORMAL, &gdk_color);
+	go_load_pango_attributes_into_buffer (attrs, 
+					      gfs->format.preview_buffer,
+					      preview);
+
+	pango_attr_list_unref (attrs);
+
 	g_free (preview);
 }
 
@@ -999,6 +999,7 @@ nfs_init (GOFormatSel *gfs)
 		pango_font_metrics_unref (metrics);
 	}
 	gfs->format.preview_buffer = gtk_text_view_get_buffer (gfs->format.preview);
+	go_create_std_tags_for_buffer (gfs->format.preview_buffer);
 
 	gfs->format.menu = go_gtk_builder_get_widget (gfs->gui, "format_menu");
 	populate_menu (gfs);
diff --git a/goffice/utils/go-format.c b/goffice/utils/go-format.c
index de13fdb..0e4ba80 100644
--- a/goffice/utils/go-format.c
+++ b/goffice/utils/go-format.c
@@ -180,6 +180,8 @@ typedef enum {
 	OP_NUM_MARK_MANTISSA,
 	OP_NUM_SIMPLIFY_MANTISSA,
 	OP_NUM_SIMPLIFY_EXPONENT,
+	OP_MARKUP_SUPERSCRIPT_START,
+	OP_MARKUP_SUPERSCRIPT_END,
 #endif
 	OP_NUM_FRACTION,	/* wholep explicitp (digits|denominator) */
 	OP_NUM_FRACTION_WHOLE,
@@ -1770,11 +1772,7 @@ go_format_parse_number_E (GOFormatParseState *pstate)
 			ADD_OP (OP_NUM_SIMPLIFY_MANTISSA);
 		ADD_OP2 (OP_CHAR, '1');
 		ADD_OP2 (OP_CHAR, '0');
-		ADD_OP2 (OP_CHAR, '<');
-		ADD_OP2 (OP_CHAR, 's');
-		ADD_OP2 (OP_CHAR, 'u');
-		ADD_OP2 (OP_CHAR, 'p');
-		ADD_OP2 (OP_CHAR, '>');
+		ADD_OP  (OP_MARKUP_SUPERSCRIPT_START);
 	} else
 #endif
 		ADD_OP2 (OP_CHAR, 'E');
@@ -1786,14 +1784,9 @@ go_format_parse_number_E (GOFormatParseState *pstate)
 
 #ifdef ALLOW_EE_MARKUP
 	if (use_markup) {
-		ADD_OP2 (OP_CHAR, '<');
-		ADD_OP2 (OP_CHAR, '/');
-		ADD_OP2 (OP_CHAR, 's');
-		ADD_OP2 (OP_CHAR, 'u');
-		ADD_OP2 (OP_CHAR, 'p');
-		ADD_OP2 (OP_CHAR, '>');
 		if (simplify_mantissa)
 			ADD_OP (OP_NUM_SIMPLIFY_EXPONENT);
+		ADD_OP  (OP_MARKUP_SUPERSCRIPT_END);
 	}
 #endif
 
@@ -2316,6 +2309,8 @@ go_format_dump_program (const guchar *prg)
 		REGULAR(OP_NUM_MARK_MANTISSA);
 		REGULAR(OP_NUM_SIMPLIFY_MANTISSA);
 		REGULAR(OP_NUM_SIMPLIFY_EXPONENT);
+		REGULAR(OP_MARKUP_SUPERSCRIPT_START);
+		REGULAR(OP_MARKUP_SUPERSCRIPT_END);
 #endif
 		REGULAR(OP_NUM_FRACTION_WHOLE);
 		REGULAR(OP_NUM_FRACTION_NOMINATOR);
@@ -2498,11 +2493,19 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 		DOUBLE w, n, d;
 		gsize nominator_start, denominator_start;
 	} fraction;
+	char *oldlocale = NULL;
 #ifdef ALLOW_EE_MARKUP
 	int mantissa_start = -1;
 	int special_mantissa = INT_MAX;
+	PangoAttrList *attrs = NULL;
+	GSList *markup_stack = NULL;
+
+	if (layout) {
+		attrs = pango_attr_list_copy (pango_layout_get_attributes (layout));
+		if (attrs == NULL)
+			attrs = pango_attr_list_new ();
+	}
 #endif
-	char *oldlocale = NULL;
 
 	memset (&fraction, 0, sizeof (fraction));
 
@@ -2511,8 +2514,15 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 
 		switch (op) {
 		case OP_END:
-			if (layout)
+			if (layout) {
 				pango_layout_set_text (layout, dst->str, -1);
+#ifdef ALLOW_EE_MARKUP
+
+				pango_layout_set_attributes (layout, attrs);
+				pango_attr_list_unref (attrs);
+				g_slist_free (markup_stack);
+#endif
+			}
 			if (numtxt)
 				g_string_free (numtxt, TRUE);
 			if (oldlocale) {
@@ -3063,6 +3073,33 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 				g_string_append_c (dst, '0');
 			}
 			break;
+
+		case OP_MARKUP_SUPERSCRIPT_START:
+			if (layout)
+				markup_stack = g_slist_prepend 
+					(markup_stack, GSIZE_TO_POINTER (dst->len));
+			break;
+
+		case OP_MARKUP_SUPERSCRIPT_END: 
+			if (layout) {
+				guint start = 0, 
+					end = (guint)dst->len;
+				PangoAttribute *attr;
+				if (markup_stack) {
+					start = (guint)GPOINTER_TO_SIZE (markup_stack->data);
+					markup_stack = g_slist_delete_link (markup_stack, markup_stack);
+				}
+				 /* FIXME: we need to calculate the right rise value */
+				attr = pango_attr_rise_new (5000);
+				attr->start_index = start;
+				attr->end_index = end;
+				pango_attr_list_insert (attrs, attr);
+				attr = pango_attr_scale_new (PANGO_SCALE_SMALL);
+				attr->start_index = start;
+				attr->end_index = end;
+				pango_attr_list_insert (attrs, attr);
+			}
+			break;
 #endif
 
 		case OP_NUM_FRACTION: {
@@ -3128,10 +3165,50 @@ SUFFIX(go_format_execute) (PangoLayout *layout, GString *dst,
 
 		case OP_NUM_FRACTION_BLANK:
 			if (fraction.n == 0) {
-				/* Replace all added characters by spaces.  */
-				gsize chars = g_utf8_strlen (dst->str + fraction.nominator_start, -1);
-				memset (dst->str + fraction.nominator_start, ' ', chars);
-				g_string_truncate (dst, fraction.nominator_start + chars);
+				/* Replace all added characters by spaces of the right length.  */
+				char const *f = dst->str + fraction.nominator_start;
+				gsize chars = g_utf8_strlen (f, -1);
+				
+				if (chars > 0) {
+					/* We have layouts that have no fontmap set, we need to avoid them */
+					if (layout && pango_context_get_font_map (pango_layout_get_context (layout))) {
+						guint start = fraction.nominator_start;
+						GList *plist, *l;
+						gint length = dst->len - fraction.nominator_start;
+						plist = pango_itemize (pango_layout_get_context (layout),
+								       dst->str,
+								       f - dst->str,
+								       length,
+								       attrs,
+								       NULL);
+						chars = 0;
+						for (l = plist; l != NULL; l = l->next) {
+							PangoItem *pi = l->data;
+							PangoGlyphString *glyphs = pango_glyph_string_new ();
+							PangoAttribute *attr;
+							PangoRectangle ink_rect;
+							PangoRectangle logical_rect;
+
+							pango_shape (f, length, &pi->analysis, glyphs);
+							pango_glyph_string_extents (glyphs,
+										    pi->analysis.font,
+										    &ink_rect,
+										    &logical_rect);
+							pango_glyph_string_free (glyphs);
+
+							attr = pango_attr_shape_new (&ink_rect, &logical_rect);
+							attr->start_index = start;
+							attr->end_index = start + 1;
+							pango_attr_list_insert (attrs, attr);
+							start++;
+							chars++;
+						}
+						go_list_free_custom (plist, (GFreeFunc) pango_item_free);
+					} 
+					
+					memset (dst->str + fraction.nominator_start, ' ', chars);
+					g_string_truncate (dst, fraction.nominator_start + chars);
+				}
 			}
 			break;
 
@@ -3452,6 +3529,7 @@ SUFFIX(go_render_general) (PangoLayout *layout, GString *str,
 	return;
 }
 
+#define FREE_NEW_STR do { if (new_str) (void)g_string_free (new_str, TRUE); } while (0)
 
 GOFormatNumberError
 SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
@@ -3465,20 +3543,38 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
 				 gboolean unicode_minus)
 {
 	gboolean inhibit = FALSE;
+	GString *new_str =  NULL;
+	GOFormatNumberError err;
 
 	g_return_val_if_fail (type == 'F' || sval != NULL,
 			      (GOFormatNumberError)-1);
 
-	g_string_truncate (str, 0);
+	if (str == NULL)
+		new_str = str = g_string_new (NULL);
+	else
+		g_string_truncate (str, 0);
 
 	if (fmt)
 		fmt = SUFFIX(go_format_specialize) (fmt, val, type, &inhibit);
 	if (!fmt)
 		fmt = go_format_general ();
-
 	if (go_color)
 		*go_color = fmt->color;
 
+	if (layout && fmt->color != 0) {
+		PangoAttrList *attrs;
+		PangoAttribute *attr;
+		attrs = pango_attr_list_ref (pango_layout_get_attributes (layout));
+		if (attrs == NULL)
+			attrs = pango_attr_list_new ();
+		attr = go_color_to_pango (fmt->color, TRUE);
+		attr->start_index = 0;
+		attr->end_index = G_MAXUINT;
+		pango_attr_list_insert (attrs, attr);
+		pango_layout_set_attributes (layout, attrs);
+		pango_attr_list_unref (attrs);
+	}
+
 	if (type == 'F') {
 		switch (fmt->typ) {
 		case GO_FMT_TEXT:
@@ -3488,14 +3584,17 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
 				(layout, str, measure, metrics,
 				 val,
 				 col_width, unicode_minus);
+			FREE_NEW_STR;
 			return GO_FORMAT_NUMBER_OK;
 
 		case GO_FMT_NUMBER:
 			if (val < 0) {
 #ifndef ALLOW_NEGATIVE_TIMES
 				if (fmt->u.number.has_date ||
-				    fmt->u.number.has_time)
+				    fmt->u.number.has_time) {
+					FREE_NEW_STR;
 					return GO_FORMAT_NUMBER_DATE_ERROR;
+				}
 #endif
 				if (inhibit)
 					val = SUFFIX(fabs)(val);
@@ -3504,16 +3603,20 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
 			g_printerr ("Executing %s\n", fmt->format);
 			go_format_dump_program (fmt->u.number.program);
 #endif
-			return SUFFIX(go_format_execute)
+
+			err = SUFFIX(go_format_execute)
 				(layout, str,
 				 measure, metrics,
 				 fmt->u.number.program,
 				 col_width,
 				 val, sval, date_conv,
 				 unicode_minus);
-
+			FREE_NEW_STR;
+			return err;
+			
 		case GO_FMT_EMPTY:
 			SETUP_LAYOUT;
+			FREE_NEW_STR;
 			return GO_FORMAT_NUMBER_OK;
 
 		default:
@@ -3521,26 +3624,30 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
 		case GO_FMT_MARKUP:
 		case GO_FMT_COND:
 			SETUP_LAYOUT;
+			FREE_NEW_STR;
 			return GO_FORMAT_NUMBER_INVALID_FORMAT;
 		}
 	} else {
 		switch (fmt->typ) {
 		case GO_FMT_TEXT:
-			return SUFFIX(go_format_execute)
+			err = SUFFIX(go_format_execute)
 				(layout, str,
 				 measure, metrics,
 				 fmt->u.text.program,
 				 col_width,
 				 val, sval, date_conv,
 				 unicode_minus);
-
+			FREE_NEW_STR;
+			return err;
 		case GO_FMT_NUMBER:
 			g_string_assign (str, sval);
 			SETUP_LAYOUT;
+			FREE_NEW_STR;
 			return GO_FORMAT_NUMBER_OK;
 
 		case GO_FMT_EMPTY:
 			SETUP_LAYOUT;
+			FREE_NEW_STR;
 			return GO_FORMAT_NUMBER_OK;
 
 		default:
@@ -3548,11 +3655,14 @@ SUFFIX(go_format_value_gstring) (PangoLayout *layout, GString *str,
 		case GO_FMT_MARKUP:
 		case GO_FMT_COND:
 			SETUP_LAYOUT;
+			FREE_NEW_STR;
 			return GO_FORMAT_NUMBER_INVALID_FORMAT;
 		}
 	}
 }
 
+#undef FREE_NEW_STR
+
 /**
  * go_format_value:
  * @fmt: a #GOFormat
@@ -3572,8 +3682,7 @@ SUFFIX(go_format_value) (GOFormat const *fmt, DOUBLE val)
 		 go_format_measure_strlen,
 		 go_font_metrics_unit,
 		 fmt,
-		 val, 'F', NULL,
-		 NULL,
+		 val, 'F', NULL, NULL,
 		 -1, NULL, FALSE);
 	if (err) {
 		/* Invalid number for format.  */
diff --git a/goffice/utils/go-pango-extras.c b/goffice/utils/go-pango-extras.c
index 9b6e677..0097cf9 100644
--- a/goffice/utils/go-pango-extras.c
+++ b/goffice/utils/go-pango-extras.c
@@ -1,3 +1,4 @@
+/* vim: set sw=8: -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
 /*
  * go-pango-extras.c: Various utility routines that should have been in pango.
  *
@@ -7,6 +8,8 @@
 
 #include <goffice/goffice-config.h>
 #include "go-pango-extras.h"
+#include "go-glib-extras.h"
+#include <string.h>
 
 struct cb_splice {
 	guint pos, len;
@@ -244,3 +247,233 @@ go_pango_attr_list_is_empty (const PangoAttrList *attrs)
 					      cb_empty, &empty);
 	return empty;
 }
+
+static gboolean
+go_load_pango_attributes_into_buffer_filter (PangoAttribute *attribute,
+					  G_GNUC_UNUSED gpointer data)
+{
+	return ((PANGO_ATTR_FOREGROUND == attribute->klass->type) ||
+		(PANGO_ATTR_UNDERLINE == attribute->klass->type) ||
+		(PANGO_ATTR_RISE == attribute->klass->type));
+}
+
+static gboolean
+go_load_pango_attributes_into_buffer_named_filter (PangoAttribute *attribute,
+						    G_GNUC_UNUSED gpointer data)
+{
+	return ((PANGO_ATTR_STYLE == attribute->klass->type) ||
+		(PANGO_ATTR_WEIGHT == attribute->klass->type) ||
+		(PANGO_ATTR_STRIKETHROUGH == attribute->klass->type));
+}
+
+void
+go_create_std_tags_for_buffer (GtkTextBuffer *buffer)
+{
+	gtk_text_buffer_create_tag (buffer, "PANGO_STYLE_NORMAL", "style", PANGO_STYLE_NORMAL,
+				    "style-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_STYLE_ITALIC", "style", PANGO_STYLE_ITALIC,
+				    "style-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_STRIKETHROUGH_TRUE", "strikethrough", TRUE,
+				    "strikethrough-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_STRIKETHROUGH_FALSE", "strikethrough", FALSE,
+				    "strikethrough-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_THIN", "weight", 100,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_ULTRALIGHT", "weight", PANGO_WEIGHT_ULTRALIGHT,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_LIGHT", "weight", PANGO_WEIGHT_LIGHT,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_BOOK", "weight", 380,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_NORMAL", "weight", PANGO_WEIGHT_NORMAL,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_MEDIUM", "weight", 500,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_SEMIBOLD", "weight", PANGO_WEIGHT_SEMIBOLD,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_BOLD", "weight", PANGO_WEIGHT_BOLD,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_ULTRABOLD", "weight", PANGO_WEIGHT_ULTRABOLD,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_HEAVY", "weight", PANGO_WEIGHT_HEAVY,
+				    "weight-set", TRUE, NULL);
+	gtk_text_buffer_create_tag (buffer, "PANGO_WEIGHT_ULTRAHEAVY", "weight", 1000,
+				    "weight-set", TRUE, NULL);
+}
+
+static gint
+go_load_pango_byte_to_char (gchar const *str, gint byte)
+{
+	if (byte >= (gint)strlen (str))
+		return g_utf8_strlen (str, -1);
+	return g_utf8_pointer_to_offset (str, g_utf8_prev_char (str + byte + 1));
+}
+
+void
+go_load_pango_attributes_into_buffer (PangoAttrList  *markup, GtkTextBuffer *buffer, gchar const *str)
+{
+	PangoAttrIterator * iter;
+	PangoAttrList  *copied_markup;
+	PangoAttrList  *our_markup;
+
+	if (markup == NULL)
+		return;
+
+/* For some styles we create named tags. The names are taken from the Pango enums */
+
+	copied_markup = pango_attr_list_copy (markup);
+	our_markup = pango_attr_list_filter (copied_markup,
+					     go_load_pango_attributes_into_buffer_named_filter,
+					     NULL);
+	pango_attr_list_unref (copied_markup);
+	if (our_markup != NULL) {
+		iter = pango_attr_list_get_iterator (our_markup);
+
+		do {
+			GSList *attr = pango_attr_iterator_get_attrs (iter);
+			if (attr != NULL) {
+				GSList *ptr;
+				gint start, end;
+				GtkTextIter start_iter, end_iter;
+				char const *name;
+
+				pango_attr_iterator_range (iter, &start, &end);
+				start = go_load_pango_byte_to_char (str, start);
+				end = go_load_pango_byte_to_char (str, end);
+				gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+				gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+
+				for (ptr = attr; ptr != NULL; ptr = ptr->next) {
+					PangoAttribute *attribute = ptr->data;
+					GtkTextTag *tag;
+					int val;
+
+					switch (attribute->klass->type) {
+					case PANGO_ATTR_STYLE:
+						name = (((PangoAttrInt *)attribute)->value
+							== PANGO_STYLE_NORMAL)
+							? "PANGO_STYLE_NORMAL" :
+							"PANGO_STYLE_ITALIC";
+						tag = gtk_text_tag_table_lookup
+							(gtk_text_buffer_get_tag_table (buffer),
+							 name);
+						gtk_text_buffer_apply_tag (buffer, tag,
+									   &start_iter, &end_iter);
+						break;
+					case PANGO_ATTR_STRIKETHROUGH:
+						name = (((PangoAttrInt *)attribute)->value) ?
+							"PANGO_STRIKETHROUGH_TRUE" :
+							"PANGO_STRIKETHROUGH_FALSE";
+						tag = gtk_text_tag_table_lookup
+							(gtk_text_buffer_get_tag_table (buffer),
+							 name);
+						gtk_text_buffer_apply_tag (buffer, tag,
+									   &start_iter, &end_iter);
+						break;
+					case PANGO_ATTR_WEIGHT:
+						val = ((PangoAttrInt *)attribute)->value;
+						if (val < (PANGO_WEIGHT_THIN + PANGO_WEIGHT_ULTRALIGHT)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_THIN",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_ULTRALIGHT + PANGO_WEIGHT_LIGHT)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRALIGHT",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_LIGHT + PANGO_WEIGHT_BOOK)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_LIGHT",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_BOOK + PANGO_WEIGHT_NORMAL)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_BOOK",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_NORMAL + PANGO_WEIGHT_MEDIUM)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_NORMAL",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_MEDIUM + PANGO_WEIGHT_SEMIBOLD)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_MEDIUM",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_SEMIBOLD + PANGO_WEIGHT_BOLD)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_SEMIBOLD",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_BOLD + PANGO_WEIGHT_ULTRABOLD)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_BOLD",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_ULTRABOLD + PANGO_WEIGHT_HEAVY)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRABOLD",
+											   &start_iter, &end_iter);
+						else if (val < (PANGO_WEIGHT_HEAVY + PANGO_WEIGHT_ULTRAHEAVY)/2)
+							gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_HEAVY",
+											   &start_iter, &end_iter);
+						else gtk_text_buffer_apply_tag_by_name (buffer,"PANGO_WEIGHT_ULTRAHEAVY",
+											&start_iter, &end_iter);
+						break;
+					default:
+						break;
+					}
+				}
+				go_slist_free_custom (attr, (GFreeFunc)pango_attribute_destroy);
+			}
+		} while (pango_attr_iterator_next (iter));
+		pango_attr_iterator_destroy (iter);
+		pango_attr_list_unref (our_markup);
+	}
+
+/* For other styles (that are not at true/false type styles) we use unnamed styles */
+
+	copied_markup = pango_attr_list_copy (markup);
+	our_markup = pango_attr_list_filter (copied_markup,
+					     go_load_pango_attributes_into_buffer_filter,
+					     NULL);
+	pango_attr_list_unref (copied_markup);
+	if (our_markup != NULL) {
+		iter = pango_attr_list_get_iterator (our_markup);
+
+		do {
+			GSList *attr = pango_attr_iterator_get_attrs (iter);
+			if (attr != NULL) {
+				char *string;
+				GSList *ptr;
+				gint start, end;
+				GtkTextIter start_iter, end_iter;
+				GtkTextTag *tag = gtk_text_buffer_create_tag (buffer, NULL, NULL);
+				for (ptr = attr; ptr != NULL; ptr = ptr->next) {
+					PangoAttribute *attribute = ptr->data;
+					switch (attribute->klass->type) {
+					case PANGO_ATTR_FOREGROUND:
+						string = pango_color_to_string
+							(&((PangoAttrColor *)attribute)->color);
+						g_object_set (G_OBJECT (tag),
+							      "foreground", string,
+							      "foreground-set", TRUE,
+							      NULL);
+						g_free (string);
+						break;
+					case PANGO_ATTR_UNDERLINE:
+						g_object_set (G_OBJECT (tag),
+							      "underline",
+							      ((PangoAttrInt *)attribute)->value,
+							      "underline-set", TRUE,
+							      NULL);
+						break;
+					case PANGO_ATTR_RISE:
+						g_object_set (G_OBJECT (tag),
+							      "rise",
+							      ((PangoAttrInt *)attribute)->value,
+							      "rise-set", TRUE,
+							      NULL);
+						break;
+					default:
+						break;
+					}
+				}
+				pango_attr_iterator_range (iter, &start, &end);
+				start = go_load_pango_byte_to_char (str, start);
+				end = go_load_pango_byte_to_char (str, end);
+				gtk_text_buffer_get_iter_at_offset (buffer, &start_iter, start);
+				gtk_text_buffer_get_iter_at_offset (buffer, &end_iter, end);
+				gtk_text_buffer_apply_tag (buffer, tag, &start_iter, &end_iter);
+				go_slist_free_custom (attr, (GFreeFunc)pango_attribute_destroy);
+			}
+		} while (pango_attr_iterator_next (iter));
+		pango_attr_iterator_destroy (iter);
+		pango_attr_list_unref (our_markup);
+	}
+}
diff --git a/goffice/utils/go-pango-extras.h b/goffice/utils/go-pango-extras.h
index 18fd95a..33c7339 100644
--- a/goffice/utils/go-pango-extras.h
+++ b/goffice/utils/go-pango-extras.h
@@ -2,6 +2,7 @@
 #define GO_PANGO_EXTRAS_H
 
 #include <pango/pango.h>
+#include <gtk/gtk.h>
 
 G_BEGIN_DECLS
 
@@ -12,6 +13,11 @@ void go_pango_attr_list_unset (PangoAttrList  *list,
 			       PangoAttrType type);
 gboolean go_pango_attr_list_is_empty (const PangoAttrList *attrs);
 
+void go_load_pango_attributes_into_buffer (PangoAttrList *markup, 
+					   GtkTextBuffer *buffer, 
+					   gchar const *str);
+void go_create_std_tags_for_buffer (GtkTextBuffer *buffer);
+
 G_END_DECLS
 
 #endif /* GO_PANGO_EXTRAS_H */
diff --git a/goffice/utils/go-string.c b/goffice/utils/go-string.c
index 6a8c173..1783810 100644
--- a/goffice/utils/go-string.c
+++ b/goffice/utils/go-string.c
@@ -221,10 +221,12 @@ go_string_new_rich (char const *str,
 	/* TODO : when we use a better representation for attributes (eg array
 	 * of GOFont indicies) look into sharing rich strings */
 
+	if (byte_len <= 0)
+		byte_len = strlen (str);
 	rich = g_slice_new (GOStringRichImpl);
 	rich->base.base.str	= str;
 	rich->base.hash		= g_str_hash (str);
-	rich->base.flags	= ((byte_len > 0) ? (guint32) byte_len : strlen (str)) | GO_STRING_IS_RICH;
+	rich->base.flags	=  ((guint32) byte_len) | GO_STRING_IS_RICH;
 	rich->base.ref_count	= 1;
 	rich->markup		= markup;
 	rich->phonetic		= phonetic;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]