[lasem] [SVG] Implement preserveAspectRation attribute.



commit 89524ec73e648de585c362e4cb338df9428c3761
Author: Emmanuel Pacaud <emmanuel pacaud lapp in2p3 fr>
Date:   Sun May 17 18:27:03 2009 +0200

    [SVG] Implement preserveAspectRation attribute.
---
 src/lsmsvgattributes.c |   38 +++++++++++++++++++
 src/lsmsvgattributes.h |   15 +++++++-
 src/lsmsvgenums.c      |   46 +++++++++++++++++++++++
 src/lsmsvgenums.h      |   26 +++++++++++++
 src/lsmsvgsvgelement.c |   39 ++++++--------------
 src/lsmsvgsvgelement.h |    3 +-
 src/lsmsvgview.c       |   95 ++++++++++++++++++++++++++++++++++++++++++++++++
 src/lsmsvgview.h       |    4 ++
 8 files changed, 235 insertions(+), 31 deletions(-)

diff --git a/src/lsmsvgattributes.c b/src/lsmsvgattributes.c
index 8f98d6d..eb0485e 100644
--- a/src/lsmsvgattributes.c
+++ b/src/lsmsvgattributes.c
@@ -619,3 +619,41 @@ lsm_svg_transform_attribute_parse (LsmSvgTransformAttribute *attribute)
 		}
 	}
 }
+
+void
+lsm_svg_preserve_aspect_ratio_attribute_parse (LsmSvgPreserveAspectRatioAttribute *attribute)
+{
+	char *string;
+
+	g_return_if_fail (attribute != NULL);
+
+	string = (char *) lsm_dom_attribute_get_value ((LsmDomAttribute *) attribute);
+	if (string != NULL) {
+		char **tokens;
+		unsigned int i = 0;
+
+		tokens = g_strsplit (string, " ", -1);
+
+		if (tokens[i] != NULL && strcmp (tokens[i], "defer") == 0) {
+			attribute->value.defer = TRUE;
+			i++;
+		} else
+			attribute->value.defer = FALSE;
+
+		if (tokens[i] != NULL) {
+			attribute->value.align = lsm_svg_align_from_string (tokens[i]);
+			i++;
+			if (tokens[i] != NULL)
+				attribute->value.meet_or_slice = lsm_svg_meet_or_slice_from_string (tokens[i]);
+			else
+				attribute->value.meet_or_slice = LSM_SVG_MEET_OR_SLICE_MEET;
+		} else attribute->value.align = LSM_SVG_ALIGN_X_MID_Y_MID;
+
+		g_strfreev (tokens);
+
+	} else {
+		attribute->value.defer = FALSE;
+		attribute->value.align = LSM_SVG_ALIGN_X_MID_Y_MID;
+		attribute->value.meet_or_slice = LSM_SVG_MEET_OR_SLICE_MEET;
+	}
+}
diff --git a/src/lsmsvgattributes.h b/src/lsmsvgattributes.h
index 65a204f..4db88ad 100644
--- a/src/lsmsvgattributes.h
+++ b/src/lsmsvgattributes.h
@@ -104,6 +104,16 @@ typedef struct {
 	LsmSvgMatrix matrix;
 } LsmSvgTransformAttribute;
 
+typedef struct {
+	gboolean defer;
+	LsmSvgAlign align;
+	LsmSvgMeetOrSlice meet_or_slice;
+} LsmSvgPreserveAspectRatio;
+
+typedef struct {
+	LsmDomAttribute attr;
+	LsmSvgPreserveAspectRatio value;
+} LsmSvgPreserveAspectRatioAttribute;
 
 /* Properties */
 
@@ -139,8 +149,9 @@ void 		lsm_svg_color_attribute_parse 		(LsmSvgColorAttribute *attribute,
 
 /* Attributes */
 
-void		lsm_svg_viewbox_attribute_parse		(LsmSvgViewboxAttribute *attribute);
-void		lsm_svg_transform_attribute_parse	(LsmSvgTransformAttribute *attribute);
+void		lsm_svg_viewbox_attribute_parse			(LsmSvgViewboxAttribute *attribute);
+void		lsm_svg_transform_attribute_parse		(LsmSvgTransformAttribute *attribute);
+void 		lsm_svg_preserve_aspect_ratio_attribute_parse 	(LsmSvgPreserveAspectRatioAttribute *attribute);
 
 G_END_DECLS
 
diff --git a/src/lsmsvgenums.c b/src/lsmsvgenums.c
index f2f8d63..1247354 100644
--- a/src/lsmsvgenums.c
+++ b/src/lsmsvgenums.c
@@ -156,3 +156,49 @@ lsm_svg_spread_method_from_string (const char *string)
 	return lsm_svg_value_from_string (string, lsm_svg_spread_method_strings,
 				       G_N_ELEMENTS (lsm_svg_spread_method_strings));
 }
+
+static const char *lsm_svg_align_strings[] = {
+	"",
+	"none",
+	"xMinYMin",
+	"xMidYMin",
+	"xMaxYMin",
+	"xMinYMid",
+	"xMidYMid",
+	"xMaxYMid",
+	"xMinYMax",
+	"xMidYMax",
+	"xMaxYMax"
+};
+
+const char *
+lsm_svg_align_to_string (LsmSvgAlign align)
+{
+	return lsm_svg_align_strings[CLAMP (align, 0, LSM_SVG_ALIGN_X_MAX_Y_MAX)];
+}
+
+LsmSvgAlign
+lsm_svg_align_from_string (const char *string)
+{
+	return lsm_svg_value_from_string (string, lsm_svg_align_strings,
+					  G_N_ELEMENTS (lsm_svg_align_strings));
+}
+
+static const char *lsm_svg_meet_or_slice_strings[] = {
+	"",
+	"meet",
+	"slice"
+};
+
+const char *
+lsm_svg_meet_or_slice_to_string (LsmSvgMeetOrSlice meet_or_slice)
+{
+	return lsm_svg_meet_or_slice_strings[CLAMP (meet_or_slice, 0, LSM_SVG_MEET_OR_SLICE_SLICE)];
+}
+
+LsmSvgMeetOrSlice
+lsm_svg_meet_or_slice_from_string (const char *string)
+{
+	return lsm_svg_value_from_string (string, lsm_svg_meet_or_slice_strings,
+					  G_N_ELEMENTS (lsm_svg_meet_or_slice_strings));
+}
diff --git a/src/lsmsvgenums.h b/src/lsmsvgenums.h
index 1a53db9..dd1e0cf 100644
--- a/src/lsmsvgenums.h
+++ b/src/lsmsvgenums.h
@@ -115,6 +115,32 @@ typedef enum {
 const char * 		lsm_svg_spread_method_to_string 		(LsmSvgSpreadMethod method);
 LsmSvgSpreadMethod	lsm_svg_spread_method_from_string		(const char *string);
 
+typedef enum {
+	LSM_SVG_ALIGN_UNKNOWN,
+	LSM_SVG_ALIGN_NONE,
+	LSM_SVG_ALIGN_X_MIN_Y_MIN,
+	LSM_SVG_ALIGN_X_MID_Y_MIN,
+	LSM_SVG_ALIGN_X_MAX_Y_MIN,
+	LSM_SVG_ALIGN_X_MIN_Y_MID,
+	LSM_SVG_ALIGN_X_MID_Y_MID,
+	LSM_SVG_ALIGN_X_MAX_Y_MID,
+	LSM_SVG_ALIGN_X_MIN_Y_MAX,
+	LSM_SVG_ALIGN_X_MID_Y_MAX,
+	LSM_SVG_ALIGN_X_MAX_Y_MAX
+} LsmSvgAlign;
+
+const char * 		lsm_svg_align_to_string 		(LsmSvgAlign align);
+LsmSvgAlign		lsm_svg_align_from_string		(const char *string);
+
+typedef enum {
+	LSM_SVG_MEET_OR_SLICE_UNKNOWN,
+	LSM_SVG_MEET_OR_SLICE_MEET,
+	LSM_SVG_MEET_OR_SLICE_SLICE
+} LsmSvgMeetOrSlice;
+
+const char * 		lsm_svg_meet_or_slice_to_string 	(LsmSvgMeetOrSlice meet_or_slice);
+LsmSvgMeetOrSlice	lsm_svg_meet_or_slice_from_string	(const char *string);
+
 G_END_DECLS
 
 #endif
diff --git a/src/lsmsvgsvgelement.c b/src/lsmsvgsvgelement.c
index 27b2f34..7ad8f89 100644
--- a/src/lsmsvgsvgelement.c
+++ b/src/lsmsvgsvgelement.c
@@ -62,6 +62,7 @@ _svg_element_update (LsmSvgElement *self, LsmSvgStyle *parent_style)
 	lsm_svg_length_attribute_parse (&svg->height, &length);
 
 	lsm_svg_viewbox_attribute_parse (&svg->viewbox);
+	lsm_svg_preserve_aspect_ratio_attribute_parse (&svg->preserve_aspect_ratio);
 
 	lsm_debug ("[LsmSvgSvgElement::update] view_bbox = %g, %g, %g, %g\n",
 		    svg->viewbox.value.x,
@@ -130,16 +131,12 @@ lsm_svg_svg_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 {
 	LsmSvgSvgElement *svg = LSM_SVG_SVG_ELEMENT (self);
 	gboolean is_viewbox_defined;
-	LsmSvgMatrix matrix;
-	double svg_x;
-	double svg_y;
-	double svg_width;
-	double svg_height;
+	LsmBox viewport;
 
-	svg_x      = lsm_svg_view_normalize_length (view, &svg->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	svg_y      = lsm_svg_view_normalize_length (view, &svg->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
-	svg_width  = lsm_svg_view_normalize_length (view, &svg->width.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
-	svg_height = lsm_svg_view_normalize_length (view, &svg->height.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	viewport.x      = lsm_svg_view_normalize_length (view, &svg->x.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	viewport.y      = lsm_svg_view_normalize_length (view, &svg->y.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
+	viewport.width  = lsm_svg_view_normalize_length (view, &svg->width.length, LSM_SVG_LENGTH_DIRECTION_HORIZONTAL);
+	viewport.height = lsm_svg_view_normalize_length (view, &svg->height.length, LSM_SVG_LENGTH_DIRECTION_VERTICAL);
 
 	is_viewbox_defined = lsm_dom_attribute_is_defined ((LsmDomAttribute *) &svg->viewbox);
 
@@ -147,28 +144,12 @@ lsm_svg_svg_element_graphic_render (LsmSvgElement *self, LsmSvgView *view)
 				   svg->viewbox.value.height <= 0.0))
 		return;
 
-	lsm_svg_matrix_init_translate (&matrix, svg_x, svg_y);
-	lsm_svg_view_push_transform (view, &matrix);
-
-	if (is_viewbox_defined) {
-
-		lsm_svg_matrix_init (&matrix,
-				     svg_width / svg->viewbox.value.width, 0.0,
-				     0.0 , svg_height / svg->viewbox.value.height,
-				     -svg->viewbox.value.x,-svg->viewbox.value.y);
-
-		lsm_svg_view_push_transform (view, &matrix);
-		lsm_svg_view_push_viewbox (view, &svg->viewbox.value);
-	}
+	lsm_svg_view_push_viewport (view, &viewport, is_viewbox_defined ? &svg->viewbox.value : NULL,
+				    &svg->preserve_aspect_ratio.value);
 
 	LSM_SVG_GRAPHIC_CLASS (parent_class)->graphic_render (self, view);
 
-	if (is_viewbox_defined) {
-		lsm_svg_view_pop_viewbox (view);
-		lsm_svg_view_pop_transform (view);
-	}
-
-	lsm_svg_view_pop_transform (view);
+	lsm_svg_view_pop_viewport (view);
 }
 
 /* LsmSvgSvgElement implementation */
@@ -279,6 +260,8 @@ lsm_svg_svg_element_class_init (LsmSvgSvgElementClass *s_svg_class)
 					     offsetof (LsmSvgSvgElement, height));
 	lsm_dom_attribute_map_add_attribute (s_element_class->attributes, "viewBox",
 					     offsetof (LsmSvgSvgElement, viewbox));
+	lsm_dom_attribute_map_add_attribute (s_element_class->attributes, "preserveAspectRatio",
+					     offsetof (LsmSvgSvgElement, preserve_aspect_ratio));
 }
 
 G_DEFINE_TYPE (LsmSvgSvgElement, lsm_svg_svg_element, LSM_TYPE_SVG_GRAPHIC)
diff --git a/src/lsmsvgsvgelement.h b/src/lsmsvgsvgelement.h
index 2f0d95b..bfb9f75 100644
--- a/src/lsmsvgsvgelement.h
+++ b/src/lsmsvgsvgelement.h
@@ -46,7 +46,8 @@ struct _LsmSvgSvgElement {
 	LsmSvgLengthAttribute	width;
 	LsmSvgLengthAttribute	height;
 
-	LsmSvgViewboxAttribute	viewbox;
+	LsmSvgViewboxAttribute			viewbox;
+	LsmSvgPreserveAspectRatioAttribute	preserve_aspect_ratio;
 
 	LsmBox svg_box;
 };
diff --git a/src/lsmsvgview.c b/src/lsmsvgview.c
index c91542c..7b03f83 100644
--- a/src/lsmsvgview.c
+++ b/src/lsmsvgview.c
@@ -686,6 +686,101 @@ 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)
+{
+	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_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_transform (LsmSvgView *view, const LsmSvgMatrix *matrix)
 {
 	cairo_matrix_t cr_matrix;
diff --git a/src/lsmsvgview.h b/src/lsmsvgview.h
index 10bae56..6aeb5d3 100644
--- a/src/lsmsvgview.h
+++ b/src/lsmsvgview.h
@@ -85,6 +85,10 @@ double 		lsm_svg_view_normalize_length 		(LsmSvgView *view, const LsmSvgLength *
 							 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_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]