[lasem/properties] Some more work on property lists.



commit 9233b1a38a6b9bb84353a9e75e776283d5b17e02
Author: Emmanuel Pacaud <emmanuel pacaud lapp in2p3 fr>
Date:   Wed Jul 22 18:14:56 2009 +0200

    Some more work on property lists.

 src/Makefile.am                   |    9 +-
 src/lasempropertytest.c           |  133 -------
 src/lsmdomdocument.c              |    6 +
 src/lsmmathmlmathelement.c        |    2 +
 src/lsmmathmltableelement.c       |    2 +
 src/lsmproperties.c               |   68 +++--
 src/lsmproperties.h               |   17 +-
 src/lsmsvgcircleelement.c         |    1 +
 src/lsmsvgelement.c               |   14 +-
 src/lsmsvgelement.h               |    2 +
 src/lsmsvgellipseelement.c        |    1 +
 src/lsmsvggraphic.c               |    1 +
 src/lsmsvgimageelement.c          |    2 +
 src/lsmsvglineargradientelement.c |    1 +
 src/lsmsvgpathelement.c           |    1 +
 src/lsmsvgradialgradientelement.c |    1 +
 src/lsmsvgrectelement.c           |    1 +
 src/lsmsvgstyle.c                 |  686 +++++++++++++++++++++++++++++++++++++
 src/lsmsvgstyle.h                 |   97 ++++++
 src/lsmsvgsvgelement.c            |    2 +
 src/lsmsvgtextelement.c           |    1 +
 21 files changed, 873 insertions(+), 175 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index e6c115c..948c13d 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -180,7 +180,7 @@ liblasem_la_HEADERS = \
 	lsmsvgview.h				\
 	lsmsvgmatrix.h
 
-bin_PROGRAMS = lasemtest lasemrender lasempropertytest
+bin_PROGRAMS = lasemtest lasemrender
 
 lasemrender_SOURCES = 				\
 	lasemrender.c
@@ -195,10 +195,3 @@ lasemtest_SOURCES = 				\
 lasemtest_LDFLAGS =
 
 lasemtest_LDADD = $(LASEM_LIBS) liblasem.la ../itex2mml/libitex2mml.la
-
-lasempropertytest_SOURCES = 				\
-	lasempropertytest.c
-
-lasempropertytest_LDFLAGS =
-
-lasempropertytest_LDADD = $(LASEM_LIBS) liblasem.la ../itex2mml/libitex2mml.la
diff --git a/src/lsmdomdocument.c b/src/lsmdomdocument.c
index 8dd9879..7d41bb8 100644
--- a/src/lsmdomdocument.c
+++ b/src/lsmdomdocument.c
@@ -24,6 +24,8 @@
 #include <lsmdebug.h>
 #include <lsmdomtext.h>
 
+static GObjectClass *parent_class;
+
 /* LsmDomNode implementation */
 
 static const char *
@@ -205,6 +207,8 @@ lsm_dom_document_finalize (GObject *object)
 
 	g_hash_table_unref (document->elements);
 	g_hash_table_unref (document->ids);
+
+	parent_class->finalize (object);
 }
 
 /* LsmDomDocument class */
@@ -215,6 +219,8 @@ lsm_dom_document_class_init (LsmDomDocumentClass *klass)
 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
 	LsmDomNodeClass *node_class = LSM_DOM_NODE_CLASS (klass);
 
+	parent_class = g_type_class_peek_parent (klass);
+
 	object_class->finalize = lsm_dom_document_finalize;
 
 	node_class->get_node_name = lsm_dom_document_get_node_name;
diff --git a/src/lsmmathmlmathelement.c b/src/lsmmathmlmathelement.c
index 2ae7673..e494c65 100644
--- a/src/lsmmathmlmathelement.c
+++ b/src/lsmmathmlmathelement.c
@@ -181,6 +181,8 @@ lsm_mathml_math_element_finalize (GObject *object)
 	LsmMathmlMathElement *math_element = LSM_MATHML_MATH_ELEMENT (object);
 
 	lsm_mathml_style_free (math_element->default_style);
+
+	parent_class->finalize (object);
 }
 
 /* LsmMathmlMathElement class */
diff --git a/src/lsmmathmltableelement.c b/src/lsmmathmltableelement.c
index c4fa903..31c869a 100644
--- a/src/lsmmathmltableelement.c
+++ b/src/lsmmathmltableelement.c
@@ -457,6 +457,8 @@ lsm_mathml_table_element_finalize (GObject *object)
 	table->widths = NULL;
 	table->heights = NULL;
 	table->depths = NULL;
+
+	parent_class->finalize (object);
 }
 
 /* LsmMathmlTableElement class */
diff --git a/src/lsmproperties.c b/src/lsmproperties.c
index 028ca51..a17a46c 100644
--- a/src/lsmproperties.c
+++ b/src/lsmproperties.c
@@ -92,7 +92,7 @@ property_free (LsmProperty *property, const LsmPropertyClass *property_class)
 }
 
 void
-lsm_property_list_set_property (GSList **property_list,
+lsm_property_bag_set_property (LsmPropertyBag *property_bag,
 				LsmPropertyManager *manager,
 				const char *name, const char *value)
 {
@@ -100,7 +100,7 @@ lsm_property_list_set_property (GSList **property_list,
 	const LsmPropertyInfos *property_infos;
 	const LsmPropertyClass *property_class;
 
-	g_return_if_fail (property_list != NULL);
+	g_return_if_fail (property_bag != NULL);
 	g_return_if_fail (manager != NULL);
 
 	property_infos = lsm_property_manager_find_infos (manager, name);
@@ -111,34 +111,29 @@ lsm_property_list_set_property (GSList **property_list,
 
 	/* We don't check for existing property in the list. The cleanup will be done later. */
 
-	property = g_slice_alloc (property_class->size);
+	property = g_slice_alloc0 (property_class->size);
 	property->id = property_infos->id;
 	property->value = g_strdup (value);
 
 	if (property_class->init)
 		property_class->init (property);
 
-	if (property->value != NULL && property_class->from_text) {
-		if (!property_class->from_text (property, value)) {
-			g_free (property->value);
-			property->value = NULL;
-			return;
-		}
-	}
+	if (property->value != NULL && property_class->from_text)
+		property_class->from_text (property, value);
 
-	*property_list = g_slist_prepend (*property_list, property);
+	property_bag->properties = g_slist_prepend (property_bag->properties, property);
 }
 
 const char *
-lsm_property_list_get_property (GSList **property_list,
-				LsmPropertyManager *manager,
-				const char *name)
+lsm_property_bag_get_property (LsmPropertyBag *property_bag,
+			       LsmPropertyManager *manager,
+			       const char *name)
 {
 	LsmProperty *property = NULL;
 	const LsmPropertyInfos *property_infos;
 	GSList *iter;
 
-	g_return_val_if_fail (property_list != NULL, NULL);
+	g_return_val_if_fail (property_bag != NULL, NULL);
 	g_return_val_if_fail (manager != NULL, NULL);
 
 	property_infos = lsm_property_manager_find_infos (manager, name);
@@ -147,7 +142,7 @@ lsm_property_list_get_property (GSList **property_list,
 
 	g_message ("Get property with name %s (%d)", name, property_infos->id);
 
-	for (iter = *property_list; iter != NULL; iter = iter->next) {
+	for (iter = property_bag->properties; iter != NULL; iter = iter->next) {
 		property = iter->data;
 		if (property->id == property_infos->id)
 			break;
@@ -160,16 +155,17 @@ lsm_property_list_get_property (GSList **property_list,
 }
 
 void
-lsm_property_list_free (GSList **property_list, LsmPropertyManager *manager)
+lsm_property_bag_clean (LsmPropertyBag *property_bag,
+			LsmPropertyManager *manager)
 {
 	LsmProperty *property;
 	const LsmPropertyInfos *property_infos;
 	GSList *iter;
 
-	g_return_if_fail (property_list != NULL);
+	g_return_if_fail (property_bag != NULL);
 	g_return_if_fail (manager != NULL);
 
-	for (iter = *property_list; iter != NULL; iter = iter->next) {
+	for (iter = property_bag->properties; iter != NULL; iter = iter->next) {
 		property = iter->data;
 
 		property_infos = lsm_property_manager_find_infos_by_id (manager, property->id);
@@ -177,19 +173,39 @@ lsm_property_list_free (GSList **property_list, LsmPropertyManager *manager)
 		property_free (property, property_infos->property_class);
 	}
 
-	g_slist_free (*property_list);
-	*property_list = NULL;
+	g_slist_free (property_bag->properties);
+	property_bag->properties = NULL;
 }
 
-void
-lsm_property_manager_apply_list	(LsmPropertyManager *manager, GSList *property_list,
-				 void **property_set, size_t set_size)
+char *
+lsm_property_bag_serialize (LsmPropertyBag *property_bag,
+			    LsmPropertyManager *property_manager)
 {
 	LsmProperty *property;
+	const LsmPropertyInfos *property_infos;
 	GSList *iter;
+	GString *string;
+	char *c_string;
+
+	g_return_val_if_fail (property_bag != NULL, NULL);
+	g_return_val_if_fail (property_manager != NULL, NULL);
+
+	string = g_string_new ("");
 
-	for (iter = property_list; iter != NULL; iter = iter->next) {
+	for (iter = property_bag->properties; iter != NULL; iter = iter->next) {
 		property = iter->data;
-		property_set[property->id] = property;
+
+		property_infos = lsm_property_manager_find_infos_by_id (property_manager, property->id);
+
+		g_string_append_printf (string, "%s=\"%s\"%s",
+					property_infos->name,
+					property->value,
+					iter->next != NULL ? " ": "");
 	}
+
+
+	c_string = string->str;
+	g_string_free (string, FALSE);
+
+	return c_string;
 }
diff --git a/src/lsmproperties.h b/src/lsmproperties.h
index 565f437..8d1d789 100644
--- a/src/lsmproperties.h
+++ b/src/lsmproperties.h
@@ -36,7 +36,7 @@ typedef struct {
 	size_t		size;
 	void 		(*init)			(LsmProperty *property);
 	void 		(*finalize)		(LsmProperty *property);
-	gboolean	(*from_text)		(LsmProperty *property, const char *value);
+	void		(*from_text)		(LsmProperty *property, const char *value);
 	char * 		(*to_text)		(LsmProperty *property);
 } LsmPropertyClass;
 
@@ -46,22 +46,25 @@ typedef struct {
 	const LsmPropertyClass *	property_class;
 } LsmPropertyInfos;
 
+typedef struct {
+	GSList *properties;
+} LsmPropertyBag;
+
 typedef struct _LsmPropertyManager LsmPropertyManager;
 
 LsmPropertyManager *	lsm_property_manager_new	(unsigned int n_properties,
 							 const LsmPropertyInfos *property_infos);
 void			lsm_property_manager_free	(LsmPropertyManager *manager);
 
-void 		lsm_property_list_set_property 		(GSList **property_list,
+void 		lsm_property_bag_set_property 		(LsmPropertyBag *property_bag,
 							 LsmPropertyManager *manager,
 							 const char *name, const char *value);
-const char *	lsm_property_list_get_property 		(GSList **property_list,
+const char *	lsm_property_bag_get_property 		(LsmPropertyBag *property_bag,
 							 LsmPropertyManager *manager,
 							 const char *name);
-void		lsm_property_list_free			(GSList **property_list,
+void		lsm_property_bag_clean			(LsmPropertyBag *property_bag,
 							 LsmPropertyManager *manager);
-
-void		lsm_property_manager_apply_list		(LsmPropertyManager *manager, GSList *property_list,
-							 void **property_set, size_t set_size);
+char * 		lsm_property_bag_serialize 		(LsmPropertyBag *property_bag,
+							 LsmPropertyManager *property_manager);
 
 G_END_DECLS
diff --git a/src/lsmsvgcircleelement.c b/src/lsmsvgcircleelement.c
index 5371a7d..ac85261 100644
--- a/src/lsmsvgcircleelement.c
+++ b/src/lsmsvgcircleelement.c
@@ -90,6 +90,7 @@ lsm_svg_circle_element_init (LsmSvgCircleElement *self)
 static void
 lsm_svg_circle_element_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgCircleElement class */
diff --git a/src/lsmsvgelement.c b/src/lsmsvgelement.c
index 26299b2..cdb37a4 100644
--- a/src/lsmsvgelement.c
+++ b/src/lsmsvgelement.c
@@ -53,13 +53,16 @@ lsm_svg_element_child_changed (LsmDomNode *parent, LsmDomNode *child)
 static void
 lsm_svg_element_set_attribute (LsmDomElement *self, const char* name, const char *value)
 {
-	LsmSvgElementClass *s_element_class = LSM_SVG_ELEMENT_GET_CLASS(self);
+	LsmSvgElementClass *s_element_class = LSM_SVG_ELEMENT_GET_CLASS (self);
+	LsmSvgElement *s_element = LSM_SVG_ELEMENT (self);
 
 	lsm_debug ("[LsmSvgElement::set_attribute] node = %s, name = %s, value = %s",
 		    lsm_dom_node_get_node_name (LSM_DOM_NODE (self)), name, value);
 
 	lsm_dom_attribute_map_set_attribute (s_element_class->attributes, self,
 					     name, value);
+
+	lsm_svg_property_bag_set_property (&s_element->property_bag, name, value);
 }
 
 const char *
@@ -220,6 +223,15 @@ lsm_svg_element_init (LsmSvgElement *element)
 static void
 lsm_svg_element_finalize (GObject *object)
 {
+	LsmSvgElement *svg_element = LSM_SVG_ELEMENT (object);
+	char *string;
+
+	string = lsm_svg_property_bag_serialize (&svg_element->property_bag);
+	lsm_debug ("%s", string);
+	g_free (string);
+
+	lsm_svg_property_bag_clean (&svg_element->property_bag);
+
 	parent_class->finalize (object);
 }
 
diff --git a/src/lsmsvgelement.h b/src/lsmsvgelement.h
index 0a877c3..42fc3a1 100644
--- a/src/lsmsvgelement.h
+++ b/src/lsmsvgelement.h
@@ -44,6 +44,8 @@ typedef struct _LsmSvgElementClass LsmSvgElementClass;
 struct _LsmSvgElement {
 	LsmDomElement	element;
 
+	LsmPropertyBag property_bag;
+
 	LsmDomAttribute	id;
 
 	/* View */
diff --git a/src/lsmsvgellipseelement.c b/src/lsmsvgellipseelement.c
index 17f7783..233b539 100644
--- a/src/lsmsvgellipseelement.c
+++ b/src/lsmsvgellipseelement.c
@@ -91,6 +91,7 @@ lsm_svg_ellipse_element_init (LsmSvgEllipseElement *self)
 static void
 lsm_svg_ellipse_element_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgEllipseElement class */
diff --git a/src/lsmsvggraphic.c b/src/lsmsvggraphic.c
index 75ec2c5..4974377 100644
--- a/src/lsmsvggraphic.c
+++ b/src/lsmsvggraphic.c
@@ -253,6 +253,7 @@ lsm_svg_graphic_init (LsmSvgGraphic *self)
 static void
 lsm_svg_graphic_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgGraphic class */
diff --git a/src/lsmsvgimageelement.c b/src/lsmsvgimageelement.c
index 61057fd..0b4b2db 100644
--- a/src/lsmsvgimageelement.c
+++ b/src/lsmsvgimageelement.c
@@ -172,6 +172,8 @@ lsm_svg_image_element_finalize (GObject *gobject)
 
 	if (image->pixbuf != NULL)
 		g_object_unref (image->pixbuf);
+
+	parent_class->finalize (gobject);
 }
 
 /* LsmSvgImageElement class */
diff --git a/src/lsmsvglineargradientelement.c b/src/lsmsvglineargradientelement.c
index 2fd37cf..9301706 100644
--- a/src/lsmsvglineargradientelement.c
+++ b/src/lsmsvglineargradientelement.c
@@ -110,6 +110,7 @@ lsm_svg_linear_gradient_element_init (LsmSvgLinearGradientElement *self)
 static void
 lsm_svg_linear_gradient_element_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgLinearGradientElement class */
diff --git a/src/lsmsvgpathelement.c b/src/lsmsvgpathelement.c
index e7e55d1..7514e5f 100644
--- a/src/lsmsvgpathelement.c
+++ b/src/lsmsvgpathelement.c
@@ -63,6 +63,7 @@ lsm_svg_path_element_init (LsmSvgPathElement *self)
 static void
 lsm_svg_path_element_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgPathElement class */
diff --git a/src/lsmsvgradialgradientelement.c b/src/lsmsvgradialgradientelement.c
index a219369..7c3279a 100644
--- a/src/lsmsvgradialgradientelement.c
+++ b/src/lsmsvgradialgradientelement.c
@@ -126,6 +126,7 @@ lsm_svg_radial_gradient_element_init (LsmSvgRadialGradientElement *self)
 static void
 lsm_svg_radial_gradient_element_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgRadialGradientElement class */
diff --git a/src/lsmsvgrectelement.c b/src/lsmsvgrectelement.c
index b039e9c..53a30b3 100644
--- a/src/lsmsvgrectelement.c
+++ b/src/lsmsvgrectelement.c
@@ -130,6 +130,7 @@ lsm_svg_rect_element_init (LsmSvgRectElement *self)
 static void
 lsm_svg_rect_element_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgRectElement class */
diff --git a/src/lsmsvgstyle.c b/src/lsmsvgstyle.c
index 8e98709..09a3717 100644
--- a/src/lsmsvgstyle.c
+++ b/src/lsmsvgstyle.c
@@ -20,7 +20,693 @@
  */
 
 #include <lsmsvgstyle.h>
+#include <lsmsvgcolors.h>
+#include <lsmsvgutils.h>
 #include <string.h>
+#include <math.h>
+
+static const LsmPropertyClass lsm_svg_property_class = {
+	.size = sizeof (LsmProperty)
+};
+
+static void
+lsm_svg_double_property_from_text (LsmProperty *property, const char *value)
+{
+	LsmSvgDoubleProperty *svg_double = (LsmSvgDoubleProperty *) property;
+
+	svg_double->value = g_strtod (value, NULL);
+}
+
+char *
+lsm_svg_double_property_to_text (LsmProperty *property)
+{
+	LsmSvgDoubleProperty *svg_double = (LsmSvgDoubleProperty *) property;
+
+	return g_strdup_printf ("%g", svg_double->value);
+}
+
+static const LsmPropertyClass lsm_svg_double_property_class = {
+	.size = sizeof (LsmSvgDoubleProperty),
+	.from_text = lsm_svg_double_property_from_text,
+	.to_text = lsm_svg_double_property_to_text
+};
+
+static void
+lsm_svg_length_property_from_text (LsmProperty *property, const char *value)
+{
+	LsmSvgLengthProperty *svg_length = (LsmSvgLengthProperty *) property;
+	char *length_type_str;
+
+	svg_length->length.value_unit = g_strtod (value, &length_type_str);
+	svg_length->length.type = lsm_svg_length_type_from_string (length_type_str);
+}
+
+char *
+lsm_svg_length_property_to_text (LsmProperty *property)
+{
+	LsmSvgLengthProperty *svg_length = (LsmSvgLengthProperty *) property;
+
+	return g_strdup_printf ("%g%s",
+				svg_length->length.value_unit,
+				lsm_svg_length_type_to_string (svg_length->length.type));
+}
+
+static const LsmPropertyClass lsm_svg_length_property_class = {
+	.size = sizeof (LsmSvgLengthProperty),
+	.from_text = lsm_svg_length_property_from_text,
+	.to_text = lsm_svg_length_property_to_text
+};
+
+static void
+_init_matrix (LsmSvgMatrix *matrix, LsmSvgTransformType transform, unsigned int n_values, double values[])
+{
+	switch (transform) {
+		case LSM_SVG_TRANSFORM_TYPE_SCALE:
+			if (n_values == 1) {
+				lsm_svg_matrix_init_scale (matrix, values[0], values[0]);
+				return;
+			} else if (n_values == 2) {
+				lsm_svg_matrix_init_scale (matrix, values[0], values[1]);
+				return;
+			}
+			break;
+		case LSM_SVG_TRANSFORM_TYPE_TRANSLATE:
+			if (n_values == 1) {
+				lsm_svg_matrix_init_translate (matrix, values[0], values[0]);
+				return;
+			} else if (n_values == 2) {
+				lsm_svg_matrix_init_translate (matrix, values[0], values[1]);
+				return;
+			}
+			break;
+		case LSM_SVG_TRANSFORM_TYPE_MATRIX:
+			if (n_values == 6) {
+				lsm_svg_matrix_init (matrix,
+						  values[0], values[1],
+						  values[2], values[3],
+						  values[4], values[5]);
+				return;
+			}
+			break;
+		case LSM_SVG_TRANSFORM_TYPE_ROTATE:
+			if (n_values == 1) {
+				lsm_svg_matrix_init_rotate (matrix, values[0] * M_PI / 180.0);
+				return;
+			} else if (n_values == 3) {
+				LsmSvgMatrix matrix_b;
+
+				lsm_svg_matrix_init_translate (matrix, values[1], values[2]);
+				lsm_svg_matrix_init_rotate (&matrix_b, values[0] * M_PI / 180.0);
+				lsm_svg_matrix_multiply (matrix, &matrix_b, matrix);
+				lsm_svg_matrix_init_translate (&matrix_b, -values[1], -values[2]);
+				lsm_svg_matrix_multiply (matrix, &matrix_b, matrix);
+				return;
+			}
+			break;
+		case LSM_SVG_TRANSFORM_TYPE_SKEW_X:
+			if (n_values == 1) {
+				lsm_svg_matrix_init_skew_x (matrix, values[0] * M_PI / 180.0);
+				return;
+			}
+			break;
+		case LSM_SVG_TRANSFORM_TYPE_SKEW_Y:
+			if (n_values == 1) {
+				lsm_svg_matrix_init_skew_y (matrix, values[0] * M_PI / 180.0);
+				return;
+			}
+		default:
+			break;
+	}
+
+	lsm_svg_matrix_init_identity (matrix);
+}
+
+static void
+lsm_svg_transform_property_from_text (LsmProperty *property, const char *value)
+{
+	LsmSvgTransformProperty *svg_transform = (LsmSvgTransformProperty *) property;
+	char *string;
+
+	string = (char *) value;
+
+	lsm_svg_matrix_init_identity (&svg_transform->matrix);
+
+	while (*string != '\0') {
+		LsmSvgTransformType transform;
+		double values[6];
+
+		lsm_svg_str_skip_spaces (&string);
+
+		if (strncmp (string, "translate", 9) == 0) {
+			transform = LSM_SVG_TRANSFORM_TYPE_TRANSLATE;
+			string += 9;
+		} else if (strncmp (string, "scale", 5) == 0) {
+			transform = LSM_SVG_TRANSFORM_TYPE_SCALE;
+			string += 5;
+		} else if (strncmp (string, "rotate", 6) == 0) {
+			transform = LSM_SVG_TRANSFORM_TYPE_ROTATE;
+			string += 6;
+		} else if (strncmp (string, "matrix", 6) == 0) {
+			transform = LSM_SVG_TRANSFORM_TYPE_MATRIX;
+			string += 6;
+		} else if (strncmp (string, "skewX", 5) == 0) {
+			transform = LSM_SVG_TRANSFORM_TYPE_SKEW_X;
+			string += 5;
+		} else if (strncmp (string, "skewY", 5) == 0) {
+			transform = LSM_SVG_TRANSFORM_TYPE_SKEW_Y;
+			string += 5;
+		} else
+			break;
+
+		lsm_svg_str_skip_spaces (&string);
+
+		if (*string == '(') {
+			unsigned int n_values = 0;
+
+			string++;
+
+			while (*string != ')' && *string != '\0' && n_values < 6) {
+				lsm_svg_str_skip_comma_and_spaces (&string);
+
+				if (!lsm_svg_str_parse_double (&string, &values[n_values]))
+					break;
+
+				n_values++;
+			}
+
+			lsm_svg_str_skip_comma_and_spaces (&string);
+
+			if (*string == ')') {
+				LsmSvgMatrix matrix;
+
+				string++;
+
+				_init_matrix (&matrix, transform, n_values, values);
+
+				lsm_svg_matrix_multiply (&svg_transform->matrix, &matrix, &svg_transform->matrix);
+			}
+		}
+	}
+}
+
+char *
+lsm_svg_transform_property_to_text (LsmProperty *property)
+{
+	LsmSvgTransformProperty *svg_transform = (LsmSvgTransformProperty *) property;
+
+	/* TODO smarter serialization, checking for zeros */
+	return g_strdup_printf ("matrix(%g,%g,%g,%g,%g,%g)",
+				svg_transform->matrix.a,
+				svg_transform->matrix.b,
+				svg_transform->matrix.c,
+				svg_transform->matrix.d,
+				svg_transform->matrix.e,
+				svg_transform->matrix.f);
+}
+
+static const LsmPropertyClass lsm_svg_transform_property_class = {
+	.size = sizeof (LsmSvgTransformProperty),
+	.from_text = lsm_svg_transform_property_from_text,
+	.to_text = lsm_svg_transform_property_to_text
+};
+
+static char *
+_parse_color (char *string,
+	      LsmSvgColor *svg_color,
+	      gboolean *is_color_set)
+{
+	unsigned int color = 0;
+	*is_color_set = FALSE;
+
+	lsm_svg_str_skip_spaces (&string);
+
+	if (g_strcmp0 (string, "currentColor") == 0) {
+		svg_color->red = -1.0;
+		svg_color->green = 1.0;
+		svg_color->blue = 1.0;
+
+		*is_color_set = TRUE;
+
+		string += 12; /* strlen ("current_color") */
+
+		return string;
+	}
+
+	if (*string == '#') {
+		int value, i;
+		string++;
+
+		for (i = 0; i < 6; i++) {
+			if (*string >= '0' && *string <= '9')
+				value = *string - '0';
+			else if (*string >= 'A' && *string <= 'F')
+				value = *string - 'A' + 10;
+			else if (*string >= 'a' && *string <= 'f')
+				value = *string - 'a' + 10;
+			else
+				break;
+
+			color = (color << 4) + value;
+			string++;
+		}
+
+		if (i == 3) {
+			color = ((color & 0xf00) << 8) | ((color & 0x0f0) << 4) | (color & 0x00f);
+			color |= color << 4;
+		} else if (i != 6)
+			color = 0;
+
+		*is_color_set = TRUE;
+	} else if (strncmp (string, "rgb(", 4) == 0) {
+		int i;
+		double value;
+
+
+		string += 4; /* strlen ("rgb(") */
+
+		for (i = 0; i < 3; i++) {
+			if (!lsm_svg_str_parse_double (&string, &value))
+				break;
+
+			if (*string == '%') {
+				value = value * 255.0 / 100.0;
+				string++;
+			}
+
+			if (i < 2)
+				lsm_svg_str_skip_comma_and_spaces (&string);
+
+			color = (color << 8) + (int) (0.5 + CLAMP (value, 0.0, 255.0));
+		}
+
+		lsm_svg_str_skip_spaces (&string);
+
+		if (*string != ')' || i != 3)
+			color = 0;
+
+		*is_color_set  = TRUE;
+	} else if (g_strcmp0 (string, "none") == 0) {
+		*is_color_set = FALSE;
+	} else {
+		color = lsm_svg_color_from_string (string);
+
+		*is_color_set = TRUE;
+	}
+
+	svg_color->red = (double) ((color & 0xff0000) >> 16) / 255.0;
+	svg_color->green = (double) ((color & 0x00ff00) >> 8) / 255.0;
+	svg_color->blue = (double) (color & 0x0000ff) / 255.0;
+
+	return string;
+}
+
+static void
+lsm_svg_paint_property_from_text (LsmProperty *abstract_property, const char *value)
+{
+	LsmSvgPaintProperty *property = (LsmSvgPaintProperty *) abstract_property;
+	char *string;
+	gboolean is_color_set;
+
+	g_free (property->paint.uri);
+
+	string = (char *) value;
+
+	if (strncmp (string, "url(#", 5) == 0) {
+		unsigned int length;
+
+		string += 5;
+		length = 0;
+		while (string[length] != ')')
+			length++;
+		length++;
+
+		property->paint.uri = g_new (char, length);
+		if (property->paint.uri != NULL) {
+			memcpy (property->paint.uri, string, length - 1);
+			property->paint.uri[length - 1] = '\0';
+		}
+		string += length;
+	} else {
+		property->paint.uri = NULL;
+	}
+
+	string = _parse_color (string, &property->paint.color, &is_color_set);
+
+	if (is_color_set)
+		property->paint.type = property->paint.uri != NULL ?
+			LSM_SVG_PAINT_TYPE_URI_RGB_COLOR :
+			LSM_SVG_PAINT_TYPE_RGB_COLOR;
+	else
+		property->paint.type = property->paint.uri != NULL ?
+			LSM_SVG_PAINT_TYPE_URI :
+			LSM_SVG_PAINT_TYPE_NONE;
+}
+
+char *
+lsm_svg_paint_property_to_text (LsmProperty *abstract_property)
+{
+	LsmSvgPaintProperty *property = (LsmSvgPaintProperty *) abstract_property;
+
+	if (property->paint.color.red < 0.0 ||
+	    property->paint.color.green < 0.0 ||
+	    property->paint.color.blue < 0.0)
+		return g_strdup ("currentColor");
+
+	if (property->paint.uri != NULL)
+		g_strdup_printf ("url(#%s)", property->paint.uri);
+
+	return g_strdup_printf ("rgb(%g%%,%g%%,%g%%)",
+				100.0 * property->paint.color.red,
+				100.0 * property->paint.color.green,
+				100.0 * property->paint.color.blue);
+}
+
+static const LsmPropertyClass lsm_svg_paint_property_class = {
+	.size = sizeof (LsmSvgPaintProperty),
+	.from_text = lsm_svg_paint_property_from_text,
+	.to_text = lsm_svg_paint_property_to_text
+};
+
+static void
+lsm_svg_fill_rule_property_from_text (LsmProperty *abstract_property, const char *value)
+{
+	LsmSvgFillRuleProperty *property = (LsmSvgFillRuleProperty *) abstract_property;
+
+	property->value = lsm_svg_fill_rule_from_string (value);
+}
+
+char *
+lsm_svg_fill_rule_property_to_text (LsmProperty *abstract_property)
+{
+	LsmSvgFillRuleProperty *property = (LsmSvgFillRuleProperty *) abstract_property;
+
+	return g_strdup (lsm_svg_fill_rule_to_string (property->value));
+}
+
+static const LsmPropertyClass lsm_svg_fill_rule_property_class = {
+	.size = sizeof (LsmSvgFillRuleProperty),
+	.from_text = lsm_svg_fill_rule_property_from_text,
+	.to_text = lsm_svg_fill_rule_property_to_text
+};
+
+static void
+lsm_svg_line_join_property_from_text (LsmProperty *abstract_property, const char *value)
+{
+	LsmSvgLineJoinProperty *property = (LsmSvgLineJoinProperty *) abstract_property;
+
+	property->value = lsm_svg_line_join_from_string (value);
+}
+
+char *
+lsm_svg_line_join_property_to_text (LsmProperty *abstract_property)
+{
+	LsmSvgLineJoinProperty *property = (LsmSvgLineJoinProperty *) abstract_property;
+
+	return g_strdup (lsm_svg_line_join_to_string (property->value));
+}
+
+static const LsmPropertyClass lsm_svg_line_join_property_class = {
+	.size = sizeof (LsmSvgLineJoinProperty),
+	.from_text = lsm_svg_line_join_property_from_text,
+	.to_text = lsm_svg_line_join_property_to_text
+};
+
+static void
+lsm_svg_line_cap_property_from_text (LsmProperty *abstract_property, const char *value)
+{
+	LsmSvgLineCapProperty *property = (LsmSvgLineCapProperty *) abstract_property;
+
+	property->value = lsm_svg_line_cap_from_string (value);
+}
+
+static char *
+lsm_svg_line_cap_property_to_text (LsmProperty *abstract_property)
+{
+	LsmSvgLineCapProperty *property = (LsmSvgLineCapProperty *) abstract_property;
+
+	return g_strdup (lsm_svg_line_cap_to_string (property->value));
+}
+
+static const LsmPropertyClass lsm_svg_line_cap_property_class = {
+	.size = sizeof (LsmSvgLineCapProperty),
+	.from_text = lsm_svg_line_cap_property_from_text,
+	.to_text = lsm_svg_line_cap_property_to_text
+};
+
+static void
+lsm_svg_dash_array_property_from_text (LsmProperty *abstract_property, const char *value)
+{
+	LsmSvgDashArrayProperty *property = (LsmSvgDashArrayProperty *) abstract_property;
+	char *string;
+	unsigned int n_dashes = 1;
+
+	string = (char *) value;
+
+	lsm_svg_dash_array_free (property->value);
+
+	if (strcmp (string, "none") == 0) {
+		property->value = (LsmSvgDashArray *) &lsm_svg_dash_array_null;
+	} else {
+		char *iter = (char *) string;
+		unsigned int i;
+
+		while (*iter != '\0') {
+			if (*iter == ',')
+				n_dashes++;
+			iter++;
+		}
+
+		property->value = lsm_svg_dash_array_new (n_dashes);
+		if (property->value != &lsm_svg_dash_array_null) {
+			LsmSvgLength length;
+
+			iter = (char *)string;
+			lsm_svg_str_skip_spaces (&iter);
+
+			for (i = 0; i < n_dashes; i++) {
+				if (lsm_svg_str_parse_double (&iter, &length.value_unit)) {
+					length.type = lsm_svg_length_type_from_string (iter);
+					property->value->dashes[i] = length;
+					while (*iter != '\0' && *iter != ' ' && *iter != ',')
+						iter ++;
+				} else {
+					property->value->dashes[i].value_unit = 0.0;
+					property->value->dashes[i].value_unit = LSM_SVG_LENGTH_TYPE_NUMBER;
+				}
+				lsm_svg_str_skip_comma_and_spaces (&iter);
+			}
+		}
+	}
+}
+
+static char *
+lsm_svg_dash_array_property_to_text (LsmProperty *abstract_property)
+{
+	g_assert_not_reached ();
+}
+
+static void
+lsm_svg_dash_array_property_finalize (LsmProperty *abstract_property)
+{
+	LsmSvgDashArrayProperty *property = (LsmSvgDashArrayProperty *) abstract_property;
+
+	lsm_svg_dash_array_free (property->value);
+	property->value = NULL;
+}
+
+static const LsmPropertyClass lsm_svg_dash_array_property_class = {
+	.size = sizeof (LsmSvgDashArrayProperty),
+	.from_text = lsm_svg_dash_array_property_from_text,
+	.to_text = lsm_svg_dash_array_property_to_text,
+	.finalize = lsm_svg_dash_array_property_finalize
+};
+
+static void
+lsm_svg_color_property_from_text (LsmProperty *abstract_property, const char *value)
+{
+	LsmSvgColorProperty *property = (LsmSvgColorProperty *) abstract_property;
+	char *string;
+	gboolean is_color_set;
+
+	string = (char *) value;
+
+	_parse_color (string, &property->value, &is_color_set);
+}
+
+char *
+lsm_svg_color_property_to_text (LsmProperty *abstract_property)
+{
+	LsmSvgColorProperty *property = (LsmSvgColorProperty *) abstract_property;
+
+	return g_strdup_printf ("rgb(%g%%,%g%%,%g%%)",
+				100.0 * property->value.red,
+				100.0 * property->value.green,
+				100.0 * property->value.blue);
+}
+
+static const LsmPropertyClass lsm_svg_color_property_class = {
+	.size = sizeof (LsmSvgColorProperty),
+	.from_text = lsm_svg_color_property_from_text,
+	.to_text = lsm_svg_color_property_to_text
+};
+
+static const LsmPropertyInfos lsm_svg_property_infos[] = {
+	{
+		.name = "x",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, x),
+		.property_class = &lsm_svg_length_property_class
+	},
+	{
+		.name = "y",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, y),
+		.property_class = &lsm_svg_length_property_class
+	},
+	{
+		.name = "opacity",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, group_opacity),
+		.property_class = &lsm_svg_double_property_class
+	},
+	{
+		.name = "transform",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, transform),
+		.property_class = &lsm_svg_transform_property_class
+	},
+	{
+		.name = "fill",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, fill.paint),
+		.property_class = &lsm_svg_paint_property_class
+	},
+	{
+		.name = "fill-opacity",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, fill.opacity),
+		.property_class = &lsm_svg_double_property_class
+	},
+	{
+		.name = "fill-rule",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, fill.rule),
+		.property_class = &lsm_svg_fill_rule_property_class
+	},
+	{
+		.name = "stroke",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.paint),
+		.property_class = &lsm_svg_paint_property_class
+	},
+	{
+		.name = "stroke-opacity",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.opacity),
+		.property_class = &lsm_svg_double_property_class
+	},
+	{
+		.name = "stroke-width",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.width),
+		.property_class = &lsm_svg_length_property_class
+	},
+	{
+		.name = "stroke-linejoin",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.line_join),
+		.property_class = &lsm_svg_line_join_property_class
+	},
+	{
+		.name = "stroke-linecap",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.line_cap),
+		.property_class = &lsm_svg_line_cap_property_class
+	},
+	{
+		.name = "stroke-miterlimit",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.miter_limit),
+		.property_class = &lsm_svg_double_property_class
+	},
+	{
+		.name = "stroke-dashoffset",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.dash_offset),
+		.property_class = &lsm_svg_length_property_class
+	},
+	{
+		.name = "stroke-dasharray",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, stroke.dash_array),
+		.property_class = &lsm_svg_dash_array_property_class
+	},
+	{
+		.name = "font-family",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, text.font_family),
+		.property_class = &lsm_svg_property_class
+	},
+	{
+		.name = "font-size",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, text.font_size),
+		.property_class = &lsm_svg_length_property_class
+	},
+	{
+		.name = "clip-path",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, clip.url),
+		.property_class = &lsm_svg_property_class
+	},
+	{
+		.name = "clip-rule",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, clip.rule),
+		.property_class = &lsm_svg_fill_rule_property_class
+	},
+	{
+		.name = "mask",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, mask.url),
+		.property_class = &lsm_svg_property_class
+	},
+	{
+		.name = "stop-color",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, gradient_stop.color),
+		.property_class = &lsm_svg_color_property_class
+	},
+	{
+		.name = "stop-opacity",
+		.id = LSM_PROPERTY_OFFSET_TO_ID (LsmSvgStyleNew, gradient_stop.opacity),
+		.property_class = &lsm_svg_double_property_class
+	}
+};
+
+static LsmPropertyManager *
+lsm_svg_get_property_manager (void)
+{
+	static LsmPropertyManager *manager = NULL;
+
+	if (G_LIKELY (manager != NULL))
+		return manager;
+
+	manager = lsm_property_manager_new (G_N_ELEMENTS (lsm_svg_property_infos), lsm_svg_property_infos);
+
+	return manager;
+}
+
+void
+lsm_svg_property_bag_set_property (LsmPropertyBag *property_bag, const char *name, const char *value)
+{
+	LsmPropertyManager *property_manager = lsm_svg_get_property_manager ();
+
+	lsm_property_bag_set_property (property_bag, property_manager, name, value);
+}
+
+const char *
+lsm_svg_property_bag_get_property (LsmPropertyBag *property_bag, const char *name)
+{
+	LsmPropertyManager *property_manager = lsm_svg_get_property_manager ();
+
+	return lsm_property_bag_get_property (property_bag, property_manager, name);
+}
+
+void
+lsm_svg_property_bag_clean (LsmPropertyBag *property_bag)
+{
+	LsmPropertyManager *property_manager = lsm_svg_get_property_manager ();
+
+	lsm_property_bag_clean (property_bag, property_manager);
+}
+
+char *
+lsm_svg_property_bag_serialize (LsmPropertyBag *property_bag)
+{
+	LsmPropertyManager *property_manager = lsm_svg_get_property_manager ();
+
+	return lsm_property_bag_serialize (property_bag, property_manager);
+}
 
 LsmSvgStyle *
 lsm_svg_style_new (void)
diff --git a/src/lsmsvgstyle.h b/src/lsmsvgstyle.h
index ccd0c37..da8ff92 100644
--- a/src/lsmsvgstyle.h
+++ b/src/lsmsvgstyle.h
@@ -22,11 +22,108 @@
 #ifndef LSM_SVG_STYLE_H
 #define LSM_SVG_STYLE_H
 
+#include <lsmproperties.h>
 #include <lsmsvg.h>
 #include <lsmsvgattributebags.h>
 
 G_BEGIN_DECLS
 
+typedef struct {
+	LsmProperty base;
+	double value;
+} LsmSvgDoubleProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgLength length;
+} LsmSvgLengthProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgPaint paint;
+} LsmSvgPaintProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgColor value;
+} LsmSvgColorProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgMatrix matrix;
+} LsmSvgTransformProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgFillRule value;
+} LsmSvgFillRuleProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgLineJoin value;
+} LsmSvgLineJoinProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgLineCap value;
+} LsmSvgLineCapProperty;
+
+typedef struct {
+	LsmProperty base;
+	LsmSvgDashArray *value;
+} LsmSvgDashArrayProperty;
+
+typedef struct _LsmSvgStyleNew {
+	LsmSvgLengthProperty *		x;
+	LsmSvgLengthProperty *		y;
+
+	LsmSvgDoubleProperty *		group_opacity;
+	LsmSvgTransformProperty * 	transform;
+
+	struct {
+		LsmSvgPaintProperty *		paint;
+		LsmSvgDoubleProperty *		opacity;
+		LsmSvgFillRuleProperty *	rule;
+	} fill;
+
+	struct {
+		LsmSvgPaintProperty *	 	paint;
+		LsmSvgDoubleProperty *		opacity;
+		LsmSvgLengthProperty *		width;
+		LsmSvgLineJoinProperty *	line_join;
+		LsmSvgLineCapProperty *		line_cap;
+		LsmSvgDoubleProperty *		miter_limit;
+		LsmSvgLengthProperty *		dash_offset;
+		LsmSvgDashArrayProperty	*	dash_array;
+	} stroke;
+
+	struct {
+		LsmProperty *			font_family;
+		LsmSvgLengthProperty *		font_size;
+	} text;
+
+	struct {
+		LsmProperty *	 		url;
+		LsmSvgFillRuleProperty * 	rule;
+	} clip;
+
+	struct {
+		LsmProperty * 			url;
+	} mask;
+
+	struct {
+		LsmSvgColorProperty *	 	color;
+		LsmSvgDoubleProperty *		opacity;
+	} gradient_stop;
+} LsmSvgStyleNew;
+
+void 		lsm_svg_property_bag_set_property 	(LsmPropertyBag *property_bag,
+							 const char *name, const char *value);
+const char *	lsm_svg_property_bag_get_property	(LsmPropertyBag *property_bag,
+							 const char *name);
+void 		lsm_svg_property_bag_clean 		(LsmPropertyBag *property_bag);
+char * 		lsm_svg_property_bag_serialize 		(LsmPropertyBag *property_bag);
+
 struct _LsmSvgStyle {
 	LsmBox viewport;
 	LsmSvgColor color;
diff --git a/src/lsmsvgsvgelement.c b/src/lsmsvgsvgelement.c
index be01e75..f009949 100644
--- a/src/lsmsvgsvgelement.c
+++ b/src/lsmsvgsvgelement.c
@@ -229,6 +229,8 @@ lsm_svg_svg_element_finalize (GObject *object)
 	LsmSvgSvgElement *svg_element = LSM_SVG_SVG_ELEMENT (object);
 
 	lsm_svg_style_free (svg_element->default_style);
+
+	parent_class->finalize (object);
 }
 
 /* LsmSvgSvgElement class */
diff --git a/src/lsmsvgtextelement.c b/src/lsmsvgtextelement.c
index f89c44e..4bfe73b 100644
--- a/src/lsmsvgtextelement.c
+++ b/src/lsmsvgtextelement.c
@@ -102,6 +102,7 @@ lsm_svg_text_element_init (LsmSvgTextElement *self)
 static void
 lsm_svg_text_element_finalize (GObject *object)
 {
+	parent_class->finalize (object);
 }
 
 /* LsmSvgTextElement class */



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