[lasem] svg_text: add support for multiple x, y, dx, and dy.



commit 409c1594c5dfcfb0a489bfa17397c16711a78637
Author: Emmanuel Pacaud <emmanuel gnome org>
Date:   Mon Nov 5 22:57:36 2012 +0100

    svg_text: add support for multiple x, y, dx, and dy.

 src/lsmsvgattributes.h   |    5 +
 src/lsmsvglength.c       |   59 ++++++++++++
 src/lsmsvglength.h       |    6 ++
 src/lsmsvgtextelement.c  |   83 ++++++++++++-----
 src/lsmsvgtextelement.h  |    6 +-
 src/lsmsvgtraits.c       |   74 +++++++++++++++
 src/lsmsvgtraits.h       |    1 +
 src/lsmsvgtspanelement.c |   65 ++++++++++----
 src/lsmsvgtspanelement.h |    6 +-
 src/lsmsvgview.c         |  221 ++++++++++++++++++++++++++++++++++++++++++----
 src/lsmsvgview.h         |   15 +++-
 tests/.gitignore         |    1 +
 12 files changed, 476 insertions(+), 66 deletions(-)
---
diff --git a/src/lsmsvgattributes.h b/src/lsmsvgattributes.h
index 3e5c8e4..9ddd92d 100644
--- a/src/lsmsvgattributes.h
+++ b/src/lsmsvgattributes.h
@@ -60,6 +60,11 @@ typedef struct {
 
 typedef struct {
 	LsmAttribute base;
+	LsmSvgLengthList list;
+} LsmSvgLengthListAttribute;
+
+typedef struct {
+	LsmAttribute base;
 	LsmSvgPaint paint;
 } LsmSvgPaintAttribute;
 
diff --git a/src/lsmsvglength.c b/src/lsmsvglength.c
index 4e04f40..83b88db 100644
--- a/src/lsmsvglength.c
+++ b/src/lsmsvglength.c
@@ -24,6 +24,7 @@
 
 #include <math.h>
 #include <lsmsvglength.h>
+#include <lsmsvgenums.h>
 
 LsmSvgViewbox *
 lsm_svg_viewbox_new (double resolution_ppi,
@@ -91,3 +92,61 @@ lsm_svg_length_normalize (const LsmSvgLength *length,
 
 	return 0.0;
 }
+
+gboolean
+lsm_svg_parse_length (char **str, LsmSvgLength *length)
+{
+	char *c;
+
+	if (str == NULL || *str == NULL || length == NULL)
+		return FALSE;
+
+	if (!lsm_str_parse_double (str, &length->value_unit))
+		return FALSE;
+
+	c = *str;
+
+	if (c[0] != '\0') {
+		if (c[0] == '%') {
+			length->type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
+			c++;
+		} else if (c[0] == 'e') {
+			if (c[1] == 'm') {
+				length->type = LSM_SVG_LENGTH_TYPE_EMS;
+				c += 2;
+			} else if (c[1] == 'x') {
+				length->type = LSM_SVG_LENGTH_TYPE_EXS;
+				c += 2;
+			} else
+				length->type = LSM_SVG_LENGTH_TYPE_ERROR;
+		} else if (c[0] == 'p') {
+			if (c[1] == 'x') {
+				length->type = LSM_SVG_LENGTH_TYPE_PX;
+				c += 2;
+			} else if (c[1] == 'c') {
+				length->type = LSM_SVG_LENGTH_TYPE_PC;
+				c += 2;
+			} else if (c[1] == 't') {
+				length->type = LSM_SVG_LENGTH_TYPE_PT;
+				c += 2;
+			} else
+				length->type = LSM_SVG_LENGTH_TYPE_ERROR;
+		} else if (c[0] == 'c' && c[0] == 'm') {
+				length->type = LSM_SVG_LENGTH_TYPE_CM;
+				c += 2;
+		} else if (c[0] == 'm' && c[0] == 'm') {
+				length->type = LSM_SVG_LENGTH_TYPE_MM;
+				c += 2;
+		} else if (c[0] == 'i' && c[0] == 'n') {
+				length->type = LSM_SVG_LENGTH_TYPE_IN;
+				c += 2;
+		} else
+			length->type = LSM_SVG_LENGTH_TYPE_NUMBER;
+	} else {
+		length->type = LSM_SVG_LENGTH_TYPE_NUMBER;
+	}
+
+	*str = c;
+
+	return TRUE;
+}
diff --git a/src/lsmsvglength.h b/src/lsmsvglength.h
index 95c21f6..10d5e52 100644
--- a/src/lsmsvglength.h
+++ b/src/lsmsvglength.h
@@ -53,6 +53,12 @@ double 			lsm_svg_length_normalize	(const LsmSvgLength *length,
 							 const LsmSvgViewbox *viewbox,
 							 double font_size,
 							 LsmSvgLengthDirection direction);
+gboolean 		lsm_svg_parse_length 		(char **str, LsmSvgLength *length);
+
+typedef struct {
+	unsigned int n_lengths;
+	LsmSvgLength *lengths;
+} LsmSvgLengthList;
 
 G_END_DECLS
 
diff --git a/src/lsmsvgtextelement.c b/src/lsmsvgtextelement.c
index bb647ce..fd21f22 100644
--- a/src/lsmsvgtextelement.c
+++ b/src/lsmsvgtextelement.c
@@ -52,37 +52,56 @@ lsm_svg_text_element_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmSvgTextElement *text = LSM_SVG_TEXT_ELEMENT (self);
 	LsmDomNode *node = LSM_DOM_NODE (self);
 	LsmDomNode *iter;
-	GString *string = g_string_new ("");
-	double x, y;
+	double *x, *y, *dx, *dy;
+	unsigned int n_x, n_y, n_dx, n_dy;
+	gboolean first_text = TRUE;
 
 	if (node->first_child == NULL)
 		return;
 
-	for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling) {
+	lsm_svg_view_start_text (view);
+
+	x = lsm_svg_view_normalize_length_list (view, &text->x.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_x);
+	y = lsm_svg_view_normalize_length_list (view, &text->y.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_y);
+	dx = lsm_svg_view_normalize_length_list (view, &text->dx.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dx);
+	dy = lsm_svg_view_normalize_length_list (view, &text->dy.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dy);
+
+	iter = LSM_DOM_NODE (self)->first_child;
+	while (iter != NULL) {
 		if (LSM_IS_DOM_TEXT (iter)) {
-			g_string_append (string, lsm_dom_node_get_node_value (iter));
+			GString *string;
+			string = g_string_new ("");
+			for (; LSM_IS_DOM_TEXT (iter); iter = iter->next_sibling)
+				g_string_append (string, lsm_dom_node_get_node_value (iter));
+			lsm_str_consolidate (string->str);
+			if (first_text) {
+				lsm_svg_view_show_text (view, string->str, n_x, x, n_y, y, n_dx, dx, n_dy, dy);
+				first_text = FALSE;
+			} else 
+				lsm_svg_view_show_text (view, string->str, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
+			g_string_free (string, TRUE);
+		} else {
+		       	if (LSM_IS_SVG_ELEMENT (iter))
+				lsm_svg_element_render (LSM_SVG_ELEMENT (iter), view);
+			iter = iter->next_sibling;
 		}
 	}
 
-	x = lsm_svg_view_normalize_length (view, &text->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	y = lsm_svg_view_normalize_length (view, &text->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
-
-	lsm_svg_view_show_text (view, g_strstrip (string->str), x, y);
+	g_free (x);
+	g_free (y);
+	g_free (dx);
+	g_free (dy);
 
-	g_string_free (string, TRUE);
-
-	for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling)
-		if (LSM_IS_SVG_ELEMENT (iter))
-		    lsm_svg_element_render (LSM_SVG_ELEMENT (iter), view);
+	lsm_svg_view_end_text (view);
 }
 
 static void
 lsm_svg_text_element_get_extents (LsmSvgElement *self, LsmSvgView *view, LsmExtents *extents)
 {
-	LsmSvgTextElement *text = LSM_SVG_TEXT_ELEMENT (self);
+/*        LsmSvgTextElement *text = LSM_SVG_TEXT_ELEMENT (self);*/
 	LsmDomNode *iter;
 	GString *string = g_string_new ("");
-	double x, y;
+/*        double x, y;*/
 
 	for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling) {
 		if (LSM_IS_DOM_TEXT (iter)) {
@@ -90,10 +109,10 @@ lsm_svg_text_element_get_extents (LsmSvgElement *self, LsmSvgView *view, LsmExte
 		}
 	}
 
-	x = lsm_svg_view_normalize_length (view, &text->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	y = lsm_svg_view_normalize_length (view, &text->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+/*        x = lsm_svg_view_normalize_length (view, &text->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);*/
+/*        y = lsm_svg_view_normalize_length (view, &text->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);*/
 
-	lsm_svg_view_text_extents (view, g_strstrip (string->str), x, y, extents);
+	lsm_svg_view_text_extents (view, g_strstrip (string->str), 0, 0, 0, NULL, 0, NULL, extents);
 
 	g_string_free (string, TRUE);
 }
@@ -106,13 +125,15 @@ lsm_svg_text_element_new (void)
 	return g_object_new (LSM_TYPE_SVG_TEXT_ELEMENT, NULL);
 }
 
-static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+static const LsmSvgLengthList length_list_default =	{.n_lengths = 0, .lengths = NULL}; 
 
 static void
 lsm_svg_text_element_init (LsmSvgTextElement *self)
 {
-	self->x.length = length_default;
-	self->y.length = length_default;
+	self->x.list = length_list_default;
+	self->y.list = length_list_default;
+	self->dx.list = length_list_default;
+	self->dy.list = length_list_default;
 }
 
 static void
@@ -127,14 +148,26 @@ static const LsmAttributeInfos lsm_svg_text_element_attribute_infos[] = {
 	{
 		.name = "x",
 		.attribute_offset = offsetof (LsmSvgTextElement, x),
-		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
 	},
 	{
 		.name = "y",
 		.attribute_offset = offsetof (LsmSvgTextElement, y),
-		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
+	},
+	{
+		.name = "dx",
+		.attribute_offset = offsetof (LsmSvgTextElement, dx),
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
+	},
+	{
+		.name = "dy",
+		.attribute_offset = offsetof (LsmSvgTextElement, dy),
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
 	}
 };
 
diff --git a/src/lsmsvgtextelement.h b/src/lsmsvgtextelement.h
index 4cd8421..b34b13f 100644
--- a/src/lsmsvgtextelement.h
+++ b/src/lsmsvgtextelement.h
@@ -41,8 +41,10 @@ typedef struct _LsmSvgTextElementClass LsmSvgTextElementClass;
 struct _LsmSvgTextElement {
 	LsmSvgTransformable base;
 
-	LsmSvgLengthAttribute	x;
-	LsmSvgLengthAttribute	y;
+	LsmSvgLengthListAttribute	x;
+	LsmSvgLengthListAttribute	y;
+	LsmSvgLengthListAttribute	dx;
+	LsmSvgLengthListAttribute	dy;
 };
 
 struct _LsmSvgTextElementClass {
diff --git a/src/lsmsvgtraits.c b/src/lsmsvgtraits.c
index 053467e..fb5ef5b 100644
--- a/src/lsmsvgtraits.c
+++ b/src/lsmsvgtraits.c
@@ -131,6 +131,78 @@ const LsmTraitClass lsm_svg_length_trait_class = {
 	.to_string = lsm_svg_length_trait_to_string
 };
 
+static gboolean
+lsm_svg_length_list_trait_from_string (LsmTrait *abstract_trait, char *string)
+{
+	LsmSvgLengthList *length_list = (LsmSvgLengthList *) abstract_trait;
+	unsigned int n_lengths = 1;
+	unsigned int i;
+	gboolean success = FALSE;
+	char *iter = (char *) string;
+
+	g_free (length_list->lengths);
+	length_list->n_lengths = 0;
+	length_list->lengths = NULL;
+
+	while (*iter != '\0') {
+		if (*iter == ',' ||
+		    *iter == ' ') {
+			n_lengths++;
+			do {
+				iter++;
+			} while (*iter == ',' ||
+				 *iter == ' ');
+		} else
+			iter++;
+	}
+
+	length_list->lengths = g_new (LsmSvgLength, n_lengths);
+	length_list->n_lengths = n_lengths;
+	iter = (char *)string;
+	lsm_str_skip_spaces (&iter);
+
+	for (i = 0; i < n_lengths; i++) {
+		success = lsm_svg_parse_length (&iter, &length_list->lengths[i]);
+
+		if (!success)
+			break;
+		lsm_str_skip_comma_and_spaces (&iter);
+	}
+
+	if (!success) {
+		g_free (length_list->lengths);
+		length_list->lengths = NULL;
+		length_list->n_lengths = 0;
+	}
+
+	return TRUE;
+}
+
+static char *
+lsm_svg_length_list_trait_to_string (LsmTrait *abstract_trait)
+{
+	g_assert_not_reached ();
+
+	return NULL;
+}
+
+static void
+lsm_svg_length_list_trait_finalize (LsmTrait *abstract_trait)
+{
+	LsmSvgLengthList *svg_length_list = (LsmSvgLengthList *) abstract_trait;
+
+	g_free (svg_length_list->lengths);
+	svg_length_list->n_lengths = 0;
+	svg_length_list->lengths = NULL;
+}
+
+const LsmTraitClass lsm_svg_length_list_trait_class = {
+	.size = sizeof (LsmSvgLengthList),
+	.from_string = lsm_svg_length_list_trait_from_string,
+	.to_string = lsm_svg_length_list_trait_to_string,
+	.finalize = lsm_svg_length_list_trait_finalize
+};
+
 static void
 _init_matrix (LsmSvgMatrix *matrix, LsmSvgTransformType transform, unsigned int n_values, double values[])
 {
@@ -785,6 +857,8 @@ static char *
 lsm_svg_dash_array_trait_to_string (LsmTrait *abstract_trait)
 {
 	g_assert_not_reached ();
+
+	return NULL;
 }
 
 static void
diff --git a/src/lsmsvgtraits.h b/src/lsmsvgtraits.h
index 7fb2644..62be70d 100644
--- a/src/lsmsvgtraits.h
+++ b/src/lsmsvgtraits.h
@@ -84,6 +84,7 @@ extern const LsmTraitClass lsm_svg_font_stretch_trait_class;
 extern const LsmTraitClass lsm_svg_font_style_trait_class;
 extern const LsmTraitClass lsm_svg_font_weight_trait_class;
 extern const LsmTraitClass lsm_svg_length_trait_class;
+extern const LsmTraitClass lsm_svg_length_list_trait_class;
 extern const LsmTraitClass lsm_svg_line_join_trait_class;
 extern const LsmTraitClass lsm_svg_line_cap_trait_class;
 extern const LsmTraitClass lsm_svg_marker_units_trait_class;
diff --git a/src/lsmsvgtspanelement.c b/src/lsmsvgtspanelement.c
index 9e16950..2e87fea 100644
--- a/src/lsmsvgtspanelement.c
+++ b/src/lsmsvgtspanelement.c
@@ -52,26 +52,45 @@ lsm_svg_tspan_element_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmSvgTspanElement *tspan = LSM_SVG_TSPAN_ELEMENT (self);
 	LsmDomNode *node = LSM_DOM_NODE (self);
 	LsmDomNode *iter;
-	GString *string = g_string_new ("");
-	double x, y;
+	double *x, *y, *dx, *dy;
+	unsigned int n_x, n_y, n_dx, n_dy;
+	gboolean first_text = TRUE;
 
 	lsm_debug_render ("[LsmSvgTspanElement::render] Render");
 
 	if (node->first_child == NULL)
 		return;
 
-	for (iter = LSM_DOM_NODE (self)->first_child; iter != NULL; iter = iter->next_sibling) {
+	x = lsm_svg_view_normalize_length_list (view, &tspan->x.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_x);
+	y = lsm_svg_view_normalize_length_list (view, &tspan->y.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_y);
+	dx = lsm_svg_view_normalize_length_list (view, &tspan->dx.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dx);
+	dy = lsm_svg_view_normalize_length_list (view, &tspan->dy.list, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL, &n_dy);
+
+	iter = LSM_DOM_NODE (self)->first_child;
+	while (iter != NULL) {
 		if (LSM_IS_DOM_TEXT (iter)) {
-			g_string_append (string, lsm_dom_node_get_node_value (iter));
+			GString *string;
+			string = g_string_new ("");
+			for (; LSM_IS_DOM_TEXT (iter); iter = iter->next_sibling)
+				g_string_append (string, lsm_dom_node_get_node_value (iter));
+			lsm_str_consolidate (string->str);
+			if (first_text) {
+				lsm_svg_view_show_text (view, string->str, n_x, x, n_y, y, n_dx, dx, n_dy, dy);
+				first_text = FALSE;
+			} else 
+				lsm_svg_view_show_text (view, string->str, 0, NULL, 0, NULL, 0, NULL, 0, NULL);
+			g_string_free (string, TRUE);
+		} else {
+		       	if (LSM_IS_SVG_ELEMENT (iter))
+				lsm_svg_element_render (LSM_SVG_ELEMENT (iter), view);
+			iter = iter->next_sibling;
 		}
 	}
 
-	x = lsm_svg_view_normalize_length (view, &tspan->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	y = lsm_svg_view_normalize_length (view, &tspan->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
-
-	lsm_svg_view_show_text (view, g_strstrip (string->str), x, y);
-
-	g_string_free (string, TRUE);
+	g_free (x);
+	g_free (y);
+	g_free (dx);
+	g_free (dy);
 }
 
 /* LsmSvgTspanElement implementation */
@@ -82,13 +101,13 @@ lsm_svg_tspan_element_new (void)
 	return g_object_new (LSM_TYPE_SVG_TSPAN_ELEMENT, NULL);
 }
 
-static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+static const LsmSvgLengthList length_list_default =	{.n_lengths = 0, .lengths = NULL}; 
 
 static void
 lsm_svg_tspan_element_init (LsmSvgTspanElement *self)
 {
-	self->x.length = length_default;
-	self->y.length = length_default;
+	self->x.list = length_list_default;
+	self->y.list = length_list_default;
 }
 
 static void
@@ -103,14 +122,26 @@ static const LsmAttributeInfos lsm_svg_tspan_element_attribute_infos[] = {
 	{
 		.name = "x",
 		.attribute_offset = offsetof (LsmSvgTspanElement, x),
-		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
 	},
 	{
 		.name = "y",
 		.attribute_offset = offsetof (LsmSvgTspanElement, y),
-		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
+	},
+	{
+		.name = "dx",
+		.attribute_offset = offsetof (LsmSvgTspanElement, dx),
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
+	},
+	{
+		.name = "dy",
+		.attribute_offset = offsetof (LsmSvgTspanElement, dy),
+		.trait_class = &lsm_svg_length_list_trait_class,
+		.trait_default = &length_list_default
 	}
 };
 
diff --git a/src/lsmsvgtspanelement.h b/src/lsmsvgtspanelement.h
index b2019b7..afb3ed1 100644
--- a/src/lsmsvgtspanelement.h
+++ b/src/lsmsvgtspanelement.h
@@ -41,8 +41,10 @@ typedef struct _LsmSvgTspanElementClass LsmSvgTspanElementClass;
 struct _LsmSvgTspanElement {
 	LsmSvgElement element;
 
-	LsmSvgLengthAttribute	x;
-	LsmSvgLengthAttribute	y;
+	LsmSvgLengthListAttribute	x;
+	LsmSvgLengthListAttribute	y;
+	LsmSvgLengthListAttribute	dx;
+	LsmSvgLengthListAttribute	dy;
 };
 
 struct _LsmSvgTspanElementClass {
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 5ea92f4..ebc487b 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -121,6 +121,27 @@ lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length, Lsm
 	return lsm_svg_length_normalize (length, view->viewbox_stack->data, view->style->font_size_px, direction);
 }
 
+double *
+lsm_svg_view_normalize_length_list (LsmSvgView *view, const LsmSvgLengthList *list, LsmSvgLengthDirection direction, unsigned int *n_data)
+{
+	double *data;
+	unsigned int i;
+
+	g_return_val_if_fail (n_data != NULL, NULL);
+	*n_data = 0;
+	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), NULL);
+
+	if (list->n_lengths == 0)
+		return NULL;
+
+	*n_data = list->n_lengths;
+	data = g_new (double, list->n_lengths);
+	for (i = 0; i < list->n_lengths; i++)
+		data[i] = lsm_svg_view_normalize_length (view, &list->lengths[i], direction);
+
+	return data;
+}
+
 static void
 _start_pattern (LsmSvgView *view, const LsmBox *extents, const LsmBox *object_extents, double opacity)
 {
@@ -1037,7 +1058,10 @@ lsm_svg_view_show_polygon (LsmSvgView *view, const char *points)
 }
 
 static void
-_update_pango_layout (LsmSvgView *view, char const *string, double x, double y, LsmSvgViewPathInfos *path_infos)
+_update_pango_layout (LsmSvgView *view, unsigned int n, char const *string, double x, double y,
+		      unsigned int n_dx, const double *dx,
+		      unsigned int n_dy, const double *dy,
+		      LsmSvgViewPathInfos *path_infos)
 {
 	const LsmSvgStyle *style;
 	PangoLayout *pango_layout;
@@ -1046,7 +1070,10 @@ _update_pango_layout (LsmSvgView *view, char const *string, double x, double y,
 	PangoStyle font_style;
 	PangoLayoutIter *iter;
 	PangoRectangle rectangle;
+	PangoAttrList *attrs;
+	PangoAttribute *attr;
 	int baseline;
+	int i;
 	double x1, y1;
 
 	style = view->style;
@@ -1104,7 +1131,38 @@ _update_pango_layout (LsmSvgView *view, char const *string, double x, double y,
 	}
 	pango_font_description_set_style (font_description, font_style);
 
-	pango_layout_set_text (pango_layout, string, -1);
+	pango_layout_set_text (pango_layout, string, n);
+
+	attrs = pango_attr_list_new ();
+	for (i = 0; i < n_dx; i++) {
+
+		attr = pango_attr_letter_spacing_new (pango_units_from_double (dx[i]));
+		attr->start_index = i;
+		if (i < n_dx - 1)
+			attr->end_index = i + 1;
+		else
+			attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
+
+		pango_attr_list_insert (attrs, attr);
+
+		printf ("spacing = %g\n", dx[i]);
+	}
+	for (i = 0; i < n_dy; i++) {
+
+		attr = pango_attr_rise_new (-pango_units_from_double (dy[i]));
+		attr->start_index = i;
+		if (i < n_dy - 1)
+			attr->end_index = i + 1;
+		else
+			attr->end_index = PANGO_ATTR_INDEX_TO_TEXT_END;
+
+		pango_attr_list_insert (attrs, attr);
+
+		printf ("rise = %g\n", dy[i]);
+	}
+	pango_layout_set_attributes (pango_layout, attrs);
+	pango_attr_list_unref (attrs);
+
 	pango_layout_set_font_description (pango_layout, font_description);
 	pango_layout_get_extents (pango_layout, &rectangle, NULL);
 
@@ -1148,7 +1206,7 @@ _lock_pango_layout (LsmSvgView *view)
 		view->pango_layout_stack = g_slist_prepend (view->pango_layout_stack, view->pango_layout);
 		view->pango_layout = pango_layout_new (pango_context);
 
-		lsm_debug_render ("[LsmSvgView::show_text] Create a new pango layout");
+		lsm_debug_render ("[LsmSvgView::_lock_pango_layout] Create a new pango layout");
 
 		return TRUE;
 	}
@@ -1163,7 +1221,7 @@ _unlock_pango_layout (LsmSvgView *view, gboolean need_pop)
 {
 
 	if (need_pop) {
-		lsm_debug_render ("[LsmSvgView::show_text] Free the child pango layout");
+		lsm_debug_render ("[LsmSvgView::_unlock_pango_layout] Free the child pango layout");
 
 		if (view->pango_layout != NULL) {
 			g_object_unref (view->pango_layout);
@@ -1172,23 +1230,31 @@ _unlock_pango_layout (LsmSvgView *view, gboolean need_pop)
 			view->pango_layout_stack = g_slist_delete_link (view->pango_layout_stack,
 									view->pango_layout_stack);
 		} else
-			g_warning ("[LsmSvgView::show_text] Pango layout stack empty");
+			g_warning ("[LsmSvgView::_unlock_pango_layout] Pango layout stack empty");
 	}
 
 	view->is_pango_layout_in_use = FALSE;
 }
 
-void
-lsm_svg_view_show_text (LsmSvgView *view, char const *string, double x, double y)
+static void
+_show_text (LsmSvgView *view,
+	    unsigned int n, char const *string, 
+	    unsigned int n_x, double *x, unsigned int n_y, double *y,
+	    unsigned int n_dx, double *dx, unsigned int n_dy, double *dy)
 {
 	LsmSvgViewPathInfos path_infos = default_path_infos;
+	PangoRectangle extents;
+	PangoLayoutIter *layout_iter;
 	const LsmSvgStyle *style;
 	gboolean need_pop;
+	double x_text;
+	double y_text;
+	double x_end, y_end;
+	double baseline;
+	cairo_t *cairo;
 
-	if (string == NULL || string[0] == '\0')
-		return;
 
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	cairo = view->dom_view.cairo;
 
 	style = view->style;
 
@@ -1196,28 +1262,143 @@ lsm_svg_view_show_text (LsmSvgView *view, char const *string, double x, double y
 
 	need_pop = _lock_pango_layout (view);
 
-	_update_pango_layout (view, string, x, y, &path_infos);
+	cairo_get_current_point (cairo, &x_text, &y_text);
+	if (x != NULL)
+		x_text = x[0];
+	if (y != NULL)
+		y_text = y[0];
+
+
+	_update_pango_layout (view, n, string, x_text, y_text, n_dx, dx, n_dy, dy, &path_infos);
 
 	if (style->writing_mode->value == LSM_SVG_WRITING_MODE_TB ||
 	    style->writing_mode->value == LSM_SVG_WRITING_MODE_TB_RL) {
 
-		cairo_save (view->dom_view.cairo);
-		cairo_rotate (view->dom_view.cairo, M_PI / 2.0);
-		cairo_move_to (view->dom_view.cairo, path_infos.extents.x1, path_infos.extents.y1);
+		cairo_save (cairo);
+		cairo_rotate (cairo, M_PI / 2.0);
+		cairo_move_to (cairo, path_infos.extents.x1, path_infos.extents.y1);
 
 		process_path (view, &path_infos);
 
-		cairo_restore (view->dom_view.cairo);
+		cairo_restore (cairo);
 	} else {
-		cairo_move_to (view->dom_view.cairo, path_infos.extents.x1, path_infos.extents.y1);
+		cairo_move_to (cairo, path_infos.extents.x1, path_infos.extents.y1);
 		process_path (view, &path_infos);
 	}
 
+	layout_iter = pango_layout_get_iter (view->pango_layout);
+	pango_layout_iter_get_line_extents (layout_iter, NULL, &extents);
+	baseline = pango_units_to_double (pango_layout_iter_get_baseline (layout_iter));
+	pango_layout_iter_free (layout_iter);
+
+	x_end = pango_units_to_double (extents.x + extents.width) + path_infos.extents.x1;
+	y_end = pango_units_to_double (extents.y) + baseline + path_infos.extents.y1;
+
+	if (view->debug_text) {
+		double x1, y1;
+
+		lsm_debug_render ("[LsmSvgView::_show_text] Logical extents %gx%g at %g,%g\n",
+			pango_units_to_double (extents.width),
+			pango_units_to_double (extents.height),
+			pango_units_to_double (extents.x),
+			pango_units_to_double (extents.y));
+
+		lsm_debug_render ("[LsmSvgView::_show_text] End point is %g, %g\n", x_end, y_end);
+		lsm_debug_render ("[LsmSvgView::_show_text] Baseline = %g\n", baseline);
+
+		x1 = 1;
+		y1 = 1;
+		cairo_device_to_user_distance (cairo, &x1, &y1);
+
+		cairo_set_source_rgba (cairo, 1.0, 0.0, 0.0, 0.2);
+		cairo_set_line_width (cairo, x1);
+		cairo_rectangle (cairo, path_infos.extents.x1, path_infos.extents.y1,
+				 pango_units_to_double (extents.x + extents.width),
+				 pango_units_to_double (extents.y + extents.height));
+		cairo_stroke (cairo);
+		cairo_set_source_rgba (cairo, 1.0, 0.0, 0.0, 0.2);
+		cairo_arc (cairo, x_end, y_end, 4.0 * x1, 0.0, 2.0 * M_PI);
+		cairo_arc (cairo, path_infos.extents.x1, path_infos.extents.y1, 4.0 * x1, 0.0, 2.0 * M_PI);
+		cairo_fill (cairo);
+	}
+
+	cairo_move_to (cairo, x_end, y_end);
+
 	_unlock_pango_layout (view, need_pop);
 }
 
 void
-lsm_svg_view_text_extents (LsmSvgView *view, char const *string, double x, double y, LsmExtents *extents)
+lsm_svg_view_start_text (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+	cairo_move_to (view->dom_view.cairo, 0, 0);
+}
+
+void
+lsm_svg_view_end_text (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+	cairo_new_path (view->dom_view.cairo);
+}
+
+void
+lsm_svg_view_show_text (LsmSvgView *view, char const *string, 
+			unsigned int n_x, double *x, unsigned int n_y, double *y,
+			unsigned int n_dx, double *dx, unsigned int n_dy, double *dy)
+{
+	unsigned int n, i;
+	char *iter = (char *) string;
+
+	if (string == NULL || string[0] == '\0')
+		return;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (n_x > 0 || x == NULL);
+	g_return_if_fail (n_y > 0 || y == NULL);
+	g_return_if_fail (n_dx > 0 || dx == NULL);
+	g_return_if_fail (n_dy > 0 || dy == NULL);
+
+	n = MAX (n_x, n_y);
+	if (n <= 1) {
+		_show_text (view, strlen (string), string, n_x, x, n_y, y, n_dx, dx, n_dy, dy);
+		return;
+	}
+
+	for (i = 0; (i < n - 1) && iter[0] != '\0'; i++) {
+		char *next_char;
+
+		next_char = g_utf8_next_char (iter);
+		_show_text (view, next_char - iter, iter,
+			    i < n_x ? n_x - i : 0,
+			    i < n_x ? &x[i] : NULL,
+			    i < n_y ? n_y - i : 0,
+			    i < n_y ? &y[i] : NULL,
+			    i < n_dx ? n_dx - i : 0,
+			    i < n_dx ? &dx[i] : NULL,
+			    i < n_dy ? n_dy - i : 0,
+			    i < n_dy ? &dy[i] : NULL);
+		iter = next_char;
+	}
+
+	if (iter[0] != '\0')
+		_show_text (view, strlen (iter), iter,
+			    i < n_x ? n_x - i : 0,
+			    i < n_x ? &x[i] : NULL,
+			    i < n_y ? n_y - i : 0,
+			    i < n_y ? &y[i] : NULL,
+			    i < n_dx ? n_dx - i : 0,
+			    i < n_dx ? &dx[i] : NULL,
+			    i < n_dy ? n_dy - i : 0,
+			    i < n_dy ? &dy[i] : NULL);
+}
+
+void
+lsm_svg_view_text_extents (LsmSvgView *view, char const *string,
+			   double x, double y,
+			   unsigned int n_dx, double *dx, unsigned int n_dy, double *dy,
+			   LsmExtents *extents)
 {
 	LsmSvgViewPathInfos path_infos = default_path_infos;
 	gboolean need_pop;
@@ -1235,7 +1416,7 @@ lsm_svg_view_text_extents (LsmSvgView *view, char const *string, double x, doubl
 
 	need_pop = _lock_pango_layout (view);
 
-	_update_pango_layout (view, string, x, y, &path_infos);
+	_update_pango_layout (view, strlen (string), string, x, y, n_dx, dx, n_dy, dy, &path_infos);
 
 	_unlock_pango_layout (view, need_pop);
 
@@ -2354,6 +2535,10 @@ lsm_svg_view_set_debug (LsmDomView *view, const char *feature, gboolean enable)
 		svg_view->debug_mask = enable;
 	else if (g_strcmp0 (feature, "pattern") == 0)
 		svg_view->debug_pattern = enable;
+	else if (g_strcmp0 (feature, "group") == 0)
+		svg_view->debug_group = enable;
+	else if (g_strcmp0 (feature, "text") == 0)
+		svg_view->debug_text = enable;
 }
 
 LsmSvgView *
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 23de59b..c60203c 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -79,6 +79,8 @@ struct _LsmSvgView {
 	gboolean debug_filter;
 	gboolean debug_mask;
 	gboolean debug_pattern;
+	gboolean debug_group;
+	gboolean debug_text;
 };
 
 struct _LsmSvgViewClass {
@@ -91,6 +93,8 @@ LsmSvgView *	lsm_svg_view_new 			(LsmSvgDocument *document);
 
 double 		lsm_svg_view_normalize_length 		(LsmSvgView *view, const LsmSvgLength *length,
 							 LsmSvgLengthDirection direction);
+double * 	lsm_svg_view_normalize_length_list 	(LsmSvgView *view, const LsmSvgLengthList *list, LsmSvgLengthDirection direction,
+							 unsigned int *n_data);
 
 const LsmBox *	lsm_svg_view_get_pattern_extents	(LsmSvgView *view);
 const LsmBox * 	lsm_svg_view_get_object_extents 	(LsmSvgView *view);
@@ -124,8 +128,15 @@ void		lsm_svg_view_show_path		(LsmSvgView *view, const char *d);
 void 		lsm_svg_view_show_line 		(LsmSvgView *view, double x1, double y1, double x2, double y2);
 void 		lsm_svg_view_show_polyline	(LsmSvgView *view, const char *points);
 void 		lsm_svg_view_show_polygon	(LsmSvgView *view, const char *points);
-void 		lsm_svg_view_show_text 		(LsmSvgView *view, char const *text, double x, double y);
-void 		lsm_svg_view_text_extents 	(LsmSvgView *view, char const *string, double x, double y, LsmExtents *extents);
+void 		lsm_svg_view_start_text 	(LsmSvgView *view);
+void 		lsm_svg_view_end_text 		(LsmSvgView *view);
+void 		lsm_svg_view_show_text 		(LsmSvgView *view, char const *string, 
+						 unsigned int n_x, double *x, unsigned int n_y, double *y,
+						 unsigned int n_dx, double *dx, unsigned int n_dy, double *dy);
+void 		lsm_svg_view_text_extents 	(LsmSvgView *view, char const *string,
+						 double x, double y,
+						 unsigned int n_dx, double *dx, unsigned int n_dy, double *dy,
+						 LsmExtents *extents);
 void		lsm_svg_view_show_pixbuf	(LsmSvgView *view, GdkPixbuf *pixbuf);
 
 void 		lsm_svg_view_push_viewbox 		(LsmSvgView *view, const LsmBox *viewbox);
diff --git a/tests/.gitignore b/tests/.gitignore
index 450d4ba..21a68cd 100644
--- a/tests/.gitignore
+++ b/tests/.gitignore
@@ -1,4 +1,5 @@
 dom
+str
 lsm-test
 fuzz.*
 *-diff.png



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