[lasem] [SVG] Don't compute the actual length value during update.



commit 9f37ee94b5d89f465762028ad39835349c508b16
Author: Emmanuel Pacaud <emmanuel pacaud lapp in2p3 fr>
Date:   Fri May 15 20:14:22 2009 +0200

    [SVG] Don't compute the actual length value during update.
    
    We don't have all the necessary informations at that time.
---
 src/Makefile.am                   |    1 +
 src/lasemtest.c                   |    8 ++-
 src/lsmdom.h                      |    7 ++
 src/lsmdomdocument.c              |   50 ++++++++----
 src/lsmdomdocument.h              |   16 ++--
 src/lsmsvgattributes.c            |  102 ++++------------------
 src/lsmsvgattributes.h            |   40 ++-------
 src/lsmsvgcircleelement.c         |   22 ++---
 src/lsmsvgellipseelement.c        |   28 +++----
 src/lsmsvgenums.c                 |   14 ++--
 src/lsmsvgenums.h                 |   10 +-
 src/lsmsvggradientelement.c       |   15 +--
 src/lsmsvggraphic.c               |   12 +--
 src/lsmsvglength.c                |   90 ++++++++++++++++++++
 src/lsmsvglength.h                |   57 +++++++++++++
 src/lsmsvglineargradientelement.c |   37 +++++----
 src/lsmsvglineelement.c           |   30 +++----
 src/lsmsvgpatternelement.c        |   73 +++++++++++-----
 src/lsmsvgradialgradientelement.c |   58 ++++++++-----
 src/lsmsvgrectelement.c           |   40 +++------
 src/lsmsvgstopelement.c           |   10 +--
 src/lsmsvgstopelement.h           |    2 +-
 src/lsmsvgstyle.h                 |   12 +---
 src/lsmsvgsvgelement.c            |  161 +++++++++++++++++++-----------------
 src/lsmsvgsvgelement.h            |    5 +-
 src/lsmsvgtextelement.c           |   15 ++--
 src/lsmsvguseelement.c            |   34 ++++----
 src/lsmsvgview.c                  |  168 ++++++++++++++++++++++++++++++-------
 src/lsmsvgview.h                  |   15 +++-
 29 files changed, 681 insertions(+), 451 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 3819a41..83ff7af 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -86,6 +86,7 @@ liblasem_la_SOURCES =				\
 	lsmsvgattributebags.c			\
 	lsmsvgstyle.c				\
 	lsmsvgcolors.c				\
+	lsmsvglength.c				\
 	lsmsvgutils.c				\
 	lsmsvgview.c				\
 	lsmsvgmatrix.c
diff --git a/src/lasemtest.c b/src/lasemtest.c
index b7760e4..b33b2d4 100644
--- a/src/lasemtest.c
+++ b/src/lasemtest.c
@@ -110,6 +110,7 @@ lasem_test_render (char const *filename)
 
 	success = g_file_get_contents (filename, &buffer, &size, NULL);
 	if (success) {
+		LsmBox viewport;
 		char *xml = NULL;
 
 		if (is_xml)
@@ -121,8 +122,13 @@ lasem_test_render (char const *filename)
 
 		view = lsm_dom_document_create_view (document);
 
-		lsm_dom_document_set_viewport_px (document, 480.0, 360.0);
+		viewport.x = 0.0;
+		viewport.y = 0.0;
+		viewport.width = 480.0;
+		viewport.height = 360.0;
+
 		lsm_dom_document_set_resolution (document, option_ppi);
+		lsm_dom_document_set_viewport_px (document, &viewport);
 		lsm_dom_view_get_size_pixels (LSM_DOM_VIEW (view), &width, &height);
 
 		surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width + 2, height + 2);
diff --git a/src/lsmdom.h b/src/lsmdom.h
index b1afee1..5c37273 100644
--- a/src/lsmdom.h
+++ b/src/lsmdom.h
@@ -28,6 +28,13 @@
 
 G_BEGIN_DECLS
 
+typedef struct {
+	double x;
+	double y;
+	double width;
+	double height;
+} LsmBox;
+
 typedef struct _GDomNode LsmDomNode;
 typedef struct _GDomElement LsmDomElement;
 typedef struct _GDomDocument LsmDomDocument;
diff --git a/src/lsmdomdocument.c b/src/lsmdomdocument.c
index d96a6ba..8dd9879 100644
--- a/src/lsmdomdocument.c
+++ b/src/lsmdomdocument.c
@@ -104,32 +104,49 @@ lsm_dom_document_set_resolution (LsmDomDocument *self, double ppi)
 }
 
 void
-lsm_dom_document_set_viewport (LsmDomDocument *self, double width, double height)
+lsm_dom_document_set_viewport (LsmDomDocument *self, const LsmBox *viewport_pt)
 {
 	g_return_if_fail (LSM_IS_DOM_DOCUMENT (self));
+	g_return_if_fail (viewport_pt != NULL);
 
-	self->viewport_width = width;
-	self->viewport_height = height;
+	self->viewport_pt = *viewport_pt;
 }
 
 void
-lsm_dom_document_set_viewport_px (LsmDomDocument *self, double width, double height)
+lsm_dom_document_set_viewport_px (LsmDomDocument *self, const LsmBox *viewport)
 {
 	g_return_if_fail (LSM_IS_DOM_DOCUMENT (self));
+	g_return_if_fail (viewport != NULL);
 
-	self->viewport_width  = width  * 72.0 / self->resolution_ppi;
-	self->viewport_height = height * 72.0 / self->resolution_ppi;
+	self->viewport_pt.x      = viewport->x      * 72.0 / self->resolution_ppi;
+	self->viewport_pt.y      = viewport->y      * 72.0 / self->resolution_ppi;
+	self->viewport_pt.width  = viewport->width  * 72.0 / self->resolution_ppi;
+	self->viewport_pt.height = viewport->height * 72.0 / self->resolution_ppi;
 }
 
-void
-lsm_dom_document_get_viewport (LsmDomDocument *self, double *width, double *height)
+LsmBox
+lsm_dom_document_get_viewport (LsmDomDocument *self)
 {
-	g_return_if_fail (LSM_IS_DOM_DOCUMENT (self));
+	static const LsmBox null_viewport = {0, 0, 0, 0};
+
+	g_return_val_if_fail (LSM_IS_DOM_DOCUMENT (self), null_viewport);
+
+	return self->viewport_pt;
+}
 
-	if (width != NULL)
-		*width = self->viewport_width;
-	if (height != NULL)
-		*height = self->viewport_height;
+LsmBox
+lsm_dom_document_get_viewport_px (LsmDomDocument *self)
+{
+	LsmBox viewport = {0, 0, 0, 0};
+
+	g_return_val_if_fail (LSM_IS_DOM_DOCUMENT (self), viewport);
+
+	viewport.x      = self->viewport_pt.x      * self->resolution_ppi / 72.0;
+	viewport.y      = self->viewport_pt.y      * self->resolution_ppi / 72.0;
+	viewport.width  = self->viewport_pt.width  * self->resolution_ppi / 72.0;
+	viewport.height = self->viewport_pt.height * self->resolution_ppi / 72.0;
+
+	return viewport;
 }
 
 LsmDomElement *
@@ -173,9 +190,12 @@ lsm_dom_document_init (LsmDomDocument *document)
 {
 	document->ids = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
 	document->elements = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL);
+
 	document->resolution_ppi = LSM_DOM_DOCUMENT_DEFAULT_RESOLUTION;
-	document->viewport_width = LSM_DOM_DOCUMENT_DEFAULT_VIEWPORT_WIDTH;
-	document->viewport_height = LSM_DOM_DOCUMENT_DEFAULT_VIEWPORT_HEIGHT;
+	document->viewport_pt.x = 0;
+	document->viewport_pt.y = 0;
+	document->viewport_pt.width  = LSM_DOM_DOCUMENT_DEFAULT_VIEWBOX_WIDTH;
+	document->viewport_pt.height = LSM_DOM_DOCUMENT_DEFAULT_VIEWBOX_HEIGHT;
 }
 
 static void
diff --git a/src/lsmdomdocument.h b/src/lsmdomdocument.h
index 1ef081b..0fed990 100644
--- a/src/lsmdomdocument.h
+++ b/src/lsmdomdocument.h
@@ -30,8 +30,8 @@
 G_BEGIN_DECLS
 
 #define LSM_DOM_DOCUMENT_DEFAULT_RESOLUTION 		 72.0
-#define LSM_DOM_DOCUMENT_DEFAULT_VIEWPORT_WIDTH		320.0
-#define LSM_DOM_DOCUMENT_DEFAULT_VIEWPORT_HEIGHT 	200.0
+#define LSM_DOM_DOCUMENT_DEFAULT_VIEWBOX_WIDTH		320.0
+#define LSM_DOM_DOCUMENT_DEFAULT_VIEWBOX_HEIGHT 	200.0
 
 #define LSM_TYPE_DOM_DOCUMENT             (lsm_dom_document_get_type ())
 #define LSM_DOM_DOCUMENT(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), LSM_TYPE_DOM_DOCUMENT, LsmDomDocument))
@@ -50,8 +50,7 @@ struct _GDomDocument {
 
 	/* Not really a document property, but that simplifies things greatly */
 	double resolution_ppi;
-	double viewport_width;
-	double viewport_height;
+	LsmBox viewport_pt;
 };
 
 struct _GDomDocumentClass {
@@ -74,11 +73,14 @@ LsmDomElement *	lsm_dom_document_get_element_by_id 	(LsmDomDocument *self, const
 void 		lsm_dom_document_register_element 	(LsmDomDocument *self, LsmDomElement *element, const char *id);
 
 LsmDomView*	lsm_dom_document_create_view		(LsmDomDocument *self);
+
 double		lsm_dom_document_get_resolution		(LsmDomDocument *self);
 void		lsm_dom_document_set_resolution		(LsmDomDocument *self, double ppi);
-void 		lsm_dom_document_set_viewport 		(LsmDomDocument *self, double width, double height);
-void 		lsm_dom_document_get_viewport 		(LsmDomDocument *self, double *width, double *height);
-void 		lsm_dom_document_set_viewport_px 	(LsmDomDocument *self, double width, double height);
+
+void 		lsm_dom_document_set_viewport 		(LsmDomDocument *self, const LsmBox *viewport);
+void 		lsm_dom_document_set_viewport_px 	(LsmDomDocument *self, const LsmBox *viewport);
+LsmBox 		lsm_dom_document_get_viewport 		(LsmDomDocument *self);
+LsmBox 		lsm_dom_document_get_viewport_px 	(LsmDomDocument *self);
 
 G_END_DECLS
 
diff --git a/src/lsmsvgattributes.c b/src/lsmsvgattributes.c
index ba5e4a5..0333247 100644
--- a/src/lsmsvgattributes.c
+++ b/src/lsmsvgattributes.c
@@ -111,68 +111,9 @@ lsm_svg_double_attribute_parse (LsmSvgDoubleAttribute *attribute,
 	*double_value = attribute->value;
 }
 
-static double
-lsm_svg_length_compute (const LsmSvgLength *length,
-			const LsmSvgStyle *style,
-			LsmSvgLengthDirection direction)
-{
-	double viewport;
-	double viewport_scale;
-
-	g_return_val_if_fail (length != NULL, 0.0);
-
-	switch (direction) {
-		case LSM_SVG_LENGTH_DIRECTION_HORIZONTAL:
-			viewport = style->viewport.width;
-			viewport_scale = style->viewport.horizontal_scale;
-			break;
-		case LSM_SVG_LENGTH_DIRECTION_VERTICAL:
-			viewport = style->viewport.height;
-			viewport_scale = style->viewport.vertical_scale;
-			break;
-		case LSM_SVG_LENGTH_DIRECTION_DIAGONAL:
-			viewport = style->viewport.diagonal;
-			viewport_scale = style->viewport.diagonal_scale;
-			break;
-		default:
-			viewport = 0.0;
-			viewport_scale = 0.0;
-	}
-
-	switch (length->type) {
-		case LSM_SVG_LENGTH_TYPE_NUMBER:
-		case LSM_SVG_LENGTH_TYPE_UNKNOWN:
-			return length->value_unit;
-		case LSM_SVG_LENGTH_TYPE_PERCENTAGE:
-			return length->value_unit * viewport / 100.0;
-		case LSM_SVG_LENGTH_TYPE_PX:
-			return length->value_unit * 72.0 * viewport_scale / style->resolution_ppi;
-		case LSM_SVG_LENGTH_TYPE_PT:
-			return length->value_unit * viewport_scale;
-		case LSM_SVG_LENGTH_TYPE_PC:
-			return length->value_unit * 72.0 * viewport_scale / 6.0;
-		case LSM_SVG_LENGTH_TYPE_CM:
-			return length->value_unit * 72.0 * viewport_scale / 2.54;
-		case LSM_SVG_LENGTH_TYPE_MM:
-			return length->value_unit * 72.0 * viewport_scale / 25.4;
-		case LSM_SVG_LENGTH_TYPE_IN:
-			return length->value_unit * 72.0 * viewport_scale;
-		case LSM_SVG_LENGTH_TYPE_EMS:
-			return length->value_unit * style->text.font_size.value;
-		case LSM_SVG_LENGTH_TYPE_EXS:
-			return length->value_unit * style->text.font_size.value * 0.5;
-	}
-
-	g_warning ("[LsmSvgLength::compute] Invalid length property");
-
-	return 0.0;
-}
-
 void
 lsm_svg_length_attribute_parse (LsmSvgLengthAttribute *attribute,
-				LsmSvgLength *default_value,
-				const LsmSvgStyle *style,
-				LsmSvgLengthDirection direction)
+				LsmSvgLength *default_value)
 {
 	const char *string;
 	char *length_type_str;
@@ -188,7 +129,6 @@ lsm_svg_length_attribute_parse (LsmSvgLengthAttribute *attribute,
 	} else {
 		attribute->length.value_unit = g_strtod (string, &length_type_str);
 		attribute->length.type = lsm_svg_length_type_from_string (length_type_str);
-		attribute->length.value = lsm_svg_length_compute (&attribute->length, style, direction);
 
 		*default_value = attribute->length;
 	}
@@ -196,9 +136,7 @@ lsm_svg_length_attribute_parse (LsmSvgLengthAttribute *attribute,
 
 void
 lsm_svg_animated_length_attribute_parse (LsmSvgAnimatedLengthAttribute *attribute,
-					 LsmSvgLength *default_value,
-					 const LsmSvgStyle *style,
-					 LsmSvgLengthDirection direction)
+					 LsmSvgLength *default_value)
 {
 	const char *string;
 	char *length_type_str;
@@ -214,7 +152,6 @@ lsm_svg_animated_length_attribute_parse (LsmSvgAnimatedLengthAttribute *attribut
 	} else {
 		attribute->length.base.value_unit = g_strtod (string, &length_type_str);
 		attribute->length.base.type = lsm_svg_length_type_from_string (length_type_str);
-		attribute->length.base.value = lsm_svg_length_compute (&attribute->length.base, style, direction);
 		attribute->length.animated = attribute->length.base;
 
 		*default_value = attribute->length.base;
@@ -234,9 +171,7 @@ lsm_svg_dash_array_attribute_finalize (void *abstract)
 
 void
 lsm_svg_dash_array_attribute_parse (LsmSvgDashArrayAttribute *attribute,
-				    LsmSvgDashArray **default_value,
-				    const LsmSvgStyle *style,
-				    LsmSvgLengthDirection direction)
+				    LsmSvgDashArray **default_value)
 {
 	const char *string;
 
@@ -274,8 +209,9 @@ lsm_svg_dash_array_attribute_parse (LsmSvgDashArrayAttribute *attribute,
 				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);
-						attribute->value->dashes[i] =
-							lsm_svg_length_compute (&length, style, direction);
+						/* FIXME */
+						attribute->value->dashes[i] = 0.0;
+/*                                                        lsm_svg_length_compute (&length, style, direction);*/
 						while (*iter != '\0' && *iter != ' ' && *iter != ',')
 							iter ++;
 					} else
@@ -312,10 +248,10 @@ lsm_svg_line_cap_attribute_parse (LsmDomEnumAttribute *attribute,
 }
 
 void
-lsm_svg_gradient_units_attribute_parse (LsmDomEnumAttribute *attribute,
+lsm_svg_pattern_units_attribute_parse (LsmDomEnumAttribute *attribute,
 					unsigned int *style_value)
 {
-	return lsm_dom_enum_attribute_parse (attribute, style_value, lsm_svg_gradient_units_from_string);
+	return lsm_dom_enum_attribute_parse (attribute, style_value, lsm_svg_pattern_units_from_string);
 }
 
 void
@@ -512,7 +448,7 @@ lsm_svg_color_attribute_parse (LsmSvgColorAttribute *attribute,
 }
 
 void
-lsm_svg_view_box_attribute_parse (LsmSvgViewBoxAttribute *attribute)
+lsm_svg_viewbox_attribute_parse (LsmSvgViewboxAttribute *attribute)
 {
 	char *string;
 
@@ -536,18 +472,18 @@ lsm_svg_view_box_attribute_parse (LsmSvgViewBoxAttribute *attribute)
 			attribute->value.y = value[1];
 			attribute->value.width = value[2];
 			attribute->value.height = value[3];
-		} else {
-			attribute->value.x = 0;
-			attribute->value.y = 0;
-			attribute->value.width = 0;
-			attribute->value.height = 0;
+
+			lsm_debug ("[LsmSvgViewboxAttribute::parse] viewbox = %g, %g, %g, %g",
+				   value[0], value[1], value[2], value[3]);
+
+			return;
 		}
-	} else {
-		attribute->value.x = 0;
-		attribute->value.y = 0;
-		attribute->value.width = 0;
-		attribute->value.height = 0;
 	}
+
+	attribute->value.x =
+	attribute->value.y =
+	attribute->value.width =
+	attribute->value.height = 0.0;
 }
 
 static void
diff --git a/src/lsmsvgattributes.h b/src/lsmsvgattributes.h
index 9cc43eb..eaa81f1 100644
--- a/src/lsmsvgattributes.h
+++ b/src/lsmsvgattributes.h
@@ -24,8 +24,10 @@
 #define LSM_SVG_ATTRIBUTES_H
 
 #include <lsmdomattributes.h>
+#include <lsmdomview.h>
 #include <lsmsvg.h>
 #include <lsmsvgenums.h>
+#include <lsmsvglength.h>
 #include <lsmsvgmatrix.h>
 
 G_BEGIN_DECLS
@@ -60,30 +62,12 @@ typedef struct {
 } LsmSvgDashArrayAttribute;
 
 typedef struct {
-	double value;
-	double value_unit;
-	LsmSvgLengthType type;
-} LsmSvgLength;
-
-typedef struct {
-	LsmSvgLength base;
-	LsmSvgLength animated;
-} LsmSvgAnimatedLength;
-
-typedef struct {
 	LsmSvgPaintType type;
 	char *uri;
 	LsmSvgColor color;
 } LsmSvgPaint;
 
 typedef struct {
-	double x;
-	double y;
-	double width;
-	double height;
-} LsmSvgViewBox;
-
-typedef struct {
 	LsmDomAttribute attr;
 	LsmSvgLength length;
 	double value;
@@ -112,8 +96,8 @@ typedef struct {
 
 typedef struct {
 	LsmDomAttribute attr;
-	LsmSvgViewBox value;
-} LsmSvgViewBoxAttribute;
+	LsmBox value;
+} LsmSvgViewboxAttribute;
 
 typedef struct {
 	LsmDomAttribute attr;
@@ -126,20 +110,14 @@ typedef struct {
 void 		lsm_svg_double_attribute_parse 		(LsmSvgDoubleAttribute *attribute,
 							 double *double_value);
 void		lsm_svg_length_attribute_parse 		(LsmSvgLengthAttribute *attribute,
-							 LsmSvgLength *default_value,
-							 const LsmSvgStyle *style,
-							 LsmSvgLengthDirection direction);
+							 LsmSvgLength *default_value);
 void 		lsm_svg_animated_length_attribute_parse (LsmSvgAnimatedLengthAttribute *attribute,
-							 LsmSvgLength *default_value,
-							 const LsmSvgStyle *style,
-							 LsmSvgLengthDirection direction);
+							 LsmSvgLength *default_value);
 
 void 		lsm_svg_dash_array_attribute_finalize 	(void *abstract);
 
 void		lsm_svg_dash_array_attribute_parse	(LsmSvgDashArrayAttribute *attribute,
-							 LsmSvgDashArray **default_value,
-							 const LsmSvgStyle *style,
-							 LsmSvgLengthDirection direction);
+							 LsmSvgDashArray **default_value);
 
 void 		lsm_svg_fill_rule_attribute_parse 	(LsmDomEnumAttribute *attribute,
 							 unsigned int *style_value);
@@ -147,7 +125,7 @@ void 		lsm_svg_line_join_attribute_parse 	(LsmDomEnumAttribute *attribute,
 							 unsigned int *style_value);
 void 		lsm_svg_line_cap_attribute_parse 	(LsmDomEnumAttribute *attribute,
 							 unsigned int *style_value);
-void 		lsm_svg_gradient_units_attribute_parse 	(LsmDomEnumAttribute *attribute,
+void 		lsm_svg_pattern_units_attribute_parse 	(LsmDomEnumAttribute *attribute,
 							 unsigned int *style_value);
 void 		lsm_svg_spread_method_attribute_parse 	(LsmDomEnumAttribute *attribute,
 							 unsigned int *style_value);
@@ -161,7 +139,7 @@ void 		lsm_svg_color_attribute_parse 		(LsmSvgColorAttribute *attribute,
 
 /* Attributes */
 
-void		lsm_svg_view_box_attribute_parse	(LsmSvgViewBoxAttribute *attribute);
+void		lsm_svg_viewbox_attribute_parse		(LsmSvgViewboxAttribute *attribute);
 void		lsm_svg_transform_attribute_parse	(LsmSvgTransformAttribute *attribute);
 
 G_END_DECLS
diff --git a/src/lsmsvgcircleelement.c b/src/lsmsvgcircleelement.c
index 5ac5190..669b790 100644
--- a/src/lsmsvgcircleelement.c
+++ b/src/lsmsvgcircleelement.c
@@ -40,23 +40,17 @@ lsm_svg_circle_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgCircleElement *circle = LSM_SVG_CIRCLE_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&circle->cx, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&circle->cx, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&circle->cy, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&circle->cy, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&circle->r, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+	lsm_svg_animated_length_attribute_parse (&circle->r, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
@@ -67,11 +61,13 @@ static void
 lsm_svg_circle_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgCircleElement *circle = LSM_SVG_CIRCLE_ELEMENT (self);
+	double cx, cy, r;
 
-	lsm_svg_view_show_circle (view,
-				  circle->cx.length.base.value,
-				  circle->cy.length.base.value,
-				  circle->r.length.base.value);
+	cx = lsm_svg_view_normalize_length (view, &circle->cx.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	cy = lsm_svg_view_normalize_length (view, &circle->cy.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	r  = lsm_svg_view_normalize_length (view, &circle->r.length.base,  LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+
+	lsm_svg_view_show_circle (view, cx, cy, r);
 }
 
 /* LsmSvgCircleElement implementation */
diff --git a/src/lsmsvgellipseelement.c b/src/lsmsvgellipseelement.c
index a26f37e..17f7783 100644
--- a/src/lsmsvgellipseelement.c
+++ b/src/lsmsvgellipseelement.c
@@ -40,29 +40,21 @@ lsm_svg_ellipse_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgEllipseElement *ellipse = LSM_SVG_ELLIPSE_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&ellipse->cx, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&ellipse->cx, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&ellipse->cy, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&ellipse->cy, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&ellipse->rx, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&ellipse->rx, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&ellipse->ry, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&ellipse->ry, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
@@ -73,12 +65,14 @@ static void
 lsm_svg_ellipse_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgEllipseElement *ellipse = LSM_SVG_ELLIPSE_ELEMENT (self);
+	double cx, cy, rx, ry;
 
-	lsm_svg_view_show_ellipse (view,
-				ellipse->cx.length.base.value,
-				ellipse->cy.length.base.value,
-				ellipse->rx.length.base.value,
-				ellipse->ry.length.base.value);
+	cx = lsm_svg_view_normalize_length (view, &ellipse->cx.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	cy = lsm_svg_view_normalize_length (view, &ellipse->cy.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	rx = lsm_svg_view_normalize_length (view, &ellipse->rx.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	ry = lsm_svg_view_normalize_length (view, &ellipse->ry.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+	lsm_svg_view_show_ellipse (view, cx, cy, rx, ry);
 }
 
 /* LsmSvgEllipseElement implementation */
diff --git a/src/lsmsvgenums.c b/src/lsmsvgenums.c
index 6053178..f2f8d63 100644
--- a/src/lsmsvgenums.c
+++ b/src/lsmsvgenums.c
@@ -120,22 +120,22 @@ lsm_svg_line_cap_from_string (const char *string)
 					  G_N_ELEMENTS (lsm_svg_line_cap_strings));
 }
 
-static const char *lsm_svg_gradient_units_strings[] = {
+static const char *lsm_svg_pattern_units_strings[] = {
 	"userSpaseOnUse",
 	"objectBoundingBox"
 };
 
 const char *
-lsm_svg_gradient_units_to_string (LsmSvgGradientUnits units)
+lsm_svg_pattern_units_to_string (LsmSvgPatternUnits units)
 {
-	return lsm_svg_gradient_units_strings[CLAMP (units, 0, LSM_SVG_GRADIENT_UNITS_OBJECT_BOUNDING_BOX)];
+	return lsm_svg_pattern_units_strings[CLAMP (units, 0, LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX)];
 }
 
-LsmSvgGradientUnits
-lsm_svg_gradient_units_from_string (const char *string)
+LsmSvgPatternUnits
+lsm_svg_pattern_units_from_string (const char *string)
 {
-	return lsm_svg_value_from_string (string, lsm_svg_gradient_units_strings,
-				       G_N_ELEMENTS (lsm_svg_gradient_units_strings));
+	return lsm_svg_value_from_string (string, lsm_svg_pattern_units_strings,
+					  G_N_ELEMENTS (lsm_svg_pattern_units_strings));
 }
 
 static const char *lsm_svg_spread_method_strings[] = {
diff --git a/src/lsmsvgenums.h b/src/lsmsvgenums.h
index fb42420..1a53db9 100644
--- a/src/lsmsvgenums.h
+++ b/src/lsmsvgenums.h
@@ -99,12 +99,12 @@ typedef enum {
 } LsmSvgTransformType;
 
 typedef enum {
-	LSM_SVG_GRADIENT_UNITS_USER_SPACE_ON_USE,
-	LSM_SVG_GRADIENT_UNITS_OBJECT_BOUNDING_BOX
-} LsmSvgGradientUnits;
+	LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE,
+	LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX
+} LsmSvgPatternUnits;
 
-const char * 		lsm_svg_gradient_units_to_string 		(LsmSvgGradientUnits units);
-LsmSvgGradientUnits	lsm_svg_gradient_units_from_string		(const char *string);
+const char * 		lsm_svg_pattern_units_to_string 		(LsmSvgPatternUnits units);
+LsmSvgPatternUnits	lsm_svg_pattern_units_from_string		(const char *string);
 
 typedef enum {
 	LSM_SVG_SPREAD_METHOD_PAD,
diff --git a/src/lsmsvggradientelement.c b/src/lsmsvggradientelement.c
index 80d4802..0d4053c 100644
--- a/src/lsmsvggradientelement.c
+++ b/src/lsmsvggradientelement.c
@@ -41,22 +41,16 @@ static void
 _gradient_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 {
 	LsmSvgGradientElement *gradient = LSM_SVG_GRADIENT_ELEMENT (self);
-	LsmSvgGradientUnits units;
+	LsmSvgPatternUnits units;
 	LsmSvgSpreadMethod method;
 
-	units = LSM_SVG_GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
+	units = LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX;
 	method = LSM_SVG_SPREAD_METHOD_PAD;
 
-	lsm_svg_gradient_units_attribute_parse (&gradient->units, &units);
+	lsm_svg_pattern_units_attribute_parse (&gradient->units, &units);
 	lsm_svg_spread_method_attribute_parse (&gradient->spread_method, &method);
 	lsm_svg_transform_attribute_parse (&gradient->transform);
 
-	if (gradient->units.value == LSM_SVG_GRADIENT_UNITS_OBJECT_BOUNDING_BOX) {
-		parent_style->viewport.width = 1.0;
-		parent_style->viewport.height = 1.0;
-		parent_style->viewport.diagonal = 1.0;
-	}
-
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
 
@@ -76,7 +70,8 @@ _gradient_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 
 			stop = LSM_SVG_STOP_ELEMENT (iter);
 
-			offset = lsm_svg_stop_element_get_offset (stop);
+			offset = lsm_svg_view_normalize_length (view,  lsm_svg_stop_element_get_offset (stop),
+								LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
 			color = lsm_svg_stop_element_get_color (stop);
 			opacity = lsm_svg_stop_element_get_opacity (stop);
 
diff --git a/src/lsmsvggraphic.c b/src/lsmsvggraphic.c
index 6f48b81..b2c557e 100644
--- a/src/lsmsvggraphic.c
+++ b/src/lsmsvggraphic.c
@@ -97,8 +97,7 @@ lsm_svg_graphic_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 
 	if (graphic->text != NULL) {
 		lsm_dom_string_attribute_parse (&graphic->text->font_family, &parent_style->text.font_family);
-		lsm_svg_length_attribute_parse (&graphic->text->font_size, &parent_style->text.font_size,
-						parent_style, LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+		lsm_svg_length_attribute_parse (&graphic->text->font_size, &parent_style->text.font_size);
 	}
 
 	if (graphic->fill != NULL) {
@@ -115,16 +114,13 @@ lsm_svg_graphic_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 
 		lsm_svg_paint_attribute_parse (&graphic->stroke->paint, &parent_style->stroke.paint,
 					       &graphic->color.value);
-		lsm_svg_length_attribute_parse (&graphic->stroke->width, &parent_style->stroke.width,
-						parent_style, LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+		lsm_svg_length_attribute_parse (&graphic->stroke->width, &parent_style->stroke.width);
 		lsm_dom_double_attribute_parse (&graphic->stroke->opacity, &parent_style->stroke.opacity);
 		lsm_svg_line_join_attribute_parse (&graphic->stroke->line_join, &parent_style->stroke.line_join);
 		lsm_svg_line_cap_attribute_parse (&graphic->stroke->line_cap, &parent_style->stroke.line_cap);
 		lsm_svg_double_attribute_parse (&graphic->stroke->miter_limit, &parent_style->stroke.miter_limit);
-		lsm_svg_dash_array_attribute_parse (&graphic->stroke->dash_array, &parent_style->stroke.dash_array,
-						    parent_style, LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
-		lsm_svg_length_attribute_parse (&graphic->stroke->dash_offset, &parent_style->stroke.dash_offset,
-						    parent_style, LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+		lsm_svg_dash_array_attribute_parse (&graphic->stroke->dash_array, &parent_style->stroke.dash_array);
+		lsm_svg_length_attribute_parse (&graphic->stroke->dash_offset, &parent_style->stroke.dash_offset);
 	}
 
 	if (graphic->transform != NULL) {
diff --git a/src/lsmsvglength.c b/src/lsmsvglength.c
new file mode 100644
index 0000000..8da7927
--- /dev/null
+++ b/src/lsmsvglength.c
@@ -0,0 +1,90 @@
+/*
+ * Copyright © 2009 Emmanuel Pacaud
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+
+#include <math.h>
+#include <lsmsvglength.h>
+
+LsmSvgViewbox *
+lsm_svg_viewbox_new (double resolution_ppi,
+		     const LsmBox *viewbox)
+{
+	LsmSvgViewbox *svg_viewbox;
+
+	svg_viewbox = g_new (LsmSvgViewbox, 1);
+	svg_viewbox->resolution_ppi = resolution_ppi;
+	svg_viewbox->viewbox = *viewbox;
+	svg_viewbox->diagonal = sqrt (viewbox->width * viewbox->width +
+				      viewbox->height * viewbox->height) / sqrt (2.0);
+
+	return svg_viewbox;
+}
+
+void
+lsm_svg_viewbox_free (LsmSvgViewbox *viewbox)
+{
+	g_free (viewbox);
+}
+
+double
+lsm_svg_length_normalize (const LsmSvgLength *length,
+			  const LsmSvgViewbox *viewbox,
+			  double font_size,
+			  LsmSvgLengthDirection direction)
+{
+	g_return_val_if_fail (length != NULL, 0.0);
+	g_return_val_if_fail (viewbox != NULL, 0.0);
+
+	switch (length->type) {
+		case LSM_SVG_LENGTH_TYPE_NUMBER:
+		case LSM_SVG_LENGTH_TYPE_UNKNOWN:
+		case LSM_SVG_LENGTH_TYPE_PX:
+			return length->value_unit;
+		case LSM_SVG_LENGTH_TYPE_PERCENTAGE:
+			switch (direction) {
+				case LSM_SVG_LENGTH_DIRECTION_HORIZONTAL:
+					return length->value_unit * viewbox->viewbox.width / 100.0;
+				case LSM_SVG_LENGTH_DIRECTION_VERTICAL:
+					return length->value_unit * viewbox->viewbox.height / 100.0;
+				case LSM_SVG_LENGTH_DIRECTION_DIAGONAL:
+					return length->value_unit * viewbox->diagonal / 100.0;
+			}
+			break;
+		case LSM_SVG_LENGTH_TYPE_PT:
+			return length->value_unit * viewbox->resolution_ppi / 72.0;
+		case LSM_SVG_LENGTH_TYPE_PC:
+			return length->value_unit * viewbox->resolution_ppi / 6.00;
+		case LSM_SVG_LENGTH_TYPE_CM:
+			return length->value_unit * viewbox->resolution_ppi / 2.54;
+		case LSM_SVG_LENGTH_TYPE_MM:
+			return length->value_unit * viewbox->resolution_ppi / 25.4;
+		case LSM_SVG_LENGTH_TYPE_IN:
+			return length->value_unit * viewbox->resolution_ppi;
+		case LSM_SVG_LENGTH_TYPE_EMS:
+			return length->value_unit * font_size;
+		case LSM_SVG_LENGTH_TYPE_EXS:
+			return length->value_unit * font_size * 0.5;
+	}
+
+	g_warning ("[LsmSvg::normalize_length] Invalid length property");
+
+	return 0.0;
+}
diff --git a/src/lsmsvglength.h b/src/lsmsvglength.h
new file mode 100644
index 0000000..70d96ec
--- /dev/null
+++ b/src/lsmsvglength.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2009 Emmanuel Pacaud
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ * 	Emmanuel Pacaud <emmanuel gnome org>
+ */
+
+#ifndef LSM_SVG_LENGTH
+#define LSM_SVG_LENGTH
+
+#include <lsmdomview.h>
+#include <lsmsvg.h>
+#include <lsmsvgenums.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+	double resolution_ppi;
+	LsmBox viewbox;
+	double diagonal;
+} LsmSvgViewbox;
+
+LsmSvgViewbox *	lsm_svg_viewbox_new 		(double resolution_ppi, const LsmBox *viewbox);
+void		lsm_svg_viewbox_free 		(LsmSvgViewbox *viewbox);
+
+typedef struct {
+	double value_unit;
+	LsmSvgLengthType type;
+} LsmSvgLength;
+
+typedef struct {
+	LsmSvgLength base;
+	LsmSvgLength animated;
+} LsmSvgAnimatedLength;
+
+double 			lsm_svg_length_normalize	(const LsmSvgLength *length,
+							 const LsmSvgViewbox *viewbox,
+							 double font_size,
+							 LsmSvgLengthDirection direction);
+
+G_END_DECLS
+
+#endif
diff --git a/src/lsmsvglineargradientelement.c b/src/lsmsvglineargradientelement.c
index d454eb8..2fd37cf 100644
--- a/src/lsmsvglineargradientelement.c
+++ b/src/lsmsvglineargradientelement.c
@@ -44,45 +44,50 @@ _linear_gradient_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
-	lsm_svg_animated_length_attribute_parse (&linear->x1, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&linear->x1, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
-	lsm_svg_animated_length_attribute_parse (&linear->y1, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&linear->y1, &length);
 
-	length.value = 100.0;
 	length.value_unit = 100.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
-	lsm_svg_animated_length_attribute_parse (&linear->x2, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&linear->x2, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
-	lsm_svg_animated_length_attribute_parse (&linear->y2, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&linear->y2, &length);
 }
 
 static void
 _linear_gradient_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgLinearGradientElement *linear = LSM_SVG_LINEAR_GRADIENT_ELEMENT (self);
+	gboolean is_object_bounding_box;
 	double x1, x2, y1, y2;
 
-	x1 = linear->x1.length.base.value;
-	y1 = linear->y1.length.base.value;
-	x2 = linear->x2.length.base.value;
-	y2 = linear->y2.length.base.value;
+	is_object_bounding_box = (LSM_SVG_GRADIENT_ELEMENT (self)->units.value ==
+				  LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
+
+	if (is_object_bounding_box) {
+		LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
+
+		lsm_svg_view_push_viewbox (view, &viewbox);
+	}
+
+	x1 = lsm_svg_view_normalize_length (view, &linear->x1.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y1 = lsm_svg_view_normalize_length (view, &linear->y1.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	x2 = lsm_svg_view_normalize_length (view, &linear->x2.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y2 = lsm_svg_view_normalize_length (view, &linear->y2.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
 
 	lsm_debug ("[LsmSvgLinearGradientElement::render] Create linear %g, %g, %g, %g",
 		    x1, y1, x2, y2);
 
+	if (is_object_bounding_box)
+		lsm_svg_view_pop_viewbox (view);
+
 	lsm_svg_view_create_linear_gradient (view, x1, y1, x2, y2);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->render_paint (self, view);
diff --git a/src/lsmsvglineelement.c b/src/lsmsvglineelement.c
index 14e7ee6..a272bb3 100644
--- a/src/lsmsvglineelement.c
+++ b/src/lsmsvglineelement.c
@@ -21,6 +21,7 @@
 
 #include <lsmsvglineelement.h>
 #include <lsmsvgview.h>
+#include <lsmdebug.h>
 
 static GObjectClass *parent_class;
 
@@ -40,29 +41,21 @@ lsm_svg_line_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgLineElement *line = LSM_SVG_LINE_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&line->x1, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&line->x1, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&line->y1, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&line->y1, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&line->x2, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&line->x2, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&line->y2, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&line->y2, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
@@ -73,11 +66,16 @@ static void
 lsm_svg_line_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgLineElement *line = LSM_SVG_LINE_ELEMENT (self);
+	double x1, y1, x2, y2;
 
-	lsm_svg_view_show_line (view,line->x1.length.base.value,
-				  line->y1.length.base.value,
-				  line->x2.length.base.value,
-				  line->y2.length.base.value);
+	x1 = lsm_svg_view_normalize_length (view, &line->x1.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y1 = lsm_svg_view_normalize_length (view, &line->y1.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	x2 = lsm_svg_view_normalize_length (view, &line->x2.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y2 = lsm_svg_view_normalize_length (view, &line->y2.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+	lsm_debug ("[LsmSvgLineElement::graphic_render] %g, %g, %g, %g", x1, y1, x2, y2);
+
+	lsm_svg_view_show_line (view, x1, y1, x2, y2);
 }
 
 /* LsmSvgLineElement implementation */
diff --git a/src/lsmsvgpatternelement.c b/src/lsmsvgpatternelement.c
index 3c06ab2..8034a66 100644
--- a/src/lsmsvgpatternelement.c
+++ b/src/lsmsvgpatternelement.c
@@ -40,40 +40,32 @@ static void
 _pattern_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 {
 	LsmSvgPatternElement *pattern = LSM_SVG_PATTERN_ELEMENT (self);
-	LsmSvgGradientUnits units;
+	LsmSvgPatternUnits units;
 	LsmSvgLength length;
 
-	units = LSM_SVG_GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
-	lsm_svg_gradient_units_attribute_parse (&pattern->units, &units);
+	units = LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX;
+	lsm_svg_pattern_units_attribute_parse (&pattern->units, &units);
 
-	units = LSM_SVG_GRADIENT_UNITS_OBJECT_BOUNDING_BOX;
-	lsm_svg_gradient_units_attribute_parse (&pattern->content_units, &units);
+	units = LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE;
+	lsm_svg_pattern_units_attribute_parse (&pattern->content_units, &units);
 
 	lsm_svg_transform_attribute_parse (&pattern->transform);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&pattern->x, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&pattern->x, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&pattern->y, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&pattern->y, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&pattern->width, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&pattern->width, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&pattern->height, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&pattern->height, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
@@ -82,23 +74,58 @@ static void
 _pattern_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgPatternElement *pattern = LSM_SVG_PATTERN_ELEMENT (self);
-	double width, height;
+	double x, y, width, height;
+	gboolean is_object_bounding_box;
 
-	width = pattern->width.length.base.value;
-	height = pattern->height.length.base.value;
+	is_object_bounding_box = (pattern->units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
 
-	if (width < 1.0 || height < 1.0)
+	if (is_object_bounding_box) {
+		LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
+
+		lsm_svg_view_push_viewbox (view, &viewbox);
+	}
+
+	x      = lsm_svg_view_normalize_length (view, &pattern->x.length.base,
+						LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y      = lsm_svg_view_normalize_length (view, &pattern->y.length.base,
+						LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	width  = lsm_svg_view_normalize_length (view, &pattern->width.length.base,
+						LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	height = lsm_svg_view_normalize_length (view, &pattern->height.length.base,
+						LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+	if (is_object_bounding_box)
+		lsm_svg_view_pop_viewbox (view);
+
+	if (width <= 0.0 || height <= 0.0)
 		return;
 
-	lsm_debug ("[LsmSvgPatternElement::render_paint] Create pattern w = %g, h = %g",
-		   width, height);
+	lsm_debug ("[LsmSvgPatternElement::render_paint] Create pattern x = %g, y = %g, w = %g, h = %g",
+		   x, y, width, height);
 
 	lsm_svg_view_create_surface_pattern (view, width, height,
 					     pattern->units.value,
 					     pattern->content_units.value,
 					     &pattern->transform.matrix);
 
+	is_object_bounding_box = (pattern->content_units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
+
+	if (is_object_bounding_box) {
+		LsmBox extents;
+		LsmSvgMatrix matrix;
+
+		extents = lsm_svg_view_get_extents (view);
+		lsm_svg_matrix_init_scale (&matrix, extents.width, extents.height);
+		lsm_svg_view_push_viewbox (view, &extents);
+		lsm_svg_view_push_transform (view, &matrix);
+	}
+
 	LSM_SVG_ELEMENT_CLASS (parent_class)->render (self, view);
+
+	if (is_object_bounding_box) {
+		lsm_svg_view_pop_transform (view);
+		lsm_svg_view_pop_viewbox (view);
+	}
 }
 
 /* LsmSvgPatternElement implementation */
diff --git a/src/lsmsvgradialgradientelement.c b/src/lsmsvgradialgradientelement.c
index 5fec09e..34ac706 100644
--- a/src/lsmsvgradialgradientelement.c
+++ b/src/lsmsvgradialgradientelement.c
@@ -23,6 +23,7 @@
 #include <lsmsvgview.h>
 #include <lsmdebug.h>
 #include <stdio.h>
+#include <math.h>
 
 static GObjectClass *parent_class;
 
@@ -44,48 +45,65 @@ _radial_gradient_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 
-	length.value = 50.0;
 	length.value_unit = 50.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
-	lsm_svg_animated_length_attribute_parse (&radial->cx, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&radial->cx, &length);
 
-	length.value = 50.0;
 	length.value_unit = 50.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
-	lsm_svg_animated_length_attribute_parse (&radial->cy, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&radial->cy, &length);
 
-	length.value = 50.0;
 	length.value_unit = 50.0;
-	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_animated_length_attribute_parse (&radial->r, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
+	lsm_svg_animated_length_attribute_parse (&radial->r, &length);
 
 	length = radial->cx.length.base;
-	lsm_svg_animated_length_attribute_parse (&radial->fx, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&radial->fx, &length);
 
 	length = radial->cy.length.base;
-	lsm_svg_animated_length_attribute_parse (&radial->fy, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&radial->fy, &length);
 }
 
 static void
 _radial_gradient_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgRadialGradientElement *radial = LSM_SVG_RADIAL_GRADIENT_ELEMENT (self);
+	gboolean is_object_bounding_box;
 	double cx, cy, fx, fy, r;
-
-	cx = radial->cx.length.base.value;
-	cy = radial->cy.length.base.value;
-	r  = radial->r.length.base.value;
-	fx = radial->fx.length.base.value;
-	fy = radial->fy.length.base.value;
+	double gradient_radius;
+
+	is_object_bounding_box = (LSM_SVG_GRADIENT_ELEMENT (self)->units.value ==
+				  LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
+
+	if (is_object_bounding_box) {
+		LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
+
+		lsm_svg_view_push_viewbox (view, &viewbox);
+	}
+
+	cx = lsm_svg_view_normalize_length (view, &radial->cx.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	cy = lsm_svg_view_normalize_length (view, &radial->cy.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	r  = lsm_svg_view_normalize_length (view, &radial->r.length.base,  LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+	fx = lsm_svg_view_normalize_length (view, &radial->fx.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	fy = lsm_svg_view_normalize_length (view, &radial->fy.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+	gradient_radius = sqrt ((fx - cx) * (fx - cx) + (fy - cy) * (fy - cy));
+	if (gradient_radius > r) {
+		if (gradient_radius > 0.0) {
+			fx = cx + ((fx - cx) * r / gradient_radius);
+			fy = cy + ((fy - cy) * r / gradient_radius);
+		} else {
+			fx = cx;
+			fy = cy;
+		}
+	}
 
 	lsm_debug ("[LsmSvgRadialElement::render] cx = %g, cy = %g, r = %g, fx = %g, fy = %g",
 		    cx, cy, r, fx, fy);
 
+	if (is_object_bounding_box)
+		lsm_svg_view_pop_viewbox (view);
+
 	lsm_svg_view_create_radial_gradient (view, cx, cy, r, fx, fy);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->render_paint (self, view);
diff --git a/src/lsmsvgrectelement.c b/src/lsmsvgrectelement.c
index fad65c7..3c2aa21 100644
--- a/src/lsmsvgrectelement.c
+++ b/src/lsmsvgrectelement.c
@@ -40,41 +40,29 @@ lsm_svg_rect_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgRectElement *rect = LSM_SVG_RECT_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&rect->x, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&rect->x, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&rect->y, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&rect->y, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&rect->width, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&rect->width, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&rect->height, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&rect->height, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&rect->rx, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&rect->rx, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&rect->ry, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&rect->ry, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
@@ -85,13 +73,16 @@ static void
 lsm_svg_rect_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgRectElement *rect = LSM_SVG_RECT_ELEMENT (self);
+	double x, y;
 	double rx, ry;
 	double w, h;
 
-	rx = rect->rx.length.base.value;
-	ry = rect->ry.length.base.value;
-	w = rect->width.length.base.value;
-	h = rect->height.length.base.value;
+	x = lsm_svg_view_normalize_length (view, &rect->x.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y = lsm_svg_view_normalize_length (view, &rect->y.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	rx = lsm_svg_view_normalize_length (view, &rect->rx.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	ry = lsm_svg_view_normalize_length (view, &rect->ry.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	w = lsm_svg_view_normalize_length (view, &rect->width.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	h = lsm_svg_view_normalize_length (view, &rect->height.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
 
 	/* SVG specification is so weird sometimes ... */
 	if (w == 0.0 || h == 0.0)
@@ -102,10 +93,7 @@ lsm_svg_rect_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 	else if (!lsm_dom_attribute_is_defined (&rect->ry.attr))
 		ry = rx;
 
-	lsm_svg_view_show_rectangle (view,
-				  rect->x.length.base.value,
-				  rect->y.length.base.value,
-				  w, h, rx, ry);
+	lsm_svg_view_show_rectangle (view, x, y, w, h, rx, ry);
 }
 
 /* LsmSvgRectElement implementation */
diff --git a/src/lsmsvgstopelement.c b/src/lsmsvgstopelement.c
index c9931f8..04196a7 100644
--- a/src/lsmsvgstopelement.c
+++ b/src/lsmsvgstopelement.c
@@ -43,22 +43,20 @@ _stop_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgStopElement *stop = LSM_SVG_STOP_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 1.0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_length_attribute_parse (&stop->offset, &length, parent_style,
-					LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+	lsm_svg_length_attribute_parse (&stop->offset, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
 
 /* LsmSvgStopElement implementation */
 
-double
+const LsmSvgLength *
 lsm_svg_stop_element_get_offset (LsmSvgStopElement *self)
 {
-	g_return_val_if_fail (LSM_IS_SVG_STOP_ELEMENT (self), 0.0);
+	g_return_val_if_fail (LSM_IS_SVG_STOP_ELEMENT (self), NULL);
 
-	return LSM_SVG_STOP_ELEMENT (self)->offset.length.value;
+	return &(LSM_SVG_STOP_ELEMENT (self)->offset.length);
 }
 
 const LsmSvgColor *
diff --git a/src/lsmsvgstopelement.h b/src/lsmsvgstopelement.h
index c821dd4..3355aca 100644
--- a/src/lsmsvgstopelement.h
+++ b/src/lsmsvgstopelement.h
@@ -50,7 +50,7 @@ GType lsm_svg_stop_element_get_type (void);
 
 LsmDomNode * lsm_svg_stop_element_new (void);
 
-double 			lsm_svg_stop_element_get_offset 	(LsmSvgStopElement *self);
+const LsmSvgLength *	lsm_svg_stop_element_get_offset 	(LsmSvgStopElement *self);
 const LsmSvgColor *	lsm_svg_stop_element_get_color 		(LsmSvgStopElement *self);
 double 			lsm_svg_stop_element_get_opacity 	(LsmSvgStopElement *self);
 
diff --git a/src/lsmsvgstyle.h b/src/lsmsvgstyle.h
index 85bfdcf..20d6ac3 100644
--- a/src/lsmsvgstyle.h
+++ b/src/lsmsvgstyle.h
@@ -28,19 +28,9 @@
 G_BEGIN_DECLS
 
 struct _LsmSvgStyle {
+	LsmBox viewport;
 	LsmSvgColor color;
 
-	double resolution_ppi;
-
-	struct {
-		double width;
-		double height;
-		double diagonal;
-		double horizontal_scale;
-		double vertical_scale;
-		double diagonal_scale;
-	} viewport;
-
 	struct {
 		LsmSvgPaint paint;
 		LsmSvgFillRule rule;
diff --git a/src/lsmsvgsvgelement.c b/src/lsmsvgsvgelement.c
index 703dd53..d553671 100644
--- a/src/lsmsvgsvgelement.c
+++ b/src/lsmsvgsvgelement.c
@@ -45,74 +45,47 @@ _svg_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgSvgElement *svg = LSM_SVG_SVG_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 0.0;
-	length.value_unit = 0.0;
+	length.value_unit = 0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_length_attribute_parse (&svg->x, &length, parent_style, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_length_attribute_parse (&svg->x, &length);
 
-	length.value = 0.0;
-	length.value_unit = 0.0;
+	length.value_unit = 0;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_length_attribute_parse (&svg->y, &length, parent_style, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_length_attribute_parse (&svg->y, &length);
 
-	length.value = 0.0;
-	length.value_unit = 0.0;
+	length.value_unit = parent_style->viewport.width;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_length_attribute_parse (&svg->width, &length, parent_style, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_length_attribute_parse (&svg->width, &length);
 
-	length.value = 0.0;
-	length.value_unit = 0.0;
+	length.value_unit = parent_style->viewport.height;
 	length.type = LSM_SVG_LENGTH_TYPE_NUMBER;
-	lsm_svg_length_attribute_parse (&svg->height, &length, parent_style, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_length_attribute_parse (&svg->height, &length);
 
-	if (svg->width.length.value <= 0.0)
-		svg->width.length.value = parent_style->viewport.width;
-	if (svg->height.length.value <= 0.0)
-		svg->height.length.value = parent_style->viewport.height;
-
-	lsm_svg_view_box_attribute_parse (&svg->view_box);
-
-	if (svg->view_box.value.width <= 0.0)
-		svg->view_box.value.width = svg->width.length.value;
-	if (svg->view_box.value.height <= 0.0)
-		svg->view_box.value.height = svg->height.length.value;
-
-	lsm_debug ("[LsmSvgSvgElement::update] height = %g px, width = %g px",
-		    svg->height.length.value,
-		    svg->width.length.value);
+	lsm_svg_viewbox_attribute_parse (&svg->viewbox);
 
 	lsm_debug ("[LsmSvgSvgElement::update] view_bbox = %g, %g, %g, %g\n",
-		    svg->view_box.value.x,
-		    svg->view_box.value.y,
-		    svg->view_box.value.width,
-		    svg->view_box.value.height);
-
-	parent_style->viewport.width = svg->view_box.value.width;
-	parent_style->viewport.height = svg->view_box.value.height;
-	parent_style->viewport.diagonal= sqrt (pow (svg->view_box.value.width, 2.0) +
-					       pow (svg->view_box.value.height, 2.0)) / sqrt (2.0);
-
-	parent_style->viewport.horizontal_scale = svg->width.length.value / svg->view_box.value.width;
-	parent_style->viewport.vertical_scale = svg->height.length.value / svg->view_box.value.height;
-	parent_style->viewport.diagonal_scale = sqrt (pow (parent_style->viewport.horizontal_scale, 2.0) +
-						      pow (parent_style->viewport.vertical_scale, 2.0)) / sqrt (2.0);
-	parent_style->viewport.horizontal_scale =
-	parent_style->viewport.vertical_scale =
-	parent_style->viewport.diagonal_scale =  parent_style->resolution_ppi / 72.0;
-
-	lsm_debug ("[LsmSvgSvgElement::update] viewport       = %g, %g",
-		   parent_style->viewport.width, parent_style->viewport.height);
-	lsm_debug ("[LsmSvgSvgElement::update] viewport_scale = %g, %g",
-		   parent_style->viewport.horizontal_scale, parent_style->viewport.vertical_scale);
+		    svg->viewbox.value.x,
+		    svg->viewbox.value.y,
+		    svg->viewbox.value.width,
+		    svg->viewbox.value.height);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
+
+	parent_style->viewport = svg->viewbox.value;
 }
 
 void
 lsm_svg_svg_element_measure (LsmSvgSvgElement *self, double *width, double *height)
 {
 	LsmDomDocument *document;
+	LsmSvgViewbox *svg_viewbox;
+	LsmBox viewport;
 	double resolution_ppi;
+	double svg_x;
+	double svg_y;
+	double svg_width;
+	double svg_height;
+	double font_size;
 
 	g_return_if_fail (LSM_IS_SVG_SVG_ELEMENT (self));
 
@@ -120,11 +93,34 @@ lsm_svg_svg_element_measure (LsmSvgSvgElement *self, double *width, double *heig
 	g_return_if_fail (LSM_IS_DOM_DOCUMENT (document));
 
 	resolution_ppi = lsm_dom_document_get_resolution (document);
+	viewport = lsm_dom_document_get_viewport_px (document);
+
+	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 (width != NULL)
-		*width = self->width.length.value * 72.0 / resolution_ppi;
+		*width = svg_width * 72.0 / resolution_ppi;
 	if (height != NULL)
-		*height = self->height.length.value * 72.0 / resolution_ppi;
+		*height = svg_height * 72.0 / resolution_ppi;
+
+	self->svg_box.x = svg_x;
+	self->svg_box.y = svg_y;
+	self->svg_box.width = svg_width;
+	self->svg_box.height = svg_height;
+
+	lsm_debug ("[LsmSvgSvgElement::measure] Size = %g, %g, %g, %g",
+		   svg_x, svg_y, svg_width, svg_height);
+
+	lsm_svg_viewbox_free (svg_viewbox);
 }
 
 /* LsmSvgGraphic implementation */
@@ -133,23 +129,37 @@ static void
 lsm_svg_svg_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgSvgElement *svg = LSM_SVG_SVG_ELEMENT (self);
-	LsmSvgMatrix matrix;
+	const LsmBox *viewbox;
+	gboolean is_viewbox_defined;
 
-	if (svg->view_box.value.width <= 0.0 ||
-	    svg->view_box.value.height <= 0.0)
-		return;
+	is_viewbox_defined = lsm_dom_attribute_is_defined ((LsmDomAttribute *) &svg->viewbox);
 
-	lsm_svg_matrix_init (&matrix,
-			     svg->width.length.value / svg->view_box.value.width,
-			     0, 0,
-			     svg->height.length.value / svg->view_box.value.height,
-			     0, 0);
+	if (is_viewbox_defined) {
+		LsmSvgMatrix matrix;
 
-	lsm_svg_view_push_transform (view, &matrix);
+		if (svg->viewbox.value.width <= 0.0 ||
+		    svg->viewbox.value.height <= 0.0)
+			return;
+
+		viewbox = &svg->viewbox.value;
+
+		lsm_svg_matrix_init (&matrix,
+				     svg->svg_box.width / svg->viewbox.value.width, 0.0,
+				     0.0 , svg->svg_box.height / svg->viewbox.value.height,
+				     -svg->viewbox.value.x,-svg->viewbox.value.y);
+
+		lsm_svg_view_push_transform (view, &matrix);
+	} else
+		viewbox = &svg->svg_box;
+
+	lsm_svg_view_push_viewbox (view, viewbox);
 
 	LSM_SVG_GRAPHIC_CLASS (parent_class)->graphic_render (self, view);
 
-	lsm_svg_view_pop_transform (view);
+	lsm_svg_view_pop_viewbox (view);
+
+	if (is_viewbox_defined)
+		lsm_svg_view_pop_transform (view);
 }
 
 /* LsmSvgSvgElement implementation */
@@ -175,16 +185,15 @@ lsm_svg_svg_element_update (LsmSvgSvgElement *svg_element)
 
 	style = lsm_svg_svg_element_get_default_style (svg_element);
 
-	style->resolution_ppi = lsm_dom_document_get_resolution (document);
-	lsm_dom_document_get_viewport (document, &style->viewport.width, &style->viewport.height);
-	style->viewport.diagonal = sqrt (pow (style->viewport.width, 2.0) + pow (style->viewport.height, 2.0)) /
-		sqrt (2.0);
-	style->viewport.horizontal_scale =
-	style->viewport.vertical_scale =
-	style->viewport.diagonal_scale = style->resolution_ppi / 72.0;
+	style->viewport = lsm_dom_document_get_viewport_px (document);
 
-	lsm_svg_element_update (LSM_SVG_ELEMENT (svg_element),
-			     lsm_svg_svg_element_get_default_style (svg_element));
+	lsm_svg_element_update (LSM_SVG_ELEMENT (svg_element), style);
+}
+
+void
+lsm_svg_svg_element_render (LsmSvgSvgElement *svg, LsmSvgView *view)
+{
+	lsm_svg_element_render (LSM_SVG_ELEMENT (svg), view);
 }
 
 LsmDomNode *
@@ -250,15 +259,15 @@ lsm_svg_svg_element_class_init (LsmSvgSvgElementClass *s_svg_class)
 	s_element_class->attributes = lsm_dom_attribute_map_duplicate (s_element_class->attributes);
 
 	lsm_dom_attribute_map_add_attribute (s_element_class->attributes, "x",
-					  offsetof (LsmSvgSvgElement, x));
+					     offsetof (LsmSvgSvgElement, x));
 	lsm_dom_attribute_map_add_attribute (s_element_class->attributes, "y",
-					  offsetof (LsmSvgSvgElement, y));
+					     offsetof (LsmSvgSvgElement, y));
 	lsm_dom_attribute_map_add_attribute (s_element_class->attributes, "width",
-					  offsetof (LsmSvgSvgElement, width));
+					     offsetof (LsmSvgSvgElement, width));
 	lsm_dom_attribute_map_add_attribute (s_element_class->attributes, "height",
-					  offsetof (LsmSvgSvgElement, height));
+					     offsetof (LsmSvgSvgElement, height));
 	lsm_dom_attribute_map_add_attribute (s_element_class->attributes, "viewBox",
-					  offsetof (LsmSvgSvgElement, view_box));
+					     offsetof (LsmSvgSvgElement, viewbox));
 }
 
 G_DEFINE_TYPE (LsmSvgSvgElement, lsm_svg_svg_element, LSM_TYPE_SVG_GRAPHIC)
diff --git a/src/lsmsvgsvgelement.h b/src/lsmsvgsvgelement.h
index b32e617..a5f7137 100644
--- a/src/lsmsvgsvgelement.h
+++ b/src/lsmsvgsvgelement.h
@@ -46,7 +46,9 @@ struct _GSvgSvgElement {
 	LsmSvgLengthAttribute	width;
 	LsmSvgLengthAttribute	height;
 
-	LsmSvgViewBoxAttribute	view_box;
+	LsmSvgViewboxAttribute	viewbox;
+
+	LsmBox svg_box;
 };
 
 struct _GSvgSvgElementClass {
@@ -60,6 +62,7 @@ LsmDomNode *		lsm_svg_svg_element_new 		(void);
 LsmSvgStyle * 		lsm_svg_svg_element_get_default_style 	(LsmSvgSvgElement *svg_element);
 void 			lsm_svg_svg_element_update 		(LsmSvgSvgElement *svg_element);
 void 			lsm_svg_svg_element_measure 		(LsmSvgSvgElement *self, double *width, double *height);
+void 			lsm_svg_svg_element_render 		(LsmSvgSvgElement *svg_element, LsmSvgView *view);
 
 G_END_DECLS
 
diff --git a/src/lsmsvgtextelement.c b/src/lsmsvgtextelement.c
index 9209afc..f89c44e 100644
--- a/src/lsmsvgtextelement.c
+++ b/src/lsmsvgtextelement.c
@@ -47,17 +47,13 @@ lsm_svg_text_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgTextElement *text = LSM_SVG_TEXT_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&text->x, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&text->x, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&text->y, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&text->y, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
@@ -71,6 +67,7 @@ lsm_svg_text_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmDomNode *node = LSM_DOM_NODE (self);
 	LsmDomNode *iter;
 	GString *string = g_string_new ("");
+	double x, y;
 
 	if (node->first_child == NULL)
 		return;
@@ -81,8 +78,10 @@ lsm_svg_text_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 		}
 	}
 
-	lsm_svg_view_show_text (view, g_strstrip (string->str),
-				text->x.length.base.value, text->y.length.base.value);
+	x = lsm_svg_view_normalize_length (view, &text->x.length.base, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y = lsm_svg_view_normalize_length (view, &text->y.length.base, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+	lsm_svg_view_show_text (view, g_strstrip (string->str), x, y);
 
 	g_string_free (string, TRUE);
 }
diff --git a/src/lsmsvguseelement.c b/src/lsmsvguseelement.c
index 7c83ab2..51775ac 100644
--- a/src/lsmsvguseelement.c
+++ b/src/lsmsvguseelement.c
@@ -49,29 +49,21 @@ lsm_svg_use_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	LsmSvgUseElement *use_element = LSM_SVG_USE_ELEMENT (self);
 	LsmSvgLength length;
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&use_element->x, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&use_element->x, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&use_element->y, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&use_element->y, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&use_element->width, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	lsm_svg_animated_length_attribute_parse (&use_element->width, &length);
 
-	length.value = 0.0;
 	length.value_unit = 0.0;
 	length.type = LSM_SVG_LENGTH_TYPE_PX;
-	lsm_svg_animated_length_attribute_parse (&use_element->height, &length, parent_style,
-						 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	lsm_svg_animated_length_attribute_parse (&use_element->height, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
 }
@@ -86,6 +78,7 @@ lsm_svg_use_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 	LsmDomElement *element;
 	LsmSvgMatrix matrix;
 	const char *id;
+	double x, y, width, height;
 
 	document = lsm_dom_node_get_owner_document (LSM_DOM_NODE (self));
 	if (document == NULL) {
@@ -109,18 +102,25 @@ lsm_svg_use_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 		return;
 	}
 
-/*        if (use_element->width.length.base.value <= 0.0 ||*/
-/*            use_element->height.length.base.value <= 0.0)*/
+	width = lsm_svg_view_normalize_length (view, &use_element->width.length.base,
+					       LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	height = lsm_svg_view_normalize_length (view, &use_element->height.length.base,
+						LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+/*        if (width <= 0.0 || height <= 0.0)*/
 /*                return;*/
 
 	lsm_debug ("[LsmSvgUseElement::graphic_render] Use '%s'", id);
 
-	lsm_svg_matrix_init_translate (&matrix,
-				    use_element->x.length.base.value,
-				    use_element->y.length.base.value);
+	x = lsm_svg_view_normalize_length (view, &use_element->x.length.base,
+					   LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	y = lsm_svg_view_normalize_length (view, &use_element->y.length.base,
+					   LSM_SVG_LENGTH_DIRECTION_VERTICAL);
 
+	lsm_svg_matrix_init_translate (&matrix, x, y);
 	lsm_svg_view_push_transform (view, &matrix);
+
 	lsm_svg_element_render (LSM_SVG_ELEMENT (element), view);
+
 	lsm_svg_view_pop_transform (view);
 }
 
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index d96e974..0d3af8a 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -40,14 +40,28 @@ struct _GSvgViewPatternData {
 	cairo_pattern_t *pattern;
 	cairo_matrix_t matrix;
 
-	LsmSvgGradientUnits units;
-	LsmSvgGradientUnits content_units;
+	LsmBox extents;
+
+	LsmSvgPatternUnits units;
+	LsmSvgPatternUnits content_units;
 	LsmSvgSpreadMethod spread_method;
 };
 
+LsmBox
+lsm_svg_view_get_extents (LsmSvgView *view)
+{
+	LsmBox null_box = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
+
+	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), null_box);
+	g_return_val_if_fail (view->pattern_data != NULL, null_box);
+
+	return view->pattern_data->extents;
+}
+
 static void
 _start_pattern (LsmSvgView *view)
 {
+	double x1, x2, y1, y2;
 	lsm_debug ("[LsmSvgView::start_pattern]");
 
 	view->pattern_stack = g_slist_prepend (view->pattern_stack, view->pattern_data);
@@ -55,11 +69,19 @@ _start_pattern (LsmSvgView *view)
 	view->pattern_data = g_new (LsmSvgViewPatternData, 1);
 	view->pattern_data->old_cairo = view->dom_view.cairo;
 	view->pattern_data->pattern = NULL;
-	view->pattern_data->units = LSM_SVG_GRADIENT_UNITS_USER_SPACE_ON_USE;
+	view->pattern_data->content_units = LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE;
+	view->pattern_data->units = LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE;
 	view->pattern_data->spread_method = LSM_SVG_SPREAD_METHOD_REPEAT;
 
+	cairo_path_extents (view->dom_view.cairo, &x1, &y1, &x2, &y2);
+
 	view->dom_view.cairo = NULL;
 
+	view->pattern_data->extents.x = x1;
+	view->pattern_data->extents.y = y1;
+	view->pattern_data->extents.width = x2 - x1;
+	view->pattern_data->extents.height = y2 - y1;
+
 	cairo_matrix_init_identity (&view->pattern_data->matrix);
 }
 
@@ -90,22 +112,20 @@ static void
 _set_pattern (LsmSvgView *view, cairo_pattern_t *pattern)
 {
 	g_return_if_fail (view->pattern_data != NULL);
-
-	if (view->pattern_data->pattern != NULL)
-		cairo_pattern_destroy (view->pattern_data->pattern);
+	g_return_if_fail (view->pattern_data->pattern == NULL);
 
 	view->pattern_data->pattern = pattern;
 }
 
 void
 lsm_svg_view_create_radial_gradient (LsmSvgView *view,
-				  double cx, double cy,
-				  double r,
-				  double fx, double fy)
+				     double cx, double cy,
+				     double r,
+				     double fx, double fy)
 {
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
 
-	_set_pattern (view, cairo_pattern_create_radial (cx, cy, 0, fx, fy, r));
+	_set_pattern (view, cairo_pattern_create_radial (fx, fy, 0, cx, cy, r));
 }
 
 void
@@ -133,7 +153,7 @@ lsm_svg_view_add_gradient_color_stop (LsmSvgView *view, double offset, const Lsm
 void
 lsm_svg_view_set_gradient_properties (LsmSvgView *view,
 				      LsmSvgSpreadMethod method,
-				      LsmSvgGradientUnits units,
+				      LsmSvgPatternUnits units,
 				      const LsmSvgMatrix *matrix)
 {
 	g_return_if_fail (LSM_IS_SVG_VIEW (view));
@@ -155,8 +175,8 @@ lsm_svg_view_set_gradient_properties (LsmSvgView *view,
 void
 lsm_svg_view_create_surface_pattern (LsmSvgView *view,
 				     double width, double height,
-				     LsmSvgGradientUnits units,
-				     LsmSvgGradientUnits content_units,
+				     LsmSvgPatternUnits units,
+				     LsmSvgPatternUnits content_units,
 				     const LsmSvgMatrix *matrix)
 {
 	cairo_surface_t *surface;
@@ -166,6 +186,14 @@ lsm_svg_view_create_surface_pattern (LsmSvgView *view,
 	g_return_if_fail (view->pattern_data != NULL);
 	g_return_if_fail (view->dom_view.cairo == NULL);
 
+	if (units == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX) {
+		width = width * view->pattern_data->extents.width;
+		height = height * view->pattern_data->extents.height;
+	}
+
+	if (height < 1 || width < 1)
+		return;
+
 	surface = cairo_surface_create_similar (cairo_get_target (view->pattern_data->old_cairo),
 						CAIRO_CONTENT_COLOR_ALPHA,
 						width, height);
@@ -610,6 +638,53 @@ _emit_svg_path (cairo_t *cr, char const *path)
 	}
 }
 
+double
+lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length, LsmSvgLengthDirection direction)
+{
+	double font_size;
+
+	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), 0.0);
+
+	/* TODO cache font size */
+	if (view->text_stack != NULL && view->viewbox_stack != NULL) {
+		LsmSvgTextAttributeBag *text;
+
+		text = view->text_stack->data;
+		font_size = lsm_svg_length_normalize (&text->font_size.length, view->viewbox_stack->data,
+						      0.0, LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+	} else
+		font_size = 0.0;
+
+	return lsm_svg_length_normalize (length, view->viewbox_stack->data, font_size, direction);
+}
+
+void
+lsm_svg_view_push_viewbox (LsmSvgView *view, const LsmBox *viewbox)
+{
+	LsmSvgViewbox *svg_viewbox;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+	lsm_debug ("[LsmSvgView::push_viewbox] viewbox = %g, %g, %g, %g",
+		   viewbox->x, viewbox->y, viewbox->width, viewbox->height);
+
+	svg_viewbox = lsm_svg_viewbox_new (view->resolution_ppi, viewbox);
+
+	view->viewbox_stack = g_slist_prepend (view->viewbox_stack, svg_viewbox);
+}
+
+void
+lsm_svg_view_pop_viewbox (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->viewbox_stack != NULL);
+
+	lsm_debug ("[LsmSvgView::pop_viewbox]");
+
+	lsm_svg_viewbox_free (view->viewbox_stack->data);
+	view->viewbox_stack = g_slist_delete_link (view->viewbox_stack, view->viewbox_stack);
+}
+
 void
 lsm_svg_view_push_transform (LsmSvgView *view, const LsmSvgMatrix *matrix)
 {
@@ -684,8 +759,13 @@ lsm_svg_view_pop_text_attributes (LsmSvgView *view)
 	view->text_stack = g_slist_delete_link (view->text_stack, view->text_stack);
 }
 
+typedef enum {
+	LSM_SVG_VIEW_PAINT_OPERATION_FILL,
+	LSM_SVG_VIEW_PAINT_OPERATION_STROKE
+} LsmSvgViewPaintOperation;
+
 static void
-_paint_uri (LsmSvgView *view, const char *uri)
+_paint_uri (LsmSvgView *view, LsmSvgViewPaintOperation operation, const char *uri)
 {
 	cairo_t *cairo;
 	LsmDomElement *element;
@@ -710,18 +790,22 @@ _paint_uri (LsmSvgView *view, const char *uri)
 		g_free (filename);
 #endif
 
-		if (view->pattern_data->units == LSM_SVG_GRADIENT_UNITS_OBJECT_BOUNDING_BOX) {
+		if (LSM_IS_SVG_GRADIENT_ELEMENT (element) &&
+		    view->pattern_data->units == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX) {
 			cairo_matrix_t matrix;
-			double x1, x2, y1, y2;
 
-			cairo_path_extents (cairo, &x1, &y1, &x2, &y2);
-			if (x2 <= x1 || y2 <= y1) {
+			if (view->pattern_data->extents.width <= 0.0 ||
+			    view->pattern_data->extents.height <= 0.0) {
 				_end_pattern (view);
 				return;
 			}
 
-			cairo_matrix_init_scale (&matrix, 1.0 / (x2 - x1), 1.0 / (y2 - y1));
-			cairo_matrix_translate (&matrix, -x1, -y1);
+			cairo_matrix_init_scale (&matrix,
+						 1.0 / view->pattern_data->extents.width,
+						 1.0 / view->pattern_data->extents.height);
+			cairo_matrix_translate (&matrix,
+						-view->pattern_data->extents.x,
+						-view->pattern_data->extents.y);
 
 			cairo_matrix_multiply (&matrix, &view->pattern_data->matrix, &matrix);
 			cairo_pattern_set_matrix (view->pattern_data->pattern, &matrix);
@@ -747,7 +831,8 @@ _paint_uri (LsmSvgView *view, const char *uri)
 }
 
 static gboolean
-_set_color (LsmSvgView *view, const LsmSvgPaint *paint, double opacity)
+_set_color (LsmSvgView *view, LsmSvgViewPaintOperation operation,
+	    const LsmSvgPaint *paint, double opacity)
 {
 	cairo_t *cairo = view->dom_view.cairo;
 
@@ -765,7 +850,7 @@ _set_color (LsmSvgView *view, const LsmSvgPaint *paint, double opacity)
 		case LSM_SVG_PAINT_TYPE_URI_RGB_COLOR:
 		case LSM_SVG_PAINT_TYPE_URI_CURRENT_COLOR:
 		case LSM_SVG_PAINT_TYPE_URI_NONE:
-			_paint_uri (view, paint->uri);
+			_paint_uri (view, operation, paint->uri);
 			break;
 		default:
 			return FALSE;
@@ -788,13 +873,17 @@ _paint (LsmSvgView *view)
 	fill = view->fill_stack->data;
 	stroke = view->stroke_stack->data;
 
-	if (_set_color (view, &fill->paint.paint, fill->opacity.value)) {
+	if (_set_color (view, LSM_SVG_VIEW_PAINT_OPERATION_FILL,
+			&fill->paint.paint, fill->opacity.value)) {
 		cairo_set_fill_rule (cairo, fill->rule.value == LSM_SVG_FILL_RULE_EVEN_ODD ?
 				     CAIRO_FILL_RULE_EVEN_ODD : CAIRO_FILL_RULE_WINDING);
 		cairo_fill_preserve (cairo);
 	}
 
-	if (_set_color (view, &stroke->paint.paint, stroke->opacity.value)) {
+	if (_set_color (view, LSM_SVG_VIEW_PAINT_OPERATION_STROKE,
+			&stroke->paint.paint, stroke->opacity.value)) {
+		double line_width;
+
 		switch (stroke->line_join.value) {
 			case LSM_SVG_LINE_JOIN_MITER:
 				cairo_set_line_join (cairo, CAIRO_LINE_JOIN_MITER);
@@ -817,15 +906,23 @@ _paint (LsmSvgView *view)
 				cairo_set_line_cap (cairo, CAIRO_LINE_CAP_SQUARE);
 		}
 
+		line_width = lsm_svg_view_normalize_length (view, &stroke->width.length,
+							    LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+
 		cairo_set_miter_limit (cairo, stroke->miter_limit.value);
-		cairo_set_line_width (cairo, stroke->width.length.value);
+		cairo_set_line_width (cairo, line_width);
+
+		if (stroke->dash_array.value != NULL) {
+			double dash_offset;
+
+			dash_offset = lsm_svg_view_normalize_length (view, &stroke->dash_offset.length,
+								     LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
 
-		if (stroke->dash_array.value != NULL)
 			cairo_set_dash (cairo,
 					stroke->dash_array.value->dashes,
 					stroke->dash_array.value->n_dashes,
-					stroke->dash_offset.length.value);
-		else
+					dash_offset);
+		} else
 			cairo_set_dash (cairo, NULL, 0, 0.0);
 
 		cairo_stroke (cairo);
@@ -986,6 +1083,7 @@ lsm_svg_view_show_text (LsmSvgView *view, char const *string, double x, double y
 	PangoLayoutIter *iter;
 	PangoRectangle ink_rect;
 	LsmSvgTextAttributeBag *text;
+	double font_size;
 	int baseline;
 
 	if (string == NULL)
@@ -999,8 +1097,10 @@ lsm_svg_view_show_text (LsmSvgView *view, char const *string, double x, double y
 	pango_layout = view->dom_view.pango_layout;
 	font_description = view->dom_view.font_description;
 
+	font_size = lsm_svg_view_normalize_length (view, &text->font_size.length, LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
+
 	pango_font_description_set_family (font_description, text->font_family.value);
-	pango_font_description_set_size (font_description, text->font_size.length.value * PANGO_SCALE);
+	pango_font_description_set_size (font_description, font_size * PANGO_SCALE);
 
 	pango_layout_set_text (pango_layout, string, -1);
 	pango_layout_set_font_description (pango_layout, font_description);
@@ -1064,12 +1164,20 @@ lsm_svg_view_render (LsmDomView *view)
 
 	lsm_svg_svg_element_update (svg_element);
 
+	svg_view->viewbox_stack = NULL;
 	svg_view->fill_stack = NULL;
 	svg_view->stroke_stack = NULL;
 	svg_view->text_stack = NULL;
 
-	lsm_svg_element_render (LSM_SVG_ELEMENT (svg_element), LSM_SVG_VIEW (view));
+	svg_view->resolution_ppi = lsm_dom_document_get_resolution (view->document);
+
+	lsm_svg_svg_element_render  (svg_element, svg_view);
 
+	if (svg_view->viewbox_stack != NULL) {
+		g_warning ("[LsmSvgView::render] Dangling viewport in stack");
+		g_slist_free (svg_view->viewbox_stack);
+		svg_view->viewbox_stack = NULL;
+	}
 	if (svg_view->fill_stack != NULL) {
 		g_warning ("[LsmSvgView::render] Dangling fill attribute in stack");
 		g_slist_free (svg_view->fill_stack);
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index f3110be..3207f36 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -43,6 +43,9 @@ typedef struct _GSvgViewPatternData LsmSvgViewPatternData;
 struct _GSvgView {
 	LsmDomView dom_view;
 
+	double resolution_ppi;
+
+	GSList *viewbox_stack;
 	GSList *fill_stack;
 	GSList *stroke_stack;
 	GSList *text_stack;
@@ -60,6 +63,8 @@ GType lsm_svg_view_get_type (void);
 
 LsmSvgView *	lsm_svg_view_new 			(LsmSvgDocument *document);
 
+LsmBox 		lsm_svg_view_get_extents 		(LsmSvgView *view);
+
 void 		lsm_svg_view_create_radial_gradient 	(LsmSvgView *view, double cx, double cy,
 							                   double r, double fx, double fy);
 void 		lsm_svg_view_create_linear_gradient 	(LsmSvgView *view, double x1, double y1,
@@ -68,14 +73,18 @@ void 		lsm_svg_view_add_gradient_color_stop	(LsmSvgView *view, double offset,
 							 const LsmSvgColor *color, double opacity);
 void 		lsm_svg_view_set_gradient_properties	(LsmSvgView *view,
 							 LsmSvgSpreadMethod method,
-							 LsmSvgGradientUnits units,
+							 LsmSvgPatternUnits units,
 							 const LsmSvgMatrix *matrix);
 
 void		lsm_svg_view_create_surface_pattern	(LsmSvgView *view, double width, double height,
-							 LsmSvgGradientUnits units,
-							 LsmSvgGradientUnits content_units,
+							 LsmSvgPatternUnits units,
+							 LsmSvgPatternUnits content_units,
 							 const LsmSvgMatrix *matrix);
 
+double 		lsm_svg_view_normalize_length 		(LsmSvgView *view, const LsmSvgLength *length,
+							 LsmSvgLengthDirection direction);
+void 		lsm_svg_view_push_viewbox 		(LsmSvgView *view, const LsmBox *viewbox);
+void 		lsm_svg_view_pop_viewbox 		(LsmSvgView *view);
 void		lsm_svg_view_push_transform 		(LsmSvgView *view, const LsmSvgMatrix *matrix);
 void		lsm_svg_view_pop_transform		(LsmSvgView *view);
 void 		lsm_svg_view_push_fill_attributes 	(LsmSvgView *view, LsmSvgFillAttributeBag *fill);



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