[lasem] svg: add circular reference checks.



commit 78722595f92ed8e122a9f780b463c27ddbeec8d9
Author: Emmanuel Pacaud <emmanuel gnome org>
Date:   Wed May 4 09:46:03 2011 +0200

    svg: add circular reference checks.
    
    It still o implemented for <use> elements.
    The code in radial, linear gradients and pattern must be factorized.

 src/lsmsvglineargradientelement.c |   52 +++++++++++++++++++++++++-----------
 src/lsmsvgpatternelement.c        |   50 +++++++++++++++++++++++++----------
 src/lsmsvgradialgradientelement.c |   52 +++++++++++++++++++++++++-----------
 src/lsmsvgview.c                  |   43 +++++++++++++++++++++++++++---
 4 files changed, 146 insertions(+), 51 deletions(-)
---
diff --git a/src/lsmsvglineargradientelement.c b/src/lsmsvglineargradientelement.c
index 8478f08..a6f9c9a 100644
--- a/src/lsmsvglineargradientelement.c
+++ b/src/lsmsvglineargradientelement.c
@@ -61,13 +61,18 @@ lsm_svg_linear_gradient_element_get_node_name (LsmDomNode *node)
 static LsmSvgGradientElement *
 lsm_svg_linear_gradient_element_inherit_referenced (LsmDomDocument *owner,
 						    LsmSvgGradientElement *gradient,
-						    LsmSvgLinearGradientElementAttributes *attributes)
+						    LsmSvgLinearGradientElementAttributes *attributes,
+						    GSList **elements)
 {
 	LsmSvgGradientElement *referenced_gradient = gradient;
 	LsmDomElement *element;
 
+	*elements = g_slist_prepend (*elements, gradient);
+
 	if (lsm_attribute_is_defined (&gradient->href)) {
 		char *id;
+		GSList *iter;
+		gboolean circular_reference_found = FALSE;
 
 		id = gradient->href.value;
 		if (id == NULL)
@@ -76,21 +81,33 @@ lsm_svg_linear_gradient_element_inherit_referenced (LsmDomDocument *owner,
 			id++;
 
 		element = lsm_dom_document_get_element_by_id (owner, id);
-		if (LSM_IS_SVG_GRADIENT_ELEMENT (element)) {
-			lsm_debug ("render",
-				   "[LsmSvgLinearGradientElement::inherit_attributes]"
-				   " Found referenced element '%s'", id);
-
-			referenced_gradient = lsm_svg_linear_gradient_element_inherit_referenced
-				(owner,
-				 LSM_SVG_GRADIENT_ELEMENT (element),
-				 attributes);
-		} else {
-			lsm_debug ("render",
-				   "[LsmSvgLinearGradientElement::inherit_attributes]"
-				   " Referenced element '%s' not found", id);
+
+		for (iter = *elements; iter != NULL; iter = iter->next)
+			if (iter->data == element) {
+				lsm_debug ("render", "[LsmSvgLinearGradientElement::inherit_attributes] "
+					   "Circular reference (id = %s)", id);
+				circular_reference_found = TRUE;
+			}
+
+		if (!circular_reference_found) {
+			if (LSM_IS_SVG_GRADIENT_ELEMENT (element)) {
+				lsm_debug ("render",
+					   "[LsmSvgLinearGradientElement::inherit_attributes]"
+					   " Found referenced element '%s'", id);
+
+				referenced_gradient = lsm_svg_linear_gradient_element_inherit_referenced
+					(owner,
+					 LSM_SVG_GRADIENT_ELEMENT (element),
+					 attributes, elements);
+
+			} else {
+				lsm_debug ("render",
+					   "[LsmSvgLinearGradientElement::inherit_attributes]"
+					   " Referenced element '%s' not found", id);
+				referenced_gradient = NULL;
+			}
+		} else
 			referenced_gradient = NULL;
-		}
 	}
 
 	if (LSM_IS_SVG_LINEAR_GRADIENT_ELEMENT (gradient)) {
@@ -128,11 +145,14 @@ lsm_svg_linear_gradient_element_create_gradient (LsmSvgElement *self,
 		LsmSvgLinearGradientElementAttributes attributes;
 		LsmDomDocument *owner;
 		attributes = default_attributes;
+		GSList *elements = NULL;
 
 		owner = lsm_dom_node_get_owner_document (LSM_DOM_NODE (self));
 
 		referenced_gradient = lsm_svg_linear_gradient_element_inherit_referenced
-			(owner, LSM_SVG_GRADIENT_ELEMENT (gradient), &attributes);
+			(owner, LSM_SVG_GRADIENT_ELEMENT (gradient), &attributes, &elements);
+
+		g_slist_free (elements);
 
 		gradient->x1.length = attributes.x1;
 		gradient->y1.length = attributes.y1;
diff --git a/src/lsmsvgpatternelement.c b/src/lsmsvgpatternelement.c
index a10d737..4cba96d 100644
--- a/src/lsmsvgpatternelement.c
+++ b/src/lsmsvgpatternelement.c
@@ -69,13 +69,18 @@ _pattern_element_get_node_name (LsmDomNode *node)
 static LsmSvgPatternElement *
 lsm_svg_pattern_element_inherit_referenced (LsmDomDocument *owner,
 					    LsmSvgPatternElement *pattern,
-					    LsmSvgPatternElementAttributes *attributes)
+					    LsmSvgPatternElementAttributes *attributes,
+					    GSList **elements)
 {
 	LsmSvgPatternElement *referenced_pattern = pattern;
 	LsmDomElement *element;
 
+	*elements = g_slist_prepend (*elements, pattern);
+
 	if (lsm_attribute_is_defined (&pattern->href)) {
 		char *id;
+		GSList *iter;
+		gboolean circular_reference_found = FALSE;
 
 		id = pattern->href.value;
 		if (id == NULL)
@@ -84,19 +89,32 @@ lsm_svg_pattern_element_inherit_referenced (LsmDomDocument *owner,
 			id++;
 
 		element = lsm_dom_document_get_element_by_id (owner, id);
-		if (LSM_IS_SVG_PATTERN_ELEMENT (element)) {
-			lsm_debug ("render",
-				   "[LsmSvgPatternElement::inherit_attributes] Found referenced element '%s'", id);
-
-			referenced_pattern = lsm_svg_pattern_element_inherit_referenced
-				(owner,
-				 LSM_SVG_PATTERN_ELEMENT (element),
-				 attributes);
-		} else {
-			lsm_debug ("render",
-				   "[LsmSvgPatternElement::inherit_attributes] Referenced element '%s' not found", id);
+
+		for (iter = *elements; iter != NULL; iter = iter->next)
+			if (iter->data == element) {
+				lsm_debug ("render", "[LsmSvgPatternElement::inherit_attributes] "
+					   "Circular reference (id = %s)", id);
+				circular_reference_found = TRUE;
+			}
+
+		if (!circular_reference_found) {
+			if (LSM_IS_SVG_PATTERN_ELEMENT (element), elements) {
+				lsm_debug ("render",
+					   "[LsmSvgPatternElement::inherit_attributes] "
+					   "Found referenced element '%s'", id);
+
+				referenced_pattern = lsm_svg_pattern_element_inherit_referenced
+					(owner,
+					 LSM_SVG_PATTERN_ELEMENT (element),
+					 attributes, elements);
+			} else {
+				lsm_debug ("render",
+					   "[LsmSvgPatternElement::inherit_attributes] "
+					   "Referenced element '%s' not found", id);
+				referenced_pattern = NULL;
+			}
+		} else
 			referenced_pattern = NULL;
-		}
 	}
 
 	if (lsm_attribute_is_defined (&pattern->x.base))
@@ -144,10 +162,14 @@ lsm_svg_pattern_element_render (LsmSvgElement *self, LsmSvgView *view)
 		LsmSvgPatternElementAttributes attributes;
 		LsmDomDocument *owner;
 		attributes = default_attributes;
+		GSList *elements = NULL;
 
 		owner = lsm_dom_node_get_owner_document (LSM_DOM_NODE (self));
 
-		referenced_pattern = lsm_svg_pattern_element_inherit_referenced (owner, pattern, &attributes);
+		referenced_pattern = lsm_svg_pattern_element_inherit_referenced (owner, pattern,
+										 &attributes, &elements);
+
+		g_slist_free (elements);
 
 		pattern->x.length = attributes.x;
 		pattern->y.length = attributes.y;
diff --git a/src/lsmsvgradialgradientelement.c b/src/lsmsvgradialgradientelement.c
index 5b8f3a1..b15c537 100644
--- a/src/lsmsvgradialgradientelement.c
+++ b/src/lsmsvgradialgradientelement.c
@@ -68,13 +68,18 @@ lsm_svg_radial_gradient_element_get_node_name (LsmDomNode *node)
 LsmSvgGradientElement *
 lsm_svg_radial_gradient_element_inherit_referenced (LsmDomDocument *owner,
 						    LsmSvgGradientElement *gradient,
-						    LsmSvgRadialGradientElementAttributes *attributes)
+						    LsmSvgRadialGradientElementAttributes *attributes,
+						    GSList **elements)
 {
 	LsmSvgGradientElement *referenced_gradient = gradient;
 	LsmDomElement *element;
 
+	*elements = g_slist_prepend (*elements, gradient);
+
 	if (lsm_attribute_is_defined (&gradient->href)) {
 		char *id;
+		GSList *iter;
+		gboolean circular_reference_found = FALSE;
 
 		id = gradient->href.value;
 		if (id == NULL)
@@ -83,21 +88,33 @@ lsm_svg_radial_gradient_element_inherit_referenced (LsmDomDocument *owner,
 			id++;
 
 		element = lsm_dom_document_get_element_by_id (owner, id);
-		if (LSM_IS_SVG_GRADIENT_ELEMENT (element)) {
-			lsm_debug ("render",
-				   "[LsmSvgRadialGradientElement::inherit_attributes]"
-				   " Found referenced element '%s'", id);
-
-			referenced_gradient = lsm_svg_radial_gradient_element_inherit_referenced
-				(owner,
-				 LSM_SVG_GRADIENT_ELEMENT (element),
-				 attributes);
-		} else {
-			lsm_debug ("render",
-				   "[LsmSvgRadialGradientElement::inherit_attributes]"
-				   " Referenced element '%s' not found", id);
+
+		for (iter = *elements; iter != NULL; iter = iter->next)
+			if (iter->data == element) {
+				lsm_debug ("render", "[LsmSvgRadialGradientElement::inherit_attributes] "
+					   "Circular reference (id = %s)", id);
+				circular_reference_found = TRUE;
+			}
+
+		if (!circular_reference_found) {
+			if (LSM_IS_SVG_GRADIENT_ELEMENT (element)) {
+				lsm_debug ("render",
+					   "[LsmSvgRadialGradientElement::inherit_attributes]"
+					   " Found referenced element '%s'", id);
+
+				referenced_gradient = lsm_svg_radial_gradient_element_inherit_referenced
+					(owner,
+					 LSM_SVG_GRADIENT_ELEMENT (element),
+					 attributes, elements);
+			} else {
+				lsm_debug ("render",
+					   "[LsmSvgRadialGradientElement::inherit_attributes]"
+					   " Referenced element '%s' not found", id);
+				referenced_gradient = NULL;
+			}
+		} else
 			referenced_gradient = NULL;
-		}
+
 	}
 
 	if (LSM_IS_SVG_RADIAL_GRADIENT_ELEMENT (gradient)) {
@@ -145,11 +162,14 @@ lsm_svg_radial_gradient_element_create_gradient (LsmSvgElement *self,
 		LsmSvgRadialGradientElementAttributes attributes;
 		LsmDomDocument *owner;
 		attributes = default_attributes;
+		GSList *elements = NULL;
 
 		owner = lsm_dom_node_get_owner_document (LSM_DOM_NODE (self));
 
 		referenced_gradient = lsm_svg_radial_gradient_element_inherit_referenced
-			(owner, LSM_SVG_GRADIENT_ELEMENT (gradient), &attributes);
+			(owner, LSM_SVG_GRADIENT_ELEMENT (gradient), &attributes, &elements);
+
+		g_slist_free (elements);
 
 		gradient->cx.length = attributes.cx;
 		gradient->cy.length = attributes.cy;
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index d821a6b..f3906af 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -40,6 +40,8 @@
 #include <math.h>
 #include <string.h>
 
+static gboolean lsm_svg_view_circular_reference_check (LsmSvgView *view, LsmSvgElement *element);
+
 static GObjectClass *parent_class;
 
 typedef struct {
@@ -761,9 +763,10 @@ _paint_url (LsmSvgView *view,
 	LsmBox extents;
 
 	element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document), url);
-	if (!LSM_IS_SVG_RADIAL_GRADIENT_ELEMENT (element) &&
-	    !LSM_IS_SVG_LINEAR_GRADIENT_ELEMENT (element) &&
-	    !LSM_IS_SVG_PATTERN_ELEMENT (element))
+	if ((!LSM_IS_SVG_RADIAL_GRADIENT_ELEMENT (element) &&
+	     !LSM_IS_SVG_LINEAR_GRADIENT_ELEMENT (element) &&
+	     !LSM_IS_SVG_PATTERN_ELEMENT (element)) ||
+	    lsm_svg_view_circular_reference_check (view, element))
 		return;
 
 	lsm_debug ("render", "[LsmSvgView::_paint_url] Paint using '%s'", url);
@@ -890,6 +893,15 @@ paint_markers (LsmSvgView *view)
 	stroke_width = lsm_svg_view_normalize_length (view, &view->style->stroke_width->length,
 						      LSM_SVG_LENGTH_DIRECTION_DIAGONAL);
 
+	if (marker != NULL && lsm_svg_view_circular_reference_check (view, marker))
+		return;
+	if (marker_start != NULL && lsm_svg_view_circular_reference_check (view, marker_start))
+		return;
+	if (marker_mid != NULL && lsm_svg_view_circular_reference_check (view, marker_mid))
+		return;
+	if (marker_end != NULL && lsm_svg_view_circular_reference_check (view, marker_end))
+		return;
+
 	if (marker_start == NULL)
 		marker_start = marker;
 	if (marker_mid == NULL)
@@ -1737,7 +1749,8 @@ lsm_svg_view_push_clip (LsmSvgView *view)
 	view->clip_extents.height = extents.y2 - extents.y1;
 
 	element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document), url);
-	if (LSM_IS_SVG_CLIP_PATH_ELEMENT (element)) {
+	if (LSM_IS_SVG_CLIP_PATH_ELEMENT (element) &&
+	    !lsm_svg_view_circular_reference_check (view, element)) {
 		view->is_clipping = TRUE;
 		lsm_svg_element_force_render (LSM_SVG_ELEMENT (element), view);
 		cairo_clip (view->dom_view.cairo);
@@ -1771,7 +1784,8 @@ lsm_svg_view_pop_mask (LsmSvgView *view)
 	mask_element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
 							    view->style->mask->value);
 
-	if (LSM_IS_SVG_MASK_ELEMENT (mask_element)) {
+	if (LSM_IS_SVG_MASK_ELEMENT (mask_element) &&
+	    !lsm_svg_view_circular_reference_check (view, mask_element)) {
 		LsmExtents extents;
 		LsmBox mask_extents;
 		cairo_t *cairo;
@@ -1876,6 +1890,8 @@ lsm_svg_view_pop_filter (LsmSvgView *view)
 	filter_element = lsm_svg_document_get_element_by_url (LSM_SVG_DOCUMENT (view->dom_view.document),
 							      view->style->filter->value);
 
+TODO: lsm_svg_view_circular_reference_check
+
 	cairo = view->pattern_data->old_cairo;
 
 	view->filter_surfaces = NULL;
@@ -1936,6 +1952,23 @@ lsm_svg_view_pop_element (LsmSvgView *view)
 	view->element_stack = g_slist_delete_link (view->element_stack, view->element_stack);
 }
 
+static gboolean
+lsm_svg_view_circular_reference_check (LsmSvgView *view, LsmSvgElement *element)
+{
+	GSList *iter;
+
+	for (iter = view->element_stack; iter != NULL; iter = iter->next)
+		if (iter->data == element) {
+			lsm_debug ("render", "[LsmSvgView::circular_reference_check] "
+				   "Circular reference to %s (id = %s)",
+				   lsm_dom_element_get_tag_name (LSM_DOM_ELEMENT (element)),
+				   lsm_dom_element_get_attribute (LSM_DOM_ELEMENT (element), "id"));
+			return TRUE;
+		}
+
+	return FALSE;
+}
+
 void
 lsm_svg_view_push_style	(LsmSvgView *view, const LsmSvgStyle *style)
 {



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