[lasem] <svg:mask> Pass the two testsuite mask example.



commit f4b610548d5d7106443ac1d46ae2c41d2293fca1
Author: Emmanuel Pacaud <emmanuel pacaud lapp in2p3 fr>
Date:   Thu Jul 2 17:44:18 2009 +0200

    <svg:mask> Pass the two testsuite mask example.

 src/lsmsvgattributebags.c  |    4 +
 src/lsmsvgattributebags.h  |    3 +-
 src/lsmsvgmaskelement.c    |   83 ++++-
 src/lsmsvgpatternelement.c |   15 +-
 src/lsmsvgview.c           |  883 ++++++++++++++++++++++++--------------------
 src/lsmsvgview.h           |   55 ++--
 6 files changed, 611 insertions(+), 432 deletions(-)
---
diff --git a/src/lsmsvgattributebags.c b/src/lsmsvgattributebags.c
index dfadb82..923498f 100644
--- a/src/lsmsvgattributebags.c
+++ b/src/lsmsvgattributebags.c
@@ -57,6 +57,10 @@ lsm_dom_attribute_map_add_mask_attribute_bag (LsmDomAttributeMap *map, ptrdiff_t
 						 offsetof (LsmSvgMaskAttributeBag, clip_rule),
 						 NULL,
 						 bag_offset, &lsm_svg_mask_attribute_bag_class);
+	lsm_dom_attribute_map_add_bag_attribute (map, "mask",
+						 offsetof (LsmSvgMaskAttributeBag, mask),
+						 NULL,
+						 bag_offset, &lsm_svg_mask_attribute_bag_class);
 }
 
 static void *
diff --git a/src/lsmsvgattributebags.h b/src/lsmsvgattributebags.h
index e84f07b..73b7311 100644
--- a/src/lsmsvgattributebags.h
+++ b/src/lsmsvgattributebags.h
@@ -28,9 +28,10 @@
 G_BEGIN_DECLS
 
 typedef struct {
+	LsmSvgDoubleAttribute opacity;
 	LsmDomAttribute clip_path;
 	LsmDomEnumAttribute clip_rule;
-	LsmSvgDoubleAttribute opacity;
+	LsmDomAttribute mask;
 } LsmSvgMaskAttributeBag;
 
 typedef struct {
diff --git a/src/lsmsvgmaskelement.c b/src/lsmsvgmaskelement.c
index d8a2a7a..c65541d 100644
--- a/src/lsmsvgmaskelement.c
+++ b/src/lsmsvgmaskelement.c
@@ -49,20 +49,20 @@ _mask_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	units = LSM_SVG_PATTERN_UNITS_USER_SPACE_ON_USE;
 	lsm_svg_pattern_units_attribute_parse (&mask->content_units, &units);
 
-	length.value_unit = 0.0;
-	length.type = LSM_SVG_LENGTH_TYPE_PX;
+	length.value_unit = -10.0;
+	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
 	lsm_svg_animated_length_attribute_parse (&mask->x, &length);
 
-	length.value_unit = 0.0;
-	length.type = LSM_SVG_LENGTH_TYPE_PX;
+	length.value_unit = -10.0;
+	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
 	lsm_svg_animated_length_attribute_parse (&mask->y, &length);
 
-	length.value_unit = 0.0;
-	length.type = LSM_SVG_LENGTH_TYPE_PX;
+	length.value_unit = 120.0;
+	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
 	lsm_svg_animated_length_attribute_parse (&mask->width, &length);
 
-	length.value_unit = 0.0;
-	length.type = LSM_SVG_LENGTH_TYPE_PX;
+	length.value_unit = 120.0;
+	length.type = LSM_SVG_LENGTH_TYPE_PERCENTAGE;
 	lsm_svg_animated_length_attribute_parse (&mask->height, &length);
 
 	LSM_SVG_ELEMENT_CLASS (parent_class)->update (self, parent_style);
@@ -71,6 +71,73 @@ _mask_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 static void
 _mask_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 {
+	LsmSvgMaskElement *mask = LSM_SVG_MASK_ELEMENT (self);
+	gboolean is_object_bounding_box;
+	LsmBox viewport;
+	const LsmBox *mask_extents;
+
+	mask_extents = lsm_svg_view_get_pattern_extents (view);
+
+	is_object_bounding_box = (mask->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);
+	}
+
+	viewport.x      = lsm_svg_view_normalize_length (view, &mask->x.length.base,
+							 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	viewport.y      = lsm_svg_view_normalize_length (view, &mask->y.length.base,
+							 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	viewport.width  = lsm_svg_view_normalize_length (view, &mask->width.length.base,
+							 LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	viewport.height = lsm_svg_view_normalize_length (view, &mask->height.length.base,
+							 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+
+	if (is_object_bounding_box) {
+		lsm_svg_view_pop_viewbox (view);
+
+		viewport.x = viewport.x * mask_extents->width + mask_extents->x;
+		viewport.y = viewport.y * mask_extents->height + mask_extents->y;
+		viewport.width *= mask_extents->width;
+		viewport.height *= mask_extents->height;
+	}
+
+	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",
+		   viewport.x, viewport.y, viewport.width, viewport.height);
+
+	lsm_svg_view_create_surface_pattern (view, &viewport,
+					     mask->units.value,
+					     mask->content_units.value, NULL,
+					     LSM_SVG_VIEW_SURFACE_TYPE_IMAGE);
+
+	is_object_bounding_box = (mask->content_units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
+
+	if (is_object_bounding_box) {
+		LsmSvgMatrix matrix;
+		LsmBox viewbox = {.x = 0.0, .y = .0, .width = 1.0, .height = 1.0};
+
+		lsm_svg_matrix_init_translate (&matrix, +mask_extents->x, +mask_extents->y);
+		lsm_svg_matrix_scale (&matrix, mask_extents->width, mask_extents->height);
+		lsm_svg_view_push_viewbox (view, &viewbox);
+		lsm_svg_view_push_matrix (view, &matrix);
+
+		lsm_debug ("[LsmSvgMaskElement::render_paint] 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);
+	}
+
+	LSM_SVG_ELEMENT_CLASS (parent_class)->render (self, view);
+
+	if (is_object_bounding_box) {
+		lsm_svg_view_pop_matrix (view);
+		lsm_svg_view_pop_viewbox (view);
+	}
 }
 
 /* LsmSvgMaskElement implementation */
diff --git a/src/lsmsvgpatternelement.c b/src/lsmsvgpatternelement.c
index f88d104..551da38 100644
--- a/src/lsmsvgpatternelement.c
+++ b/src/lsmsvgpatternelement.c
@@ -101,9 +101,15 @@ _pattern_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 	viewport.height = lsm_svg_view_normalize_length (view, &pattern->height.length.base,
 							 LSM_SVG_LENGTH_DIRECTION_VERTICAL);
 
-	if (is_object_bounding_box)
+	if (is_object_bounding_box) {
 		lsm_svg_view_pop_viewbox (view);
 
+		viewport.x *= pattern_extents->width;
+		viewport.y *= pattern_extents->height;
+		viewport.width *= pattern_extents->width;
+		viewport.height *= pattern_extents->height;
+	}
+
 	if (viewport.width <= 0.0 || viewport.height <= 0.0)
 		return;
 
@@ -113,7 +119,8 @@ _pattern_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 	lsm_svg_view_create_surface_pattern (view, &viewport,
 					     pattern->units.value,
 					     pattern->content_units.value,
-					     &pattern->transform.matrix);
+					     &pattern->transform.matrix,
+					     LSM_SVG_VIEW_SURFACE_TYPE_AUTO);
 
 	is_object_bounding_box = (pattern->content_units.value == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX);
 
@@ -127,7 +134,9 @@ _pattern_element_render_paint (LsmSvgElement *self, LsmSvgView *view)
 		lsm_svg_view_push_matrix (view, &matrix);
 
 		lsm_debug ("[LsmSvgPatternElement::render_paint] object_bounding_box"
-			   " x_scale = %g, y_scale = %g",pattern_extents->width, pattern_extents->height);
+			   " x_scale = %g, y_scale = %g, x_offset = %g, y_offset = %g",
+			   pattern_extents->width, pattern_extents->height,
+			   pattern_extents->x,     pattern_extents->y);
 	}
 
 	is_viewbox_defined = lsm_dom_attribute_is_defined ((LsmDomAttribute *) &pattern->viewbox);
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index 52bd449..648d1ff 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -27,6 +27,7 @@
 #include <lsmsvggradientelement.h>
 #include <lsmsvgpatternelement.h>
 #include <lsmsvgclippathelement.h>
+#include <lsmsvgmaskelement.h>
 #include <lsmsvgutils.h>
 #include <gdk/gdk.h>
 #include <glib/gprintf.h>
@@ -69,383 +70,9 @@ lsm_svg_view_normalize_length (LsmSvgView *view, const LsmSvgLength *length, Lsm
 	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_viewport (LsmSvgView *view, const LsmBox *viewport, const LsmBox *viewbox,
-			    const LsmSvgPreserveAspectRatio *aspect_ratio)
-{
-	cairo_t *cairo;
-	double x_ratio, x_scale;
-	double y_ratio, y_scale;
-	double x, y;
-
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (viewport != NULL);
-	g_return_if_fail (aspect_ratio != NULL);
-
-	x = viewport->x;
-	y = viewport->y;
-
-	if (viewbox != NULL) {
-		x_ratio = viewbox->width  > 0.0 ? viewport->width  / viewbox->width  : 0.0;
-		y_ratio = viewbox->height > 0.0 ? viewport->height / viewbox->height : 0.0;
-
-		if (aspect_ratio->align > LSM_SVG_ALIGN_NONE) {
-			if (aspect_ratio->meet_or_slice == LSM_SVG_MEET_OR_SLICE_MEET) {
-				x_scale = MIN (x_ratio, y_ratio);
-				y_scale = x_scale;
-			} else {
-				x_scale = MAX (x_ratio, y_ratio);
-				y_scale = x_scale;
-			}
-
-			x -= viewbox->x;
-			y -= viewbox->y;
-
-			switch (aspect_ratio->align) {
-				case LSM_SVG_ALIGN_X_MIN_Y_MIN:
-					break;
-				case LSM_SVG_ALIGN_X_MIN_Y_MID:
-					y += (viewport->height- viewbox->height * y_scale) * 0.5;
-					break;
-				case LSM_SVG_ALIGN_X_MIN_Y_MAX:
-					y += (viewport->height - viewbox->height * y_scale);
-					break;
-				case LSM_SVG_ALIGN_X_MID_Y_MIN:
-					x += (viewport->width - viewbox->width * x_scale) * 0.5;
-					break;
-				case LSM_SVG_ALIGN_X_MID_Y_MID:
-					x += (viewport->width - viewbox->width * x_scale) * 0.5;
-					y += (viewport->height- viewbox->height * y_scale) * 0.5;
-					break;
-				case LSM_SVG_ALIGN_X_MID_Y_MAX:
-					x += (viewport->width - viewbox->width * x_scale) * 0.5;
-					y += (viewport->height - viewbox->height * y_scale);
-					break;
-				case LSM_SVG_ALIGN_X_MAX_Y_MIN:
-					x += (viewport->width - viewbox->width * x_scale);
-					break;
-				case LSM_SVG_ALIGN_X_MAX_Y_MID:
-					x += (viewport->width - viewbox->width * x_scale);
-					y += (viewport->height- viewbox->height * y_scale) * 0.5;
-					break;
-				case LSM_SVG_ALIGN_X_MAX_Y_MAX:
-					x += (viewport->width - viewbox->width * x_scale);
-					y += (viewport->height - viewbox->height * y_scale);
-					break;
-				default:
-					break;
-			}
-		} else {
-			x_scale = x_ratio;
-			y_scale = y_ratio;
-		}
-
-		lsm_debug ("[LsmSvgView::push_viewport] scale = %g, %g", x_scale, y_scale);
-
-		lsm_svg_view_push_viewbox (view, viewbox);
-
-	} else {
-		x_scale = y_scale = 1.0;
-		lsm_svg_view_push_viewbox (view, viewport);
-	}
-
-	cairo = view->dom_view.cairo;
-
-	cairo_save (cairo);
-	cairo_rectangle (cairo, viewport->x, viewport->y, viewport->width, viewport->height);
-	cairo_clip (cairo);
-	cairo_translate (cairo, x, y);
-	cairo_scale (cairo, x_scale, y_scale);
-}
-
-void
-lsm_svg_view_pop_viewport (LsmSvgView *view)
-{
-	cairo_restore (view->dom_view.cairo);
-
-	lsm_svg_view_pop_viewbox (view);
-}
-
-void
-lsm_svg_view_push_matrix (LsmSvgView *view, LsmSvgMatrix *matrix)
-{
-	cairo_matrix_t cr_matrix;
-	cairo_matrix_t *ctm;
-
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-
-	ctm = g_new (cairo_matrix_t, 1);
-	cairo_get_matrix (view->dom_view.cairo, ctm);
-
-	view->matrix_stack = g_slist_prepend (view->matrix_stack, ctm);
-
-	lsm_debug ("[LsmSvgView::push_matrix] New transform %g, %g, %g, %g, %g, %g",
-		   matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f);
-
-	cairo_matrix_init (&cr_matrix, matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f);
-	cairo_transform (view->dom_view.cairo, &cr_matrix);
-
-	{
-		cairo_matrix_t current_ctm;
-		cairo_get_matrix (view->dom_view.cairo, &current_ctm);
-
-		lsm_debug ("[LsmSvgView::push_matrix] Current ctm %g, %g, %g, %g, %g, %g",
-			   current_ctm.xx, current_ctm.xy, current_ctm.yx, current_ctm.yy,
-			   current_ctm.x0, current_ctm.y0);
-	}
-}
-
-void
-lsm_svg_view_pop_matrix (LsmSvgView *view)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-
-	if (view->matrix_stack != NULL) {
-		cairo_matrix_t *ctm;
-
-		ctm = view->matrix_stack->data;
-
-		cairo_set_matrix (view->dom_view.cairo, ctm);
-
-		g_free (ctm);
-		view->matrix_stack = g_slist_delete_link (view->matrix_stack, view->matrix_stack);
-	}
-}
-
-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);
-}
-
 static void
-lsm_svg_view_push_clip (LsmSvgView *view, char *clip_path, LsmSvgFillRule clip_rule)
+_start_pattern (LsmSvgView *view, const LsmBox *extents)
 {
-	LsmDomElement *element;
-	LsmExtents extents;
-	char *uri;
-
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (!view->is_clipping);
-
-	lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
-
-	uri = clip_path;
-
-	lsm_debug ("[LsmSvgView::push_clip] Using '%s'", clip_path);
-
-	cairo_save (view->dom_view.cairo);
-
-	view->clip_extents.x = extents.x1;
-	view->clip_extents.y = extents.y1;
-	view->clip_extents.width  = extents.x2 - extents.x1;
-	view->clip_extents.height = extents.y2 - extents.y1;
-
-	if (strncmp (uri, "url(#", 5) ==0) {
-		char *end;
-
-		uri = g_strdup (uri + 5);
-		for (end = uri; *end != '\0' && *end != ')'; end++);
-		*end = '\0';
-
-		element = lsm_dom_document_get_element_by_id (view->dom_view.document, uri);
-
-		g_free (uri);
-
-		if (element != NULL && LSM_IS_SVG_CLIP_PATH_ELEMENT (element)) {
-			view->is_clipping = TRUE;
-			lsm_svg_element_render_clip (LSM_SVG_ELEMENT (element), view);
-			cairo_clip (view->dom_view.cairo);
-			view->is_clipping = FALSE;
-		}
-	}
-}
-
-static void
-lsm_svg_view_pop_clip (LsmSvgView *view)
-{
-	lsm_debug ("[LsmSvgView::pop_clip");
-
-	cairo_restore (view->dom_view.cairo);
-}
-
-void
-lsm_svg_view_push_group_opacity (LsmSvgView *view)
-{
-	LsmSvgMaskAttributeBag *mask;
-
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->mask_stack != NULL);
-
-	mask = view->mask_stack->data;
-
-	if (mask->opacity.value < 1.0)
-		cairo_push_group (view->dom_view.cairo);
-}
-
-void
-lsm_svg_view_pop_group_opacity (LsmSvgView *view)
-{
-	LsmSvgMaskAttributeBag *mask;
-
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->mask_stack != NULL);
-
-	mask = view->mask_stack->data;
-
-	if (mask->opacity.value < 1.0) {
-		cairo_pop_group_to_source (view->dom_view.cairo);
-		cairo_paint_with_alpha (view->dom_view.cairo, mask->opacity.value);
-	}
-}
-
-void
-lsm_svg_view_push_mask_attributes (LsmSvgView *view, const LsmSvgMaskAttributeBag *mask)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (mask != NULL);
-
-	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);
-}
-
-void
-lsm_svg_view_pop_mask_attributes (LsmSvgView *view)
-{
-	LsmSvgMaskAttributeBag *mask;
-
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->mask_stack != NULL);
-
-	mask = view->mask_stack->data;
-
-	if (mask->clip_path.value != NULL)
-		lsm_svg_view_pop_clip (view);
-
-	view->mask_stack = g_slist_delete_link (view->mask_stack, view->mask_stack);
-}
-
-void
-lsm_svg_view_push_fill_attributes (LsmSvgView *view, const LsmSvgFillAttributeBag *fill)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (fill != NULL);
-
-	view->fill_stack = g_slist_prepend (view->fill_stack, (void *) fill);
-}
-
-void
-lsm_svg_view_pop_fill_attributes (LsmSvgView *view)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->fill_stack != NULL);
-
-	view->fill_stack = g_slist_delete_link (view->fill_stack, view->fill_stack);
-}
-
-void
-lsm_svg_view_push_stroke_attributes (LsmSvgView *view, const LsmSvgStrokeAttributeBag *stroke)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (stroke != NULL);
-
-	view->stroke_stack = g_slist_prepend (view->stroke_stack, (void *) stroke);
-}
-
-void
-lsm_svg_view_pop_stroke_attributes (LsmSvgView *view)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->stroke_stack != NULL);
-
-	view->stroke_stack = g_slist_delete_link (view->stroke_stack, view->stroke_stack);
-}
-
-void
-lsm_svg_view_push_text_attributes (LsmSvgView *view, const LsmSvgTextAttributeBag *text)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (text != NULL);
-
-	view->text_stack = g_slist_prepend (view->text_stack, (void *) text);
-}
-
-void
-lsm_svg_view_pop_text_attributes (LsmSvgView *view)
-{
-	g_return_if_fail (LSM_IS_SVG_VIEW (view));
-	g_return_if_fail (view->text_stack != NULL);
-
-	view->text_stack = g_slist_delete_link (view->text_stack, view->text_stack);
-}
-
-const LsmBox *
-lsm_svg_view_get_pattern_extents (LsmSvgView *view)
-{
-	static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
-
-	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
-	g_return_val_if_fail (view->pattern_data != NULL, &null_extents);
-
-	return &view->pattern_data->extents;
-}
-
-const LsmBox *
-lsm_svg_view_get_clip_extents (LsmSvgView *view)
-{
-	static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
-
-	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
-	g_return_val_if_fail (view->is_clipping, &null_extents);
-
-	return &view->clip_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);
@@ -456,16 +83,10 @@ _start_pattern (LsmSvgView *view)
 	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->pattern_data->extents = *extents;
 
 	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);
 }
 
@@ -561,7 +182,8 @@ lsm_svg_view_create_surface_pattern (LsmSvgView *view,
 				     const LsmBox *viewport,
 				     LsmSvgPatternUnits units,
 				     LsmSvgPatternUnits content_units,
-				     const LsmSvgMatrix *matrix)
+				     const LsmSvgMatrix *matrix,
+				     LsmSvgViewSurfaceType surface_type)
 {
 	cairo_surface_t *surface;
 	cairo_pattern_t *pattern;
@@ -577,22 +199,31 @@ lsm_svg_view_create_surface_pattern (LsmSvgView *view,
 	width = viewport->width;
 	height = viewport->height;
 
-	if (units == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX) {
-		x *= view->pattern_data->extents.width;
-		y *= view->pattern_data->extents.height;
-		width *= view->pattern_data->extents.width;
-		height *= view->pattern_data->extents.height;
-	}
+/*        if (units == LSM_SVG_PATTERN_UNITS_OBJECT_BOUNDING_BOX) {*/
+/*                x *= view->pattern_data->extents.width;*/
+/*                y *= view->pattern_data->extents.height;*/
+/*                width *= view->pattern_data->extents.width;*/
+/*                height *= view->pattern_data->extents.height;*/
+/*        }*/
 
-	lsm_debug ("[LsmSvgView::create_pattern] pattern size = %g ,%g",
-		   width, height);
+	lsm_debug ("[LsmSvgView::create_pattern] pattern size = %g ,%g at %g, %g",
+		   width, height, x, y);
 
 	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);
+	switch (surface_type) {
+		case LSM_SVG_VIEW_SURFACE_TYPE_AUTO:
+			surface = cairo_surface_create_similar (cairo_get_target (view->pattern_data->old_cairo),
+								CAIRO_CONTENT_COLOR_ALPHA,
+								width, height);
+			break;
+		default:
+		case LSM_SVG_VIEW_SURFACE_TYPE_IMAGE:
+			surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
+			break;
+	}
+
 	pattern = cairo_pattern_create_for_surface (surface);
 	view->dom_view.cairo = cairo_create (surface);
 	cairo_surface_destroy (surface);
@@ -633,7 +264,7 @@ typedef struct {
  * 	_emit_smooth_curve
  * 	_emit_smooth_quadratic_curve
  *
- * is adpated from the goocanvas library (goocanvasutils.c)
+ * is adapted from the goocanvas library (goocanvasutils.c)
  *
  * GooCanvas. Copyright (C) 2005 Damon Chaplin.
  */
@@ -1046,13 +677,22 @@ _paint_uri (LsmSvgView *view, LsmSvgViewPaintOperation operation, const char *ur
 {
 	cairo_t *cairo;
 	LsmDomElement *element;
+	LsmBox extents;
+	double x1, x2, y1, y2;
 
 	element = lsm_dom_document_get_element_by_id (view->dom_view.document, uri);
 	if (!LSM_IS_SVG_GRADIENT_ELEMENT (element) &&
 	    !LSM_IS_SVG_PATTERN_ELEMENT (element))
 		return;
 
-	_start_pattern (view);
+	cairo_path_extents (view->dom_view.cairo, &x1, &y1, &x2, &y2);
+
+	extents.x = x1;
+	extents.y = y1;
+	extents.width = x2 - x1;
+	extents.height = y2 - y1;
+
+	_start_pattern (view, &extents);
 
 	lsm_svg_element_render_paint (LSM_SVG_ELEMENT (element), view);
 
@@ -1462,6 +1102,457 @@ lsm_svg_view_show_pixbuf (LsmSvgView *view, GdkPixbuf *pixbuf)
 	cairo_paint (view->dom_view.cairo);
 }
 
+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_viewport (LsmSvgView *view, const LsmBox *viewport, const LsmBox *viewbox,
+			    const LsmSvgPreserveAspectRatio *aspect_ratio)
+{
+	cairo_t *cairo;
+	double x_ratio, x_scale;
+	double y_ratio, y_scale;
+	double x, y;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (viewport != NULL);
+	g_return_if_fail (aspect_ratio != NULL);
+
+	x = viewport->x;
+	y = viewport->y;
+
+	if (viewbox != NULL) {
+		x_ratio = viewbox->width  > 0.0 ? viewport->width  / viewbox->width  : 0.0;
+		y_ratio = viewbox->height > 0.0 ? viewport->height / viewbox->height : 0.0;
+
+		if (aspect_ratio->align > LSM_SVG_ALIGN_NONE) {
+			if (aspect_ratio->meet_or_slice == LSM_SVG_MEET_OR_SLICE_MEET) {
+				x_scale = MIN (x_ratio, y_ratio);
+				y_scale = x_scale;
+			} else {
+				x_scale = MAX (x_ratio, y_ratio);
+				y_scale = x_scale;
+			}
+
+			x -= viewbox->x;
+			y -= viewbox->y;
+
+			switch (aspect_ratio->align) {
+				case LSM_SVG_ALIGN_X_MIN_Y_MIN:
+					break;
+				case LSM_SVG_ALIGN_X_MIN_Y_MID:
+					y += (viewport->height- viewbox->height * y_scale) * 0.5;
+					break;
+				case LSM_SVG_ALIGN_X_MIN_Y_MAX:
+					y += (viewport->height - viewbox->height * y_scale);
+					break;
+				case LSM_SVG_ALIGN_X_MID_Y_MIN:
+					x += (viewport->width - viewbox->width * x_scale) * 0.5;
+					break;
+				case LSM_SVG_ALIGN_X_MID_Y_MID:
+					x += (viewport->width - viewbox->width * x_scale) * 0.5;
+					y += (viewport->height- viewbox->height * y_scale) * 0.5;
+					break;
+				case LSM_SVG_ALIGN_X_MID_Y_MAX:
+					x += (viewport->width - viewbox->width * x_scale) * 0.5;
+					y += (viewport->height - viewbox->height * y_scale);
+					break;
+				case LSM_SVG_ALIGN_X_MAX_Y_MIN:
+					x += (viewport->width - viewbox->width * x_scale);
+					break;
+				case LSM_SVG_ALIGN_X_MAX_Y_MID:
+					x += (viewport->width - viewbox->width * x_scale);
+					y += (viewport->height- viewbox->height * y_scale) * 0.5;
+					break;
+				case LSM_SVG_ALIGN_X_MAX_Y_MAX:
+					x += (viewport->width - viewbox->width * x_scale);
+					y += (viewport->height - viewbox->height * y_scale);
+					break;
+				default:
+					break;
+			}
+		} else {
+			x_scale = x_ratio;
+			y_scale = y_ratio;
+		}
+
+		lsm_debug ("[LsmSvgView::push_viewport] scale = %g, %g", x_scale, y_scale);
+
+		lsm_svg_view_push_viewbox (view, viewbox);
+
+	} else {
+		x_scale = y_scale = 1.0;
+		lsm_svg_view_push_viewbox (view, viewport);
+	}
+
+	cairo = view->dom_view.cairo;
+
+	cairo_save (cairo);
+	cairo_rectangle (cairo, viewport->x, viewport->y, viewport->width, viewport->height);
+	cairo_clip (cairo);
+	cairo_translate (cairo, x, y);
+	cairo_scale (cairo, x_scale, y_scale);
+}
+
+void
+lsm_svg_view_pop_viewport (LsmSvgView *view)
+{
+	cairo_restore (view->dom_view.cairo);
+
+	lsm_svg_view_pop_viewbox (view);
+}
+
+void
+lsm_svg_view_push_matrix (LsmSvgView *view, LsmSvgMatrix *matrix)
+{
+	cairo_matrix_t cr_matrix;
+	cairo_matrix_t *ctm;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+	ctm = g_new (cairo_matrix_t, 1);
+	cairo_get_matrix (view->dom_view.cairo, ctm);
+
+	view->matrix_stack = g_slist_prepend (view->matrix_stack, ctm);
+
+	lsm_debug ("[LsmSvgView::push_matrix] New transform %g, %g, %g, %g, %g, %g",
+		   matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f);
+
+	cairo_matrix_init (&cr_matrix, matrix->a, matrix->b, matrix->c, matrix->d, matrix->e, matrix->f);
+	cairo_transform (view->dom_view.cairo, &cr_matrix);
+
+	{
+		cairo_matrix_t current_ctm;
+		cairo_get_matrix (view->dom_view.cairo, &current_ctm);
+
+		lsm_debug ("[LsmSvgView::push_matrix] Current ctm %g, %g, %g, %g, %g, %g",
+			   current_ctm.xx, current_ctm.xy, current_ctm.yx, current_ctm.yy,
+			   current_ctm.x0, current_ctm.y0);
+	}
+}
+
+void
+lsm_svg_view_pop_matrix (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+
+	if (view->matrix_stack != NULL) {
+		cairo_matrix_t *ctm;
+
+		ctm = view->matrix_stack->data;
+
+		cairo_set_matrix (view->dom_view.cairo, ctm);
+
+		g_free (ctm);
+		view->matrix_stack = g_slist_delete_link (view->matrix_stack, view->matrix_stack);
+	}
+}
+
+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);
+}
+
+static void
+lsm_svg_view_push_clip (LsmSvgView *view, char *clip_path, LsmSvgFillRule clip_rule)
+{
+	LsmDomElement *element;
+	LsmExtents extents;
+	char *uri;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (!view->is_clipping);
+
+	lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
+
+	uri = clip_path;
+
+	lsm_debug ("[LsmSvgView::push_clip] Using '%s'", clip_path);
+
+	cairo_save (view->dom_view.cairo);
+
+	view->clip_extents.x = extents.x1;
+	view->clip_extents.y = extents.y1;
+	view->clip_extents.width  = extents.x2 - extents.x1;
+	view->clip_extents.height = extents.y2 - extents.y1;
+
+	if (strncmp (uri, "url(#", 5) ==0) {
+		char *end;
+
+		uri = g_strdup (uri + 5);
+		for (end = uri; *end != '\0' && *end != ')'; end++);
+		*end = '\0';
+
+		element = lsm_dom_document_get_element_by_id (view->dom_view.document, uri);
+
+		g_free (uri);
+
+		if (element != NULL && LSM_IS_SVG_CLIP_PATH_ELEMENT (element)) {
+			view->is_clipping = TRUE;
+			lsm_svg_element_render_clip (LSM_SVG_ELEMENT (element), view);
+			cairo_clip (view->dom_view.cairo);
+			view->is_clipping = FALSE;
+		}
+	}
+}
+
+static void
+lsm_svg_view_pop_clip (LsmSvgView *view)
+{
+	lsm_debug ("[LsmSvgView::pop_clip");
+
+	cairo_restore (view->dom_view.cairo);
+}
+
+void
+lsm_svg_view_push_group_opacity (LsmSvgView *view)
+{
+	LsmSvgMaskAttributeBag *mask;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->mask_stack != NULL);
+
+	mask = view->mask_stack->data;
+
+	if (mask->opacity.value < 1.0)
+		cairo_push_group (view->dom_view.cairo);
+}
+
+void
+lsm_svg_view_pop_group_opacity (LsmSvgView *view)
+{
+	LsmSvgMaskAttributeBag *mask;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->mask_stack != NULL);
+
+	mask = view->mask_stack->data;
+
+	if (mask->opacity.value < 1.0) {
+		cairo_pop_group_to_source (view->dom_view.cairo);
+		cairo_paint_with_alpha (view->dom_view.cairo, mask->opacity.value);
+	}
+}
+
+void
+lsm_svg_view_push_mask_attributes (LsmSvgView *view, const LsmSvgMaskAttributeBag *mask)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (mask != NULL);
+
+	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->mask.value != NULL)
+		cairo_push_group (view->dom_view.cairo);
+}
+
+void
+lsm_svg_view_pop_mask_attributes (LsmSvgView *view)
+{
+	LsmSvgMaskAttributeBag *mask;
+
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->mask_stack != NULL);
+
+	mask = view->mask_stack->data;
+
+	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) {
+			LsmDomElement *mask_element;
+			char *end;
+			char *uri;
+
+			uri = g_strdup (mask->mask.value + 5);
+			for (end = uri; *end != '\0' && *end != ')'; end++);
+			*end = '\0';
+
+			mask_element = lsm_dom_document_get_element_by_id (view->dom_view.document, uri);
+
+			if (LSM_IS_SVG_MASK_ELEMENT (mask_element)) {
+				LsmExtents extents;
+				LsmBox mask_extents;
+				cairo_t *cairo;
+
+				lsm_svg_element_get_extents (view->element_stack->data, view, &extents);
+
+				mask_extents.x = extents.x1;
+				mask_extents.y = extents.y1;
+				mask_extents.width = extents.x2 - extents.x1;
+				mask_extents.height = extents.y2 - extents.y1;
+
+				cairo = view->dom_view.cairo;
+
+				_start_pattern (view, &mask_extents);
+
+				lsm_svg_element_render_paint (LSM_SVG_ELEMENT (mask_element), view);
+
+				cairo_pop_group_to_source (cairo);
+				if (view->pattern_data->pattern != NULL) {
+					cairo_surface_t *surface;
+					int width, height, row, i, stride;
+					unsigned char *pixels;
+
+					cairo_pattern_get_surface (view->pattern_data->pattern, &surface);
+					pixels = cairo_image_surface_get_data (surface);
+					height = cairo_image_surface_get_height (surface);
+					width = cairo_image_surface_get_width (surface);
+					stride = cairo_image_surface_get_stride (surface);
+
+					for (row = 0; row < height; row++) {
+						guint8 *row_data = (pixels + (row * stride));
+						for (i = 0; i < width; i++) {
+							guint32 *pixel = (guint32 *) row_data + i;
+							*pixel = ((((*pixel & 0x00ff0000) >> 16) * 13817 +
+								   ((*pixel & 0x0000ff00) >> 8) * 46518 +
+								   ((*pixel & 0x000000ff)) * 4688) * 0xff
+								  /* * opacity */);
+						}
+					}
+
+					cairo_pattern_set_matrix (view->pattern_data->pattern,
+								  &view->pattern_data->matrix);
+					cairo_pattern_set_extend (view->pattern_data->pattern, CAIRO_EXTEND_NONE);
+#if 0
+					cairo_surface_write_to_png (surface, "mask.png");
+#endif
+					cairo_mask (cairo, view->pattern_data->pattern);
+				} else {
+					cairo_paint (cairo);
+				}
+
+				_end_pattern (view);
+			} else {
+				cairo_pop_group_to_source (view->dom_view.cairo);
+				cairo_paint (view->dom_view.cairo);
+			}
+		} else {
+			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);
+}
+
+void
+lsm_svg_view_push_fill_attributes (LsmSvgView *view, const LsmSvgFillAttributeBag *fill)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (fill != NULL);
+
+	view->fill_stack = g_slist_prepend (view->fill_stack, (void *) fill);
+}
+
+void
+lsm_svg_view_pop_fill_attributes (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->fill_stack != NULL);
+
+	view->fill_stack = g_slist_delete_link (view->fill_stack, view->fill_stack);
+}
+
+void
+lsm_svg_view_push_stroke_attributes (LsmSvgView *view, const LsmSvgStrokeAttributeBag *stroke)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (stroke != NULL);
+
+	view->stroke_stack = g_slist_prepend (view->stroke_stack, (void *) stroke);
+}
+
+void
+lsm_svg_view_pop_stroke_attributes (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->stroke_stack != NULL);
+
+	view->stroke_stack = g_slist_delete_link (view->stroke_stack, view->stroke_stack);
+}
+
+void
+lsm_svg_view_push_text_attributes (LsmSvgView *view, const LsmSvgTextAttributeBag *text)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (text != NULL);
+
+	view->text_stack = g_slist_prepend (view->text_stack, (void *) text);
+}
+
+void
+lsm_svg_view_pop_text_attributes (LsmSvgView *view)
+{
+	g_return_if_fail (LSM_IS_SVG_VIEW (view));
+	g_return_if_fail (view->text_stack != NULL);
+
+	view->text_stack = g_slist_delete_link (view->text_stack, view->text_stack);
+}
+
+const LsmBox *
+lsm_svg_view_get_pattern_extents (LsmSvgView *view)
+{
+	static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
+
+	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
+	g_return_val_if_fail (view->pattern_data != NULL, &null_extents);
+
+	return &view->pattern_data->extents;
+}
+
+const LsmBox *
+lsm_svg_view_get_clip_extents (LsmSvgView *view)
+{
+	static LsmBox null_extents = {.x = 0.0, .y = 0.0, .width = 0.0, .height = 0.0};
+
+	g_return_val_if_fail (LSM_IS_SVG_VIEW (view), &null_extents);
+	g_return_val_if_fail (view->is_clipping, &null_extents);
+
+	return &view->clip_extents;
+}
+
 static void
 lsm_svg_view_measure (LsmDomView *view, double *width, double *height)
 {
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 54fbb90..d295ffe 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -29,6 +29,11 @@
 
 G_BEGIN_DECLS
 
+typedef enum {
+	LSM_SVG_VIEW_SURFACE_TYPE_AUTO,
+	LSM_SVG_VIEW_SURFACE_TYPE_IMAGE
+} LsmSvgViewSurfaceType;
+
 #define LSM_TYPE_SVG_VIEW             (lsm_svg_view_get_type ())
 #define LSM_SVG_VIEW(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), LSM_TYPE_SVG_VIEW, LsmSvgView))
 #define LSM_SVG_VIEW_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), LSM_TYPE_SVG_VIEW, LsmSvgViewClass))
@@ -72,29 +77,6 @@ LsmSvgView *	lsm_svg_view_new 			(LsmSvgDocument *document);
 
 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_viewport 		(LsmSvgView *view, const LsmBox *viewport,
-							 const LsmBox *viewbox,
-							 const LsmSvgPreserveAspectRatio *aspect_ratio);
-void 		lsm_svg_view_pop_viewport 		(LsmSvgView *view);
-void 		lsm_svg_view_push_matrix		(LsmSvgView *view, LsmSvgMatrix *matrix);
-void 		lsm_svg_view_pop_matrix			(LsmSvgView *view);
-
-void		lsm_svg_view_push_element		(LsmSvgView *view, const LsmSvgElement *element);
-void		lsm_svg_view_pop_element		(LsmSvgView *view);
-
-void 		lsm_svg_view_push_group_opacity 	(LsmSvgView *view);
-void 		lsm_svg_view_pop_group_opacity 		(LsmSvgView *view);
-
-void		lsm_svg_view_push_mask_attributes	(LsmSvgView *view, const LsmSvgMaskAttributeBag *mask);
-void		lsm_svg_view_pop_mask_attributes	(LsmSvgView *view);
-void 		lsm_svg_view_push_fill_attributes 	(LsmSvgView *view, const LsmSvgFillAttributeBag *fill);
-void 		lsm_svg_view_pop_fill_attributes 	(LsmSvgView *view);
-void 		lsm_svg_view_push_stroke_attributes 	(LsmSvgView *view, const LsmSvgStrokeAttributeBag *stroke);
-void 		lsm_svg_view_pop_stroke_attributes 	(LsmSvgView *view);
-void 		lsm_svg_view_push_text_attributes 	(LsmSvgView *view, const LsmSvgTextAttributeBag *text);
-void 		lsm_svg_view_pop_text_attributes 	(LsmSvgView *view);
 
 const LsmBox *	lsm_svg_view_get_pattern_extents	(LsmSvgView *view);
 const LsmBox *	lsm_svg_view_get_clip_extents		(LsmSvgView *view);
@@ -113,7 +95,8 @@ void 		lsm_svg_view_set_gradient_properties	(LsmSvgView *view,
 void		lsm_svg_view_create_surface_pattern	(LsmSvgView *view, const LsmBox *viewport,
 							 LsmSvgPatternUnits units,
 							 LsmSvgPatternUnits content_units,
-							 const LsmSvgMatrix *matrix);
+							 const LsmSvgMatrix *matrix,
+							 LsmSvgViewSurfaceType surface_type);
 
 void 		lsm_svg_view_show_rectangle 	(LsmSvgView *view, double x, double y,
 						                   double width, double height,
@@ -127,6 +110,30 @@ void 		lsm_svg_view_show_polygon	(LsmSvgView *view, const char *points);
 void 		lsm_svg_view_show_text 		(LsmSvgView *view, char const *text, double x, double y);
 void		lsm_svg_view_show_pixbuf	(LsmSvgView *view, GdkPixbuf *pixbuf);
 
+void 		lsm_svg_view_push_viewbox 		(LsmSvgView *view, const LsmBox *viewbox);
+void 		lsm_svg_view_pop_viewbox 		(LsmSvgView *view);
+void 		lsm_svg_view_push_viewport 		(LsmSvgView *view, const LsmBox *viewport,
+							 const LsmBox *viewbox,
+							 const LsmSvgPreserveAspectRatio *aspect_ratio);
+void 		lsm_svg_view_pop_viewport 		(LsmSvgView *view);
+void 		lsm_svg_view_push_matrix		(LsmSvgView *view, LsmSvgMatrix *matrix);
+void 		lsm_svg_view_pop_matrix			(LsmSvgView *view);
+
+void		lsm_svg_view_push_element		(LsmSvgView *view, const LsmSvgElement *element);
+void		lsm_svg_view_pop_element		(LsmSvgView *view);
+
+void 		lsm_svg_view_push_group_opacity 	(LsmSvgView *view);
+void 		lsm_svg_view_pop_group_opacity 		(LsmSvgView *view);
+
+void		lsm_svg_view_push_mask_attributes	(LsmSvgView *view, const LsmSvgMaskAttributeBag *mask);
+void		lsm_svg_view_pop_mask_attributes	(LsmSvgView *view);
+void 		lsm_svg_view_push_fill_attributes 	(LsmSvgView *view, const LsmSvgFillAttributeBag *fill);
+void 		lsm_svg_view_pop_fill_attributes 	(LsmSvgView *view);
+void 		lsm_svg_view_push_stroke_attributes 	(LsmSvgView *view, const LsmSvgStrokeAttributeBag *stroke);
+void 		lsm_svg_view_pop_stroke_attributes 	(LsmSvgView *view);
+void 		lsm_svg_view_push_text_attributes 	(LsmSvgView *view, const LsmSvgTextAttributeBag *text);
+void 		lsm_svg_view_pop_text_attributes 	(LsmSvgView *view);
+
 G_END_DECLS
 
 #endif



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