[lasem/properties] [SVG] Property list WIP.



commit b83bf9fdba6550feeb43c3d79361aa9e9d32f543
Author: Emmanuel Pacaud <emmanuel pacaud lapp in2p3 fr>
Date:   Thu Aug 6 22:07:29 2009 +0200

    [SVG] Property list WIP.

 .gitignore                                 |    1 +
 src/lasemrender.c                          |  150 ++++++++-------------
 src/lasemtest.c                            |    7 +-
 src/lsmdomdocument.c                       |   75 +++++++++++
 src/lsmdomdocument.h                       |   12 ++-
 src/lsmdomnode.h                           |   24 ++--
 src/lsmdomparser.c                         |  134 ++++++++++++++++---
 src/lsmdomparser.h                         |    9 +-
 src/lsmmathmldocument.c                    |   40 +++---
 src/lsmmathmldocument.h                    |    2 +-
 src/lsmstr.c                               |   59 ++++++++
 src/lsmstr.h                               |    3 +
 src/lsmsvgcircleelement.c                  |    7 +-
 src/lsmsvgclippathelement.c                |   22 +++-
 src/lsmsvgclippathelement.h                |    2 +
 src/lsmsvgelement.c                        |   15 +--
 src/lsmsvgelement.h                        |    3 +-
 src/lsmsvgellipseelement.c                 |    8 +-
 src/lsmsvgimageelement.c                   |   63 ++++++++-
 src/lsmsvgmaskelement.c                    |   43 +++++--
 src/lsmsvgmaskelement.h                    |    2 +
 src/lsmsvgpatternelement.c                 |   10 +-
 src/lsmsvgradialgradientelement.c          |   12 ++-
 src/lsmsvgrectelement.c                    |   19 ++--
 src/lsmsvgsvgelement.c                     |   33 ++++--
 src/lsmsvgtraits.c                         |   64 ++++++----
 src/lsmsvgview.c                           |  200 ++++++++++++++++------------
 test/.gitignore                            |    1 -
 test/svg/svg1.1/color/images/colorprof.png |  Bin 0 -> 705 bytes
 29 files changed, 697 insertions(+), 323 deletions(-)
---
diff --git a/.gitignore b/.gitignore
index ba0eeca..1832f85 100644
--- a/.gitignore
+++ b/.gitignore
@@ -24,4 +24,5 @@ tags
 *.swp
 lasem.svg
 lasem.pc
+lasemtest.xml
 manugen
diff --git a/src/lasemrender.c b/src/lasemrender.c
index 32c89ab..b93cc01 100644
--- a/src/lasemrender.c
+++ b/src/lasemrender.c
@@ -85,16 +85,11 @@ int main(int argc, char **argv)
 	cairo_surface_t *surface;
 	GError *error = NULL;
 	GOptionContext *context;
-	GFile *file;
 	FileFormat format;
 	char *output_filename;
 	char *input_filename;
-	char *mime;
-	char *buffer = NULL;
-	size_t size;
 	double height_pt, width_pt;
 	unsigned int height, width;
-	gboolean success;
 
 	g_type_init ();
 
@@ -164,102 +159,69 @@ int main(int argc, char **argv)
 		g_free (directory);
 	}
 
-	mime = g_content_type_guess (input_filename, NULL, 0, NULL);
-	file = g_file_new_for_path (input_filename);
+	document = lsm_dom_document_new_from_path (input_filename, NULL);
+	if (document == NULL)
+		document = lsm_dom_document_new_from_url (input_filename, NULL);
 
-	success = g_file_load_contents (file, NULL, &buffer, &size, NULL, NULL);
-	if (!success) {
-		g_object_unref (file);
-		file = g_file_new_for_uri (input_filename);
-		success = g_file_load_contents (file, NULL, &buffer, &size, NULL, NULL);
-	}
+	if (document != NULL) {
+		lsm_dom_document_set_resolution (document, option_ppi);
+
+		view = lsm_dom_document_create_view (document);
+
+		lsm_dom_view_set_debug (view, option_debug);
 
-	if (success) {
-		char *mathml;
+		width_pt = 2.0;
+		height_pt = 2.0;
 
-		if (strcmp (mime, "text/mathml") == 0 ||
-		    strcmp (mime, "image/svg+xml") == 0)
-			mathml = buffer;
-		else {
-			mathml = itex2MML_parse (buffer, size);
-			g_free (buffer);
-			buffer = NULL;
+		lsm_dom_view_get_size (view, &width_pt, &height_pt);
+		lsm_dom_view_get_size_pixels (view, &width, &height);
+
+		switch (format) {
+			case FORMAT_PDF:
+				surface = cairo_pdf_surface_create (output_filename,
+								    width_pt, height_pt);
+				break;
+			case FORMAT_PS:
+				surface = cairo_ps_surface_create (output_filename,
+								   width_pt, height_pt);
+				break;
+			case FORMAT_PNG:
+				surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
+								      width,
+								      height);
+				break;
+			case FORMAT_SVG:
+			default:
+				surface = cairo_svg_surface_create (output_filename,
+								    width_pt, height_pt);
+				break;
 		}
 
-		if (mathml != NULL) {
-			document = lsm_dom_document_new_from_memory (mathml);
-			lsm_dom_document_set_resolution (document, option_ppi);
-
-			if (document != NULL) {
-				view = lsm_dom_document_create_view (document);
-
-				lsm_dom_view_set_debug (view, option_debug);
-
-				width_pt = 2.0;
-				height_pt = 2.0;
-
-				lsm_dom_view_get_size (view, &width_pt, &height_pt);
-				lsm_dom_view_get_size_pixels (view, &width, &height);
-
-				switch (format) {
-					case FORMAT_PDF:
-						surface = cairo_pdf_surface_create (output_filename,
-										    width_pt, height_pt);
-						break;
-					case FORMAT_PS:
-						surface = cairo_ps_surface_create (output_filename,
-										   width_pt, height_pt);
-						break;
-					case FORMAT_PNG:
-						surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
-										      width,
-										      height);
-						break;
-					case FORMAT_SVG:
-					default:
-						surface = cairo_svg_surface_create (output_filename,
-										    width_pt, height_pt);
-						break;
-				}
-
-				cairo = cairo_create (surface);
-				cairo_surface_destroy (surface);
-
-				lsm_dom_view_set_cairo (view, cairo);
-
-				lsm_dom_view_render (view, 0, 0);
-
-				switch (format) {
-					case FORMAT_PNG:
-						cairo_surface_write_to_png (cairo_get_target (cairo),
-									    output_filename);
-						break;
-					default:
-						break;
-				}
-
-				cairo_destroy (cairo);
-
-				g_object_unref (view);
-
-				g_object_unref (document);
-
-				lsm_debug ("width = %g pt, height = %g pt",  width_pt, height_pt);
-			} else
-				g_warning ("Can't load %s", input_filename);
-		} else
-			g_warning ("Invalid document");
-
-		if (mathml == buffer)
-			g_free (mathml);
-		else
-			itex2MML_free_string (mathml);
-
-		g_object_unref (file);
+		cairo = cairo_create (surface);
+		cairo_surface_destroy (surface);
+
+		lsm_dom_view_set_cairo (view, cairo);
+
+		lsm_dom_view_render (view, 0, 0);
+
+		switch (format) {
+			case FORMAT_PNG:
+				cairo_surface_write_to_png (cairo_get_target (cairo),
+							    output_filename);
+				break;
+			default:
+				break;
+		}
+
+		cairo_destroy (cairo);
+
+		g_object_unref (view);
+
+		g_object_unref (document);
+
+		lsm_debug ("width = %g pt, height = %g pt",  width_pt, height_pt);
 	} else
 		g_warning ("Can't load %s", input_filename);
 
-	g_free (mime);
-
 	return (0);
 }
diff --git a/src/lasemtest.c b/src/lasemtest.c
index 4a3a16e..bf385f6 100644
--- a/src/lasemtest.c
+++ b/src/lasemtest.c
@@ -115,10 +115,13 @@ lasem_test_render (char const *filename)
 
 		if (is_xml)
 			xml = buffer;
-		else
+		else {
 			xml = itex2MML_parse (buffer, size);
+			size = 0;
+		}
 
-		document = lsm_dom_document_new_from_memory (xml);
+		document = lsm_dom_document_new_from_memory (xml, size, NULL);
+		lsm_dom_document_set_path (document, filename);
 
 		view = lsm_dom_document_create_view (document);
 
diff --git a/src/lsmdomdocument.c b/src/lsmdomdocument.c
index 7d41bb8..c8062f1 100644
--- a/src/lsmdomdocument.c
+++ b/src/lsmdomdocument.c
@@ -21,8 +21,11 @@
 
 #include <lsmdomdocument.h>
 #include <lsmdomelement.h>
+#include <lsmstr.h>
 #include <lsmdebug.h>
 #include <lsmdomtext.h>
+#include <gio/gio.h>
+#include <string.h>
 
 static GObjectClass *parent_class;
 
@@ -187,6 +190,76 @@ lsm_dom_document_register_element (LsmDomDocument *self, LsmDomElement *element,
 	}
 }
 
+const char *
+lsm_dom_document_get_url (LsmDomDocument *self)
+{
+	g_return_val_if_fail (LSM_IS_DOM_DOCUMENT (self), NULL);
+
+	return self->url;
+}
+
+void
+lsm_dom_document_set_path (LsmDomDocument *self, const char *path)
+{
+	g_return_if_fail (LSM_IS_DOM_DOCUMENT (self));
+
+	g_free (self->url);
+
+	if (path == NULL) {
+		self->url = NULL;
+		return;
+	}
+
+	self->url = lsm_str_to_uri (path);
+}
+
+void
+lsm_dom_document_set_url (LsmDomDocument *self, const char *url)
+{
+	g_return_if_fail (LSM_IS_DOM_DOCUMENT (self));
+	g_return_if_fail (url == NULL || lsm_str_is_uri (url));
+
+	g_free (self->url);
+	self->url = g_strdup (url);
+}
+
+void *
+lsm_dom_document_get_href_data (LsmDomDocument *self, const char *href, gsize *size)
+{
+	GFile *file;
+	char *data = NULL;
+
+	g_return_val_if_fail (LSM_IS_DOM_DOCUMENT (self), NULL);
+	g_return_val_if_fail (href != NULL, NULL);
+
+	if (strncmp (href, "data:", 5) == 0) {
+		while (*href != '\0' && *href != ',')
+			href++;
+		return g_base64_decode (href, size);
+	}
+
+	file = g_file_new_for_uri (href);
+
+	if (!g_file_load_contents (file, NULL, &data, size, NULL, NULL) && self->url != NULL) {
+		GFile *document_file;
+		GFile *parent_file;
+
+		g_object_unref (file);
+
+		document_file = g_file_new_for_uri (self->url);
+		parent_file = g_file_get_parent (document_file);
+		file = g_file_resolve_relative_path (parent_file, href);
+		g_object_unref (document_file);
+		g_object_unref (parent_file);
+
+		g_file_load_contents (file, NULL, &data, size, NULL, NULL);
+	}
+
+	g_object_unref (file);
+
+	return data;
+}
+
 static void
 lsm_dom_document_init (LsmDomDocument *document)
 {
@@ -208,6 +281,8 @@ lsm_dom_document_finalize (GObject *object)
 	g_hash_table_unref (document->elements);
 	g_hash_table_unref (document->ids);
 
+	g_free (document->url);
+
 	parent_class->finalize (object);
 }
 
diff --git a/src/lsmdomdocument.h b/src/lsmdomdocument.h
index 3321d36..78697ec 100644
--- a/src/lsmdomdocument.h
+++ b/src/lsmdomdocument.h
@@ -45,8 +45,10 @@ typedef struct _LsmDomDocumentClass LsmDomDocumentClass;
 struct _LsmDomDocument {
 	LsmDomNode node;
 
-	GHashTable *		ids;
-	GHashTable *		elements;
+	GHashTable *	ids;
+	GHashTable *	elements;
+
+	char *		url;
 
 	/* Not really a document property, but that simplifies things greatly */
 	double resolution_ppi;
@@ -82,6 +84,12 @@ void 		lsm_dom_document_set_viewport_px 	(LsmDomDocument *self, const LsmBox *vi
 LsmBox 		lsm_dom_document_get_viewport 		(LsmDomDocument *self);
 LsmBox 		lsm_dom_document_get_viewport_px 	(LsmDomDocument *self);
 
+const char * 	lsm_dom_document_get_url 		(LsmDomDocument *self);
+void		lsm_dom_document_set_url		(LsmDomDocument *self, const char *url);
+void 		lsm_dom_document_set_path 		(LsmDomDocument *self, const char *path);
+
+void * 		lsm_dom_document_get_href_data 		(LsmDomDocument *self, const char *href, gsize *size);
+
 G_END_DECLS
 
 #endif
diff --git a/src/lsmdomnode.h b/src/lsmdomnode.h
index 86cae17..8305525 100644
--- a/src/lsmdomnode.h
+++ b/src/lsmdomnode.h
@@ -89,30 +89,30 @@ struct _LsmDomNodeClass {
 
 GType lsm_dom_node_get_type (void);
 
-const char* 		lsm_dom_node_get_node_name 	(LsmDomNode* self);
-const char* 		lsm_dom_node_get_node_value 	(LsmDomNode* self);
-void 			lsm_dom_node_set_node_value 	(LsmDomNode* self, const char* new_value);
-LsmDomNodeType 		lsm_dom_node_get_node_type 	(LsmDomNode* self);
-LsmDomNode* 		lsm_dom_node_get_parent_node 	(LsmDomNode* self);
+const char* 		lsm_dom_node_get_node_name 		(LsmDomNode* self);
+const char* 		lsm_dom_node_get_node_value 		(LsmDomNode* self);
+void 			lsm_dom_node_set_node_value 		(LsmDomNode* self, const char* new_value);
+LsmDomNodeType 		lsm_dom_node_get_node_type 		(LsmDomNode* self);
+LsmDomNode* 		lsm_dom_node_get_parent_node 		(LsmDomNode* self);
 #if 0
 LsmDomNodeList* 		lsm_dom_node_get_child_nodes 	(LsmDomNode* self);
 #endif
-LsmDomNode* 		lsm_dom_node_get_first_child 	(LsmDomNode* self);
-LsmDomNode* 		lsm_dom_node_get_last_child 	(LsmDomNode* self);
+LsmDomNode* 		lsm_dom_node_get_first_child 		(LsmDomNode* self);
+LsmDomNode* 		lsm_dom_node_get_last_child 		(LsmDomNode* self);
 LsmDomNode* 		lsm_dom_node_get_previous_sibling 	(LsmDomNode* self);
-LsmDomNode* 		lsm_dom_node_get_next_sibling 	(LsmDomNode* self);
+LsmDomNode* 		lsm_dom_node_get_next_sibling 		(LsmDomNode* self);
 #if 0
 LsmDomNamedNodeMap* 	lsm_dom_node_get_attributes 	(LsmDomNode* self);
 #endif
 LsmDomNode* 		lsm_dom_node_insert_before		(LsmDomNode* self, LsmDomNode* new_child, LsmDomNode* ref_child);
-LsmDomNode* 		lsm_dom_node_replace_child 	(LsmDomNode* self, LsmDomNode* new_child, LsmDomNode* old_child);
+LsmDomNode* 		lsm_dom_node_replace_child 		(LsmDomNode* self, LsmDomNode* new_child, LsmDomNode* old_child);
 LsmDomNode* 		lsm_dom_node_append_child 		(LsmDomNode* self, LsmDomNode* new_child);
 LsmDomNode* 		lsm_dom_node_remove_child 		(LsmDomNode* self, LsmDomNode* old_child);
-gboolean 		lsm_dom_node_has_child_nodes 	(LsmDomNode* self);
+gboolean 		lsm_dom_node_has_child_nodes 		(LsmDomNode* self);
 
-void 			lsm_dom_node_changed 		(LsmDomNode *self);
+void 			lsm_dom_node_changed 			(LsmDomNode *self);
 
-LsmDomDocument* 		lsm_dom_node_get_owner_document 	(LsmDomNode* self);
+LsmDomDocument*		lsm_dom_node_get_owner_document 	(LsmDomNode* self);
 
 void 			lsm_dom_node_dump 			(LsmDomNode *self);
 
diff --git a/src/lsmdomparser.c b/src/lsmdomparser.c
index 8d3bbef..66024f4 100644
--- a/src/lsmdomparser.c
+++ b/src/lsmdomparser.c
@@ -24,8 +24,11 @@
 #include <lsmmathmlpresentationtoken.h>
 #include <lsmmathmlentitydictionary.h>
 #include <lsmsvgtextelement.h>
+#include <lsmstr.h>
 #include <libxml/parser.h>
+#include <gio/gio.h>
 #include <string.h>
+#include <../itex2mml/itex2MML.h>
 
 typedef enum {
 	STATE
@@ -256,37 +259,134 @@ static xmlSAXHandler sax_handler = {
 	.entityDecl = lsm_dom_parser_declare_entity
 };
 
-LsmDomDocument *
-lsm_dom_document_new_from_file (const char *filename)
+static GQuark
+lsm_dom_document_error_quark (void)
+{
+	static GQuark q = 0;
+
+        if (q == 0) {
+                q = g_quark_from_static_string ("mrp-error-quark");
+        }
+
+        return q;
+}
+
+#define LSM_DOM_DOCUMENT_ERROR lsm_dom_document_error_quark ()
+
+typedef enum {
+	LSM_DOM_DOCUMENT_ERROR_INVALID_XML
+} LsmDomDocumentError;
+
+static void
+_dummy_error (const char *msg)
+{
+}
+
+static LsmDomDocument *
+lsm_dom_document_new_from_contents (const char *contents, gsize size, GError **error)
 {
 	static LsmDomSaxParserState state;
+	char *mime;
+	char *xml;
+
+	state.document = NULL;
 
-	if (xmlSAXUserParseFile (&sax_handler, &state, filename) < 0) {
+	mime = g_content_type_guess (NULL, (guchar *) contents, size, NULL);
+	lsm_debug ("[LsmDomDocument::new_from_contents] mime = '%s'", mime);
+	if (g_strcmp0 (mime, "image/svg+xml") == 0 ||
+	    g_strcmp0 (mime, "text/mathml") == 0 ||
+	    g_strcmp0 (mime, "application/xml") == 0) {
+		xml = (char *) contents;
+	} else {
+		itex2MML_error = _dummy_error;
+
+		xml = itex2MML_parse (contents, size);
+		size = strlen (contents);
+	}
+
+	if (xmlSAXUserParseMemory (&sax_handler, &state, xml, size) < 0) {
 		if (state.document !=  NULL)
 			g_object_unref (state.document);
-		g_warning ("[LsmDomParser::from_file] invalid document");
-		return NULL;
+		state.document = NULL;
+
+		lsm_debug ("[LsmDomParser::from_memory] invalid document");
+
+		g_set_error (error,
+			     LSM_DOM_DOCUMENT_ERROR,
+			     LSM_DOM_DOCUMENT_ERROR_INVALID_XML,
+			     "Invalid document.");
 	}
 
-	return LSM_DOM_DOCUMENT (state.document);
+	if (xml != contents)
+		itex2MML_free_string (xml);
+
+	return state.document;
 }
 
 LsmDomDocument *
-lsm_dom_document_new_from_memory (const char *buffer)
+lsm_dom_document_new_from_memory (const char *buffer, gsize size, GError **error)
 {
-	static LsmDomSaxParserState state;
+	g_return_val_if_fail (buffer != NULL, NULL);
 
-	if (buffer == NULL)
-		return NULL;
+	if (size < 1)
+		size = strlen (buffer);
 
-	state.document = NULL;
+	return lsm_dom_document_new_from_contents (buffer, size, error);
+}
 
-	if (xmlSAXUserParseMemory (&sax_handler, &state, buffer, strlen (buffer)) < 0) {
-		if (state.document !=  NULL)
-			g_object_unref (state.document);
-		g_warning ("[LsmDomParser::from_memory] invalid document");
+static LsmDomDocument *
+lsm_dom_document_new_from_file (GFile *file, GError **error)
+{
+	LsmDomDocument *document;
+	gsize size = 0;
+	char *contents = NULL;
+
+	if (!g_file_load_contents (file, NULL, &contents, &size, NULL, error))
 		return NULL;
-	}
 
-	return LSM_DOM_DOCUMENT (state.document);
+	document = lsm_dom_document_new_from_contents (contents, size, error);
+
+	g_free (contents);
+
+	return document;
+}
+
+LsmDomDocument *
+lsm_dom_document_new_from_path (const char *path, GError **error)
+{
+	LsmDomDocument *document;
+	GFile *file;
+
+	g_return_val_if_fail (path != NULL, NULL);
+
+	file = g_file_new_for_path (path);
+
+	document = lsm_dom_document_new_from_file (file, error);
+
+	g_object_unref (file);
+
+	if (document != NULL)
+		lsm_dom_document_set_path (document, path);
+
+	return document;
+}
+
+LsmDomDocument *
+lsm_dom_document_new_from_url (const char *url, GError **error)
+{
+	LsmDomDocument *document;
+	GFile *file;
+
+	g_return_val_if_fail (url != NULL, NULL);
+
+	file = g_file_new_for_uri (url);
+
+	document = lsm_dom_document_new_from_file (file, error);
+
+	g_object_unref (file);
+
+	if (document != NULL)
+		lsm_dom_document_set_url (document, url);
+
+	return document;
 }
diff --git a/src/lsmdomparser.h b/src/lsmdomparser.h
index 1af26b8..51e6a78 100644
--- a/src/lsmdomparser.h
+++ b/src/lsmdomparser.h
@@ -26,8 +26,13 @@
 
 G_BEGIN_DECLS
 
-LsmDomDocument * 	lsm_dom_document_new_from_file 	(const char *filename);
-LsmDomDocument * 	lsm_dom_document_new_from_memory 	(const char *buffer);
+typedef enum {
+	LSM_DOM_DOCUMENT_ERROR_INVALID_XML
+} LsmDomDocumentError;
+
+LsmDomDocument * 	lsm_dom_document_new_from_memory 	(const char *buffer, gsize size, GError *error);
+LsmDomDocument * 	lsm_dom_document_new_from_path 		(const char *path, GError *error);
+LsmDomDocument * 	lsm_dom_document_new_from_url 		(const char *url, GError *error);
 
 G_END_DECLS
 
diff --git a/src/lsmmathmldocument.c b/src/lsmmathmldocument.c
index 83d7d3a..dc516c9 100644
--- a/src/lsmmathmldocument.c
+++ b/src/lsmmathmldocument.c
@@ -168,29 +168,29 @@ lsm_mathml_document_class_init (LsmMathmlDocumentClass *m_document_class)
 
 G_DEFINE_TYPE (LsmMathmlDocument, lsm_mathml_document, LSM_TYPE_DOM_DOCUMENT)
 
-static void
-_dummy_error (const char *msg)
-{
-}
+/*static void*/
+/*_dummy_error (const char *msg)*/
+/*{*/
+/*}*/
 
-LsmMathmlDocument *
-lsm_mathml_document_new_from_itex (const char *itex)
-{
-	LsmMathmlDocument *document;
-	char *mathml;
+/*LsmMathmlDocument **/
+/*lsm_mathml_document_new_from_itex (const char *itex)*/
+/*{*/
+/*        LsmMathmlDocument *document;*/
+/*        char *mathml;*/
 
-	g_return_val_if_fail (itex != NULL, NULL);
+/*        g_return_val_if_fail (itex != NULL, NULL);*/
 
-	itex2MML_error = _dummy_error;
+/*        itex2MML_error = _dummy_error;*/
 
-	mathml = itex2MML_parse (itex, strlen (itex));
-	document = LSM_MATHML_DOCUMENT (lsm_dom_document_new_from_memory (mathml));
-	itex2MML_free_string (mathml);
+/*        mathml = itex2MML_parse (itex, strlen (itex));*/
+/*        document = LSM_MATHML_DOCUMENT (lsm_dom_document_new_from_memory (mathml));*/
+/*        itex2MML_free_string (mathml);*/
 
-	if (document != NULL && !LSM_IS_MATHML_DOCUMENT (document)) {
-		g_object_unref (document);
-		return NULL;
-	}
+/*        if (document != NULL && !LSM_IS_MATHML_DOCUMENT (document)) {*/
+/*                g_object_unref (document);*/
+/*                return NULL;*/
+/*        }*/
 
-	return document;
-}
+/*        return document;*/
+/*}*/
diff --git a/src/lsmmathmldocument.h b/src/lsmmathmldocument.h
index 59a2046..48feef4 100644
--- a/src/lsmmathmldocument.h
+++ b/src/lsmmathmldocument.h
@@ -50,7 +50,7 @@ GType lsm_mathml_document_get_type (void);
 LsmMathmlDocument *	lsm_mathml_document_new 		(void);
 LsmMathmlMathElement * 	lsm_mathml_document_get_root_element 	(const LsmMathmlDocument *document);
 
-LsmMathmlDocument * 	lsm_mathml_document_new_from_itex	(const char *itex);
+//LsmMathmlDocument * 	lsm_mathml_document_new_from_itex	(const char *itex);
 
 G_END_DECLS
 
diff --git a/src/lsmstr.c b/src/lsmstr.c
index 486af43..d86173d 100644
--- a/src/lsmstr.c
+++ b/src/lsmstr.c
@@ -20,9 +20,68 @@
  */
 
 #include <lsmstr.h>
+#include <glib.h>
 #include <stdio.h>
+#include <string.h>
 #include <math.h>
 
+/* http://www.ietf.org/rfc/rfc2396.txt - Implementation comes from librsvg (rsvg-base.c). */
+
+gboolean
+lsm_str_is_uri  (const char *str)
+{
+	char const *p;
+
+	if (str == NULL)
+		return FALSE;
+
+	if (strlen (str) < 4)
+		return FALSE;
+
+	if (   (str[0] < 'a' || str[0] > 'z')
+	       && (str[0] < 'A' || str[0] > 'Z'))
+		return FALSE;
+
+	for (p = &str[1];
+	     (*p >= 'a' && *p <= 'z')
+	     || (*p >= 'A' && *p <= 'Z')
+	     || (*p >= '0' && *p <= '9')
+	     || *p == '+'
+	     || *p == '-'
+	     || *p == '.';
+	     p++);
+
+	if (strlen (p) < 3)
+		return FALSE;
+
+	return (p[0] == ':' && p[1] == '/' && p[2] == '/');
+}
+
+char *
+lsm_str_to_uri (const char *str)
+{
+	gchar *current_dir;
+	gchar *absolute_filename;
+	gchar *uri;
+
+	if (str == NULL)
+		return NULL;
+
+	if (lsm_str_is_uri (str))
+		return g_strdup (str);
+
+	if (g_path_is_absolute (str))
+		return g_filename_to_uri (str, NULL, NULL);
+
+	current_dir = g_get_current_dir ();
+	absolute_filename = g_build_filename (current_dir, str, NULL);
+	uri = g_filename_to_uri (absolute_filename, NULL, NULL);
+	g_free (absolute_filename);
+	g_free (current_dir);
+
+	return uri;
+}
+
 gboolean
 lsm_str_parse_double (char **str, double *x)
 {
diff --git a/src/lsmstr.h b/src/lsmstr.h
index e091128..2f7e4c6 100644
--- a/src/lsmstr.h
+++ b/src/lsmstr.h
@@ -27,6 +27,9 @@
 
 G_BEGIN_DECLS
 
+gboolean lsm_str_is_uri 		(const char *str);
+char *   lsm_str_to_uri 		(const char *str);
+
 gboolean lsm_str_parse_double 		(char **str, double *x);
 gboolean lsm_str_parse_double_list 	(char **str, unsigned int n_values, double *values);
 
diff --git a/src/lsmsvgcircleelement.c b/src/lsmsvgcircleelement.c
index 7645438..c37b65e 100644
--- a/src/lsmsvgcircleelement.c
+++ b/src/lsmsvgcircleelement.c
@@ -84,9 +84,14 @@ lsm_svg_circle_element_new (void)
 	return g_object_new (LSM_TYPE_SVG_CIRCLE_ELEMENT, NULL);
 }
 
+static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+
 static void
 lsm_svg_circle_element_init (LsmSvgCircleElement *self)
 {
+	self->cx.length = length_default;
+	self->cy.length = length_default;
+	self->r.length = length_default;
 }
 
 static void
@@ -97,8 +102,6 @@ lsm_svg_circle_element_finalize (GObject *object)
 
 /* LsmSvgCircleElement class */
 
-static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
-
 static const LsmAttributeInfos lsm_svg_circle_element_attribute_infos[] = {
 	{
 		.name = "cx",
diff --git a/src/lsmsvgclippathelement.c b/src/lsmsvgclippathelement.c
index 0f03de4..bb8079c 100644
--- a/src/lsmsvgclippathelement.c
+++ b/src/lsmsvgclippathelement.c
@@ -58,6 +58,13 @@ lsm_svg_clip_path_element_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmSvgClipPathElement *clip = LSM_SVG_CLIP_PATH_ELEMENT (self);
 	gboolean is_object_bounding_box;
 
+	if (!clip->enable_rendering) {
+		lsm_debug ("[LsmSvgClipPathElement::render] Direct rendering not allowed");
+		return;
+	}
+
+	clip->enable_rendering = FALSE;
+
 	is_object_bounding_box = (clip->units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
 
 	if (is_object_bounding_box) {
@@ -79,15 +86,26 @@ lsm_svg_clip_path_element_render (LsmSvgElement *self, LsmSvgView *view)
 	}
 }
 
+static void
+lsm_svg_clip_path_element_enable_rendering (LsmSvgElement *element)
+{
+	LSM_SVG_CLIP_PATH_ELEMENT (element)->enable_rendering  = TRUE;
+}
+
 LsmDomNode *
 lsm_svg_clip_path_element_new (void)
 {
 	return g_object_new (LSM_TYPE_SVG_CLIP_PATH_ELEMENT, NULL);
 }
 
+static const LsmSvgPatternUnits units_default = LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE;
+
 static void
 lsm_svg_clip_path_element_init (LsmSvgClipPathElement *self)
 {
+	self->enable_rendering = FALSE;
+	self->units.value = units_default;
+
 	/* Hack - Force the creation of the attribute bags,
 	   making sure the properties will be inherited from the
 	   pattern element ancestor, not the referencing one. */
@@ -105,7 +123,8 @@ static const LsmAttributeInfos lsm_svg_clip_path_element_attribute_infos[] = {
 	{
 		.name = "clipPathUnits",
 		.trait_class = &lsm_svg_pattern_units_trait_class,
-		.attribute_offset = offsetof (LsmSvgClipPathElement, units)
+		.attribute_offset = offsetof (LsmSvgClipPathElement, units),
+		.trait_default = &units_default
 	}
 };
 
@@ -123,6 +142,7 @@ lsm_svg_clip_path_element_class_init (LsmSvgClipPathElementClass *klass)
 /*        s_element_class->render_clip = _clip_path_element_render_clip;*/
 /*        s_element_class->render = NULL;*/
 	s_element_class->render = lsm_svg_clip_path_element_render;
+	s_element_class->enable_rendering = lsm_svg_clip_path_element_enable_rendering;
 
 	s_element_class->attribute_manager = lsm_attribute_manager_duplicate (s_element_class->attribute_manager);
 
diff --git a/src/lsmsvgclippathelement.h b/src/lsmsvgclippathelement.h
index cadfd19..5794396 100644
--- a/src/lsmsvgclippathelement.h
+++ b/src/lsmsvgclippathelement.h
@@ -40,6 +40,8 @@ struct _LsmSvgClipPathElement {
 	LsmSvgElement element;
 
 	LsmSvgPatternUnitsAttribute units;
+
+	gboolean enable_rendering;
 };
 
 struct _LsmSvgClipPathElementClass {
diff --git a/src/lsmsvgelement.c b/src/lsmsvgelement.c
index 27ad1b6..2a11892 100644
--- a/src/lsmsvgelement.c
+++ b/src/lsmsvgelement.c
@@ -27,6 +27,7 @@
 #include <lsmsvgpatternelement.h>
 #include <lsmsvggradientelement.h>
 #include <lsmsvgclippathelement.h>
+#include <lsmsvgmaskelement.h>
 #include <lsmsvgview.h>
 #include <string.h>
 
@@ -230,18 +231,12 @@ lsm_svg_element_enable_rendering (LsmSvgElement *element)
 }
 
 void
-lsm_svg_element_render_paint (LsmSvgElement *element, LsmSvgView *view)
+lsm_svg_element_force_render (LsmSvgElement *element, LsmSvgView *view)
 {
 	g_return_if_fail (LSM_IS_SVG_PATTERN_ELEMENT (element) ||
-			  LSM_IS_SVG_GRADIENT_ELEMENT (element));
-
-	lsm_svg_element_enable_rendering (element);
-	lsm_svg_element_render (element, view);
-}
-
-void lsm_svg_element_render_clip (LsmSvgElement *element, LsmSvgView *view)
-{
-	g_return_if_fail (LSM_IS_SVG_CLIP_PATH_ELEMENT (element));
+			  LSM_IS_SVG_GRADIENT_ELEMENT (element) ||
+			  LSM_IS_SVG_MASK_ELEMENT (element) ||
+			  LSM_IS_SVG_CLIP_PATH_ELEMENT (element));
 
 	lsm_svg_element_enable_rendering (element);
 	lsm_svg_element_render (element, view);
diff --git a/src/lsmsvgelement.h b/src/lsmsvgelement.h
index 1bcba80..7ac867e 100644
--- a/src/lsmsvgelement.h
+++ b/src/lsmsvgelement.h
@@ -79,8 +79,7 @@ GType lsm_svg_element_get_type (void);
 //void		lsm_svg_element_update 		(LsmSvgElement *element, const LsmSvgStyle *style);
 //void 		lsm_svg_element_enable_rendering(LsmSvgElement *self);
 void 		lsm_svg_element_render 		(LsmSvgElement *element, LsmSvgView *view);
-void 		lsm_svg_element_render_paint 	(LsmSvgElement *element, LsmSvgView *view);
-void 		lsm_svg_element_render_clip 	(LsmSvgElement *element, LsmSvgView *view);
+void 		lsm_svg_element_force_render 	(LsmSvgElement *element, LsmSvgView *view);
 void		lsm_svg_element_get_extents	(LsmSvgElement *element, LsmSvgView *view, LsmExtents *extents);
 
 G_END_DECLS
diff --git a/src/lsmsvgellipseelement.c b/src/lsmsvgellipseelement.c
index 926fda9..5703364 100644
--- a/src/lsmsvgellipseelement.c
+++ b/src/lsmsvgellipseelement.c
@@ -85,9 +85,15 @@ lsm_svg_ellipse_element_new (void)
 	return g_object_new (LSM_TYPE_SVG_ELLIPSE_ELEMENT, NULL);
 }
 
+static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+
 static void
 lsm_svg_ellipse_element_init (LsmSvgEllipseElement *self)
 {
+	self->cx.length = length_default;
+	self->cy.length = length_default;
+	self->rx.length = length_default;
+	self->ry.length = length_default;
 }
 
 static void
@@ -98,8 +104,6 @@ lsm_svg_ellipse_element_finalize (GObject *object)
 
 /* LsmSvgEllipseElement class */
 
-static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
-
 static const LsmAttributeInfos lsm_svg_ellipse_element_attribute_infos[] = {
 	{
 		.name = "cx",
diff --git a/src/lsmsvgimageelement.c b/src/lsmsvgimageelement.c
index e77a832..ff27449 100644
--- a/src/lsmsvgimageelement.c
+++ b/src/lsmsvgimageelement.c
@@ -36,6 +36,19 @@ lsm_svg_image_element_get_node_name (LsmDomNode *node)
 	return "image";
 }
 
+static void
+lsm_svg_image_element_set_attribute (LsmDomElement *self, const char *name, const char *value)
+{
+	LsmSvgImageElement *image_element = LSM_SVG_IMAGE_ELEMENT (self);
+
+	LSM_DOM_ELEMENT_CLASS (parent_class)->set_attribute (self, name, value);
+
+	if (g_strcmp0 (name, "xlink:href") == 0 && image_element->pixbuf != NULL) {
+		g_object_unref (image_element->pixbuf);
+		image_element->pixbuf = NULL;
+	}
+}
+
 static gboolean
 lsm_svg_use_can_append_child (LsmDomNode *node, LsmDomNode *child)
 {
@@ -126,6 +139,34 @@ lsm_svg_image_element_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmBox viewbox;
 
 	image = LSM_SVG_IMAGE_ELEMENT (self);
+
+	if (image->pixbuf == NULL) {
+		LsmDomDocument *document;
+		char *data;
+		gsize size;
+
+		document = lsm_dom_node_get_owner_document (LSM_DOM_NODE (self));
+		data = lsm_dom_document_get_href_data (document, image->href.value, &size);
+
+		if (data != NULL) {
+			GdkPixbufLoader *loader;
+			int result;
+
+			loader = gdk_pixbuf_loader_new ();
+
+			result = gdk_pixbuf_loader_write (loader, (guchar *) data, size, NULL);
+
+			g_free (data);
+
+			gdk_pixbuf_loader_close (loader, NULL);
+
+			image->pixbuf = gdk_pixbuf_loader_get_pixbuf (loader);
+			g_object_ref (image->pixbuf);
+
+			g_object_unref (loader);
+		}
+	}
+
 	if (image->pixbuf == NULL)
 		return;
 
@@ -161,10 +202,22 @@ lsm_svg_image_element_new (void)
 	return g_object_new (LSM_TYPE_SVG_IMAGE_ELEMENT, NULL);
 }
 
+static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+static const LsmSvgPreserveAspectRatio preserve_aspect_ratio_default = {
+	.defer = FALSE,
+	.align = LSM_SVG_ALIGN_X_MID_Y_MID,
+	.meet_or_slice = LSM_SVG_MEET_OR_SLICE_MEET
+};
+
 static void
 lsm_svg_image_element_init (LsmSvgImageElement *self)
 {
 	self->pixbuf = NULL;
+	self->x.length = length_default;
+	self->y.length = length_default;
+	self->width.length = length_default;
+	self->height.length = length_default;
+	self->preserve_aspect_ratio.value = preserve_aspect_ratio_default;
 }
 
 static void
@@ -180,13 +233,6 @@ lsm_svg_image_element_finalize (GObject *gobject)
 
 /* LsmSvgImageElement class */
 
-static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
-static const LsmSvgPreserveAspectRatio preserve_aspect_ratio_default = {
-	.defer = FALSE,
-	.align = LSM_SVG_ALIGN_X_MID_Y_MID,
-	.meet_or_slice = LSM_SVG_MEET_OR_SLICE_MEET
-};
-
 static const LsmAttributeInfos lsm_svg_image_element_attribute_infos[] = {
 	{
 		.name = "x",
@@ -230,6 +276,7 @@ lsm_svg_image_element_class_init (LsmSvgImageElementClass *klass)
 {
 	GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
 	LsmDomNodeClass *d_node_class = LSM_DOM_NODE_CLASS (klass);
+	LsmDomElementClass *d_element_class = LSM_DOM_ELEMENT_CLASS (klass);
 	LsmSvgElementClass *s_element_class = LSM_SVG_ELEMENT_CLASS (klass);
 /*        LsmSvgGraphicClass *s_graphic_class = LSM_SVG_GRAPHIC_CLASS (klass);*/
 
@@ -240,6 +287,8 @@ lsm_svg_image_element_class_init (LsmSvgImageElementClass *klass)
 	d_node_class->get_node_name = lsm_svg_image_element_get_node_name;
 	d_node_class->can_append_child = lsm_svg_use_can_append_child;
 
+	d_element_class->set_attribute = lsm_svg_image_element_set_attribute;
+
 /*        s_element_class->update = lsm_svg_image_element_update;*/
 
 	s_element_class->render = lsm_svg_image_element_render;
diff --git a/src/lsmsvgmaskelement.c b/src/lsmsvgmaskelement.c
index 5e1be92..dff2e23 100644
--- a/src/lsmsvgmaskelement.c
+++ b/src/lsmsvgmaskelement.c
@@ -78,6 +78,13 @@ lsm_svg_mask_element_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmBox viewport;
 	const LsmBox *mask_extents;
 
+	if (!mask->enable_rendering) {
+		lsm_debug ("[LsmSvgMaskElement::render] Direct rendering not allowed");
+		return;
+	}
+
+	mask->enable_rendering = FALSE;
+
 	mask_extents = lsm_svg_view_get_pattern_extents (view);
 
 	is_object_bounding_box = (mask->units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
@@ -109,7 +116,7 @@ lsm_svg_mask_element_render (LsmSvgElement *self, LsmSvgView *view)
 	if (viewport.width <= 0.0 || viewport.height <= 0.0)
 		return;
 
-	lsm_debug ("[LsmSvgMaskElement::render_paint] Create mask x = %g, y = %g, w = %g, h = %g",
+	lsm_debug ("[LsmSvgMaskElement::render] Create mask x = %g, y = %g, w = %g, h = %g",
 		   viewport.x, viewport.y, viewport.width, viewport.height);
 
 	lsm_svg_view_create_surface_pattern (view, &viewport,
@@ -128,7 +135,7 @@ lsm_svg_mask_element_render (LsmSvgElement *self, LsmSvgView *view)
 		lsm_svg_view_push_viewbox (view, &viewbox);
 		lsm_svg_view_push_matrix (view, &matrix);
 
-		lsm_debug ("[LsmSvgMaskElement::render_paint] object_bounding_box"
+		lsm_debug ("[LsmSvgMaskElement::render] object_bounding_box"
 			   " x_scale = %g, y_scale = %g, x_offset = %g, y_offset = %g",
 			   mask_extents->width, mask_extents->height,
 			   mask_extents->x, mask_extents->y);
@@ -142,6 +149,12 @@ lsm_svg_mask_element_render (LsmSvgElement *self, LsmSvgView *view)
 	}
 }
 
+static void
+lsm_svg_mask_element_enable_rendering (LsmSvgElement *element)
+{
+	LSM_SVG_MASK_ELEMENT (element)->enable_rendering  = TRUE;
+}
+
 /* LsmSvgMaskElement implementation */
 
 LsmDomNode *
@@ -150,9 +163,22 @@ lsm_svg_mask_element_new (void)
 	return g_object_new (LSM_TYPE_SVG_MASK_ELEMENT, NULL);
 }
 
+static const LsmSvgLength x_y_default = 	{ .value_unit = -10.0, .type = LSM_SVG_LENGTH_TYPE_PERCENTAGE};
+static const LsmSvgLength width_height_default ={ .value_unit = 120.0, .type = LSM_SVG_LENGTH_TYPE_PERCENTAGE};
+static const LsmSvgPatternUnits units_default =  	LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX;
+static const LsmSvgPatternUnits content_units_default = LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE;
+
 static void
 lsm_svg_mask_element_init (LsmSvgMaskElement *self)
 {
+	self->enable_rendering = FALSE;
+	self->x.length = x_y_default;
+	self->y.length = x_y_default;
+	self->width.length = width_height_default;
+	self->height.length = width_height_default;
+	self->units.value = units_default;
+	self->content_units.value = content_units_default;
+
 	/* Hack - Force the creation of the attribute bags,
 	   making sure the properties will be inherited from the
 	   mask element ancestor, not the referencing one. */
@@ -166,34 +192,30 @@ lsm_svg_mask_element_init (LsmSvgMaskElement *self)
 
 /* LsmSvgMaskElement class */
 
-static const LsmSvgLength length_default = 	{ .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
-static const LsmSvgPatternUnits units_default =  	LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX;
-static const LsmSvgPatternUnits content_units_default = LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE;
-
 static const LsmAttributeInfos lsm_svg_mask_element_attribute_infos[] = {
 	{
 		.name = "x",
 		.attribute_offset = offsetof (LsmSvgMaskElement, x),
 		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_default = &x_y_default
 	},
 	{
 		.name = "y",
 		.attribute_offset = offsetof (LsmSvgMaskElement, y),
 		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_default = &x_y_default
 	},
 	{
 		.name = "width",
 		.attribute_offset = offsetof (LsmSvgMaskElement, width),
 		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_default = &width_height_default
 	},
 	{
 		.name = "height",
 		.attribute_offset = offsetof (LsmSvgMaskElement, height),
 		.trait_class = &lsm_svg_length_trait_class,
-		.trait_default = &length_default
+		.trait_default = &width_height_default
 	},
 	{
 		.name = "maskUnits",
@@ -225,6 +247,7 @@ lsm_svg_mask_element_class_init (LsmSvgMaskElementClass *klass)
 	s_element_class->render = lsm_svg_mask_element_render;
 
 	s_element_class->attribute_manager = lsm_attribute_manager_duplicate (s_element_class->attribute_manager);
+	s_element_class->enable_rendering = lsm_svg_mask_element_enable_rendering;
 
 	lsm_attribute_manager_add_attributes (s_element_class->attribute_manager,
 					      G_N_ELEMENTS (lsm_svg_mask_element_attribute_infos),
diff --git a/src/lsmsvgmaskelement.h b/src/lsmsvgmaskelement.h
index 63e3430..fe6a81e 100644
--- a/src/lsmsvgmaskelement.h
+++ b/src/lsmsvgmaskelement.h
@@ -45,6 +45,8 @@ struct _LsmSvgMaskElement {
 	LsmSvgLengthAttribute		height;
 	LsmSvgPatternUnitsAttribute	units;
 	LsmSvgPatternUnitsAttribute	content_units;
+
+	gboolean enable_rendering;
 };
 
 struct _LsmSvgMaskElementClass {
diff --git a/src/lsmsvgpatternelement.c b/src/lsmsvgpatternelement.c
index e183d43..870ab1c 100644
--- a/src/lsmsvgpatternelement.c
+++ b/src/lsmsvgpatternelement.c
@@ -84,8 +84,10 @@ lsm_svg_pattern_element_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmBox viewport;
 	const LsmBox *pattern_extents;
 
-	if (!pattern->enable_rendering)
+	if (!pattern->enable_rendering) {
+		lsm_debug ("[LsmSvgPatternElement::render] Direct rendering not allowed");
 		return;
+	}
 
 	pattern->enable_rendering = FALSE;
 
@@ -120,7 +122,7 @@ lsm_svg_pattern_element_render (LsmSvgElement *self, LsmSvgView *view)
 	if (viewport.width <= 0.0 || viewport.height <= 0.0)
 		return;
 
-	lsm_debug ("[LsmSvgPatternElement::render_paint] Create pattern x = %g, y = %g, w = %g, h = %g",
+	lsm_debug ("[LsmSvgPatternElement::render] Create pattern x = %g, y = %g, w = %g, h = %g",
 		   viewport.x, viewport.y, viewport.width, viewport.height);
 
 	lsm_svg_view_create_surface_pattern (view, &viewport,
@@ -140,7 +142,7 @@ lsm_svg_pattern_element_render (LsmSvgElement *self, LsmSvgView *view)
 		lsm_svg_view_push_viewbox (view, &viewbox);
 		lsm_svg_view_push_matrix (view, &matrix);
 
-		lsm_debug ("[LsmSvgPatternElement::render_paint] object_bounding_box"
+		lsm_debug ("[LsmSvgPatternElement::render] object_bounding_box"
 			   " x_scale = %g, y_scale = %g, x_offset = %g, y_offset = %g",
 			   pattern_extents->width, pattern_extents->height,
 			   pattern_extents->x,     pattern_extents->y);
@@ -203,7 +205,6 @@ lsm_svg_pattern_element_init (LsmSvgPatternElement *self)
 	self->content_units.value = content_units_default;
 	self->preserve_aspect_ratio.value = preserve_aspect_ratio_default;
 
-#if 0
 	/* Hack - Force the creation of the attribute bags,
 	   making sure the properties will be inherited from the
 	   pattern element ancestor, not the referencing one. */
@@ -213,7 +214,6 @@ lsm_svg_pattern_element_init (LsmSvgPatternElement *self)
 	lsm_dom_element_set_attribute (LSM_DOM_ELEMENT (self), "transform", NULL);
 	lsm_dom_element_set_attribute (LSM_DOM_ELEMENT (self), "font-family", NULL);
 	lsm_dom_element_set_attribute (LSM_DOM_ELEMENT (self), "stop-color", NULL);
-#endif
 }
 
 /* LsmSvgPatternElement class */
diff --git a/src/lsmsvgradialgradientelement.c b/src/lsmsvgradialgradientelement.c
index 1934687..d8a036c 100644
--- a/src/lsmsvgradialgradientelement.c
+++ b/src/lsmsvgradialgradientelement.c
@@ -86,8 +86,16 @@ lsm_svg_radial_gradient_element_create_gradient (LsmSvgElement *self, LsmSvgView
 	cx = lsm_svg_view_normalize_length (view, &radial->cx.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
 	cy = lsm_svg_view_normalize_length (view, &radial->cy.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
 	r  = lsm_svg_view_normalize_length (view, &radial->r.length,  LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
-	fx = lsm_svg_view_normalize_length (view, &radial->fx.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	fy = lsm_svg_view_normalize_length (view, &radial->fy.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+	if (lsm_attribute_is_defined (&radial->fx.base))
+		fx = lsm_svg_view_normalize_length (view, &radial->fx.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	else
+		fx = cx;
+
+	if (lsm_attribute_is_defined (&radial->fy.base))
+		fy = lsm_svg_view_normalize_length (view, &radial->fy.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	else
+		fy = cy;
 
 	gradient_radius = sqrt ((fx - cx) * (fx - cx) + (fy - cy) * (fy - cy));
 	if (gradient_radius > r) {
diff --git a/src/lsmsvgrectelement.c b/src/lsmsvgrectelement.c
index 18b6215..807d81d 100644
--- a/src/lsmsvgrectelement.c
+++ b/src/lsmsvgrectelement.c
@@ -95,13 +95,6 @@ lsm_svg_rect_element_render (LsmSvgElement *self, LsmSvgView *view)
 	else if (!lsm_attribute_is_defined (&rect->ry.base))
 		ry = rx;
 
-
-/*        if (rect->rx.length.type == LSM_SVG_LENGTH_TYPE_UNKNOWN) {*/
-/*                rx = ry;*/
-/*        } else if (rect->rx.length.type == LSM_SVG_LENGTH_TYPE_UNKNOWN) {*/
-/*                ry = rx;*/
-/*        }*/
-
 	lsm_svg_view_show_rectangle (view, x, y, w, h, rx, ry);
 }
 
@@ -131,9 +124,18 @@ lsm_svg_rect_element_new (void)
 	return g_object_new (LSM_TYPE_SVG_RECT_ELEMENT, NULL);
 }
 
+static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
+static const LsmSvgLength unset_length_default = { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_UNKNOWN};
+
 static void
 lsm_svg_rect_element_init (LsmSvgRectElement *self)
 {
+	self->x.length = length_default;
+	self->y.length = length_default;
+	self->width.length = length_default;
+	self->height.length = length_default;
+	self->rx.length = unset_length_default;
+	self->ry.length = unset_length_default;
 }
 
 static void
@@ -144,9 +146,6 @@ lsm_svg_rect_element_finalize (GObject *object)
 
 /* LsmSvgRectElement class */
 
-static const LsmSvgLength length_default = 	 { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_PX};
-static const LsmSvgLength unset_length_default = { .value_unit =   0.0, .type = LSM_SVG_LENGTH_TYPE_UNKNOWN};
-
 static const LsmAttributeInfos lsm_svg_rect_element_attribute_infos[] = {
 	{
 		.name = "x",
diff --git a/src/lsmsvgsvgelement.c b/src/lsmsvgsvgelement.c
index 74da14a..c8ed8d4 100644
--- a/src/lsmsvgsvgelement.c
+++ b/src/lsmsvgsvgelement.c
@@ -101,14 +101,29 @@ lsm_svg_svg_element_measure (LsmSvgSvgElement *self, double *width, double *heig
 	svg_viewbox = lsm_svg_viewbox_new (resolution_ppi, &viewport);
 	font_size = 10 * resolution_ppi / 72.0;
 
-	svg_x      = lsm_svg_length_normalize (&self->x.length, svg_viewbox,
-					       font_size, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	svg_y      = lsm_svg_length_normalize (&self->y.length, svg_viewbox,
-					       font_size, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
-	svg_width  = lsm_svg_length_normalize (&self->width.length, svg_viewbox,
-					       font_size, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	svg_height = lsm_svg_length_normalize (&self->height.length, svg_viewbox,
-					       font_size, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	if (lsm_attribute_is_defined (&self->x.base))
+		svg_x = lsm_svg_length_normalize (&self->x.length, svg_viewbox,
+						  font_size, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	else
+		svg_x = viewport.x;
+
+	if (lsm_attribute_is_defined (&self->y.base))
+		svg_y = lsm_svg_length_normalize (&self->y.length, svg_viewbox,
+						  font_size, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	else
+		svg_y = viewport.y;
+
+	if (lsm_attribute_is_defined (&self->width.base))
+		svg_width = lsm_svg_length_normalize (&self->width.length, svg_viewbox,
+						       font_size, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	else
+		svg_width = viewport.width;
+
+	if (lsm_attribute_is_defined (&self->height.base))
+		svg_height = lsm_svg_length_normalize (&self->height.length, svg_viewbox,
+						       font_size, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	else
+		svg_height = viewport.height;
 
 	if (width != NULL)
 		*width = svg_width * 72.0 / resolution_ppi;
@@ -146,7 +161,7 @@ _svg_element_render (LsmSvgElement *self, LsmSvgView *view)
 				   svg->viewbox.value.height <= 0.0))
 		return;
 
-	lsm_debug ("[LsmSvgSvgElement::graphic_render] viewport %g, %g, %g, %g",
+	lsm_debug ("[LsmSvgSvgElement::render] viewport %g, %g, %g, %g",
 		   viewport.x, viewport.y, viewport.width, viewport.height);
 
 	lsm_svg_view_push_viewport (view, &viewport, is_viewbox_defined ? &svg->viewbox.value : NULL,
diff --git a/src/lsmsvgtraits.c b/src/lsmsvgtraits.c
index 93e4f91..8eb4c49 100644
--- a/src/lsmsvgtraits.c
+++ b/src/lsmsvgtraits.c
@@ -208,19 +208,18 @@ const LsmTraitClass lsm_svg_matrix_trait_class = {
 static char *
 _parse_color (char *string,
 	      LsmSvgColor *svg_color,
-	      gboolean *is_color_set)
+	      LsmSvgPaintType *paint_type)
 {
 	unsigned int color = 0;
-	*is_color_set = FALSE;
 
 	lsm_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;
+		svg_color->green = -1.0;
+		svg_color->blue = -1.0;
 
-		*is_color_set = TRUE;
+		*paint_type = LSM_SVG_PAINT_TYPE_CURRENT_COLOR;
 
 		string += 12; /* strlen ("current_color") */
 
@@ -251,7 +250,7 @@ _parse_color (char *string,
 		} else if (i != 6)
 			color = 0;
 
-		*is_color_set = TRUE;
+		*paint_type = LSM_SVG_PAINT_TYPE_RGB_COLOR;
 	} else if (strncmp (string, "rgb(", 4) == 0) {
 		int i;
 		double value;
@@ -279,13 +278,13 @@ _parse_color (char *string,
 		if (*string != ')' || i != 3)
 			color = 0;
 
-		*is_color_set  = TRUE;
-	} else if (g_strcmp0 (string, "none") == 0) {
-		*is_color_set = FALSE;
-	} else {
+		*paint_type = LSM_SVG_PAINT_TYPE_RGB_COLOR;
+	} else if (g_strcmp0 (string, "none") != 0) {
 		color = lsm_svg_color_from_string (string);
 
-		*is_color_set = TRUE;
+		*paint_type = LSM_SVG_PAINT_TYPE_RGB_COLOR;
+	} else {
+		*paint_type = LSM_SVG_PAINT_TYPE_NONE;
 	}
 
 	svg_color->red = (double) ((color & 0xff0000) >> 16) / 255.0;
@@ -299,7 +298,7 @@ static void
 lsm_svg_paint_trait_from_string (LsmTrait *abstract_trait, char *string)
 {
 	LsmSvgPaint *paint = (LsmSvgPaint *) abstract_trait;
-	gboolean is_color_set;
+	LsmSvgPaintType paint_type;
 
 	g_free (paint->uri);
 
@@ -322,16 +321,28 @@ lsm_svg_paint_trait_from_string (LsmTrait *abstract_trait, char *string)
 		paint->uri = NULL;
 	}
 
-	string = _parse_color (string, &paint->color, &is_color_set);
+	string = _parse_color (string, &paint->color, &paint_type);
+
+	if (paint->uri != NULL)
+		switch (paint_type) {
+			case LSM_SVG_PAINT_TYPE_RGB_COLOR:
+				paint_type = LSM_SVG_PAINT_TYPE_URI_RGB_COLOR;
+				break;
+			case LSM_SVG_PAINT_TYPE_CURRENT_COLOR:
+				paint_type = LSM_SVG_PAINT_TYPE_URI_CURRENT_COLOR;
+				break;
+			case LSM_SVG_PAINT_TYPE_NONE:
+				paint_type = LSM_SVG_PAINT_TYPE_URI;
+				break;
+			case LSM_SVG_PAINT_TYPE_RGB_COLOR_ICC_COLOR:
+				paint_type = LSM_SVG_PAINT_TYPE_URI_RGB_COLOR_ICC_COLOR;
+				break;
+			default:
+				paint_type = LSM_SVG_PAINT_TYPE_URI;
+				break;
+		}
 
-	if (is_color_set)
-		paint->type = paint->uri != NULL ?
-			LSM_SVG_PAINT_TYPE_URI_RGB_COLOR :
-			LSM_SVG_PAINT_TYPE_RGB_COLOR;
-	else
-		paint->type = paint->uri != NULL ?
-			LSM_SVG_PAINT_TYPE_URI :
-			LSM_SVG_PAINT_TYPE_NONE;
+	paint->type = paint_type;
 }
 
 char *
@@ -339,9 +350,7 @@ lsm_svg_paint_trait_to_string (LsmTrait *abstract_trait)
 {
 	LsmSvgPaint *paint = (LsmSvgPaint *) abstract_trait;
 
-	if (paint->color.red < 0.0 ||
-	    paint->color.green < 0.0 ||
-	    paint->color.blue < 0.0)
+	if (paint->color.red < 0.0 || paint->color.green < 0.0 || paint->color.blue < 0.0)
 		return g_strdup ("currentColor");
 
 	if (paint->uri != NULL)
@@ -542,9 +551,9 @@ static void
 lsm_svg_color_trait_from_string (LsmTrait *abstract_trait, char *string)
 {
 	LsmSvgColor *color = (LsmSvgColor *) abstract_trait;
-	gboolean is_color_set;
+	LsmSvgPaintType paint_type;
 
-	_parse_color (string, color, &is_color_set);
+	_parse_color (string, color, &paint_type);
 }
 
 static char *
@@ -552,6 +561,9 @@ lsm_svg_color_trait_to_string (LsmTrait *abstract_trait)
 {
 	LsmSvgColor *color = (LsmSvgColor *) abstract_trait;
 
+	if (color->red < 0.0 || color->green < 0.0 || color->blue < 0.0)
+		return g_strdup ("currentColor");
+
 	return g_strdup_printf ("rgb(%g%%,%g%%,%g%%)",
 				100.0 * color->red,
 				100.0 * color->green,
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 87f1a23..d98a79a 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -152,6 +152,7 @@ lsm_svg_view_add_gradient_color_stop (LsmSvgView *view, double offset)
 /*        , const LsmSvgColor *color, double opacity)*/
 {
 	const LsmSvgStyle *style;
+	const LsmSvgColor *color;
 
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
 	g_return_if_fail (view->pattern_data != NULL);
@@ -172,11 +173,15 @@ lsm_svg_view_add_gradient_color_stop (LsmSvgView *view, double offset)
 /*                                           color->red, color->green, color->blue, opacity);*/
 	lsm_debug ("[LsmSvgView::add_gradient_color_stop] opacity = %g", style->stop_opacity->value);
 
+	color = &style->stop_color->value;
+
+	if (color->red < 0.0 || color->blue < 0.0 || color->green < 0.0)
+		color = &style->color->value;
 
 	cairo_pattern_add_color_stop_rgba (view->pattern_data->pattern, offset,
-					   style->stop_color->value.red,
-					   style->stop_color->value.green,
-					   style->stop_color->value.blue,
+					   color->red,
+					   color->green,
+					   color->blue,
 					   style->stop_opacity->value);
 /*                                           color->red, color->green, color->blue, opacity);*/
 }
@@ -720,7 +725,7 @@ _paint_uri (LsmSvgView *view, LsmSvgViewPaintOperation operation, const char *ur
 
 	_start_pattern (view, &extents);
 
-	lsm_svg_element_render_paint (LSM_SVG_ELEMENT (element), view);
+	lsm_svg_element_force_render (LSM_SVG_ELEMENT (element), view);
 
 	cairo = view->pattern_data->old_cairo;
 
@@ -791,6 +796,13 @@ _set_color (LsmSvgView *view, LsmSvgViewPaintOperation operation,
 					       paint->color.blue,
 					       opacity);
 			break;
+		case LSM_SVG_PAINT_TYPE_CURRENT_COLOR:
+			cairo_set_source_rgba (cairo,
+					       view->style->color->value.red,
+					       view->style->color->value.green,
+					       view->style->color->value.blue,
+					       opacity);
+			break;
 		case LSM_SVG_PAINT_TYPE_URI:
 		case LSM_SVG_PAINT_TYPE_URI_RGB_COLOR:
 		case LSM_SVG_PAINT_TYPE_URI_CURRENT_COLOR:
@@ -929,6 +941,8 @@ paint (LsmSvgView *view)
 static void
 process_path (LsmSvgView *view)
 {
+	g_return_if_fail (view->style != NULL);
+
 	if (view->is_clipping) {
 /*                LsmSvgMaskAttributeBag *mask;*/
 
@@ -1312,53 +1326,29 @@ lsm_svg_view_pop_matrix (LsmSvgView *view)
 }
 
 void
-lsm_svg_view_push_element (LsmSvgView *view, const LsmSvgElement *element)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (LSM_IS_SVG_ELEMENT (element));
-
-	view->element_stack = g_slist_prepend (view->element_stack, (void *) element);
-}
-
-void
-lsm_svg_view_pop_element (LsmSvgView *view)
+lsm_svg_view_push_group_opacity (LsmSvgView *view)
 {
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->element_stack != NULL);
+	g_return_if_fail (view->style != NULL);
 
-	view->element_stack = g_slist_delete_link (view->element_stack, view->element_stack);
+	if (view->style->opacity->value < 1.0)
+		cairo_push_group (view->dom_view.cairo);
 }
 
 void
-lsm_svg_view_push_style	(LsmSvgView *view, const LsmSvgStyle *style)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (style != NULL);
-
-	view->style_stack = g_slist_prepend (view->style_stack, (void *) style);
-	view->style = style;
-}
-
-void lsm_svg_view_pop_style (LsmSvgView *view)
+lsm_svg_view_pop_group_opacity (LsmSvgView *view)
 {
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->style_stack != NULL);
-
-	view->style_stack = g_slist_delete_link (view->style_stack, view->style_stack);
-	view->style = view->style_stack != NULL ? view->style_stack->data : NULL;
-}
-
-const LsmSvgStyle *
-lsm_svg_view_get_current_style (LsmSvgView *view)
-{
-	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), NULL);
+	g_return_if_fail (view->style != NULL);
 
-	return view->style;
+	if (view->style->opacity->value < 1.0) {
+		cairo_pop_group_to_source (view->dom_view.cairo);
+		cairo_paint_with_alpha (view->dom_view.cairo, view->style->opacity->value);
+	}
 }
 
-#if 0
 static void
-lsm_svg_view_push_clip (LsmSvgView *view, char *clip_path, LsmSvgFillRule clip_rule)
+lsm_svg_view_push_clip (LsmSvgView *view)
 {
 	LsmDomElement *element;
 	LsmExtents extents;
@@ -1369,9 +1359,9 @@ lsm_svg_view_push_clip (LsmSvgView *view, char *clip_path, LsmSvgFillRule clip_r
 
 	lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
 
-	uri = clip_path;
+	uri = view->style->clip_path->value;
 
-	lsm_debug ("[LsmSvgView::push_clip] Using '%s'", clip_path);
+	lsm_debug ("[LsmSvgView::push_clip] Using '%s'", uri);
 
 	cairo_save (view->dom_view.cairo);
 
@@ -1393,7 +1383,7 @@ lsm_svg_view_push_clip (LsmSvgView *view, char *clip_path, LsmSvgFillRule clip_r
 
 		if (element != NULL && LSM_IS_SVG_CLIP_PATH_ELEMENT (element)) {
 			view->is_clipping = TRUE;
-			lsm_svg_element_render_clip (LSM_SVG_ELEMENT (element), view);
+			lsm_svg_element_force_render (LSM_SVG_ELEMENT (element), view);
 			cairo_clip (view->dom_view.cairo);
 			view->is_clipping = FALSE;
 		}
@@ -1407,66 +1397,42 @@ lsm_svg_view_pop_clip (LsmSvgView *view)
 
 	cairo_restore (view->dom_view.cairo);
 }
-#endif
-
-void
-lsm_svg_view_push_group_opacity (LsmSvgView *view)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->style != NULL);
-
-	if (view->style->opacity->value < 1.0)
-		cairo_push_group (view->dom_view.cairo);
-}
-
-void
-lsm_svg_view_pop_group_opacity (LsmSvgView *view)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->style != NULL);
-
-	if (view->style->opacity->value < 1.0) {
-		cairo_pop_group_to_source (view->dom_view.cairo);
-		cairo_paint_with_alpha (view->dom_view.cairo, view->style->opacity->value);
-	}
-}
 
-#if 0
-void
-lsm_svg_view_push_mask_attributes (LsmSvgView *view, const LsmSvgMaskAttributeBag *mask)
+static void
+lsm_svg_view_push_mask (LsmSvgView *view)
 {
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (mask != NULL);
+/*        g_return_if_fail (mask != NULL);*/
 
-	view->mask_stack = g_slist_prepend (view->mask_stack, (void *) mask);
+/*        view->mask_stack = g_slist_prepend (view->mask_stack, (void *) mask);*/
 
-	if (mask->clip_path.value != NULL)
-		lsm_svg_view_push_clip (view, mask->clip_path.value, mask->clip_rule.value);
+/*        if (mask->clip_path.value != NULL)*/
+/*                lsm_svg_view_push_clip (view, mask->clip_path.value, mask->clip_rule.value);*/
 
-	if (mask->mask.value != NULL)
+/*        if (mask->mask.value != NULL)*/
 		cairo_push_group (view->dom_view.cairo);
 }
 
-void
-lsm_svg_view_pop_mask_attributes (LsmSvgView *view)
+static void
+lsm_svg_view_pop_mask (LsmSvgView *view)
 {
-	LsmSvgMaskAttributeBag *mask;
+/*        LsmSvgMaskAttributeBag *mask;*/
 
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->mask_stack != NULL);
+/*        g_return_if_fail (view->mask_stack != NULL);*/
 
-	mask = view->mask_stack->data;
+/*        mask = view->mask_stack->data;*/
 
-	if (mask->clip_path.value != NULL)
-		lsm_svg_view_pop_clip (view);
+/*        if (mask->clip_path.value != NULL)*/
+/*                lsm_svg_view_pop_clip (view);*/
 
-	if (mask->mask.value != NULL) {
-		if (strncmp (mask->mask.value, "url(#", 5) == 0) {
+/*        if (mask->mask.value != NULL) {*/
+		if (strncmp (view->style->mask->value, "url(#", 5) == 0) {
 			LsmDomElement *mask_element;
 			char *end;
 			char *uri;
 
-			uri = g_strdup (mask->mask.value + 5);
+			uri = g_strdup (view->style->mask->value + 5);
 			for (end = uri; *end != '\0' && *end != ')'; end++);
 			*end = '\0';
 
@@ -1488,7 +1454,7 @@ lsm_svg_view_pop_mask_attributes (LsmSvgView *view)
 
 				_start_pattern (view, &mask_extents);
 
-				lsm_svg_element_render_paint (LSM_SVG_ELEMENT (mask_element), view);
+				lsm_svg_element_force_render (LSM_SVG_ELEMENT (mask_element), view);
 
 				cairo_pop_group_to_source (cairo);
 				if (view->pattern_data->pattern != NULL) {
@@ -1533,11 +1499,12 @@ lsm_svg_view_pop_mask_attributes (LsmSvgView *view)
 			cairo_pop_group_to_source (view->dom_view.cairo);
 			cairo_paint (view->dom_view.cairo);
 		}
-	}
+/*        }*/
 
-	view->mask_stack = g_slist_delete_link (view->mask_stack, view->mask_stack);
+/*        view->mask_stack = g_slist_delete_link (view->mask_stack, view->mask_stack);*/
 }
 
+#if 0
 void
 lsm_svg_view_push_fill_attributes (LsmSvgView *view, const LsmSvgFillAttributeBag *fill)
 {
@@ -1594,6 +1561,67 @@ lsm_svg_view_pop_text_attributes (LsmSvgView *view)
 
 #endif
 
+void
+lsm_svg_view_push_element (LsmSvgView *view, const LsmSvgElement *element)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (LSM_IS_SVG_ELEMENT (element));
+
+	view->element_stack = g_slist_prepend (view->element_stack, (void *) element);
+}
+
+void
+lsm_svg_view_pop_element (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->element_stack != NULL);
+
+	view->element_stack = g_slist_delete_link (view->element_stack, view->element_stack);
+}
+
+void
+lsm_svg_view_push_style	(LsmSvgView *view, const LsmSvgStyle *style)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (style != NULL);
+
+	view->style_stack = g_slist_prepend (view->style_stack, (void *) style);
+	view->style = style;
+
+	if (g_strcmp0 (style->clip_path->value, "none") != 0) {
+		lsm_debug ("[LsmSvgView::push_style] Start clip '%s'", style->clip_path->value);
+		lsm_svg_view_push_clip (view);
+	}
+
+	if (g_strcmp0 (style->mask->value, "none") != 0) {
+		lsm_debug ("[LsmSvgView::push_style] Start mask '%s'", style->mask->value);
+		lsm_svg_view_push_mask (view);
+	}
+}
+
+void lsm_svg_view_pop_style (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->style_stack != NULL);
+
+	if (g_strcmp0 (view->style->mask->value, "none") != 0)
+		lsm_svg_view_pop_mask (view);
+
+	if (g_strcmp0 (view->style->clip_path->value, "none") != 0)
+		lsm_svg_view_pop_clip (view);
+
+	view->style_stack = g_slist_delete_link (view->style_stack, view->style_stack);
+	view->style = view->style_stack != NULL ? view->style_stack->data : NULL;
+}
+
+const LsmSvgStyle *
+lsm_svg_view_get_current_style (LsmSvgView *view)
+{
+	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), NULL);
+
+	return view->style;
+}
+
 const LsmBox *
 lsm_svg_view_get_pattern_extents (LsmSvgView *view)
 {
diff --git a/test/.gitignore b/test/.gitignore
index d109f53..b4dc037 100644
--- a/test/.gitignore
+++ b/test/.gitignore
@@ -1,3 +1,2 @@
-lasemtest.xml
 log
 *-out.png
diff --git a/test/svg/svg1.1/color/images/colorprof.png b/test/svg/svg1.1/color/images/colorprof.png
new file mode 100755
index 0000000..c03ab9c
Binary files /dev/null and b/test/svg/svg1.1/color/images/colorprof.png differ



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