Clone in a terminal:
Commit 35c3bcd
Johan Mattsson - 2016-01-05T12:06:34+00:00
35c3bcd01066afe48c7a6e5bc6490057aa3a8616johan.mattsson.m@gmail.com

Move SVG classes to a subdirectory

Changed files (14)

Diff

diff --git a/dodo.py b/dodo.pyindex f324d67..76db874 100644--- a/dodo.py+++ b/dodo.py@@ -302,6 +302,7 @@ def make_libbirdfont(target_binary, deps):         libbirdfont/*.vala \         libbirdfont/OpenFontFormat/*.vala \         libbirdfont/TextRendering/*.vala \+        libbirdfont/Svg/*.vala \         --pkg """ + config.GEE + """ \         --pkg gio-2.0 \         --pkg cairo \diff --git a/libbirdfont/Svg.vala b/libbirdfont/Svg.valadeleted file mode 100644index 5b2682b..0000000--- a/libbirdfont/Svg.vala+++ /dev/null@@ -1,353 +0,0 @@-/*-	Copyright (C) 2012 Johan Mattsson--	This library is free software; you can redistribute it and/or modify -	it under the terms of the GNU Lesser General Public License as -	published by the Free Software Foundation; either version 3 of the -	License, or (at your option) any later version.--	This library 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 -	Lesser General Public License for more details.-*/--using Cairo;--namespace BirdFont {--public class Svg {--	/** Export to svg glyph data. */-	public static string to_svg_glyph (Glyph g) {	-		StringBuilder svg = new StringBuilder ();-		PathList stroke_list;-		-		foreach (Path p in g.get_visible_paths ()) {-			if (p.stroke == 0) {-				write_path_as_glyph (p, svg, g);-			} else {-				stroke_list = p.get_completed_stroke ();-				write_paths_as_glyph (stroke_list, svg, g);-			}-		}-		-		return svg.str;-	}--	/** Export to svg-font data. */-	public static string to_svg_path (Path pl, Glyph g) {	-		StringBuilder svg = new StringBuilder ();-		pl.create_list ();-		write_path (pl, svg, g, false);-		return svg.str;-	}--	private static void write_paths_as_glyph (PathList pl, StringBuilder svg, Glyph g) {-		foreach (Path p in pl.paths) {-			write_path_as_glyph (p, svg, g);-		}-	}--	private static void write_path_as_glyph (Path pl, StringBuilder svg, Glyph g) {-		write_path (pl, svg, g, true);-	}--	private static void write_path (Path p, StringBuilder svg, Glyph g, bool do_glyph) {-		int i = 0;-		EditPoint? n = null;-		EditPoint m;-		-		if (p.points.size < 2) {-			return;-		}--		p.create_list ();-			-		foreach (var e in p.points) {-			if (i == 0) {-				add_abs_start (e, svg, g, do_glyph);-				i++;-				n = e;-				continue;-			}-			-			m = (!) n;--			add_abs_next (m, e, svg, g, do_glyph);-			-			n = e;-			i++;-		}--		if (!p.is_open ()) {-			m = p.points.get (0);	-			add_abs_next ((!) n, m, svg, g, do_glyph);-			close_path (svg);-		}-	}--	private static void add_abs_next (EditPoint start, EditPoint end, StringBuilder svg, Glyph g, bool do_glyph) {-		if (start.right_handle.type == PointType.LINE_QUADRATIC) {-			add_abs_line_to (start, end, svg, g, do_glyph);-		} else if (start.right_handle.type == PointType.LINE_CUBIC && end.left_handle.type == PointType.LINE_CUBIC) {-			add_abs_line_to (start, end, svg, g, do_glyph);-		} else if (end.left_handle.type == PointType.QUADRATIC || start.right_handle.type == PointType.QUADRATIC) {-			add_quadratic_abs_path (start, end, svg, g, do_glyph);-		} else if (end.left_handle.type == PointType.DOUBLE_CURVE || start.right_handle.type == PointType.DOUBLE_CURVE) {-			add_double_quadratic_abs_path (start, end, svg, g, do_glyph);-		} else {-			add_cubic_abs_path (start, end, svg, g, do_glyph);-		}-	}--	private static void add_abs_start (EditPoint ep, StringBuilder svg, Glyph g, bool to_glyph) {		-		double left = g.left_limit;-		double baseline = -BirdFont.get_current_font ().base_line;-		double height = g.get_height ();-		-		svg.append_printf ("M");-		-		if (!to_glyph) {-			svg.append_printf ("%s ",  round (ep.x - left));-			svg.append_printf ("%s ",  round (-ep.y + height / 2));-		} else {-			svg.append_printf ("%s ",  round (ep.x - left));-			svg.append_printf ("%s ",  round (ep.y + baseline));-		}-	}-		-	private static void close_path (StringBuilder svg) {-		svg.append ("z");-	}	-	-	private static void add_abs_line_to (EditPoint start, EditPoint stop, StringBuilder svg, Glyph g, bool to_glyph) {-		double baseline = -BirdFont.get_current_font ().base_line;-		double left = g.left_limit;-		double height = g.get_height ();-		-		double xa, ya, xb, yb;-		-		Path.get_line_points (start, stop, out xa, out ya, out xb, out yb);--		double center_x = Glyph.xc ();-		double center_y = Glyph.yc ();-		-		svg.append ("L");-	-		if (!to_glyph) {-			svg.append_printf ("%s ", round (xb - center_x - left));-			svg.append_printf ("%s ", round (yb - center_y + height / 2));	-		} else {-			svg.append_printf ("%s ", round (xb - center_x - left));-			svg.append_printf ("%s ", round (-yb + center_y + baseline));-		}-	}-	-	private static void add_double_quadratic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) {-		EditPoint middle;-		double x, y;-		-		x = start.get_right_handle ().x + (end.get_left_handle ().x - start.get_right_handle ().x) / 2;-		y = start.get_right_handle ().y + (end.get_left_handle ().y - start.get_right_handle ().y) / 2;-		-		middle = new EditPoint (x, y, PointType.QUADRATIC);-		middle.right_handle = end.get_left_handle ().copy ();-		-		add_quadratic_abs_path (start, middle, svg, g, to_glyph);-		add_quadratic_abs_path (middle, end, svg, g, to_glyph);-	}-		-	private static void add_quadratic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) {-		double left = g.left_limit;-		double baseline = -BirdFont.get_current_font ().base_line;-		double height = g.get_height ();-		-		double xa, ya, xb, yb, xc, yc, xd, yd;-		-		Path.get_bezier_points (start, end, out xa, out ya, out xb, out yb, out xc, out yc, out xd, out yd);--		double center_x = Glyph.xc ();-		double center_y = Glyph.yc ();--		// cubic path-		if (!to_glyph) {-			svg.append_printf ("Q");--			svg.append_printf ("%s ", round (xb - center_x - left));-			svg.append_printf ("%s ", round (yb - center_y + height / 2));-			-			svg.append_printf ("%s ", round (xd - center_x - left));-			svg.append_printf ("%s ", round (yd - center_y + height / 2));--		} else {		-			svg.append_printf ("Q");--			svg.append_printf ("%s ", round (xb - center_x - left));-			svg.append_printf ("%s ", round (-yb + center_y + baseline));-			-			svg.append_printf ("%s ", round (xd - center_x - left));-			svg.append_printf ("%s ", round (-yd + center_y + baseline));	-		}-	}-			-	private static void add_cubic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) {-		double left = g.left_limit;-		double baseline = -BirdFont.get_current_font ().base_line;-		double height = g.get_height ();-		-		double xa, ya, xb, yb, xc, yc, xd, yd;-		-		Path.get_bezier_points (start, end, out xa, out ya, out xb, out yb, out xc, out yc, out xd, out yd);--		double center_x = Glyph.xc ();-		double center_y = Glyph.yc ();-		-		// cubic path-		if (!to_glyph) {-			svg.append_printf ("C");--			svg.append_printf ("%s ", round (xb - center_x - left));-			svg.append_printf ("%s ", round (yb - center_y + height / 2));-			-			svg.append_printf ("%s ", round (xc - center_x - left));-			svg.append_printf ("%s ", round (yc - center_y + height / 2));-			-			svg.append_printf ("%s ", round (xd - center_x - left));-			svg.append_printf ("%s ", round (yd - center_y + height / 2));	--		} else {		-			svg.append_printf ("C");--			svg.append_printf ("%s ", round (xb - center_x - left));-			svg.append_printf ("%s ", round (-yb + center_y + baseline));-			-			svg.append_printf ("%s ", round (xc - center_x - left));-			svg.append_printf ("%s ", round (-yc + center_y + baseline));	-			-			svg.append_printf ("%s ", round (xd - center_x - left));-			svg.append_printf ("%s ", round (-yd + center_y + baseline));	-		}-	}-	-	/** Draw path from svg font data. */-	public static void draw_svg_path (Context cr, string svg, double x, double y) {-		double x1, x2, x3;-		double y1, y2, y3;-		double px, py;-		string[] d = svg.split (" ");--		if (d.length == 0) {-			return;-		}-		-		px = 0;-		py = 0;-		-		cr.save ();--		cr.set_line_width (0);-		-		if (svg == "") {-			return;-		}-		-		for (int i = 0; i < d.length; i++) {-			-			// trim off leading white space	-			while (d[i].index_of (" ") == 0) { -				d[i] = d[i].substring (1); // FIXME: maybe no ascii-			}-			-			if (d[i].index_of ("L") == 0) {-				x1 = double.parse (d[i].substring (1)) + x;-				y1 = -double.parse (d[i+1]) + y;-				cr.line_to (x1, y1);-				-				px = x1;-				py = y1;			-				continue;-			}--			if (d[i].index_of ("Q") == 0) {-				x1 = double.parse (d[i].substring (1)) + x;-				y1 = -double.parse (d[i+1]) + y;--				x2 = double.parse (d[i+2]) + x;-				y2 = -double.parse (d[i+3]) + y;-											-				cr.curve_to ((px + 2 * x1) / 3, (py + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2);-				-				px = x2;-				py = y2;-				continue;-			}-			-			if (d[i].index_of ("C") == 0) {-				x1 = double.parse (d[i].substring (1)) + x;-				y1 = -double.parse (d[i+1]) + y;--				x2 = double.parse (d[i+2]) + x;-				y2 = -double.parse (d[i+3]) + y;--				x3 = double.parse (d[i+4]) + x;-				y3 = -double.parse (d[i+5]) + y;-																-				cr.curve_to (x1, y1, x2, y2, x3, y3);-				-				px = x3;-				py = y3;-				continue;-			}--			if (d[i].index_of ("M") == 0) {-				x1 = double.parse (d[i].substring (1)) + x;-				y1 = -double.parse (d[i+1]) + y;-				-				cr.move_to (x1, y1);--				px = x1;-				py = y1;-				continue;-			}-								-			if (d[i].index_of ("zM") == 0) {-				cr.close_path ();-				-				x1 = double.parse (d[i].substring (2)) + x;-				y1 = -double.parse (d[i+1]) + y;-				-				cr.move_to (x1, y1);--				px = x1;-				py = y1;-				continue;-			}--			if (d[i].index_of ("z") == 0) {-				cr.close_path ();-				continue;-			}-		-		}-		-		cr.fill ();-		cr.restore ();-	}--}--internal static string round (double p) {-	string v = p.to_string ();-	char[] c = new char [501];-	-	v = p.format (c, "%3.15f");-	-	if (v.index_of ("e") != -1) {	-		return "0.0";-	}-	-	return v;-}-	-}diff --git a/libbirdfont/Svg/Svg.vala b/libbirdfont/Svg/Svg.valanew file mode 100644index 0000000..5b2682b--- /dev/null+++ b/libbirdfont/Svg/Svg.vala@@ -0,0 +1,353 @@+/*+	Copyright (C) 2012 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library 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 +	Lesser General Public License for more details.+*/++using Cairo;++namespace BirdFont {++public class Svg {++	/** Export to svg glyph data. */+	public static string to_svg_glyph (Glyph g) {	+		StringBuilder svg = new StringBuilder ();+		PathList stroke_list;+		+		foreach (Path p in g.get_visible_paths ()) {+			if (p.stroke == 0) {+				write_path_as_glyph (p, svg, g);+			} else {+				stroke_list = p.get_completed_stroke ();+				write_paths_as_glyph (stroke_list, svg, g);+			}+		}+		+		return svg.str;+	}++	/** Export to svg-font data. */+	public static string to_svg_path (Path pl, Glyph g) {	+		StringBuilder svg = new StringBuilder ();+		pl.create_list ();+		write_path (pl, svg, g, false);+		return svg.str;+	}++	private static void write_paths_as_glyph (PathList pl, StringBuilder svg, Glyph g) {+		foreach (Path p in pl.paths) {+			write_path_as_glyph (p, svg, g);+		}+	}++	private static void write_path_as_glyph (Path pl, StringBuilder svg, Glyph g) {+		write_path (pl, svg, g, true);+	}++	private static void write_path (Path p, StringBuilder svg, Glyph g, bool do_glyph) {+		int i = 0;+		EditPoint? n = null;+		EditPoint m;+		+		if (p.points.size < 2) {+			return;+		}++		p.create_list ();+			+		foreach (var e in p.points) {+			if (i == 0) {+				add_abs_start (e, svg, g, do_glyph);+				i++;+				n = e;+				continue;+			}+			+			m = (!) n;++			add_abs_next (m, e, svg, g, do_glyph);+			+			n = e;+			i++;+		}++		if (!p.is_open ()) {+			m = p.points.get (0);	+			add_abs_next ((!) n, m, svg, g, do_glyph);+			close_path (svg);+		}+	}++	private static void add_abs_next (EditPoint start, EditPoint end, StringBuilder svg, Glyph g, bool do_glyph) {+		if (start.right_handle.type == PointType.LINE_QUADRATIC) {+			add_abs_line_to (start, end, svg, g, do_glyph);+		} else if (start.right_handle.type == PointType.LINE_CUBIC && end.left_handle.type == PointType.LINE_CUBIC) {+			add_abs_line_to (start, end, svg, g, do_glyph);+		} else if (end.left_handle.type == PointType.QUADRATIC || start.right_handle.type == PointType.QUADRATIC) {+			add_quadratic_abs_path (start, end, svg, g, do_glyph);+		} else if (end.left_handle.type == PointType.DOUBLE_CURVE || start.right_handle.type == PointType.DOUBLE_CURVE) {+			add_double_quadratic_abs_path (start, end, svg, g, do_glyph);+		} else {+			add_cubic_abs_path (start, end, svg, g, do_glyph);+		}+	}++	private static void add_abs_start (EditPoint ep, StringBuilder svg, Glyph g, bool to_glyph) {		+		double left = g.left_limit;+		double baseline = -BirdFont.get_current_font ().base_line;+		double height = g.get_height ();+		+		svg.append_printf ("M");+		+		if (!to_glyph) {+			svg.append_printf ("%s ",  round (ep.x - left));+			svg.append_printf ("%s ",  round (-ep.y + height / 2));+		} else {+			svg.append_printf ("%s ",  round (ep.x - left));+			svg.append_printf ("%s ",  round (ep.y + baseline));+		}+	}+		+	private static void close_path (StringBuilder svg) {+		svg.append ("z");+	}	+	+	private static void add_abs_line_to (EditPoint start, EditPoint stop, StringBuilder svg, Glyph g, bool to_glyph) {+		double baseline = -BirdFont.get_current_font ().base_line;+		double left = g.left_limit;+		double height = g.get_height ();+		+		double xa, ya, xb, yb;+		+		Path.get_line_points (start, stop, out xa, out ya, out xb, out yb);++		double center_x = Glyph.xc ();+		double center_y = Glyph.yc ();+		+		svg.append ("L");+	+		if (!to_glyph) {+			svg.append_printf ("%s ", round (xb - center_x - left));+			svg.append_printf ("%s ", round (yb - center_y + height / 2));	+		} else {+			svg.append_printf ("%s ", round (xb - center_x - left));+			svg.append_printf ("%s ", round (-yb + center_y + baseline));+		}+	}+	+	private static void add_double_quadratic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) {+		EditPoint middle;+		double x, y;+		+		x = start.get_right_handle ().x + (end.get_left_handle ().x - start.get_right_handle ().x) / 2;+		y = start.get_right_handle ().y + (end.get_left_handle ().y - start.get_right_handle ().y) / 2;+		+		middle = new EditPoint (x, y, PointType.QUADRATIC);+		middle.right_handle = end.get_left_handle ().copy ();+		+		add_quadratic_abs_path (start, middle, svg, g, to_glyph);+		add_quadratic_abs_path (middle, end, svg, g, to_glyph);+	}+		+	private static void add_quadratic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) {+		double left = g.left_limit;+		double baseline = -BirdFont.get_current_font ().base_line;+		double height = g.get_height ();+		+		double xa, ya, xb, yb, xc, yc, xd, yd;+		+		Path.get_bezier_points (start, end, out xa, out ya, out xb, out yb, out xc, out yc, out xd, out yd);++		double center_x = Glyph.xc ();+		double center_y = Glyph.yc ();++		// cubic path+		if (!to_glyph) {+			svg.append_printf ("Q");++			svg.append_printf ("%s ", round (xb - center_x - left));+			svg.append_printf ("%s ", round (yb - center_y + height / 2));+			+			svg.append_printf ("%s ", round (xd - center_x - left));+			svg.append_printf ("%s ", round (yd - center_y + height / 2));++		} else {		+			svg.append_printf ("Q");++			svg.append_printf ("%s ", round (xb - center_x - left));+			svg.append_printf ("%s ", round (-yb + center_y + baseline));+			+			svg.append_printf ("%s ", round (xd - center_x - left));+			svg.append_printf ("%s ", round (-yd + center_y + baseline));	+		}+	}+			+	private static void add_cubic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) {+		double left = g.left_limit;+		double baseline = -BirdFont.get_current_font ().base_line;+		double height = g.get_height ();+		+		double xa, ya, xb, yb, xc, yc, xd, yd;+		+		Path.get_bezier_points (start, end, out xa, out ya, out xb, out yb, out xc, out yc, out xd, out yd);++		double center_x = Glyph.xc ();+		double center_y = Glyph.yc ();+		+		// cubic path+		if (!to_glyph) {+			svg.append_printf ("C");++			svg.append_printf ("%s ", round (xb - center_x - left));+			svg.append_printf ("%s ", round (yb - center_y + height / 2));+			+			svg.append_printf ("%s ", round (xc - center_x - left));+			svg.append_printf ("%s ", round (yc - center_y + height / 2));+			+			svg.append_printf ("%s ", round (xd - center_x - left));+			svg.append_printf ("%s ", round (yd - center_y + height / 2));	++		} else {		+			svg.append_printf ("C");++			svg.append_printf ("%s ", round (xb - center_x - left));+			svg.append_printf ("%s ", round (-yb + center_y + baseline));+			+			svg.append_printf ("%s ", round (xc - center_x - left));+			svg.append_printf ("%s ", round (-yc + center_y + baseline));	+			+			svg.append_printf ("%s ", round (xd - center_x - left));+			svg.append_printf ("%s ", round (-yd + center_y + baseline));	+		}+	}+	+	/** Draw path from svg font data. */+	public static void draw_svg_path (Context cr, string svg, double x, double y) {+		double x1, x2, x3;+		double y1, y2, y3;+		double px, py;+		string[] d = svg.split (" ");++		if (d.length == 0) {+			return;+		}+		+		px = 0;+		py = 0;+		+		cr.save ();++		cr.set_line_width (0);+		+		if (svg == "") {+			return;+		}+		+		for (int i = 0; i < d.length; i++) {+			+			// trim off leading white space	+			while (d[i].index_of (" ") == 0) { +				d[i] = d[i].substring (1); // FIXME: maybe no ascii+			}+			+			if (d[i].index_of ("L") == 0) {+				x1 = double.parse (d[i].substring (1)) + x;+				y1 = -double.parse (d[i+1]) + y;+				cr.line_to (x1, y1);+				+				px = x1;+				py = y1;			+				continue;+			}++			if (d[i].index_of ("Q") == 0) {+				x1 = double.parse (d[i].substring (1)) + x;+				y1 = -double.parse (d[i+1]) + y;++				x2 = double.parse (d[i+2]) + x;+				y2 = -double.parse (d[i+3]) + y;+											+				cr.curve_to ((px + 2 * x1) / 3, (py + 2 * y1) / 3, (x2 + 2 * x1) / 3, (y2 + 2 * y1) / 3, x2, y2);+				+				px = x2;+				py = y2;+				continue;+			}+			+			if (d[i].index_of ("C") == 0) {+				x1 = double.parse (d[i].substring (1)) + x;+				y1 = -double.parse (d[i+1]) + y;++				x2 = double.parse (d[i+2]) + x;+				y2 = -double.parse (d[i+3]) + y;++				x3 = double.parse (d[i+4]) + x;+				y3 = -double.parse (d[i+5]) + y;+																+				cr.curve_to (x1, y1, x2, y2, x3, y3);+				+				px = x3;+				py = y3;+				continue;+			}++			if (d[i].index_of ("M") == 0) {+				x1 = double.parse (d[i].substring (1)) + x;+				y1 = -double.parse (d[i+1]) + y;+				+				cr.move_to (x1, y1);++				px = x1;+				py = y1;+				continue;+			}+								+			if (d[i].index_of ("zM") == 0) {+				cr.close_path ();+				+				x1 = double.parse (d[i].substring (2)) + x;+				y1 = -double.parse (d[i+1]) + y;+				+				cr.move_to (x1, y1);++				px = x1;+				py = y1;+				continue;+			}++			if (d[i].index_of ("z") == 0) {+				cr.close_path ();+				continue;+			}+		+		}+		+		cr.fill ();+		cr.restore ();+	}++}++internal static string round (double p) {+	string v = p.to_string ();+	char[] c = new char [501];+	+	v = p.format (c, "%3.15f");+	+	if (v.index_of ("e") != -1) {	+		return "0.0";+	}+	+	return v;+}+	+}diff --git a/libbirdfont/Svg/SvgArc.vala b/libbirdfont/Svg/SvgArc.valanew file mode 100644index 0000000..92f3689--- /dev/null+++ b/libbirdfont/Svg/SvgArc.vala@@ -0,0 +1,181 @@+/*+ * BirdFont code from SVG Salamander+ * + * Copyright (c) 2004, Mark McKay+ * Copyright (c) 2014, Johan Mattsson+ * All rights reserved.+ *+ * Redistribution and use in source and binary forms, with or + * without modification, are permitted provided that the following+ * conditions are met:+ *+ *   - Redistributions of source code must retain the above + *     copyright notice, this list of conditions and the following+ *     disclaimer.+ *   - Redistributions in binary form must reproduce the above+ *     copyright notice, this list of conditions and the following+ *     disclaimer in the documentation and/or other materials + *     provided with the distribution.+ *+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS+ * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED+ * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Mark McKay can be contacted at mark@kitfox.com.  Salamander and other+ * projects can be found at http://www.kitfox.com+ *+ * Created on January 26, 2004, 8:40 PM+ * Adapded to BirdFont on Juli 2, 2014, 5:01 PM+ */++using Math;++namespace BirdFont {++/** Convert an SVG arc instruction to a Beziรฉr path. */+static void add_arc_points (BezierPoints[] bezier_points, ref int bi, double x0, double y0, double rx, double ry, double angle, bool largeArcFlag, bool sweepFlag, double x, double y) {++	//+	// Elliptical arc implementation based on the SVG specification notes+	//++	double dx2, dy2, cosAngle, sinAngle;+	double x1, y1, Prx, Pry, Px1, Py1, radiiCheck;+	double sign, sq, coef, cx1, cy1;+	double sx2, sy2, cx, cy;+	double ux, uy, vx, vy, p, n;+	double angleStart, angleExtent;+	double s, step, theta;+	+	// Compute the half distance between the current and the final point+	dx2 = (x0 - x) / 2.0;+	dy2 = (y0 - y) / 2.0;+	+	// Convert angle from degrees to radians+	angle = 2 * PI * ((angle % 360.0) / 360.0);+	+	cosAngle = cos (angle);+	sinAngle = sin (angle);++	//+	// Step 1 : Compute (x1, y1)+	//+	x1 = cosAngle * dx2 + sinAngle * dy2;+	y1 = -sinAngle * dx2 + cosAngle * dy2;+	+	// Ensure radii are large enough+	rx = fabs(rx);+	ry = fabs(ry);+	Prx = rx * rx;+	Pry = ry * ry;+	Px1 = x1 * x1;+	Py1 = y1 * y1;++	+	// Check that radii are large enough+	radiiCheck = Px1 / Prx + Py1 / Pry;+	+	if (radiiCheck > 1) {+		rx = sqrt (radiiCheck) * rx;+		ry = sqrt (radiiCheck) * ry;+		Prx = rx * rx;+		Pry = ry * ry;+	}++	//+	// Step 2 : Compute (cx1, cy1)+	//+	sign = (largeArcFlag == sweepFlag) ? -1 : 1;+	sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1));+	sq = (sq < 0) ? 0 : sq;+	coef = (sign * Math.sqrt(sq));+	cx1 = coef * ((rx * y1) / ry);+	cy1 = coef * -((ry * x1) / rx);++	//+	// Step 3 : Compute (cx, cy) from (cx1, cy1)+	//+	+	sx2 = (x0 + x) / 2.0;+	sy2 = (y0 + y) / 2.0;+	cx = sx2 - (cosAngle * cx1 - sinAngle * cy1);+	cy = sy2 - (sinAngle * cx1 + cosAngle * cy1);++	//+	// Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)+	//+	+	ux = (x1 - cx1) / rx;+	uy = (y1 - cy1) / ry;+	vx = (-x1 - cx1) / rx;+	vy = (-y1 - cy1) / ry;++	// Compute the angle start+	n = sqrt((ux * ux) + (uy * uy));+	p = ux; // (1 * ux) + (0 * uy)+	sign = (uy < 0) ? -1d : 1d;+	angleStart = sign * acos(p / n);++	// Compute the angle extent+	n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));+	p = ux * vx + uy * vy;+	sign = (ux * vy - uy * vx < 0) ? -1d : 1d;+	angleExtent = sign * Math.acos(p / n);+	+	if(!sweepFlag && angleExtent > 0) {+		angleExtent -= 2 *PI;+	} else if (sweepFlag && angleExtent < 0) {+		angleExtent += 2 *PI;+	}+	angleExtent %= 2 * PI;+	angleStart %= 2 * PI;++	angleExtent *= -1;+	angleStart *= -1;+	+	// Approximate the path with Beziรฉr points+	s = (angleExtent > 0) ? 1 : -1;+	step = fabs (angleExtent) / (2 * fabs (angleExtent));++	theta = PI - angleStart - angleExtent;+	+	bezier_points[bi].type = 'L';+	bezier_points[bi].svg_type = 'a';++	bezier_points[bi].x0 = cx + rx * cos (theta);+	bezier_points[bi].y0 = cy + ry * sin (theta);+									+	bi++;+					+	for (double a = 0; a < fabs (angleExtent); a += step) {+		theta = PI - angleStart - angleExtent + s * a;++		return_if_fail (0 <= bi < bezier_points.length);++		bezier_points[bi].type = 'S';+		bezier_points[bi].svg_type = 'a';++		bezier_points[bi].x0 = cx + rx * cos (theta);+		bezier_points[bi].y0 = cy + ry * sin (theta);++		bezier_points[bi].x1 = cx + rx * cos (theta + 1 * step / 4);+		bezier_points[bi].y1 = cy + ry * sin (theta + 1 * step / 4);+		+		bezier_points[bi].x2 = cx + rx * cos (theta + 2 * step / 4);+		bezier_points[bi].y2 = cy + ry * sin (theta + 2 * step / 4);+						+		bi++;+	}+}++}+	diff --git a/libbirdfont/Svg/SvgFile.vala b/libbirdfont/Svg/SvgFile.valanew file mode 100644index 0000000..2418f3f--- /dev/null+++ b/libbirdfont/Svg/SvgFile.vala@@ -0,0 +1,21 @@+/*+	Copyright (C) 2015 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library 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 +	Lesser General Public License for more details.+*/++namespace BirdFont {++public class SvgFile : GLib.Object {++}++}diff --git a/libbirdfont/Svg/SvgFont.vala b/libbirdfont/Svg/SvgFont.valanew file mode 100644index 0000000..7223c2f--- /dev/null+++ b/libbirdfont/Svg/SvgFont.vala@@ -0,0 +1,264 @@+/*+	Copyright (C) 2013 2014 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library 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 +	Lesser General Public License for more details.+*/++using B;++namespace BirdFont {++class SvgFont : GLib.Object {+	Font font;+	double units = 1;+	double font_advance = 0;+	+	public SvgFont (Font f) {+		this.font = f;+	}+	+	/** Load svg font from file. */+	public void load (string path) {+		string data;+		XmlParser xml_parser;+		try {+			FileUtils.get_contents (path, out data);+			xml_parser = new XmlParser (data);+			parse_svg_font (xml_parser.get_root_tag ());+		} catch (GLib.Error e) {+			warning (e.message);+		}+	}+	+	void parse_svg_font (Tag tag) {+		foreach (Tag t in tag) {+			if (t.get_name () == "defs") {+				parse_svg_font (t);+			}+			+			if (t.get_name () == "font") {+				parse_font_tag (t);+				parse_svg_font (t);+			}++			if (t.get_name () == "font-face") {+				parse_font_limits (t);+			}++			if (t.get_name () == "hkern") {+				parse_hkern (t);+			}+									+			if (t.get_name () == "glyph") {+				parse_glyph (t);+			}+		}		+	}++	void parse_hkern (Tag tag) {+		string left = "";+		string right = "";+		string left_name = "";+		string right_name = "";+		double kerning = 0;+		unichar l, r;+		StringBuilder sl, sr;+		GlyphRange grr, grl;+		KerningClasses classes = BirdFont.get_current_font ().get_kerning_classes ();+		+		foreach (Attribute attr in tag.get_attributes ()) {+			// left+			if (attr.get_name () == "u1") {+				left = attr.get_content ();+			}	+					+			// right	+			if (attr.get_name () == "u2") {+				right = attr.get_content ();+			}++			if (attr.get_name () == "g1") {+				left_name = attr.get_content ();+			}+			+			if (attr.get_name () == "g2") {+				right_name = attr.get_content ();+			}+				+			// kerning+			if (attr.get_name () == "k") {+				kerning = double.parse (attr.get_content ()) * units;+			}+		}+				+		// FIXME: ranges and sequences for u1 & u2 + g1 & g2+		foreach (string lk in left.split (",")) {+			foreach (string rk in right.split (",")) {+				l = get_unichar (lk);+				r = get_unichar (rk);+				+				sl = new StringBuilder ();+				sl.append_unichar (l);+				+				sr = new StringBuilder ();+				sr.append_unichar (r);+				+				try {+					grl = new GlyphRange ();+					grl.parse_ranges (sl.str);+					+					grr = new GlyphRange ();+					grr.parse_ranges (sr.str);+				+					classes.set_kerning (grl, grr, -kerning);+				} catch (MarkupError e) {+					warning (e.message);+				}		+			}+		}+	}++	void parse_font_limits (Tag tag) {+		double top_limit = 0;+		double bottom_limit = 0;+		+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "units-per-em") {+				units = 100.0 / double.parse (attr.get_content ());+			}	+		}++		foreach (Attribute attr in tag.get_attributes ()) {	+			if (attr.get_name () == "ascent") {+				top_limit = double.parse (attr.get_content ());+			}+			+			if (attr.get_name () == "descent") {+				bottom_limit = double.parse (attr.get_content ());+			}		+		}+		+		top_limit *= units;+		bottom_limit *= units;+		+		font.bottom_limit = bottom_limit;+		font.top_limit = top_limit;+	}+	+	void parse_font_tag (Tag tag) {+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "horiz-adv-x") {+				font_advance = double.parse (attr.get_content ());+			}+						+			if (attr.get_name () == "id") {+				font.set_name (attr.get_content ());+			}+		}+	}+	+	/** Obtain unichar value from either a character, a hex representation of+	 *  a character or series of characters (f, &#x6d; or ffi).+	 */+	static unichar get_unichar (string val) {+		string v = val;+		unichar unicode_value;+		+		if (val == "&") {+			return '&';+		}+		+		// TODO: parse ligatures+		if (v.has_prefix ("&")) {+			// parse hex value+			v = v.substring (0, v.index_of (";"));+			v = v.replace ("&#x", "U+");+			v = v.replace (";", "");+			unicode_value = Font.to_unichar (v);+		} else {+			// obtain unicode value+			+			if (v.char_count () > 1) {+				warning ("font contains ligatures");+				return '\0';+			}+			+			unicode_value = v.get_char (0);+		}+		+		return unicode_value;	+	}+	+	bool is_ligature (string v) {+		if (v.has_prefix ("&")) {+			return false;+		}+		+		return v.char_count () > 1;+	}+	+	void parse_glyph (Tag tag) {+		unichar unicode_value = 0;+		string glyph_name = "";+		string svg = "";+		Glyph glyph;+		GlyphCollection glyph_collection;+		double advance = font_advance;+		string ligature = "";+		SvgParser parser = new SvgParser ();+		StringBuilder unicode_name; ++		parser.set_format (SvgFormat.INKSCAPE);++		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "unicode") {+				unicode_value = get_unichar (attr.get_content ());+				+				if (glyph_name == "") {+					glyph_name = attr.get_content ();+				}+				+				if (is_ligature (attr.get_content ())) {+					ligature = attr.get_content ();+				}+			}+			+			// svg data+			if (attr.get_name () == "d") {+				svg = attr.get_content ();+			}+			+			if (attr.get_name () == "glyph-name") {+				glyph_name = attr.get_content ();+			}++			if (attr.get_name () == "horiz-adv-x") {+				advance = double.parse (attr.get_content ());+			}+		}++		unicode_name = new StringBuilder ();+		unicode_name.append_unichar (unicode_value);++		glyph = new Glyph (unicode_name.str, unicode_value);+		parser.add_path_to_glyph (svg, glyph, true, units);			+		glyph.right_limit = glyph.left_limit + advance * units;+		+		// FIXME: add svg font ligatures+		+		glyph_collection = new GlyphCollection (unicode_value, glyph_name);+		glyph_collection.insert_glyph (glyph, true);+		+		font.add_glyph_collection (glyph_collection);+	}+}++}diff --git a/libbirdfont/Svg/SvgFontFormatWriter.vala b/libbirdfont/Svg/SvgFontFormatWriter.valanew file mode 100644index 0000000..b2e907b--- /dev/null+++ b/libbirdfont/Svg/SvgFontFormatWriter.vala@@ -0,0 +1,132 @@+/*+	Copyright (C) 2012, 2014 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library 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 +	Lesser General Public License for more details.+*/++namespace BirdFont {++class SvgFontFormatWriter : GLib.Object  {++	DataOutputStream os;++	public SvgFontFormatWriter () {+	}++	public void open (File file) throws Error {+		if (file.query_exists ()) {+			throw new FileError.EXIST ("SvgFontFormatWriter: file exists.");+		}+		+		os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION));+	}++	public void close () throws Error {+		os.close ();+	}+	+	public void write_font_file (Font font) throws Error {+		string font_name = font.get_full_name ();+		+		int units_per_em = 100;+		+		int ascent = 80;+		int descent = -20;+		+		StringBuilder b;+		+		Glyph? g;+		Glyph glyph;+		unichar index = 0;+		+		string uni;+		+		KerningClasses classes;+		+		put ("""<?xml version="1.0" standalone="no"?>""");+		put ("""<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >""");+		put ("""<svg>""");++		// (metadata goes here)++		put ("<defs>");++		put (@"<font id=\"$font_name\" horiz-adv-x=\"250\" >");+		put (@"<font-face units-per-em=\"$(to_float (units_per_em))\" ascent=\"$(to_float (ascent))\" descent=\"$(to_float (descent))\" />");++		// (missing-glyph goes here)++		// regular glyphs +		while (true) {+			g = font.get_glyph_index (index++);+			+			if (g == null) {+				break;+			}+			+			glyph = (!) g;+			+			b = new StringBuilder ();+			b.append_unichar (glyph.get_unichar ());++			if (glyph.get_unichar () >= ' ' && b.str.validate ()) {+				if (b.str == "\"" || b.str == "&" || b.str == "<" || b.str == ">") {+					uni = Font.to_hex_code (glyph.get_unichar ());+					put (@"<glyph unicode=\"&#x$(uni);\" horiz-adv-x=\"$(to_float (glyph.get_width ()))\" d=\"$(glyph.get_svg_data ())\" />");			+				} else {+					put (@"<glyph unicode=\"$(b.str)\" horiz-adv-x=\"$(to_float (glyph.get_width ()))\" d=\"$(glyph.get_svg_data ())\" />");+				}+			}+		}+		+		// FIXME: ligatures+		classes = BirdFont.get_current_font ().get_kerning_classes ();+		classes.all_pairs ((kerning) => {+			string l, r;+			+			foreach (Kerning k in kerning.kerning) {+				try {+					if (k.glyph != null) {+						l = Font.to_hex_code (kerning.character.unichar_code);+						r = Font.to_hex_code (((!)k.glyph).unichar_code);	+						os.put_string (@"<hkern u1=\"&#x$l;\" u2=\"&#x$r;\" k=\"$(to_float (-k.val))\"/>\n");+					} else {+						warning ("No glyph.");+					}+				} catch (GLib.Error e) {+					warning (e.message);+				}+			}+		});	++		put ("</font>");+		put ("</defs>");+		put ("</svg>");+	}++	string to_float (double d) {+		string s = @"$d";+		if (s.index_of ("e") != -1) {+			return "0".dup ();+		}+		return s.replace (",", ".");+	}++	/** Write a new line */+	private void put (string line) throws Error {+		os.put_string (line);+		os.put_string ("\n");+	}++}+++}diff --git a/libbirdfont/Svg/SvgParser.vala b/libbirdfont/Svg/SvgParser.valanew file mode 100644index 0000000..e3e0575--- /dev/null+++ b/libbirdfont/Svg/SvgParser.vala@@ -0,0 +1,2114 @@+/*+	Copyright (C) 2012 2013 2014 2015 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library 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 +	Lesser General Public License for more details.+*/++using B;+using Math;++namespace BirdFont {++public enum SvgFormat {+	NONE,+	INKSCAPE,+	ILLUSTRATOR+}++public enum SvgType {+	COLOR,+	REGULAR+}++public class SvgParser {+	+	SvgFormat format = SvgFormat.ILLUSTRATOR;+	+	public SvgParser () {+	}+	+	public void set_format (SvgFormat f) {+		format = f;+	}+	+	public static void import (SvgType type) {+		FileChooser fc = new FileChooser ();+		fc.file_selected.connect ((p) => {+			string path;+				+			if (p == null) {+				return;+			}+			+			path = (!) p;+			+			if (type == SvgType.REGULAR) {+				import_svg (path);+			} else if (type == SvgType.COLOR) {+				Glyph glyph = MainWindow.get_current_glyph ();+				import_color_svg (glyph, path);+			}+		});+		+		fc.add_extension ("svg");+		MainWindow.file_chooser (t_("Import"), fc, FileChooser.LOAD);+	}+		+	public static void import_color_svg (Glyph glyph, string path) {+		try {+			string data;+			FileUtils.get_contents (path, out data);+			glyph.color_svg_data = data;++			if (glyph.color_svg_data != null) {+				glyph.svg_x = glyph.left_limit;+				glyph.svg_y = BirdFont.get_current_font ().top_position;+			}+		} catch (GLib.Error e) {+			warning (e.message);+		}+	}+	+	public static void import_folder (SvgType type) {+		FileChooser fc = new FileChooser ();+		fc.file_selected.connect ((p) => {+			string path;+			File svg_folder;+			File svg;+			bool imported;+			FileEnumerator enumerator;+			FileInfo? file_info;+			string file_name;+			Font font;+			+			if (p == null) {+				return;+			}+			+			path = (!) p;+			svg_folder = File.new_for_path (path);+			font = BirdFont.get_current_font ();+				+			try {+				enumerator = svg_folder.enumerate_children (FileAttribute.STANDARD_NAME, 0);+				while ((file_info = enumerator.next_file ()) != null) {+					file_name = ((!) file_info).get_name ();+					+					if (file_name.has_suffix (".svg")) {+						svg = get_child (svg_folder, file_name);+						imported = import_svg_file (font, svg, type);+						+						if (!imported) {+							warning ("Can't import %s.", (!) svg.get_path ());+						} else {+							font.touch ();+						}+					}+				}+			} catch (Error e) {+				warning (e.message);+			}+		});+		+		MainWindow.file_chooser (t_("Import"), fc, FileChooser.LOAD | FileChooser.DIRECTORY);+	}+	+	public static void import_svg_data (string xml_data, SvgFormat format = SvgFormat.NONE) {+		PathList path_list = new PathList ();+		Glyph glyph; +		string[] lines = xml_data.split ("\n");+		bool has_format = false;+		SvgParser parser = new SvgParser ();+		XmlParser xmlparser;++		foreach (string l in lines) {+			if (l.index_of ("Illustrator") > -1 || l.index_of ("illustrator") > -1) {+				parser.set_format (SvgFormat.ILLUSTRATOR);+				has_format = true;+			}+			+			if (l.index_of ("Inkscape") > -1 || l.index_of ("inkscape") > -1) {+				parser.set_format (SvgFormat.INKSCAPE);+				has_format = true;+			}+		}+		+		if (format != SvgFormat.NONE) {+			parser.set_format (format);+		}++		// parse the file+		if (!has_format) {+			warn_if_test ("No format identifier found in SVG parser.\n");+		}++		xmlparser = new XmlParser (xml_data);+		+		if (!xmlparser.validate()) {+			warning("Invalid XML in SVG parser."); +		}+		+		path_list = parser.parse_svg_file (xmlparser.get_root_tag ());+	+		glyph = MainWindow.get_current_glyph ();+		foreach (Path p in path_list.paths) {+			FastPath path = new FastPath.for_path (p);+			glyph.add_object (path);+			glyph.add_active_object (null, path); // FIXME: groups+			path.update_region_boundaries ();+		}+		+		glyph.close_path ();	+	}+	+	public static string replace (string content, string start, string stop, string replacement) {+		int i_tag = content.index_of (start);+		int end_tag = content.index_of (stop, i_tag);+		string c = "";+		+		if (i_tag > -1) {+			c = content.substring (0, i_tag) +				+ replacement+				+ content.substring (end_tag + stop.length);+		} else {+			c = content;+		}+		+		return c;+	}+	+	public static void import_svg (string path) {+		string svg_data;+		try {+			FileUtils.get_contents (path, out svg_data);+		} catch (GLib.Error e) {+			warning (e.message);+		}+		import_svg_data (svg_data);+	}+	+	private PathList parse_svg_file (Tag tag) {+		Layer pl = new Layer ();+	+		foreach (Tag t in tag) {+			+			if (t.get_name () == "g") {+				parse_layer (t, pl);+			}++			if (t.get_name () == "switch") {+				parse_layer (t, pl);+			}+						+			if (t.get_name () == "path") {+				parse_path (t, pl);+			}+			+			if (t.get_name () == "polygon") {+				parse_polygon (t, pl);+			}++			if (t.get_name () == "polyline") {+				parse_polyline (t, pl);+			}+						+			if (t.get_name () == "circle") {+				parse_circle (t, pl);+			}+			+			if (t.get_name () == "ellipse") {+				parse_ellipse (t, pl);+			}++			if (t.get_name () == "line") {+				parse_line (t, pl);+			}			+		}+		+		return pl.get_all_paths ();+	}+	+	private void parse_layer (Tag tag, Layer pl) {+		Layer layer;+		bool hidden = false;++		foreach (Attribute attr in tag.get_attributes ()) {	+			if (attr.get_name () == "display" && attr.get_content () == "none") {+				hidden = true;+			}+			+			if (attr.get_name () == "visibility"+				&& (attr.get_content () == "hidden" +					|| attr.get_content () == "collapse")) {+				hidden = true;+			}+		}+		+		if (hidden) {+			return;+		}+					+		foreach (Tag t in tag) {+			if (t.get_name () == "path") {+				parse_path (t, pl);+			}+			+			if (t.get_name () == "g") {+				layer = new Layer ();+				parse_layer (t, layer);+				pl.subgroups.add (layer);+			}+			+			if (t.get_name () == "polygon") {+				parse_polygon (t, pl);+			}++			if (t.get_name () == "polyline") {+				parse_polyline (t, pl);+			}+			+			if (t.get_name () == "rect") {+				parse_rect (t, pl);+			}++			if (t.get_name () == "circle") {+				parse_circle (t, pl);+			}++			if (t.get_name () == "ellipse") {+				parse_ellipse (t, pl);+			}+			+			if (t.get_name () == "line") {+				parse_line (t, pl);+			}+		}++		foreach (Attribute attr in tag.get_attributes ()) {	+			if (attr.get_name () == "transform") {+				transform (attr.get_content (), pl);+			}+		}+	}+	+	private void transform (string transform_functions, Layer layer) {+		PathList path_list = new PathList ();+		+		foreach (Object o in layer.objects) {+			if (o is FastPath) {+				path_list.add (((FastPath) o).get_path ());+			}+		}+		+		transform_paths (transform_functions, path_list);+		transform_subgroups (transform_functions, layer);+	}+	+	private void transform_subgroups (string transform_functions, Layer layer) {+		foreach (Layer subgroup in layer.subgroups) {+			transform (transform_functions, subgroup);+		}+	}+	+	private void transform_paths (string transform_functions, PathList pl) {+		string data = transform_functions.dup ();+		string[] functions;+				+		// use only a single space as separator+		while (data.index_of ("  ") > -1) {+			data = data.replace ("  ", " ");+		}+		+		return_if_fail (data.index_of (")") > -1);+		+		 // add separator+		data = data.replace (") ", "|");+		data = data.replace (")", "|"); +		functions = data.split ("|");+		+		for (int i = functions.length - 1; i >= 0; i--) {+			if (functions[i].has_prefix ("translate")) {+				translate (functions[i], pl);+			}+			+			if (functions[i].has_prefix ("scale")) {+				scale (functions[i], pl);+			}++			if (functions[i].has_prefix ("matrix")) {+				matrix (functions[i], pl);+			}+			+			// TODO: rotate etc.+		}+	}++	/** @param path a path in the cartesian coordinate system+	 * The other parameters are in the SVG coordinate system.+	 */+	public static void apply_matrix (Path path, double a, double b, double c, +		double d, double e, double f){+		+		double dx, dy;+		Font font = BirdFont.get_current_font ();+		Glyph glyph = MainWindow.get_current_glyph ();+		+		foreach (EditPoint ep in path.points) {+			ep.tie_handles = false;+			ep.reflective_point = false;+		}+		+		foreach (EditPoint ep in path.points) {+			apply_matrix_on_handle (ep.get_right_handle (), a, b, c, d, e, f);+			apply_matrix_on_handle (ep.get_left_handle (), a, b, c, d, e, f);++			ep.independent_y = font.top_position - ep.independent_y;+			ep.independent_x -= glyph.left_limit;+			+			dx = a * ep.independent_x + c * ep.independent_y + e;+			dy = b * ep.independent_x + d * ep.independent_y + f;+			+			ep.independent_x = dx;+			ep.independent_y = dy;+			+			ep.independent_y = font.top_position - ep.independent_y;+			ep.independent_x += glyph.left_limit;+		}+	}++	public static void apply_matrix_on_handle (EditPointHandle h, +		double a, double b, double c, +		double d, double e, double f){+		+		double dx, dy;+		Font font = BirdFont.get_current_font ();+		Glyph glyph = MainWindow.get_current_glyph ();++		h.y = font.top_position - h.y;+		h.x -= glyph.left_limit;+		+		dx = a * h.x + c * h.y + e;+		dy = b * h.x + d * h.y + f;+		+		h.x = dx;+		h.y = dy;+		+		h.y = font.top_position - h.y;+		h.x += glyph.left_limit;+	}+++	private void matrix (string function, PathList pl) {+		string parameters = get_transform_parameters (function);+		string[] p = parameters.split (" ");++		if (p.length != 6) {+			warning ("Expecting six parameters for matrix transformation.");+			return;+		}++		foreach (Path path in pl.paths) {+			apply_matrix (path, parse_double (p[0]), parse_double (p[1]), +				parse_double (p[2]), parse_double (p[3]), +				parse_double (p[4]), parse_double (p[5]));+		}+	}+		+	private void scale (string function, PathList pl) {+		string parameters = get_transform_parameters (function);+		string[] p = parameters.split (" ");+		double x, y;+		+		x = 1;+		y = 1;+		+		if (p.length > 0) {+			x = parse_double (p[0]);+		}+		+		if (p.length > 1) {+			y = parse_double (p[1]);+		}+		+		foreach (Path path in pl.paths) {+			path.scale (-x, y);+		}+	}+	+	private void translate (string function, PathList pl) {+		string parameters = get_transform_parameters (function);+		string[] p = parameters.split (" ");+		double x, y;+		+		x = 0;+		y = 0;+		+		if (p.length > 0) {+			x = parse_double (p[0]);+		}+		+		if (p.length > 1) {+			y = parse_double (p[1]);+		}+		+		foreach (Path path in pl.paths) {+			path.move (x, -y);+		}+	}++	private string get_transform_parameters (string function) {+		int i;+		string param = "";+		+		i = function.index_of ("(");+		return_val_if_fail (i != -1, param);+		param = function.substring (i);++		param = param.replace ("(", "");+		param = param.replace ("\n", " ");+		param = param.replace ("\t", " ");+		param = param.replace (",", " ");+		+		while (param.index_of ("  ") > -1) {+			param.replace ("  ", " ");+		}+			+		return param.strip();			+	}+	+	private void parse_circle (Tag tag, Layer pl) {+		Path p;+		double x, y, r;+		Glyph g;+		PathList npl;+		BezierPoints[] bezier_points;+		SvgStyle style = new SvgStyle ();+		bool hidden = false;+		+		npl = new PathList ();+		+		x = 0;+		y = 0;+		r = 0;+			+		foreach (Attribute attr in tag.get_attributes ()) {			+			if (attr.get_name () == "cx") {+				x = parse_double (attr.get_content ());+			}+			+			if (attr.get_name () == "cy") {+				y = -parse_double (attr.get_content ());+			}++			if (attr.get_name () == "r") {+				r = parse_double (attr.get_content ());+			}+	+			if (attr.get_name () == "display" && attr.get_content () == "none") {+				hidden = true;+			}+		}+		+		style = SvgStyle.parse (tag.get_attributes ());+		+		if (hidden) {+			return;+		}+		+		bezier_points = new BezierPoints[1];+		bezier_points[0] = new BezierPoints ();+		bezier_points[0].type == 'L';+		bezier_points[0].x0 = x;+		bezier_points[0].y0 = y;++		g = MainWindow.get_current_glyph ();+		move_and_resize (bezier_points, 1, false, 1, g);+			+		p = CircleTool.create_circle (bezier_points[0].x0,+			bezier_points[0].y0, r, PointType.CUBIC);++		npl.add (p);+		+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "transform") {+				transform_paths (attr.get_content (), npl);+			}+		}+		+		style.apply (npl);+		pl.append_paths (npl);+	}++	private void parse_ellipse (Tag tag, Layer pl) {+		Path p;+		double x, y, rx, ry;+		Glyph g;+		PathList npl;+		BezierPoints[] bezier_points;+		SvgStyle style = new SvgStyle ();+		bool hidden = false;+		+		npl = new PathList ();+		+		x = 0;+		y = 0;+		rx = 0;+		ry = 0;+		+		foreach (Attribute attr in tag.get_attributes ()) {			+			if (attr.get_name () == "cx") {+				x = parse_double (attr.get_content ());+			}+			+			if (attr.get_name () == "cy") {+				y = -parse_double (attr.get_content ());+			}++			if (attr.get_name () == "rx") {+				rx = parse_double (attr.get_content ());+			}++			if (attr.get_name () == "ry") {+				ry = parse_double (attr.get_content ());+			}+	+			if (attr.get_name () == "display" && attr.get_content () == "none") {+				hidden = true;+			}+		}+		+		style = SvgStyle.parse (tag.get_attributes ());+		+		if (hidden) {+			return;+		}+		+		bezier_points = new BezierPoints[1];+		bezier_points[0] = new BezierPoints ();+		bezier_points[0].type == 'L';+		bezier_points[0].x0 = x;+		bezier_points[0].y0 = y;++		g = MainWindow.get_current_glyph ();+		move_and_resize (bezier_points, 1, false, 1, g);+			+		p = CircleTool.create_ellipse (bezier_points[0].x0,+			bezier_points[0].y0, rx, ry, PointType.CUBIC);++		npl.add (p);+		+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "transform") {+				transform_paths (attr.get_content (), npl);+			}+		}+		+		style.apply (npl);+		pl.append_paths (npl);+	}++	private void parse_line (Tag tag, Layer pl) {+		Path p;+		double x1, y1, x2, y2;+		BezierPoints[] bezier_points;+		Glyph g;+		PathList npl = new PathList ();+		SvgStyle style = new SvgStyle ();+		bool hidden = false;+		+		x1 = 0;+		y1 = 0;+		x2 = 0;+		y2 = 0;+			+		foreach (Attribute attr in tag.get_attributes ()) {			+			if (attr.get_name () == "x1") {+				x1 = parse_double (attr.get_content ());+			}+			+			if (attr.get_name () == "y1") {+				y1 = -parse_double (attr.get_content ());+			}++			if (attr.get_name () == "x2") {+				x2 = parse_double (attr.get_content ());+			}+			+			if (attr.get_name () == "xy") {+				y2 = -parse_double (attr.get_content ());+			}+	+			if (attr.get_name () == "display" && attr.get_content () == "none") {+				hidden = true;+			}+		}+		+		style = SvgStyle.parse (tag.get_attributes ());+		+		if (hidden) {+			return;+		}++		bezier_points = new BezierPoints[2];+		bezier_points[0] = new BezierPoints ();+		bezier_points[0].type == 'L';+		bezier_points[0].x0 = x1;+		bezier_points[0].y0 = y1;++		bezier_points[1] = new BezierPoints ();+		bezier_points[1].type == 'L';+		bezier_points[1].x0 = x2;+		bezier_points[1].y0 = y2;+		+		g = MainWindow.get_current_glyph ();+		move_and_resize (bezier_points, 4, false, 1, g);+					+		p = new Path ();	+		+		p.add (bezier_points[0].x0, bezier_points[0].y0);+		p.add (bezier_points[1].x0, bezier_points[1].y0);+						+		p.close ();+		p.create_list ();+		p.recalculate_linear_handles ();		+		+		npl.add (p);+		+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "transform") {+				transform_paths (attr.get_content (), npl);+			}+		}+		+		style.apply (npl);+		pl.append_paths (npl);+	}+		+	private void parse_rect (Tag tag, Layer layer) {+		Path p;+		double x, y, x2, y2;+		BezierPoints[] bezier_points;+		Glyph g;+		PathList npl = new PathList ();+		SvgStyle style = new SvgStyle ();+		bool hidden = false;+		EditPoint ep;+		+		x = 0;+		y = 0;+		x2 = 0;+		y2 = 0;+			+		foreach (Attribute attr in tag.get_attributes ()) {			+			if (attr.get_name () == "x") {+				x = parse_double (attr.get_content ());+			}+			+			if (attr.get_name () == "y") {+				y = -parse_double (attr.get_content ());+			}++			if (attr.get_name () == "width") {+				x2 = parse_double (attr.get_content ());+			}+			+			if (attr.get_name () == "height") {+				y2 = -parse_double (attr.get_content ());+			}+	+			if (attr.get_name () == "display" && attr.get_content () == "none") {+				hidden = true;+			}+		}+		+		style = SvgStyle.parse (tag.get_attributes ());+		+		if (hidden) {+			return;+		}+		+		x2 += x;+		y2 += y;++		bezier_points = new BezierPoints[4];+		bezier_points[0] = new BezierPoints ();+		bezier_points[0].type == 'L';+		bezier_points[0].x0 = x;+		bezier_points[0].y0 = y;++		bezier_points[1] = new BezierPoints ();+		bezier_points[1].type == 'L';+		bezier_points[1].x0 = x2;+		bezier_points[1].y0 = y;++		bezier_points[2] = new BezierPoints ();+		bezier_points[2].type == 'L';+		bezier_points[2].x0 = x2;+		bezier_points[2].y0 = y2;++		bezier_points[3] = new BezierPoints ();+		bezier_points[3].type == 'L';+		bezier_points[3].x0 = x;+		bezier_points[3].y0 = y2;+		+		g = MainWindow.get_current_glyph ();+		move_and_resize (bezier_points, 4, false, 1, g);+					+		p = new Path ();	+		+		ep = p.add (bezier_points[0].x0, bezier_points[0].y0);+		ep.set_point_type (PointType.CUBIC);+		+		ep = p.add (bezier_points[1].x0, bezier_points[1].y0);+		ep.set_point_type (PointType.CUBIC);+		+		ep = p.add (bezier_points[2].x0, bezier_points[2].y0);+		ep.set_point_type (PointType.CUBIC);+		+		ep = p.add (bezier_points[3].x0, bezier_points[3].y0);+		ep.set_point_type (PointType.CUBIC);+						+		p.close ();+		p.create_list ();+		p.recalculate_linear_handles ();		+		+		npl.add (p);+		+		// FIXME: right layer for other transforms+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "transform") {+				transform_paths (attr.get_content (), npl);+			}+		}+		+		style.apply (npl);+		layer.append_paths (npl);+	}+	+	private void parse_polygon (Tag tag, Layer layer) {+		PathList path_list = get_polyline (tag);+		+		foreach (Path p in path_list.paths) {+			p.close ();+		}+		+		layer.append_paths (path_list);+	}++	+	private void parse_polyline (Tag tag, Layer layer) {	+		layer.append_paths (get_polyline (tag));+	}+	+	private PathList get_polyline (Tag tag) {+		Path p = new Path ();+		bool hidden = false;+		PathList path_list = new PathList ();+		SvgStyle style = new SvgStyle ();+				+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "points") {+				p = parse_poly_data (attr.get_content ());+			}+	+			if (attr.get_name () == "display" && attr.get_content () == "none") {+				hidden = true;+			}+		}++		style = SvgStyle.parse (tag.get_attributes ());+		+		if (hidden) {+			return path_list;+		}+		+		path_list.add (p);+		style.apply (path_list);+		+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "transform") {+				transform_paths (attr.get_content (), path_list);+			}+		}+		+		return path_list;+	}+	+	private void parse_path (Tag tag, Layer layer) {+		Glyph glyph = MainWindow.get_current_glyph ();+		PathList path_list = new PathList ();+		SvgStyle style = new SvgStyle ();+		bool hidden = false;++		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "d") {+				path_list = parse_svg_data (attr.get_content (), glyph);+			}+	+			if (attr.get_name () == "display" && attr.get_content () == "none") {+				hidden = true;+			}+			+			if (attr.get_name () == "visibility"+				&& (attr.get_content () == "hidden" +					|| attr.get_content () == "collapse")) {+				hidden = true;+			}+		}+		+		style = SvgStyle.parse (tag.get_attributes ());+		+		if (hidden) {+			return;+		}+		+		foreach (Path path in path_list.paths) {+			layer.add_path (path);+		}+		+		style.apply (path_list);++		// assume the even odd rule is applied and convert the path+		// to a path using the non-zero rule+		int inside_count;+		bool inside;+		foreach (Object o1 in layer.objects) {+			if (o1 is FastPath) {+				Path p1 = ((FastPath) o1).get_path ();+				inside_count = 0;+				+				foreach (Object o2 in layer.objects) {+					if (o2 is FastPath) {+						Path p2 = ((FastPath) o2).get_path ();+					+						if (p1 != p2) {+							inside = true;+							+							foreach (EditPoint ep in p1.points) {+								if (!is_inside (ep, p2)) {+									inside = false;+								}+							}++							if (inside) {+								inside_count++; +							}+						}+					}+				}+				+				if (inside_count % 2 == 0) {+					p1.force_direction (Direction.CLOCKWISE);+				} else {+					p1.force_direction (Direction.COUNTER_CLOCKWISE);+				}+			}+		}+		+		foreach (Attribute attr in tag.get_attributes ()) {+			if (attr.get_name () == "transform") {+				transform_paths (attr.get_content (), path_list);+			}+		}+	}++	public static void create_lines_for_segment (Path path, EditPoint start, EditPoint end, double tolerance) {+		double x1, x2, x3;+		double y1, y2, y3;+		double step_start, step, step_end;++		path.add (start.x, start.y);++		step_start = 0;+		step = 0.5;+		step_end = 1;+					+		while (true) {+			Path.get_point_for_step (start, end, step_start, out x1, out y1);+			Path.get_point_for_step (start, end, step, out x2, out y2);+			Path.get_point_for_step (start, end, step_end, out x3, out y3);+		+			if (!StrokeTool.is_flat (x1, y1, x2, y2, x3, y3, tolerance)+				&& step_end - step / 2.0 > step_start +				&& step_end - step / 2.0 > 0.1+				&& step > 0.05+				&& Path.distance_to_point (start, end) > 1) {+				+				step /= 2.0;+	+				if (step < 0.05) {+					step = 0.05;+				} else {+					step_end = step_start + 2 * step;+				}+			} else {+				path.add (x3, y3);+				+				if (step_end + step < 1) {+					step_start = step_end;+					step_end += step;+				} else {+					break;+				}+			}+		}+	}++	public static Path get_lines (Path p) {+		EditPoint start;+		Path path = new Path ();+		+		if (p.points.size == 0) {+			return path;+		}+		+		// create a set of straight lines+		start = p.points.get (p.points.size - 1);+		+		foreach (EditPoint end in p.points) {+			create_lines_for_segment (path, start, end, 1);+			start = end;+		}+						+		return path;+	}++	/** Check if a point is inside using the even odd fill rule.+	 * The path should only have straight lines.+	 */+	public static bool is_inside (EditPoint point, Path path) {+		EditPoint prev;+		bool inside = false;+		+		if (path.points.size <= 1) {+			return false;+		}++		if (!(path.xmin <= point.x <= path.xmax)) {+			return false;+		}+		+		if (!(path.ymin <= point.y <= path.ymax)) {+			return false;+		}+				+		prev = path.points.get (path.points.size - 1);+		+		foreach (EditPoint p in path.points) {+			if  ((p.y > point.y) != (prev.y > point.y) +				&& point.x < (prev.x - p.x) * (point.y - p.y) / (prev.y - p.y) + p.x) {+				inside = !inside;+			}+			+			prev = p;+		}+		+		return inside;+	}++	/** Add space as separator to svg data. +	 * @param d svg data+	 */+	static string add_separators (string d) {+		string data = d;+		+		data = data.replace (",", " ");+		data = data.replace ("a", " a ");+		data = data.replace ("A", " A ");+		data = data.replace ("m", " m ");+		data = data.replace ("M", " M ");+		data = data.replace ("h", " h ");+		data = data.replace ("H", " H ");+		data = data.replace ("v", " v ");+		data = data.replace ("V", " V ");+		data = data.replace ("l", " l ");+		data = data.replace ("L", " L ");+		data = data.replace ("q", " q ");+		data = data.replace ("Q", " Q ");		+		data = data.replace ("c", " c ");+		data = data.replace ("C", " C ");+		data = data.replace ("t", " t ");+		data = data.replace ("T", " T ");+		data = data.replace ("s", " s ");+		data = data.replace ("S", " S ");+		data = data.replace ("zM", " z M ");+		data = data.replace ("zm", " z m ");+		data = data.replace ("z", " z ");+		data = data.replace ("Z", " Z ");+		data = data.replace ("-", " -");+		data = data.replace ("e -", "e-"); // minus can be either separator or a negative exponent+		data = data.replace ("\t", " ");+		data = data.replace ("\r\n", " ");+		data = data.replace ("\n", " ");+		+		// use only a single space as separator+		while (data.index_of ("  ") > -1) {+			data = data.replace ("  ", " ");+		}+		+		return data;+	}+	+	public void add_path_to_glyph (string d, Glyph g, bool svg_glyph = false, double units = 1) {+		PathList p = parse_svg_data (d, g, svg_glyph, units);+		foreach (Path path in p.paths) {+			g.add_path (path);+		}+	}+	+	/** +	 * @param d svg data+	 * @param glyph use lines from this glyph but don't add the generated paths+	 * @param svg_glyph parse svg glyph with origo in lower left corner+	 * +	 * @return the new paths+	 */+	public PathList parse_svg_data (string d, Glyph glyph, bool svg_glyph = false, double units = 1) {+		double px = 0;+		double py = 0;+		double px2 = 0;+		double py2 = 0;+		double cx = 0;+		double cy = 0;+		string data;+		Font font;+		PathList path_list = new PathList ();+		BezierPoints[] bezier_points;+		string[] c;+		double arc_rx, arc_ry;+		double arc_rotation;+		int large_arc;+		int arc_sweep;+		double arc_dest_x, arc_dest_y;++		font = BirdFont.get_current_font ();+		+		data = add_separators (d);+		c = data.split (" ");+		bezier_points = new BezierPoints[8 * c.length + 1]; // the arc instruction can use up to eight points+		+		for (int i = 0; i < 2 * c.length + 1; i++) {+			bezier_points[i] = new BezierPoints ();+		}+		+		int bi = 0;+		+		// parse path+		int i = -1;+		while (++i < c.length && bi < bezier_points.length) {	+			if (c[i] == "m") {+				while (i + 2 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'M';+					bezier_points[bi].svg_type = 'm';+					+					px += parse_double (c[++i]);+					+					if (svg_glyph) {+						py += parse_double (c[++i]);+					} else {+						py += -parse_double (c[++i]);+					}+					+					bezier_points[bi].x0 = px;+					bezier_points[bi].y0 = py;+					bi++;+				}+			} else if (c[i] == "M") {+				while (i + 2 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'M';+					bezier_points[bi].svg_type = 'M';+					+					px = parse_double (c[++i]);+					+					if (svg_glyph) {+						py = parse_double (c[++i]);+					} else {+						py = -parse_double (c[++i]);+					}+					+					bezier_points[bi].x0 = px;+					bezier_points[bi].y0 = py;+					bi++;+				}+			} else if (c[i] == "h") {+				while (i + 1 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'L';+					bezier_points[bi].svg_type = 'h';+					+					px += parse_double (c[++i]);++					bezier_points[bi].x0 = px;+					bezier_points[bi].y0 = py;+					bi++;+				}+			} else if (i + 1 < c.length && c[i] == "H") {+				while (is_point (c[i + 1])) {+					bezier_points[bi].type = 'L';+					bezier_points[bi].svg_type = 'H';+					+					px = parse_double (c[++i]);++					bezier_points[bi].x0 = px;+					bezier_points[bi].y0 = py;+					bi++;+				}+			} else if (c[i] == "v") {+				while (i + 1 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'L';+					bezier_points[bi].svg_type = 'v';+										+					if (svg_glyph) {+						py = py + parse_double (c[++i]);+					} else {+						py = py - parse_double (c[++i]);+					}+					+					bezier_points[bi].x0 = px;+					bezier_points[bi].y0 = py;+					bi++;+				}				+			} else if (i + 1 < c.length && c[i] == "V") {+				while (is_point (c[i + 1])) {+					bezier_points[bi].type = 'L';+					bezier_points[bi].svg_type = 'V';+										+					if (svg_glyph) {+						py = parse_double (c[++i]);+					} else {+						py = -parse_double (c[++i]);+					}+					+					bezier_points[bi].x0 = px;+					bezier_points[bi].y0 = py;+					bi++;+				}+			} else if (c[i] == "l") {+				while (i + 2 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'L';+					bezier_points[bi].svg_type = 'l';+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					px = cx;+					py = cy;++					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+					bi++;+				}+			} else if (c[i] == "L") {+				while (i + 2 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'L';+					bezier_points[bi].svg_type = 'L';+										+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					px = cx;+					py = cy;+					+					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+					bi++;				+				}	+			} else if (c[i] == "c") {+				while (i + 6 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'C';+					bezier_points[bi].svg_type = 'C';+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					px2 = cx;+					py2 = cy;+										+					bezier_points[bi].x1 = px2;+					bezier_points[bi].y1 = py2;+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py + -parse_double (c[++i]);+					}+					+					bezier_points[bi].x2 = cx;+					bezier_points[bi].y2 = cy;+										+					px = cx;+					py = cy;+					+					bi++;+				}+			} else if (c[i] == "C") {+				while (i + 6 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'C';+					bezier_points[bi].svg_type = 'C';+										+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+									+					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+					+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					px2 = cx;+					py2 = cy;+					+					bezier_points[bi].x1 = cx;+					bezier_points[bi].y1 = cy;+										+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					bezier_points[bi].x2 = cx;+					bezier_points[bi].y2 = cy;+										+					px = cx;+					py = cy;+					+					bi++;				+				}	+			} else if (c[i] == "q") {+				while (i + 4 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'Q';+					bezier_points[bi].svg_type = 'q';+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+										+					px2 = cx;+					py2 = cy;+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					bezier_points[bi].x1 = cx;+					bezier_points[bi].y1 = cy;+										+					px = cx;+					py = cy;+					+					bi++;+				}+			} else if (c[i] == "Q") {++				while (i + 4 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'Q';+					bezier_points[bi].svg_type = 'Q';+										+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+					+					px2 = cx;+					py2 = cy;+										+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					px = cx;+					py = cy;++					bezier_points[bi].x1 = cx;+					bezier_points[bi].y1 = cy;+										+					bi++;					+				}	+			} else if (c[i] == "t") {+				while (i + 2 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'Q';+					bezier_points[bi].svg_type = 't';+										+					// the first point is the reflection+					cx = 2 * px - px2;+					cy = 2 * py - py2; // if (svg_glyph) ?+					+					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+					+					px2 = cx;+					py2 = cy;+										+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					px = cx;+					py = cy;+					+					bezier_points[bi].x1 = px;+					bezier_points[bi].y1 = py;+										+					bi++;+				}+			} else if (c[i] == "T") {+				while (i + 2 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'Q';+					bezier_points[bi].svg_type = 'T';+										+					// the reflection+					cx = 2 * px - px2;+					cy = 2 * py - py2; // if (svg_glyph) ?+					+					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+										+					px2 = cx;+					py2 = cy;+					+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					px = cx;+					py = cy;+					+					bezier_points[bi].x1 = px;+					bezier_points[bi].y1 = py;+										+					bi++;				+				}+			} else if (c[i] == "s") {+				while (i + 4 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'C';+					bezier_points[bi].svg_type = 's';+										+					// the first point is the reflection+					cx = 2 * px - px2;+					cy = 2 * py - py2; // if (svg_glyph) ?++					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+															+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					px2 = cx;+					py2 = cy;+					+					bezier_points[bi].x1 = px2;+					bezier_points[bi].y1 = py2;+					+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					bezier_points[bi].x2 = cx;+					bezier_points[bi].y2 = cy;+												+					px = cx;+					py = cy;+					+					bi++;+				}+			} else if (c[i] == "S") {+				while (i + 4 < c.length && is_point (c[i + 1])) {+					bezier_points[bi].type = 'C';+					bezier_points[bi].svg_type = 'S';+										+					// the reflection+					cx = 2 * px - px2;+					cy = 2 * py - py2; // if (svg_glyph) ?			++					bezier_points[bi].x0 = cx;+					bezier_points[bi].y0 = cy;+					+					// the other two are regular cubic points+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					px2 = cx;+					py2 = cy;+					+					bezier_points[bi].x1 = px2;+					bezier_points[bi].y1 = py2;+					+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					bezier_points[bi].x2 = cx;+					bezier_points[bi].y2 = cy;+					+					px = cx;+					py = cy;	+					+					bi++;				+				}+			} else if (c[i] == "a") {+				while (i + 7 < c.length && is_point (c[i + 1])) {					+					arc_rx = parse_double (c[++i]);+					arc_ry = parse_double (c[++i]);+					+					arc_rotation = parse_double (c[++i]);+					large_arc = parse_int (c[++i]);+					arc_sweep = parse_int (c[++i]);+							+					cx = px + parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = py + parse_double (c[++i]);+					} else {+						cy = py - parse_double (c[++i]);+					}+					+					arc_dest_x = cx;+					arc_dest_y = cy;+					+					add_arc_points (bezier_points, ref bi, px, py, arc_rx, arc_ry, arc_rotation, large_arc == 1, arc_sweep == 1, cx, cy);+					+					px = cx;+					py = cy;+					+					+				}+			} else if (i + 7 < c.length && c[i] == "A") {+				while (is_point (c[i + 1])) {					+					arc_rx = parse_double (c[++i]);+					arc_ry = parse_double (c[++i]);+					+					arc_rotation = parse_double (c[++i]);+					large_arc = parse_int (c[++i]);+					arc_sweep = parse_int (c[++i]);+							+					cx = parse_double (c[++i]);+					+					if (svg_glyph) {+						cy = parse_double (c[++i]);+					} else {+						cy = -parse_double (c[++i]);+					}+					+					arc_dest_x = cx;+					arc_dest_y = cy;+					+					add_arc_points (bezier_points, ref bi, px, py, arc_rx, arc_ry, arc_rotation, large_arc == 1, arc_sweep == 1, cx, cy);++					px = cx;+					py = cy;+					+					+				}+			} else if (c[i] == "z") {+				bezier_points[bi].type = 'z';+				bezier_points[bi].svg_type = 'z';+				+				bi++;+			} else if (c[i] == "Z") {+				bezier_points[bi].type = 'z';+				bezier_points[bi].svg_type = 'z';+									+				bi++;+			} else if (c[i] == "") {+			} else if (c[i] == " ") {+			} else {+				warning (@"Unknown instruction: $(c[i])");+			}+		}+		+		if (bi == 0) {+			warning ("No points in path.");+			return path_list;	+		}+		+		move_and_resize (bezier_points, bi, svg_glyph, units, glyph);+		+		if (format == SvgFormat.ILLUSTRATOR) {+			path_list = create_paths_illustrator (bezier_points, bi);+		} else {+			path_list = create_paths_inkscape (bezier_points, bi);+		}++		// TODO: Find out if it is possible to tie handles.+		return path_list;+	}++	void move_and_resize (BezierPoints[] b, int num_b, bool svg_glyph, double units, Glyph glyph) {+		Font font = BirdFont.get_current_font ();+		+		for (int i = 0; i < num_b; i++) {+			// resize all points+			b[i].x0 *= units;+			b[i].y0 *= units;+			b[i].x1 *= units;+			b[i].y1 *= units;+			b[i].x2 *= units;+			b[i].y2 *= units;++			// move all points+			if (svg_glyph) {+				b[i].x0 += glyph.left_limit;+				b[i].y0 += font.base_line;+				b[i].x1 += glyph.left_limit;+				b[i].y1 += font.base_line;+				b[i].x2 += glyph.left_limit;+				b[i].y2 += font.base_line;+			} else {+				b[i].x0 += glyph.left_limit;+				b[i].y0 += font.top_position;+				b[i].x1 += glyph.left_limit;+				b[i].y1 += font.top_position;+				b[i].x2 += glyph.left_limit;+				b[i].y2 += font.top_position;+			}+		}+	}+	+	void find_last_handle (int start_index, BezierPoints[] b, int num_b, out double left_x, out double left_y, out PointType last_type) {+		BezierPoints last = new BezierPoints ();+		bool found = false;+		+		left_x = 0;+		left_y = 0;+		last_type = PointType.NONE;+		+		return_if_fail (b.length != 0);+		return_if_fail (b[0].type != 'z');+		return_if_fail (num_b < b.length);++		if (num_b == 2) {+			left_x = b[0].x0 + (b[1].x0 - b[0].x0) / 3.0;+			left_y = b[0].y0 + (b[1].y0 - b[0].y0) / 3.0;+			last_type = PointType.LINE_CUBIC;+			return;+		}+		+		for (int i = start_index; i < num_b; i++) {+			switch (b[i].type) {+				case 'Q':+					break;+				case 'C':+					break;+				case 'z':+					found = true;+					break;+				default:+					break;+			}+			+			if (found || i + 1 == num_b) {+				+				return_if_fail (i >= 1);+				+				if (b[i - 1].type == 'Q') {+					return_if_fail (i >= 1);+					left_x = b[i - 1].x0;+					left_y = b[i - 1].y0;+					last_type = PointType.QUADRATIC;+				} else if (b[i - 1].type == 'C') {+					return_if_fail (i >= 1);+					left_x = b[i - 1].x1;+					left_y = b[i - 1].y1;+					last_type = PointType.CUBIC;+				} else if (b[i - 1].type == 'S') {+					return_if_fail (i >= 1);+					left_x = b[i - 1].x1;+					left_y = b[i - 1].y1;+					last_type = PointType.CUBIC;+				} else if (b[i - 1].type == 'L' || last.type == 'M') {+					return_if_fail (i >= 2); // FIXME: -2 can be C or L+					left_x = b[i - 2].x0 + (b[i - 1].x0 - b[i - 2].x0) / 3.0;+					left_y = b[i - 2].y0 + (b[i - 1].y0 - b[i - 2].y0) / 3.0;+					last_type = PointType.LINE_CUBIC;+				} else {+					warning (@"Unexpected type. $(b[i - 1])\n");+				}+				return;	+			}+			+			last = b[i];+		}+		+		warning ("Last point not found.");+	}++	PathList create_paths_inkscape (BezierPoints[] b, int num_b) {+		double last_x;+		double last_y; +		PointType last_type;+		Path path;+		PathList path_list = new PathList ();+		EditPoint ep = new EditPoint ();+		Gee.ArrayList<EditPoint> smooth_points = new Gee.ArrayList<EditPoint> ();+				+		path = new Path ();+		+		if (num_b == 0) {+			warning ("No SVG data");+			return path_list;+		}++		if (b[0].type != 'M') {+			warning ("Path must begin with M or m.");+			return path_list;+		}+		+		find_last_handle (0, b, num_b, out last_x, out last_y, out last_type);++		for (int i = 0; i < num_b; i++) {+			if (b[i].type == '\0') {+				warning ("Parser error.");+				return path_list;+			}++			if (b[i].type == 'z') {+				path.close ();+				path.create_list ();+				path.recalculate_linear_handles ();+				path_list.add (path);+				path = new Path ();+				+				if (i + 1 >= num_b) {+					break;+				} else {+					find_last_handle (i + 1, b, num_b, out last_x, out last_y, out last_type);+				}+			}+			+			if (i >= num_b) {+				break;+			}+			+			if (b[i].type == 'M') {+				ep = path.add (b[i].x0, b[i].y0);+				ep.set_point_type (PointType.CUBIC);++				ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);+				+				if (i == 0 || (b[i - 1].type == 'z')) {+					ep.get_left_handle ().set_point_type (last_type);+					ep.get_left_handle ().move_to_coordinate (last_x, last_y);+				} else {+					if (b[i - 1].type == 'C' || b[i - 1].type == 'S') {+						ep.get_left_handle ().set_point_type (PointType.CUBIC);+						ep.get_left_handle ().move_to_coordinate (b[i + 1].x1, b[i + 1].y1);+					} +					+					if (b[i + 1].type == 'C' || b[i - 1].type == 'S') {+						ep.get_right_handle ().set_point_type (PointType.CUBIC);+						ep.get_right_handle ().move_to_coordinate (b[i + 1].x0, b[i + 1].y0);+					} else if (b[i + 1].type == 'L' || b[i + 1].type == 'M') {+						ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);					+					}+				}+			}++			if (b[i].type == 'L') {+				return_val_if_fail (i != 0, path_list);+				+				ep = path.add (b[i].x0, b[i].y0);+				ep.set_point_type (PointType.CUBIC);+				ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);+				ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);++				if (b[i + 1].type == 'L' || b[i + 1].type == 'M' || b[i + 1].type == 'z') {+					ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);+				}++				if (b[i -1].type == 'L' || b[i - 1].type == 'M') {+					ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);+				}+			}+			+			if (b[i].type == 'Q') {+				return_val_if_fail (i != 0, path_list);++				ep.set_point_type (PointType.QUADRATIC);+				+				ep.get_right_handle ().set_point_type (PointType.QUADRATIC);+				ep.get_right_handle ().move_to_coordinate (b[i].x0, b[i].y0);+				+				if (b[i + 1].type != 'z') {+					ep = path.add (b[i].x1, b[i].y1);++					ep.get_left_handle ().set_point_type (PointType.QUADRATIC);+					ep.get_left_handle ().move_to_coordinate (b[i].x0, b[i].y0);+				}+			}+	+			if (b[i].type == 'C' || b[i].type == 'S') {+				return_val_if_fail (i != 0, path_list);++				ep.set_point_type (PointType.CUBIC);+				+				ep.get_right_handle ().set_point_type (PointType.CUBIC);+				ep.get_right_handle ().move_to_coordinate (b[i].x0, b[i].y0);+				+				if (b[i].type == 'S') {+					smooth_points.add (ep);+				}+				+				if (b[i + 1].type != 'z') {+					ep = path.add (b[i].x2, b[i].y2);++					ep.get_left_handle ().set_point_type (PointType.CUBIC);+					ep.get_left_handle ().move_to_coordinate (b[i].x1, b[i].y1);+				}+			}+		}++		foreach (EditPoint e in smooth_points) {+			e.set_point_type (PointType.LINE_DOUBLE_CURVE);+			e.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+			e.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+		}++		foreach (EditPoint e in smooth_points) {+			path.recalculate_linear_handles_for_point (e);+		}+		+		for (int i = 0; i < 3; i++) {+			foreach (EditPoint e in smooth_points) {+				e.set_tie_handle (true);+				e.process_tied_handle ();+			}+		}+		+		if (path.points.size > 0) {+			path_list.add (path);+		}++		foreach (Path p in path_list.paths) {+			p.remove_points_on_points ();+		}+				+		return path_list;+	}++	PathList create_paths_illustrator (BezierPoints[] b, int num_b) {+		Path path;+		PathList path_list = new PathList ();+		EditPoint ep;+		bool first_point = true;+		double first_left_x, first_left_y;+		Gee.ArrayList<EditPoint> smooth_points = new Gee.ArrayList<EditPoint> ();+		+		if (num_b > b.length) {+			warning ("num_b > b.length: $num_b > $(b.length)");+			return path_list;+		}+		+		path = new Path ();+				+		if (num_b <= 1) {+			warning ("No SVG data");+			return path_list;+		}+		+		first_left_x = 0;+		first_left_y = 0;++		// FIXME: array boundaries+		for (int i = 0; i < num_b; i++) {			+			if (b[i].type == '\0') {+				warning ("Parser error.");+				return path_list;+			} else if (b[i].type == 'z') {+				path.close ();+				path.create_list ();+				+				int first_index = 1;++				for (int j = i - 1; j >= 1; j--) {+					if (b[j].type == 'z') {+						first_index = j + 1; // from z to M +					}+				}+				+				if (b[first_index].type == 'C' || b[first_index].type == 'S') {+					return_val_if_fail (path.points.size != 0, path_list);+					ep = path.points.get (path.points.size - 1);+					+					if (b[i - 1].type != 'L' ) {+						ep.get_right_handle ().set_point_type (PointType.CUBIC);+						ep.get_right_handle ().move_to_coordinate (b[first_index].x0, b[first_index].y0);+					}+				} else if (b[first_index].type == 'L') {+					return_val_if_fail (path.points.size != 0, path_list);+					ep = path.points.get (path.points.size - 1);+					ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);+					path.recalculate_linear_handles_for_point (ep);+				} else {+					warning ("Unexpected type: %s", (!) b[first_index].type.to_string ());+				}+				+				path.recalculate_linear_handles ();+				path_list.add (path);+				+				path = new Path ();+				first_point = true;				+			} else if (b[i].type == 'M') {+			} else if (b[i].type == 'L') {++				if (first_point) {+					first_left_x = b[i].x0;+					first_left_y = b[i].y0;+				}+				+				ep = path.add (b[i].x0, b[i].y0);+				ep.set_point_type (PointType.LINE_CUBIC); // TODO: quadratic+				ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);++				if (b[i -1].type == 'L' || first_point) {+					// ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);+				}+				+				if (b[i + 1].type == 'C' || b[i + 1].type == 'S') {+					return_val_if_fail (i + 1 < num_b, path_list);+					ep.get_right_handle ().set_point_type (PointType.CUBIC);+					ep.get_right_handle ().move_to_coordinate (b[i + 1].x0, b[i + 1].y0);+				}+				+				first_point = false;+			} else if (b[i].type == 'Q') {+				warning ("Illustrator does not support quadratic control points.");+				warning (@"$(b[i])\n");+			} else if (b[i].type == 'C' || b[i].type == 'S') {+				+				if (first_point) {+					first_left_x = b[i].x0;+					first_left_y = b[i].y0;+				}+				+				ep = path.add (b[i].x2, b[i].y2);+				ep.set_point_type (PointType.CUBIC);++				ep.get_right_handle ().set_point_type (PointType.CUBIC);+				ep.get_left_handle ().set_point_type (PointType.CUBIC);+				+				ep.get_left_handle ().move_to_coordinate (b[i].x1, b[i].y1);++				if (b[i].type == 'S') {+					smooth_points.add (ep);+				}		++				if (b[i + 1].type != 'z') {+					ep.get_right_handle ().move_to_coordinate (b[i + 1].x0, b[i + 1].y0);+				} else {+					ep.get_right_handle ().move_to_coordinate (first_left_x, first_left_y);+				}+								+				first_point = false;+			} else {+				warning ("Unknown control point type.");+				warning (@"$(b[i])\n");+			}+		}+		+		foreach (EditPoint e in smooth_points) {+			e.set_point_type (PointType.LINE_DOUBLE_CURVE);+			e.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+			e.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);+		}++		foreach (EditPoint e in smooth_points) {+			path.recalculate_linear_handles_for_point (e);+		}+		+		for (int i = 0; i < 3; i++) {+			foreach (EditPoint e in smooth_points) {+				e.set_tie_handle (true);+				e.process_tied_handle ();+			}+		}+				+		if (path.points.size > 0) {+			path_list.add (path);+		}+		+		foreach (Path p in path_list.paths) {+			p.remove_points_on_points ();+		}+		+		return path_list;+	}+	+	// TODO: implement a default svg parser++	static int parse_int (string? s) {+		if (is_null (s)) {+			warning ("null instead of string");+			return 0;+		}+		+		if (!is_point ((!) s)) {+			warning (@"Expecting an integer got: $((!) s)");+			return 0;+		}+		+		return int.parse ((!) s);+	}+	+	static double parse_double (string? s) {+		if (is_null (s)) {+			warning ("Got null instead of expected string.");+			return 0;+		}+		+		if (!is_point ((!) s)) {+			warning (@"Expecting a double got: $((!) s)");+			return 0;+		}+		+		return double.parse ((!) s);+	}+	+	static bool is_point (string? s) {+		if (s == null) {+			warning ("s is null");+			return false;+		}+		+		return double.try_parse ((!) s);+	}+	+	Path parse_poly_data (string polygon_points) {+		string data = add_separators (polygon_points);+		string[] c = data.split (" ");+		Path path;+		BezierPoints[] bezier_points = new BezierPoints[c.length + 1];+		int bi;+		Glyph g;+		EditPoint ep;+		+		bi = 0;+		for (int i = 0; i < c.length - 1; i += 2) {	+			if (i + 1 >= c.length) {+				warning ("No y value.");+				break;+			}++			if (bi >= bezier_points.length) {+				warning ("End of bezier_points");+				break;+			}++			bezier_points[bi] = new BezierPoints ();+			bezier_points[bi].type == 'L';+			bezier_points[bi].x0 = parse_double (c[i]);+			bezier_points[bi].y0 = -parse_double (c[i + 1]);+			bi++;+		}+			+		g = MainWindow.get_current_glyph ();+		move_and_resize (bezier_points, bi, false, 1, g);+		+		path = new Path ();+		for (int i = 0; i < bi; i++) {	+			ep = path.add (bezier_points[i].x0, bezier_points[i].y0);+			ep.set_point_type (PointType.LINE_CUBIC);+		}+		+		path.create_list ();+		path.recalculate_linear_handles ();+		+		return path;+	}+}++}diff --git a/libbirdfont/Svg/SvgStyle.vala b/libbirdfont/Svg/SvgStyle.valanew file mode 100644index 0000000..33a6cdc--- /dev/null+++ b/libbirdfont/Svg/SvgStyle.vala@@ -0,0 +1,124 @@+/*+	Copyright (C) 2015 Johan Mattsson++	This library is free software; you can redistribute it and/or modify +	it under the terms of the GNU Lesser General Public License as +	published by the Free Software Foundation; either version 3 of the +	License, or (at your option) any later version.++	This library 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 +	Lesser General Public License for more details.+*/++using B;+using Math;++namespace BirdFont {++public class SvgStyle {+	+	Gee.HashMap<string, string> style;+	+	public SvgStyle () {+		style = new Gee.HashMap<string, string> ();+	}+	+	public LineCap get_line_cap () {+		string l;+		+		if (!style.has_key ("stroke-linecap")) {+			return LineCap.BUTT;+		}+		+		l = style.get ("stroke-linecap");+		+		if (l == "round") {+			return LineCap.ROUND;+		} else if (l == "square") {+			return LineCap.SQUARE;+		}+		+		return LineCap.BUTT; 	+	}+	+	public bool has_stroke () {+		bool s = true;+		+		if (style.has_key ("stroke")) {+			s = style.get ("stroke") != "none";+		}+				+		return get_stroke_width () > 0 && s;+	}+		+	public double get_stroke_width () {+		if (!style.has_key ("stroke-width")) {+			return 0;+		}++		return double.parse (style.get ("stroke-width"));+	}+	+	+	public static SvgStyle parse (Attributes attributes) {+		SvgStyle s = new SvgStyle ();+		+		foreach (Attribute a in attributes) {+			if (a.get_name () == "style") {+				s.parse_key_value_pairs (a.get_content ());+			}+			+			if (a.get_name () == "stroke-width") {+				s.style.set ("stroke-width", a.get_content ());+			}++			if (a.get_name () == "stroke") {+				s.style.set ("stroke", a.get_content ());+			}++			if (a.get_name () == "fill") {+				s.style.set ("fill", a.get_content ());+			}+		}+		+		return s;+	}+	+	void parse_key_value_pairs (string svg_style) {+		string[] p = svg_style.split (";");+		string[] pair;+		string k, v;+		+		foreach (string kv in p) {+			pair = kv.split (":");+			+			if (pair.length != 2) {+				warning ("pair.length != 2");+				continue;+			}+			+			k = pair[0];+			v = pair[1];+			+			style.set (k, v);+		}+	}+	+	public void apply (PathList path_list) {+		foreach (Path p in path_list.paths) {+			if (has_stroke ()) {+				p.stroke = get_stroke_width ();+			} else {+				p.stroke = 0;+			}+			+			p.line_cap = get_line_cap ();+			p.reset_stroke ();+			p.update_region_boundaries ();		+		}+	}+}++}diff --git a/libbirdfont/SvgArc.vala b/libbirdfont/SvgArc.valadeleted file mode 100644index 92f3689..0000000--- a/libbirdfont/SvgArc.vala+++ /dev/null@@ -1,181 +0,0 @@-/*- * BirdFont code from SVG Salamander- * - * Copyright (c) 2004, Mark McKay- * Copyright (c) 2014, Johan Mattsson- * All rights reserved.- *- * Redistribution and use in source and binary forms, with or - * without modification, are permitted provided that the following- * conditions are met:- *- *   - Redistributions of source code must retain the above - *     copyright notice, this list of conditions and the following- *     disclaimer.- *   - Redistributions in binary form must reproduce the above- *     copyright notice, this list of conditions and the following- *     disclaimer in the documentation and/or other materials - *     provided with the distribution.- *- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT- * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS- * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE- * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,- * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES- * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,- * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)- * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED- * OF THE POSSIBILITY OF SUCH DAMAGE. - * - * Mark McKay can be contacted at mark@kitfox.com.  Salamander and other- * projects can be found at http://www.kitfox.com- *- * Created on January 26, 2004, 8:40 PM- * Adapded to BirdFont on Juli 2, 2014, 5:01 PM- */--using Math;--namespace BirdFont {--/** Convert an SVG arc instruction to a Beziรฉr path. */-static void add_arc_points (BezierPoints[] bezier_points, ref int bi, double x0, double y0, double rx, double ry, double angle, bool largeArcFlag, bool sweepFlag, double x, double y) {--	//-	// Elliptical arc implementation based on the SVG specification notes-	//--	double dx2, dy2, cosAngle, sinAngle;-	double x1, y1, Prx, Pry, Px1, Py1, radiiCheck;-	double sign, sq, coef, cx1, cy1;-	double sx2, sy2, cx, cy;-	double ux, uy, vx, vy, p, n;-	double angleStart, angleExtent;-	double s, step, theta;-	-	// Compute the half distance between the current and the final point-	dx2 = (x0 - x) / 2.0;-	dy2 = (y0 - y) / 2.0;-	-	// Convert angle from degrees to radians-	angle = 2 * PI * ((angle % 360.0) / 360.0);-	-	cosAngle = cos (angle);-	sinAngle = sin (angle);--	//-	// Step 1 : Compute (x1, y1)-	//-	x1 = cosAngle * dx2 + sinAngle * dy2;-	y1 = -sinAngle * dx2 + cosAngle * dy2;-	-	// Ensure radii are large enough-	rx = fabs(rx);-	ry = fabs(ry);-	Prx = rx * rx;-	Pry = ry * ry;-	Px1 = x1 * x1;-	Py1 = y1 * y1;--	-	// Check that radii are large enough-	radiiCheck = Px1 / Prx + Py1 / Pry;-	-	if (radiiCheck > 1) {-		rx = sqrt (radiiCheck) * rx;-		ry = sqrt (radiiCheck) * ry;-		Prx = rx * rx;-		Pry = ry * ry;-	}--	//-	// Step 2 : Compute (cx1, cy1)-	//-	sign = (largeArcFlag == sweepFlag) ? -1 : 1;-	sq = ((Prx * Pry) - (Prx * Py1) - (Pry * Px1)) / ((Prx * Py1) + (Pry * Px1));-	sq = (sq < 0) ? 0 : sq;-	coef = (sign * Math.sqrt(sq));-	cx1 = coef * ((rx * y1) / ry);-	cy1 = coef * -((ry * x1) / rx);--	//-	// Step 3 : Compute (cx, cy) from (cx1, cy1)-	//-	-	sx2 = (x0 + x) / 2.0;-	sy2 = (y0 + y) / 2.0;-	cx = sx2 - (cosAngle * cx1 - sinAngle * cy1);-	cy = sy2 - (sinAngle * cx1 + cosAngle * cy1);--	//-	// Step 4 : Compute the angleStart (angle1) and the angleExtent (dangle)-	//-	-	ux = (x1 - cx1) / rx;-	uy = (y1 - cy1) / ry;-	vx = (-x1 - cx1) / rx;-	vy = (-y1 - cy1) / ry;--	// Compute the angle start-	n = sqrt((ux * ux) + (uy * uy));-	p = ux; // (1 * ux) + (0 * uy)-	sign = (uy < 0) ? -1d : 1d;-	angleStart = sign * acos(p / n);--	// Compute the angle extent-	n = Math.sqrt((ux * ux + uy * uy) * (vx * vx + vy * vy));-	p = ux * vx + uy * vy;-	sign = (ux * vy - uy * vx < 0) ? -1d : 1d;-	angleExtent = sign * Math.acos(p / n);-	-	if(!sweepFlag && angleExtent > 0) {-		angleExtent -= 2 *PI;-	} else if (sweepFlag && angleExtent < 0) {-		angleExtent += 2 *PI;-	}-	angleExtent %= 2 * PI;-	angleStart %= 2 * PI;--	angleExtent *= -1;-	angleStart *= -1;-	-	// Approximate the path with Beziรฉr points-	s = (angleExtent > 0) ? 1 : -1;-	step = fabs (angleExtent) / (2 * fabs (angleExtent));--	theta = PI - angleStart - angleExtent;-	-	bezier_points[bi].type = 'L';-	bezier_points[bi].svg_type = 'a';--	bezier_points[bi].x0 = cx + rx * cos (theta);-	bezier_points[bi].y0 = cy + ry * sin (theta);-									-	bi++;-					-	for (double a = 0; a < fabs (angleExtent); a += step) {-		theta = PI - angleStart - angleExtent + s * a;--		return_if_fail (0 <= bi < bezier_points.length);--		bezier_points[bi].type = 'S';-		bezier_points[bi].svg_type = 'a';--		bezier_points[bi].x0 = cx + rx * cos (theta);-		bezier_points[bi].y0 = cy + ry * sin (theta);--		bezier_points[bi].x1 = cx + rx * cos (theta + 1 * step / 4);-		bezier_points[bi].y1 = cy + ry * sin (theta + 1 * step / 4);-		-		bezier_points[bi].x2 = cx + rx * cos (theta + 2 * step / 4);-		bezier_points[bi].y2 = cy + ry * sin (theta + 2 * step / 4);-						-		bi++;-	}-}--}-	diff --git a/libbirdfont/SvgFont.vala b/libbirdfont/SvgFont.valadeleted file mode 100644index 7223c2f..0000000--- a/libbirdfont/SvgFont.vala+++ /dev/null@@ -1,264 +0,0 @@-/*-	Copyright (C) 2013 2014 Johan Mattsson--	This library is free software; you can redistribute it and/or modify -	it under the terms of the GNU Lesser General Public License as -	published by the Free Software Foundation; either version 3 of the -	License, or (at your option) any later version.--	This library 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 -	Lesser General Public License for more details.-*/--using B;--namespace BirdFont {--class SvgFont : GLib.Object {-	Font font;-	double units = 1;-	double font_advance = 0;-	-	public SvgFont (Font f) {-		this.font = f;-	}-	-	/** Load svg font from file. */-	public void load (string path) {-		string data;-		XmlParser xml_parser;-		try {-			FileUtils.get_contents (path, out data);-			xml_parser = new XmlParser (data);-			parse_svg_font (xml_parser.get_root_tag ());-		} catch (GLib.Error e) {-			warning (e.message);-		}-	}-	-	void parse_svg_font (Tag tag) {-		foreach (Tag t in tag) {-			if (t.get_name () == "defs") {-				parse_svg_font (t);-			}-			-			if (t.get_name () == "font") {-				parse_font_tag (t);-				parse_svg_font (t);-			}--			if (t.get_name () == "font-face") {-				parse_font_limits (t);-			}--			if (t.get_name () == "hkern") {-				parse_hkern (t);-			}-									-			if (t.get_name () == "glyph") {-				parse_glyph (t);-			}-		}		-	}--	void parse_hkern (Tag tag) {-		string left = "";-		string right = "";-		string left_name = "";-		string right_name = "";-		double kerning = 0;-		unichar l, r;-		StringBuilder sl, sr;-		GlyphRange grr, grl;-		KerningClasses classes = BirdFont.get_current_font ().get_kerning_classes ();-		-		foreach (Attribute attr in tag.get_attributes ()) {-			// left-			if (attr.get_name () == "u1") {-				left = attr.get_content ();-			}	-					-			// right	-			if (attr.get_name () == "u2") {-				right = attr.get_content ();-			}--			if (attr.get_name () == "g1") {-				left_name = attr.get_content ();-			}-			-			if (attr.get_name () == "g2") {-				right_name = attr.get_content ();-			}-				-			// kerning-			if (attr.get_name () == "k") {-				kerning = double.parse (attr.get_content ()) * units;-			}-		}-				-		// FIXME: ranges and sequences for u1 & u2 + g1 & g2-		foreach (string lk in left.split (",")) {-			foreach (string rk in right.split (",")) {-				l = get_unichar (lk);-				r = get_unichar (rk);-				-				sl = new StringBuilder ();-				sl.append_unichar (l);-				-				sr = new StringBuilder ();-				sr.append_unichar (r);-				-				try {-					grl = new GlyphRange ();-					grl.parse_ranges (sl.str);-					-					grr = new GlyphRange ();-					grr.parse_ranges (sr.str);-				-					classes.set_kerning (grl, grr, -kerning);-				} catch (MarkupError e) {-					warning (e.message);-				}		-			}-		}-	}--	void parse_font_limits (Tag tag) {-		double top_limit = 0;-		double bottom_limit = 0;-		-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "units-per-em") {-				units = 100.0 / double.parse (attr.get_content ());-			}	-		}--		foreach (Attribute attr in tag.get_attributes ()) {	-			if (attr.get_name () == "ascent") {-				top_limit = double.parse (attr.get_content ());-			}-			-			if (attr.get_name () == "descent") {-				bottom_limit = double.parse (attr.get_content ());-			}		-		}-		-		top_limit *= units;-		bottom_limit *= units;-		-		font.bottom_limit = bottom_limit;-		font.top_limit = top_limit;-	}-	-	void parse_font_tag (Tag tag) {-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "horiz-adv-x") {-				font_advance = double.parse (attr.get_content ());-			}-						-			if (attr.get_name () == "id") {-				font.set_name (attr.get_content ());-			}-		}-	}-	-	/** Obtain unichar value from either a character, a hex representation of-	 *  a character or series of characters (f, &#x6d; or ffi).-	 */-	static unichar get_unichar (string val) {-		string v = val;-		unichar unicode_value;-		-		if (val == "&") {-			return '&';-		}-		-		// TODO: parse ligatures-		if (v.has_prefix ("&")) {-			// parse hex value-			v = v.substring (0, v.index_of (";"));-			v = v.replace ("&#x", "U+");-			v = v.replace (";", "");-			unicode_value = Font.to_unichar (v);-		} else {-			// obtain unicode value-			-			if (v.char_count () > 1) {-				warning ("font contains ligatures");-				return '\0';-			}-			-			unicode_value = v.get_char (0);-		}-		-		return unicode_value;	-	}-	-	bool is_ligature (string v) {-		if (v.has_prefix ("&")) {-			return false;-		}-		-		return v.char_count () > 1;-	}-	-	void parse_glyph (Tag tag) {-		unichar unicode_value = 0;-		string glyph_name = "";-		string svg = "";-		Glyph glyph;-		GlyphCollection glyph_collection;-		double advance = font_advance;-		string ligature = "";-		SvgParser parser = new SvgParser ();-		StringBuilder unicode_name; --		parser.set_format (SvgFormat.INKSCAPE);--		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "unicode") {-				unicode_value = get_unichar (attr.get_content ());-				-				if (glyph_name == "") {-					glyph_name = attr.get_content ();-				}-				-				if (is_ligature (attr.get_content ())) {-					ligature = attr.get_content ();-				}-			}-			-			// svg data-			if (attr.get_name () == "d") {-				svg = attr.get_content ();-			}-			-			if (attr.get_name () == "glyph-name") {-				glyph_name = attr.get_content ();-			}--			if (attr.get_name () == "horiz-adv-x") {-				advance = double.parse (attr.get_content ());-			}-		}--		unicode_name = new StringBuilder ();-		unicode_name.append_unichar (unicode_value);--		glyph = new Glyph (unicode_name.str, unicode_value);-		parser.add_path_to_glyph (svg, glyph, true, units);			-		glyph.right_limit = glyph.left_limit + advance * units;-		-		// FIXME: add svg font ligatures-		-		glyph_collection = new GlyphCollection (unicode_value, glyph_name);-		glyph_collection.insert_glyph (glyph, true);-		-		font.add_glyph_collection (glyph_collection);-	}-}--}diff --git a/libbirdfont/SvgFontFormatWriter.vala b/libbirdfont/SvgFontFormatWriter.valadeleted file mode 100644index b2e907b..0000000--- a/libbirdfont/SvgFontFormatWriter.vala+++ /dev/null@@ -1,132 +0,0 @@-/*-	Copyright (C) 2012, 2014 Johan Mattsson--	This library is free software; you can redistribute it and/or modify -	it under the terms of the GNU Lesser General Public License as -	published by the Free Software Foundation; either version 3 of the -	License, or (at your option) any later version.--	This library 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 -	Lesser General Public License for more details.-*/--namespace BirdFont {--class SvgFontFormatWriter : GLib.Object  {--	DataOutputStream os;--	public SvgFontFormatWriter () {-	}--	public void open (File file) throws Error {-		if (file.query_exists ()) {-			throw new FileError.EXIST ("SvgFontFormatWriter: file exists.");-		}-		-		os = new DataOutputStream (file.create(FileCreateFlags.REPLACE_DESTINATION));-	}--	public void close () throws Error {-		os.close ();-	}-	-	public void write_font_file (Font font) throws Error {-		string font_name = font.get_full_name ();-		-		int units_per_em = 100;-		-		int ascent = 80;-		int descent = -20;-		-		StringBuilder b;-		-		Glyph? g;-		Glyph glyph;-		unichar index = 0;-		-		string uni;-		-		KerningClasses classes;-		-		put ("""<?xml version="1.0" standalone="no"?>""");-		put ("""<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd" >""");-		put ("""<svg>""");--		// (metadata goes here)--		put ("<defs>");--		put (@"<font id=\"$font_name\" horiz-adv-x=\"250\" >");-		put (@"<font-face units-per-em=\"$(to_float (units_per_em))\" ascent=\"$(to_float (ascent))\" descent=\"$(to_float (descent))\" />");--		// (missing-glyph goes here)--		// regular glyphs -		while (true) {-			g = font.get_glyph_index (index++);-			-			if (g == null) {-				break;-			}-			-			glyph = (!) g;-			-			b = new StringBuilder ();-			b.append_unichar (glyph.get_unichar ());--			if (glyph.get_unichar () >= ' ' && b.str.validate ()) {-				if (b.str == "\"" || b.str == "&" || b.str == "<" || b.str == ">") {-					uni = Font.to_hex_code (glyph.get_unichar ());-					put (@"<glyph unicode=\"&#x$(uni);\" horiz-adv-x=\"$(to_float (glyph.get_width ()))\" d=\"$(glyph.get_svg_data ())\" />");			-				} else {-					put (@"<glyph unicode=\"$(b.str)\" horiz-adv-x=\"$(to_float (glyph.get_width ()))\" d=\"$(glyph.get_svg_data ())\" />");-				}-			}-		}-		-		// FIXME: ligatures-		classes = BirdFont.get_current_font ().get_kerning_classes ();-		classes.all_pairs ((kerning) => {-			string l, r;-			-			foreach (Kerning k in kerning.kerning) {-				try {-					if (k.glyph != null) {-						l = Font.to_hex_code (kerning.character.unichar_code);-						r = Font.to_hex_code (((!)k.glyph).unichar_code);	-						os.put_string (@"<hkern u1=\"&#x$l;\" u2=\"&#x$r;\" k=\"$(to_float (-k.val))\"/>\n");-					} else {-						warning ("No glyph.");-					}-				} catch (GLib.Error e) {-					warning (e.message);-				}-			}-		});	--		put ("</font>");-		put ("</defs>");-		put ("</svg>");-	}--	string to_float (double d) {-		string s = @"$d";-		if (s.index_of ("e") != -1) {-			return "0".dup ();-		}-		return s.replace (",", ".");-	}--	/** Write a new line */-	private void put (string line) throws Error {-		os.put_string (line);-		os.put_string ("\n");-	}--}---}diff --git a/libbirdfont/SvgParser.vala b/libbirdfont/SvgParser.valadeleted file mode 100644index e3e0575..0000000--- a/libbirdfont/SvgParser.vala+++ /dev/null@@ -1,2114 +0,0 @@-/*-	Copyright (C) 2012 2013 2014 2015 Johan Mattsson--	This library is free software; you can redistribute it and/or modify -	it under the terms of the GNU Lesser General Public License as -	published by the Free Software Foundation; either version 3 of the -	License, or (at your option) any later version.--	This library 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 -	Lesser General Public License for more details.-*/--using B;-using Math;--namespace BirdFont {--public enum SvgFormat {-	NONE,-	INKSCAPE,-	ILLUSTRATOR-}--public enum SvgType {-	COLOR,-	REGULAR-}--public class SvgParser {-	-	SvgFormat format = SvgFormat.ILLUSTRATOR;-	-	public SvgParser () {-	}-	-	public void set_format (SvgFormat f) {-		format = f;-	}-	-	public static void import (SvgType type) {-		FileChooser fc = new FileChooser ();-		fc.file_selected.connect ((p) => {-			string path;-				-			if (p == null) {-				return;-			}-			-			path = (!) p;-			-			if (type == SvgType.REGULAR) {-				import_svg (path);-			} else if (type == SvgType.COLOR) {-				Glyph glyph = MainWindow.get_current_glyph ();-				import_color_svg (glyph, path);-			}-		});-		-		fc.add_extension ("svg");-		MainWindow.file_chooser (t_("Import"), fc, FileChooser.LOAD);-	}-		-	public static void import_color_svg (Glyph glyph, string path) {-		try {-			string data;-			FileUtils.get_contents (path, out data);-			glyph.color_svg_data = data;--			if (glyph.color_svg_data != null) {-				glyph.svg_x = glyph.left_limit;-				glyph.svg_y = BirdFont.get_current_font ().top_position;-			}-		} catch (GLib.Error e) {-			warning (e.message);-		}-	}-	-	public static void import_folder (SvgType type) {-		FileChooser fc = new FileChooser ();-		fc.file_selected.connect ((p) => {-			string path;-			File svg_folder;-			File svg;-			bool imported;-			FileEnumerator enumerator;-			FileInfo? file_info;-			string file_name;-			Font font;-			-			if (p == null) {-				return;-			}-			-			path = (!) p;-			svg_folder = File.new_for_path (path);-			font = BirdFont.get_current_font ();-				-			try {-				enumerator = svg_folder.enumerate_children (FileAttribute.STANDARD_NAME, 0);-				while ((file_info = enumerator.next_file ()) != null) {-					file_name = ((!) file_info).get_name ();-					-					if (file_name.has_suffix (".svg")) {-						svg = get_child (svg_folder, file_name);-						imported = import_svg_file (font, svg, type);-						-						if (!imported) {-							warning ("Can't import %s.", (!) svg.get_path ());-						} else {-							font.touch ();-						}-					}-				}-			} catch (Error e) {-				warning (e.message);-			}-		});-		-		MainWindow.file_chooser (t_("Import"), fc, FileChooser.LOAD | FileChooser.DIRECTORY);-	}-	-	public static void import_svg_data (string xml_data, SvgFormat format = SvgFormat.NONE) {-		PathList path_list = new PathList ();-		Glyph glyph; -		string[] lines = xml_data.split ("\n");-		bool has_format = false;-		SvgParser parser = new SvgParser ();-		XmlParser xmlparser;--		foreach (string l in lines) {-			if (l.index_of ("Illustrator") > -1 || l.index_of ("illustrator") > -1) {-				parser.set_format (SvgFormat.ILLUSTRATOR);-				has_format = true;-			}-			-			if (l.index_of ("Inkscape") > -1 || l.index_of ("inkscape") > -1) {-				parser.set_format (SvgFormat.INKSCAPE);-				has_format = true;-			}-		}-		-		if (format != SvgFormat.NONE) {-			parser.set_format (format);-		}--		// parse the file-		if (!has_format) {-			warn_if_test ("No format identifier found in SVG parser.\n");-		}--		xmlparser = new XmlParser (xml_data);-		-		if (!xmlparser.validate()) {-			warning("Invalid XML in SVG parser."); -		}-		-		path_list = parser.parse_svg_file (xmlparser.get_root_tag ());-	-		glyph = MainWindow.get_current_glyph ();-		foreach (Path p in path_list.paths) {-			FastPath path = new FastPath.for_path (p);-			glyph.add_object (path);-			glyph.add_active_object (null, path); // FIXME: groups-			path.update_region_boundaries ();-		}-		-		glyph.close_path ();	-	}-	-	public static string replace (string content, string start, string stop, string replacement) {-		int i_tag = content.index_of (start);-		int end_tag = content.index_of (stop, i_tag);-		string c = "";-		-		if (i_tag > -1) {-			c = content.substring (0, i_tag) -				+ replacement-				+ content.substring (end_tag + stop.length);-		} else {-			c = content;-		}-		-		return c;-	}-	-	public static void import_svg (string path) {-		string svg_data;-		try {-			FileUtils.get_contents (path, out svg_data);-		} catch (GLib.Error e) {-			warning (e.message);-		}-		import_svg_data (svg_data);-	}-	-	private PathList parse_svg_file (Tag tag) {-		Layer pl = new Layer ();-	-		foreach (Tag t in tag) {-			-			if (t.get_name () == "g") {-				parse_layer (t, pl);-			}--			if (t.get_name () == "switch") {-				parse_layer (t, pl);-			}-						-			if (t.get_name () == "path") {-				parse_path (t, pl);-			}-			-			if (t.get_name () == "polygon") {-				parse_polygon (t, pl);-			}--			if (t.get_name () == "polyline") {-				parse_polyline (t, pl);-			}-						-			if (t.get_name () == "circle") {-				parse_circle (t, pl);-			}-			-			if (t.get_name () == "ellipse") {-				parse_ellipse (t, pl);-			}--			if (t.get_name () == "line") {-				parse_line (t, pl);-			}			-		}-		-		return pl.get_all_paths ();-	}-	-	private void parse_layer (Tag tag, Layer pl) {-		Layer layer;-		bool hidden = false;--		foreach (Attribute attr in tag.get_attributes ()) {	-			if (attr.get_name () == "display" && attr.get_content () == "none") {-				hidden = true;-			}-			-			if (attr.get_name () == "visibility"-				&& (attr.get_content () == "hidden" -					|| attr.get_content () == "collapse")) {-				hidden = true;-			}-		}-		-		if (hidden) {-			return;-		}-					-		foreach (Tag t in tag) {-			if (t.get_name () == "path") {-				parse_path (t, pl);-			}-			-			if (t.get_name () == "g") {-				layer = new Layer ();-				parse_layer (t, layer);-				pl.subgroups.add (layer);-			}-			-			if (t.get_name () == "polygon") {-				parse_polygon (t, pl);-			}--			if (t.get_name () == "polyline") {-				parse_polyline (t, pl);-			}-			-			if (t.get_name () == "rect") {-				parse_rect (t, pl);-			}--			if (t.get_name () == "circle") {-				parse_circle (t, pl);-			}--			if (t.get_name () == "ellipse") {-				parse_ellipse (t, pl);-			}-			-			if (t.get_name () == "line") {-				parse_line (t, pl);-			}-		}--		foreach (Attribute attr in tag.get_attributes ()) {	-			if (attr.get_name () == "transform") {-				transform (attr.get_content (), pl);-			}-		}-	}-	-	private void transform (string transform_functions, Layer layer) {-		PathList path_list = new PathList ();-		-		foreach (Object o in layer.objects) {-			if (o is FastPath) {-				path_list.add (((FastPath) o).get_path ());-			}-		}-		-		transform_paths (transform_functions, path_list);-		transform_subgroups (transform_functions, layer);-	}-	-	private void transform_subgroups (string transform_functions, Layer layer) {-		foreach (Layer subgroup in layer.subgroups) {-			transform (transform_functions, subgroup);-		}-	}-	-	private void transform_paths (string transform_functions, PathList pl) {-		string data = transform_functions.dup ();-		string[] functions;-				-		// use only a single space as separator-		while (data.index_of ("  ") > -1) {-			data = data.replace ("  ", " ");-		}-		-		return_if_fail (data.index_of (")") > -1);-		-		 // add separator-		data = data.replace (") ", "|");-		data = data.replace (")", "|"); -		functions = data.split ("|");-		-		for (int i = functions.length - 1; i >= 0; i--) {-			if (functions[i].has_prefix ("translate")) {-				translate (functions[i], pl);-			}-			-			if (functions[i].has_prefix ("scale")) {-				scale (functions[i], pl);-			}--			if (functions[i].has_prefix ("matrix")) {-				matrix (functions[i], pl);-			}-			-			// TODO: rotate etc.-		}-	}--	/** @param path a path in the cartesian coordinate system-	 * The other parameters are in the SVG coordinate system.-	 */-	public static void apply_matrix (Path path, double a, double b, double c, -		double d, double e, double f){-		-		double dx, dy;-		Font font = BirdFont.get_current_font ();-		Glyph glyph = MainWindow.get_current_glyph ();-		-		foreach (EditPoint ep in path.points) {-			ep.tie_handles = false;-			ep.reflective_point = false;-		}-		-		foreach (EditPoint ep in path.points) {-			apply_matrix_on_handle (ep.get_right_handle (), a, b, c, d, e, f);-			apply_matrix_on_handle (ep.get_left_handle (), a, b, c, d, e, f);--			ep.independent_y = font.top_position - ep.independent_y;-			ep.independent_x -= glyph.left_limit;-			-			dx = a * ep.independent_x + c * ep.independent_y + e;-			dy = b * ep.independent_x + d * ep.independent_y + f;-			-			ep.independent_x = dx;-			ep.independent_y = dy;-			-			ep.independent_y = font.top_position - ep.independent_y;-			ep.independent_x += glyph.left_limit;-		}-	}--	public static void apply_matrix_on_handle (EditPointHandle h, -		double a, double b, double c, -		double d, double e, double f){-		-		double dx, dy;-		Font font = BirdFont.get_current_font ();-		Glyph glyph = MainWindow.get_current_glyph ();--		h.y = font.top_position - h.y;-		h.x -= glyph.left_limit;-		-		dx = a * h.x + c * h.y + e;-		dy = b * h.x + d * h.y + f;-		-		h.x = dx;-		h.y = dy;-		-		h.y = font.top_position - h.y;-		h.x += glyph.left_limit;-	}---	private void matrix (string function, PathList pl) {-		string parameters = get_transform_parameters (function);-		string[] p = parameters.split (" ");--		if (p.length != 6) {-			warning ("Expecting six parameters for matrix transformation.");-			return;-		}--		foreach (Path path in pl.paths) {-			apply_matrix (path, parse_double (p[0]), parse_double (p[1]), -				parse_double (p[2]), parse_double (p[3]), -				parse_double (p[4]), parse_double (p[5]));-		}-	}-		-	private void scale (string function, PathList pl) {-		string parameters = get_transform_parameters (function);-		string[] p = parameters.split (" ");-		double x, y;-		-		x = 1;-		y = 1;-		-		if (p.length > 0) {-			x = parse_double (p[0]);-		}-		-		if (p.length > 1) {-			y = parse_double (p[1]);-		}-		-		foreach (Path path in pl.paths) {-			path.scale (-x, y);-		}-	}-	-	private void translate (string function, PathList pl) {-		string parameters = get_transform_parameters (function);-		string[] p = parameters.split (" ");-		double x, y;-		-		x = 0;-		y = 0;-		-		if (p.length > 0) {-			x = parse_double (p[0]);-		}-		-		if (p.length > 1) {-			y = parse_double (p[1]);-		}-		-		foreach (Path path in pl.paths) {-			path.move (x, -y);-		}-	}--	private string get_transform_parameters (string function) {-		int i;-		string param = "";-		-		i = function.index_of ("(");-		return_val_if_fail (i != -1, param);-		param = function.substring (i);--		param = param.replace ("(", "");-		param = param.replace ("\n", " ");-		param = param.replace ("\t", " ");-		param = param.replace (",", " ");-		-		while (param.index_of ("  ") > -1) {-			param.replace ("  ", " ");-		}-			-		return param.strip();			-	}-	-	private void parse_circle (Tag tag, Layer pl) {-		Path p;-		double x, y, r;-		Glyph g;-		PathList npl;-		BezierPoints[] bezier_points;-		SvgStyle style = new SvgStyle ();-		bool hidden = false;-		-		npl = new PathList ();-		-		x = 0;-		y = 0;-		r = 0;-			-		foreach (Attribute attr in tag.get_attributes ()) {			-			if (attr.get_name () == "cx") {-				x = parse_double (attr.get_content ());-			}-			-			if (attr.get_name () == "cy") {-				y = -parse_double (attr.get_content ());-			}--			if (attr.get_name () == "r") {-				r = parse_double (attr.get_content ());-			}-	-			if (attr.get_name () == "display" && attr.get_content () == "none") {-				hidden = true;-			}-		}-		-		style = SvgStyle.parse (tag.get_attributes ());-		-		if (hidden) {-			return;-		}-		-		bezier_points = new BezierPoints[1];-		bezier_points[0] = new BezierPoints ();-		bezier_points[0].type == 'L';-		bezier_points[0].x0 = x;-		bezier_points[0].y0 = y;--		g = MainWindow.get_current_glyph ();-		move_and_resize (bezier_points, 1, false, 1, g);-			-		p = CircleTool.create_circle (bezier_points[0].x0,-			bezier_points[0].y0, r, PointType.CUBIC);--		npl.add (p);-		-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "transform") {-				transform_paths (attr.get_content (), npl);-			}-		}-		-		style.apply (npl);-		pl.append_paths (npl);-	}--	private void parse_ellipse (Tag tag, Layer pl) {-		Path p;-		double x, y, rx, ry;-		Glyph g;-		PathList npl;-		BezierPoints[] bezier_points;-		SvgStyle style = new SvgStyle ();-		bool hidden = false;-		-		npl = new PathList ();-		-		x = 0;-		y = 0;-		rx = 0;-		ry = 0;-		-		foreach (Attribute attr in tag.get_attributes ()) {			-			if (attr.get_name () == "cx") {-				x = parse_double (attr.get_content ());-			}-			-			if (attr.get_name () == "cy") {-				y = -parse_double (attr.get_content ());-			}--			if (attr.get_name () == "rx") {-				rx = parse_double (attr.get_content ());-			}--			if (attr.get_name () == "ry") {-				ry = parse_double (attr.get_content ());-			}-	-			if (attr.get_name () == "display" && attr.get_content () == "none") {-				hidden = true;-			}-		}-		-		style = SvgStyle.parse (tag.get_attributes ());-		-		if (hidden) {-			return;-		}-		-		bezier_points = new BezierPoints[1];-		bezier_points[0] = new BezierPoints ();-		bezier_points[0].type == 'L';-		bezier_points[0].x0 = x;-		bezier_points[0].y0 = y;--		g = MainWindow.get_current_glyph ();-		move_and_resize (bezier_points, 1, false, 1, g);-			-		p = CircleTool.create_ellipse (bezier_points[0].x0,-			bezier_points[0].y0, rx, ry, PointType.CUBIC);--		npl.add (p);-		-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "transform") {-				transform_paths (attr.get_content (), npl);-			}-		}-		-		style.apply (npl);-		pl.append_paths (npl);-	}--	private void parse_line (Tag tag, Layer pl) {-		Path p;-		double x1, y1, x2, y2;-		BezierPoints[] bezier_points;-		Glyph g;-		PathList npl = new PathList ();-		SvgStyle style = new SvgStyle ();-		bool hidden = false;-		-		x1 = 0;-		y1 = 0;-		x2 = 0;-		y2 = 0;-			-		foreach (Attribute attr in tag.get_attributes ()) {			-			if (attr.get_name () == "x1") {-				x1 = parse_double (attr.get_content ());-			}-			-			if (attr.get_name () == "y1") {-				y1 = -parse_double (attr.get_content ());-			}--			if (attr.get_name () == "x2") {-				x2 = parse_double (attr.get_content ());-			}-			-			if (attr.get_name () == "xy") {-				y2 = -parse_double (attr.get_content ());-			}-	-			if (attr.get_name () == "display" && attr.get_content () == "none") {-				hidden = true;-			}-		}-		-		style = SvgStyle.parse (tag.get_attributes ());-		-		if (hidden) {-			return;-		}--		bezier_points = new BezierPoints[2];-		bezier_points[0] = new BezierPoints ();-		bezier_points[0].type == 'L';-		bezier_points[0].x0 = x1;-		bezier_points[0].y0 = y1;--		bezier_points[1] = new BezierPoints ();-		bezier_points[1].type == 'L';-		bezier_points[1].x0 = x2;-		bezier_points[1].y0 = y2;-		-		g = MainWindow.get_current_glyph ();-		move_and_resize (bezier_points, 4, false, 1, g);-					-		p = new Path ();	-		-		p.add (bezier_points[0].x0, bezier_points[0].y0);-		p.add (bezier_points[1].x0, bezier_points[1].y0);-						-		p.close ();-		p.create_list ();-		p.recalculate_linear_handles ();		-		-		npl.add (p);-		-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "transform") {-				transform_paths (attr.get_content (), npl);-			}-		}-		-		style.apply (npl);-		pl.append_paths (npl);-	}-		-	private void parse_rect (Tag tag, Layer layer) {-		Path p;-		double x, y, x2, y2;-		BezierPoints[] bezier_points;-		Glyph g;-		PathList npl = new PathList ();-		SvgStyle style = new SvgStyle ();-		bool hidden = false;-		EditPoint ep;-		-		x = 0;-		y = 0;-		x2 = 0;-		y2 = 0;-			-		foreach (Attribute attr in tag.get_attributes ()) {			-			if (attr.get_name () == "x") {-				x = parse_double (attr.get_content ());-			}-			-			if (attr.get_name () == "y") {-				y = -parse_double (attr.get_content ());-			}--			if (attr.get_name () == "width") {-				x2 = parse_double (attr.get_content ());-			}-			-			if (attr.get_name () == "height") {-				y2 = -parse_double (attr.get_content ());-			}-	-			if (attr.get_name () == "display" && attr.get_content () == "none") {-				hidden = true;-			}-		}-		-		style = SvgStyle.parse (tag.get_attributes ());-		-		if (hidden) {-			return;-		}-		-		x2 += x;-		y2 += y;--		bezier_points = new BezierPoints[4];-		bezier_points[0] = new BezierPoints ();-		bezier_points[0].type == 'L';-		bezier_points[0].x0 = x;-		bezier_points[0].y0 = y;--		bezier_points[1] = new BezierPoints ();-		bezier_points[1].type == 'L';-		bezier_points[1].x0 = x2;-		bezier_points[1].y0 = y;--		bezier_points[2] = new BezierPoints ();-		bezier_points[2].type == 'L';-		bezier_points[2].x0 = x2;-		bezier_points[2].y0 = y2;--		bezier_points[3] = new BezierPoints ();-		bezier_points[3].type == 'L';-		bezier_points[3].x0 = x;-		bezier_points[3].y0 = y2;-		-		g = MainWindow.get_current_glyph ();-		move_and_resize (bezier_points, 4, false, 1, g);-					-		p = new Path ();	-		-		ep = p.add (bezier_points[0].x0, bezier_points[0].y0);-		ep.set_point_type (PointType.CUBIC);-		-		ep = p.add (bezier_points[1].x0, bezier_points[1].y0);-		ep.set_point_type (PointType.CUBIC);-		-		ep = p.add (bezier_points[2].x0, bezier_points[2].y0);-		ep.set_point_type (PointType.CUBIC);-		-		ep = p.add (bezier_points[3].x0, bezier_points[3].y0);-		ep.set_point_type (PointType.CUBIC);-						-		p.close ();-		p.create_list ();-		p.recalculate_linear_handles ();		-		-		npl.add (p);-		-		// FIXME: right layer for other transforms-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "transform") {-				transform_paths (attr.get_content (), npl);-			}-		}-		-		style.apply (npl);-		layer.append_paths (npl);-	}-	-	private void parse_polygon (Tag tag, Layer layer) {-		PathList path_list = get_polyline (tag);-		-		foreach (Path p in path_list.paths) {-			p.close ();-		}-		-		layer.append_paths (path_list);-	}--	-	private void parse_polyline (Tag tag, Layer layer) {	-		layer.append_paths (get_polyline (tag));-	}-	-	private PathList get_polyline (Tag tag) {-		Path p = new Path ();-		bool hidden = false;-		PathList path_list = new PathList ();-		SvgStyle style = new SvgStyle ();-				-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "points") {-				p = parse_poly_data (attr.get_content ());-			}-	-			if (attr.get_name () == "display" && attr.get_content () == "none") {-				hidden = true;-			}-		}--		style = SvgStyle.parse (tag.get_attributes ());-		-		if (hidden) {-			return path_list;-		}-		-		path_list.add (p);-		style.apply (path_list);-		-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "transform") {-				transform_paths (attr.get_content (), path_list);-			}-		}-		-		return path_list;-	}-	-	private void parse_path (Tag tag, Layer layer) {-		Glyph glyph = MainWindow.get_current_glyph ();-		PathList path_list = new PathList ();-		SvgStyle style = new SvgStyle ();-		bool hidden = false;--		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "d") {-				path_list = parse_svg_data (attr.get_content (), glyph);-			}-	-			if (attr.get_name () == "display" && attr.get_content () == "none") {-				hidden = true;-			}-			-			if (attr.get_name () == "visibility"-				&& (attr.get_content () == "hidden" -					|| attr.get_content () == "collapse")) {-				hidden = true;-			}-		}-		-		style = SvgStyle.parse (tag.get_attributes ());-		-		if (hidden) {-			return;-		}-		-		foreach (Path path in path_list.paths) {-			layer.add_path (path);-		}-		-		style.apply (path_list);--		// assume the even odd rule is applied and convert the path-		// to a path using the non-zero rule-		int inside_count;-		bool inside;-		foreach (Object o1 in layer.objects) {-			if (o1 is FastPath) {-				Path p1 = ((FastPath) o1).get_path ();-				inside_count = 0;-				-				foreach (Object o2 in layer.objects) {-					if (o2 is FastPath) {-						Path p2 = ((FastPath) o2).get_path ();-					-						if (p1 != p2) {-							inside = true;-							-							foreach (EditPoint ep in p1.points) {-								if (!is_inside (ep, p2)) {-									inside = false;-								}-							}--							if (inside) {-								inside_count++; -							}-						}-					}-				}-				-				if (inside_count % 2 == 0) {-					p1.force_direction (Direction.CLOCKWISE);-				} else {-					p1.force_direction (Direction.COUNTER_CLOCKWISE);-				}-			}-		}-		-		foreach (Attribute attr in tag.get_attributes ()) {-			if (attr.get_name () == "transform") {-				transform_paths (attr.get_content (), path_list);-			}-		}-	}--	public static void create_lines_for_segment (Path path, EditPoint start, EditPoint end, double tolerance) {-		double x1, x2, x3;-		double y1, y2, y3;-		double step_start, step, step_end;--		path.add (start.x, start.y);--		step_start = 0;-		step = 0.5;-		step_end = 1;-					-		while (true) {-			Path.get_point_for_step (start, end, step_start, out x1, out y1);-			Path.get_point_for_step (start, end, step, out x2, out y2);-			Path.get_point_for_step (start, end, step_end, out x3, out y3);-		-			if (!StrokeTool.is_flat (x1, y1, x2, y2, x3, y3, tolerance)-				&& step_end - step / 2.0 > step_start -				&& step_end - step / 2.0 > 0.1-				&& step > 0.05-				&& Path.distance_to_point (start, end) > 1) {-				-				step /= 2.0;-	-				if (step < 0.05) {-					step = 0.05;-				} else {-					step_end = step_start + 2 * step;-				}-			} else {-				path.add (x3, y3);-				-				if (step_end + step < 1) {-					step_start = step_end;-					step_end += step;-				} else {-					break;-				}-			}-		}-	}--	public static Path get_lines (Path p) {-		EditPoint start;-		Path path = new Path ();-		-		if (p.points.size == 0) {-			return path;-		}-		-		// create a set of straight lines-		start = p.points.get (p.points.size - 1);-		-		foreach (EditPoint end in p.points) {-			create_lines_for_segment (path, start, end, 1);-			start = end;-		}-						-		return path;-	}--	/** Check if a point is inside using the even odd fill rule.-	 * The path should only have straight lines.-	 */-	public static bool is_inside (EditPoint point, Path path) {-		EditPoint prev;-		bool inside = false;-		-		if (path.points.size <= 1) {-			return false;-		}--		if (!(path.xmin <= point.x <= path.xmax)) {-			return false;-		}-		-		if (!(path.ymin <= point.y <= path.ymax)) {-			return false;-		}-				-		prev = path.points.get (path.points.size - 1);-		-		foreach (EditPoint p in path.points) {-			if  ((p.y > point.y) != (prev.y > point.y) -				&& point.x < (prev.x - p.x) * (point.y - p.y) / (prev.y - p.y) + p.x) {-				inside = !inside;-			}-			-			prev = p;-		}-		-		return inside;-	}--	/** Add space as separator to svg data. -	 * @param d svg data-	 */-	static string add_separators (string d) {-		string data = d;-		-		data = data.replace (",", " ");-		data = data.replace ("a", " a ");-		data = data.replace ("A", " A ");-		data = data.replace ("m", " m ");-		data = data.replace ("M", " M ");-		data = data.replace ("h", " h ");-		data = data.replace ("H", " H ");-		data = data.replace ("v", " v ");-		data = data.replace ("V", " V ");-		data = data.replace ("l", " l ");-		data = data.replace ("L", " L ");-		data = data.replace ("q", " q ");-		data = data.replace ("Q", " Q ");		-		data = data.replace ("c", " c ");-		data = data.replace ("C", " C ");-		data = data.replace ("t", " t ");-		data = data.replace ("T", " T ");-		data = data.replace ("s", " s ");-		data = data.replace ("S", " S ");-		data = data.replace ("zM", " z M ");-		data = data.replace ("zm", " z m ");-		data = data.replace ("z", " z ");-		data = data.replace ("Z", " Z ");-		data = data.replace ("-", " -");-		data = data.replace ("e -", "e-"); // minus can be either separator or a negative exponent-		data = data.replace ("\t", " ");-		data = data.replace ("\r\n", " ");-		data = data.replace ("\n", " ");-		-		// use only a single space as separator-		while (data.index_of ("  ") > -1) {-			data = data.replace ("  ", " ");-		}-		-		return data;-	}-	-	public void add_path_to_glyph (string d, Glyph g, bool svg_glyph = false, double units = 1) {-		PathList p = parse_svg_data (d, g, svg_glyph, units);-		foreach (Path path in p.paths) {-			g.add_path (path);-		}-	}-	-	/** -	 * @param d svg data-	 * @param glyph use lines from this glyph but don't add the generated paths-	 * @param svg_glyph parse svg glyph with origo in lower left corner-	 * -	 * @return the new paths-	 */-	public PathList parse_svg_data (string d, Glyph glyph, bool svg_glyph = false, double units = 1) {-		double px = 0;-		double py = 0;-		double px2 = 0;-		double py2 = 0;-		double cx = 0;-		double cy = 0;-		string data;-		Font font;-		PathList path_list = new PathList ();-		BezierPoints[] bezier_points;-		string[] c;-		double arc_rx, arc_ry;-		double arc_rotation;-		int large_arc;-		int arc_sweep;-		double arc_dest_x, arc_dest_y;--		font = BirdFont.get_current_font ();-		-		data = add_separators (d);-		c = data.split (" ");-		bezier_points = new BezierPoints[8 * c.length + 1]; // the arc instruction can use up to eight points-		-		for (int i = 0; i < 2 * c.length + 1; i++) {-			bezier_points[i] = new BezierPoints ();-		}-		-		int bi = 0;-		-		// parse path-		int i = -1;-		while (++i < c.length && bi < bezier_points.length) {	-			if (c[i] == "m") {-				while (i + 2 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'M';-					bezier_points[bi].svg_type = 'm';-					-					px += parse_double (c[++i]);-					-					if (svg_glyph) {-						py += parse_double (c[++i]);-					} else {-						py += -parse_double (c[++i]);-					}-					-					bezier_points[bi].x0 = px;-					bezier_points[bi].y0 = py;-					bi++;-				}-			} else if (c[i] == "M") {-				while (i + 2 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'M';-					bezier_points[bi].svg_type = 'M';-					-					px = parse_double (c[++i]);-					-					if (svg_glyph) {-						py = parse_double (c[++i]);-					} else {-						py = -parse_double (c[++i]);-					}-					-					bezier_points[bi].x0 = px;-					bezier_points[bi].y0 = py;-					bi++;-				}-			} else if (c[i] == "h") {-				while (i + 1 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'L';-					bezier_points[bi].svg_type = 'h';-					-					px += parse_double (c[++i]);--					bezier_points[bi].x0 = px;-					bezier_points[bi].y0 = py;-					bi++;-				}-			} else if (i + 1 < c.length && c[i] == "H") {-				while (is_point (c[i + 1])) {-					bezier_points[bi].type = 'L';-					bezier_points[bi].svg_type = 'H';-					-					px = parse_double (c[++i]);--					bezier_points[bi].x0 = px;-					bezier_points[bi].y0 = py;-					bi++;-				}-			} else if (c[i] == "v") {-				while (i + 1 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'L';-					bezier_points[bi].svg_type = 'v';-										-					if (svg_glyph) {-						py = py + parse_double (c[++i]);-					} else {-						py = py - parse_double (c[++i]);-					}-					-					bezier_points[bi].x0 = px;-					bezier_points[bi].y0 = py;-					bi++;-				}				-			} else if (i + 1 < c.length && c[i] == "V") {-				while (is_point (c[i + 1])) {-					bezier_points[bi].type = 'L';-					bezier_points[bi].svg_type = 'V';-										-					if (svg_glyph) {-						py = parse_double (c[++i]);-					} else {-						py = -parse_double (c[++i]);-					}-					-					bezier_points[bi].x0 = px;-					bezier_points[bi].y0 = py;-					bi++;-				}-			} else if (c[i] == "l") {-				while (i + 2 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'L';-					bezier_points[bi].svg_type = 'l';-										-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					px = cx;-					py = cy;--					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-					bi++;-				}-			} else if (c[i] == "L") {-				while (i + 2 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'L';-					bezier_points[bi].svg_type = 'L';-										-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					px = cx;-					py = cy;-					-					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-					bi++;				-				}	-			} else if (c[i] == "c") {-				while (i + 6 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'C';-					bezier_points[bi].svg_type = 'C';-										-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-										-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					px2 = cx;-					py2 = cy;-										-					bezier_points[bi].x1 = px2;-					bezier_points[bi].y1 = py2;-										-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py + -parse_double (c[++i]);-					}-					-					bezier_points[bi].x2 = cx;-					bezier_points[bi].y2 = cy;-										-					px = cx;-					py = cy;-					-					bi++;-				}-			} else if (c[i] == "C") {-				while (i + 6 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'C';-					bezier_points[bi].svg_type = 'C';-										-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-									-					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-					-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					px2 = cx;-					py2 = cy;-					-					bezier_points[bi].x1 = cx;-					bezier_points[bi].y1 = cy;-										-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					bezier_points[bi].x2 = cx;-					bezier_points[bi].y2 = cy;-										-					px = cx;-					py = cy;-					-					bi++;				-				}	-			} else if (c[i] == "q") {-				while (i + 4 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'Q';-					bezier_points[bi].svg_type = 'q';-										-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-										-					px2 = cx;-					py2 = cy;-										-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					bezier_points[bi].x1 = cx;-					bezier_points[bi].y1 = cy;-										-					px = cx;-					py = cy;-					-					bi++;-				}-			} else if (c[i] == "Q") {--				while (i + 4 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'Q';-					bezier_points[bi].svg_type = 'Q';-										-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-					-					px2 = cx;-					py2 = cy;-										-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					px = cx;-					py = cy;--					bezier_points[bi].x1 = cx;-					bezier_points[bi].y1 = cy;-										-					bi++;					-				}	-			} else if (c[i] == "t") {-				while (i + 2 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'Q';-					bezier_points[bi].svg_type = 't';-										-					// the first point is the reflection-					cx = 2 * px - px2;-					cy = 2 * py - py2; // if (svg_glyph) ?-					-					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-					-					px2 = cx;-					py2 = cy;-										-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					px = cx;-					py = cy;-					-					bezier_points[bi].x1 = px;-					bezier_points[bi].y1 = py;-										-					bi++;-				}-			} else if (c[i] == "T") {-				while (i + 2 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'Q';-					bezier_points[bi].svg_type = 'T';-										-					// the reflection-					cx = 2 * px - px2;-					cy = 2 * py - py2; // if (svg_glyph) ?-					-					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-										-					px2 = cx;-					py2 = cy;-					-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					px = cx;-					py = cy;-					-					bezier_points[bi].x1 = px;-					bezier_points[bi].y1 = py;-										-					bi++;				-				}-			} else if (c[i] == "s") {-				while (i + 4 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'C';-					bezier_points[bi].svg_type = 's';-										-					// the first point is the reflection-					cx = 2 * px - px2;-					cy = 2 * py - py2; // if (svg_glyph) ?--					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-															-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					px2 = cx;-					py2 = cy;-					-					bezier_points[bi].x1 = px2;-					bezier_points[bi].y1 = py2;-					-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					bezier_points[bi].x2 = cx;-					bezier_points[bi].y2 = cy;-												-					px = cx;-					py = cy;-					-					bi++;-				}-			} else if (c[i] == "S") {-				while (i + 4 < c.length && is_point (c[i + 1])) {-					bezier_points[bi].type = 'C';-					bezier_points[bi].svg_type = 'S';-										-					// the reflection-					cx = 2 * px - px2;-					cy = 2 * py - py2; // if (svg_glyph) ?			--					bezier_points[bi].x0 = cx;-					bezier_points[bi].y0 = cy;-					-					// the other two are regular cubic points-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					px2 = cx;-					py2 = cy;-					-					bezier_points[bi].x1 = px2;-					bezier_points[bi].y1 = py2;-					-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					bezier_points[bi].x2 = cx;-					bezier_points[bi].y2 = cy;-					-					px = cx;-					py = cy;	-					-					bi++;				-				}-			} else if (c[i] == "a") {-				while (i + 7 < c.length && is_point (c[i + 1])) {					-					arc_rx = parse_double (c[++i]);-					arc_ry = parse_double (c[++i]);-					-					arc_rotation = parse_double (c[++i]);-					large_arc = parse_int (c[++i]);-					arc_sweep = parse_int (c[++i]);-							-					cx = px + parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = py + parse_double (c[++i]);-					} else {-						cy = py - parse_double (c[++i]);-					}-					-					arc_dest_x = cx;-					arc_dest_y = cy;-					-					add_arc_points (bezier_points, ref bi, px, py, arc_rx, arc_ry, arc_rotation, large_arc == 1, arc_sweep == 1, cx, cy);-					-					px = cx;-					py = cy;-					-					-				}-			} else if (i + 7 < c.length && c[i] == "A") {-				while (is_point (c[i + 1])) {					-					arc_rx = parse_double (c[++i]);-					arc_ry = parse_double (c[++i]);-					-					arc_rotation = parse_double (c[++i]);-					large_arc = parse_int (c[++i]);-					arc_sweep = parse_int (c[++i]);-							-					cx = parse_double (c[++i]);-					-					if (svg_glyph) {-						cy = parse_double (c[++i]);-					} else {-						cy = -parse_double (c[++i]);-					}-					-					arc_dest_x = cx;-					arc_dest_y = cy;-					-					add_arc_points (bezier_points, ref bi, px, py, arc_rx, arc_ry, arc_rotation, large_arc == 1, arc_sweep == 1, cx, cy);--					px = cx;-					py = cy;-					-					-				}-			} else if (c[i] == "z") {-				bezier_points[bi].type = 'z';-				bezier_points[bi].svg_type = 'z';-				-				bi++;-			} else if (c[i] == "Z") {-				bezier_points[bi].type = 'z';-				bezier_points[bi].svg_type = 'z';-									-				bi++;-			} else if (c[i] == "") {-			} else if (c[i] == " ") {-			} else {-				warning (@"Unknown instruction: $(c[i])");-			}-		}-		-		if (bi == 0) {-			warning ("No points in path.");-			return path_list;	-		}-		-		move_and_resize (bezier_points, bi, svg_glyph, units, glyph);-		-		if (format == SvgFormat.ILLUSTRATOR) {-			path_list = create_paths_illustrator (bezier_points, bi);-		} else {-			path_list = create_paths_inkscape (bezier_points, bi);-		}--		// TODO: Find out if it is possible to tie handles.-		return path_list;-	}--	void move_and_resize (BezierPoints[] b, int num_b, bool svg_glyph, double units, Glyph glyph) {-		Font font = BirdFont.get_current_font ();-		-		for (int i = 0; i < num_b; i++) {-			// resize all points-			b[i].x0 *= units;-			b[i].y0 *= units;-			b[i].x1 *= units;-			b[i].y1 *= units;-			b[i].x2 *= units;-			b[i].y2 *= units;--			// move all points-			if (svg_glyph) {-				b[i].x0 += glyph.left_limit;-				b[i].y0 += font.base_line;-				b[i].x1 += glyph.left_limit;-				b[i].y1 += font.base_line;-				b[i].x2 += glyph.left_limit;-				b[i].y2 += font.base_line;-			} else {-				b[i].x0 += glyph.left_limit;-				b[i].y0 += font.top_position;-				b[i].x1 += glyph.left_limit;-				b[i].y1 += font.top_position;-				b[i].x2 += glyph.left_limit;-				b[i].y2 += font.top_position;-			}-		}-	}-	-	void find_last_handle (int start_index, BezierPoints[] b, int num_b, out double left_x, out double left_y, out PointType last_type) {-		BezierPoints last = new BezierPoints ();-		bool found = false;-		-		left_x = 0;-		left_y = 0;-		last_type = PointType.NONE;-		-		return_if_fail (b.length != 0);-		return_if_fail (b[0].type != 'z');-		return_if_fail (num_b < b.length);--		if (num_b == 2) {-			left_x = b[0].x0 + (b[1].x0 - b[0].x0) / 3.0;-			left_y = b[0].y0 + (b[1].y0 - b[0].y0) / 3.0;-			last_type = PointType.LINE_CUBIC;-			return;-		}-		-		for (int i = start_index; i < num_b; i++) {-			switch (b[i].type) {-				case 'Q':-					break;-				case 'C':-					break;-				case 'z':-					found = true;-					break;-				default:-					break;-			}-			-			if (found || i + 1 == num_b) {-				-				return_if_fail (i >= 1);-				-				if (b[i - 1].type == 'Q') {-					return_if_fail (i >= 1);-					left_x = b[i - 1].x0;-					left_y = b[i - 1].y0;-					last_type = PointType.QUADRATIC;-				} else if (b[i - 1].type == 'C') {-					return_if_fail (i >= 1);-					left_x = b[i - 1].x1;-					left_y = b[i - 1].y1;-					last_type = PointType.CUBIC;-				} else if (b[i - 1].type == 'S') {-					return_if_fail (i >= 1);-					left_x = b[i - 1].x1;-					left_y = b[i - 1].y1;-					last_type = PointType.CUBIC;-				} else if (b[i - 1].type == 'L' || last.type == 'M') {-					return_if_fail (i >= 2); // FIXME: -2 can be C or L-					left_x = b[i - 2].x0 + (b[i - 1].x0 - b[i - 2].x0) / 3.0;-					left_y = b[i - 2].y0 + (b[i - 1].y0 - b[i - 2].y0) / 3.0;-					last_type = PointType.LINE_CUBIC;-				} else {-					warning (@"Unexpected type. $(b[i - 1])\n");-				}-				return;	-			}-			-			last = b[i];-		}-		-		warning ("Last point not found.");-	}--	PathList create_paths_inkscape (BezierPoints[] b, int num_b) {-		double last_x;-		double last_y; -		PointType last_type;-		Path path;-		PathList path_list = new PathList ();-		EditPoint ep = new EditPoint ();-		Gee.ArrayList<EditPoint> smooth_points = new Gee.ArrayList<EditPoint> ();-				-		path = new Path ();-		-		if (num_b == 0) {-			warning ("No SVG data");-			return path_list;-		}--		if (b[0].type != 'M') {-			warning ("Path must begin with M or m.");-			return path_list;-		}-		-		find_last_handle (0, b, num_b, out last_x, out last_y, out last_type);--		for (int i = 0; i < num_b; i++) {-			if (b[i].type == '\0') {-				warning ("Parser error.");-				return path_list;-			}--			if (b[i].type == 'z') {-				path.close ();-				path.create_list ();-				path.recalculate_linear_handles ();-				path_list.add (path);-				path = new Path ();-				-				if (i + 1 >= num_b) {-					break;-				} else {-					find_last_handle (i + 1, b, num_b, out last_x, out last_y, out last_type);-				}-			}-			-			if (i >= num_b) {-				break;-			}-			-			if (b[i].type == 'M') {-				ep = path.add (b[i].x0, b[i].y0);-				ep.set_point_type (PointType.CUBIC);--				ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);-				-				if (i == 0 || (b[i - 1].type == 'z')) {-					ep.get_left_handle ().set_point_type (last_type);-					ep.get_left_handle ().move_to_coordinate (last_x, last_y);-				} else {-					if (b[i - 1].type == 'C' || b[i - 1].type == 'S') {-						ep.get_left_handle ().set_point_type (PointType.CUBIC);-						ep.get_left_handle ().move_to_coordinate (b[i + 1].x1, b[i + 1].y1);-					} -					-					if (b[i + 1].type == 'C' || b[i - 1].type == 'S') {-						ep.get_right_handle ().set_point_type (PointType.CUBIC);-						ep.get_right_handle ().move_to_coordinate (b[i + 1].x0, b[i + 1].y0);-					} else if (b[i + 1].type == 'L' || b[i + 1].type == 'M') {-						ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);					-					}-				}-			}--			if (b[i].type == 'L') {-				return_val_if_fail (i != 0, path_list);-				-				ep = path.add (b[i].x0, b[i].y0);-				ep.set_point_type (PointType.CUBIC);-				ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);-				ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);--				if (b[i + 1].type == 'L' || b[i + 1].type == 'M' || b[i + 1].type == 'z') {-					ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);-				}--				if (b[i -1].type == 'L' || b[i - 1].type == 'M') {-					ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);-				}-			}-			-			if (b[i].type == 'Q') {-				return_val_if_fail (i != 0, path_list);--				ep.set_point_type (PointType.QUADRATIC);-				-				ep.get_right_handle ().set_point_type (PointType.QUADRATIC);-				ep.get_right_handle ().move_to_coordinate (b[i].x0, b[i].y0);-				-				if (b[i + 1].type != 'z') {-					ep = path.add (b[i].x1, b[i].y1);--					ep.get_left_handle ().set_point_type (PointType.QUADRATIC);-					ep.get_left_handle ().move_to_coordinate (b[i].x0, b[i].y0);-				}-			}-	-			if (b[i].type == 'C' || b[i].type == 'S') {-				return_val_if_fail (i != 0, path_list);--				ep.set_point_type (PointType.CUBIC);-				-				ep.get_right_handle ().set_point_type (PointType.CUBIC);-				ep.get_right_handle ().move_to_coordinate (b[i].x0, b[i].y0);-				-				if (b[i].type == 'S') {-					smooth_points.add (ep);-				}-				-				if (b[i + 1].type != 'z') {-					ep = path.add (b[i].x2, b[i].y2);--					ep.get_left_handle ().set_point_type (PointType.CUBIC);-					ep.get_left_handle ().move_to_coordinate (b[i].x1, b[i].y1);-				}-			}-		}--		foreach (EditPoint e in smooth_points) {-			e.set_point_type (PointType.LINE_DOUBLE_CURVE);-			e.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);-			e.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);-		}--		foreach (EditPoint e in smooth_points) {-			path.recalculate_linear_handles_for_point (e);-		}-		-		for (int i = 0; i < 3; i++) {-			foreach (EditPoint e in smooth_points) {-				e.set_tie_handle (true);-				e.process_tied_handle ();-			}-		}-		-		if (path.points.size > 0) {-			path_list.add (path);-		}--		foreach (Path p in path_list.paths) {-			p.remove_points_on_points ();-		}-				-		return path_list;-	}--	PathList create_paths_illustrator (BezierPoints[] b, int num_b) {-		Path path;-		PathList path_list = new PathList ();-		EditPoint ep;-		bool first_point = true;-		double first_left_x, first_left_y;-		Gee.ArrayList<EditPoint> smooth_points = new Gee.ArrayList<EditPoint> ();-		-		if (num_b > b.length) {-			warning ("num_b > b.length: $num_b > $(b.length)");-			return path_list;-		}-		-		path = new Path ();-				-		if (num_b <= 1) {-			warning ("No SVG data");-			return path_list;-		}-		-		first_left_x = 0;-		first_left_y = 0;--		// FIXME: array boundaries-		for (int i = 0; i < num_b; i++) {			-			if (b[i].type == '\0') {-				warning ("Parser error.");-				return path_list;-			} else if (b[i].type == 'z') {-				path.close ();-				path.create_list ();-				-				int first_index = 1;--				for (int j = i - 1; j >= 1; j--) {-					if (b[j].type == 'z') {-						first_index = j + 1; // from z to M -					}-				}-				-				if (b[first_index].type == 'C' || b[first_index].type == 'S') {-					return_val_if_fail (path.points.size != 0, path_list);-					ep = path.points.get (path.points.size - 1);-					-					if (b[i - 1].type != 'L' ) {-						ep.get_right_handle ().set_point_type (PointType.CUBIC);-						ep.get_right_handle ().move_to_coordinate (b[first_index].x0, b[first_index].y0);-					}-				} else if (b[first_index].type == 'L') {-					return_val_if_fail (path.points.size != 0, path_list);-					ep = path.points.get (path.points.size - 1);-					ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);-					path.recalculate_linear_handles_for_point (ep);-				} else {-					warning ("Unexpected type: %s", (!) b[first_index].type.to_string ());-				}-				-				path.recalculate_linear_handles ();-				path_list.add (path);-				-				path = new Path ();-				first_point = true;				-			} else if (b[i].type == 'M') {-			} else if (b[i].type == 'L') {--				if (first_point) {-					first_left_x = b[i].x0;-					first_left_y = b[i].y0;-				}-				-				ep = path.add (b[i].x0, b[i].y0);-				ep.set_point_type (PointType.LINE_CUBIC); // TODO: quadratic-				ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);--				if (b[i -1].type == 'L' || first_point) {-					// ep.get_left_handle ().set_point_type (PointType.LINE_CUBIC);-				}-				-				if (b[i + 1].type == 'C' || b[i + 1].type == 'S') {-					return_val_if_fail (i + 1 < num_b, path_list);-					ep.get_right_handle ().set_point_type (PointType.CUBIC);-					ep.get_right_handle ().move_to_coordinate (b[i + 1].x0, b[i + 1].y0);-				}-				-				first_point = false;-			} else if (b[i].type == 'Q') {-				warning ("Illustrator does not support quadratic control points.");-				warning (@"$(b[i])\n");-			} else if (b[i].type == 'C' || b[i].type == 'S') {-				-				if (first_point) {-					first_left_x = b[i].x0;-					first_left_y = b[i].y0;-				}-				-				ep = path.add (b[i].x2, b[i].y2);-				ep.set_point_type (PointType.CUBIC);--				ep.get_right_handle ().set_point_type (PointType.CUBIC);-				ep.get_left_handle ().set_point_type (PointType.CUBIC);-				-				ep.get_left_handle ().move_to_coordinate (b[i].x1, b[i].y1);--				if (b[i].type == 'S') {-					smooth_points.add (ep);-				}		--				if (b[i + 1].type != 'z') {-					ep.get_right_handle ().move_to_coordinate (b[i + 1].x0, b[i + 1].y0);-				} else {-					ep.get_right_handle ().move_to_coordinate (first_left_x, first_left_y);-				}-								-				first_point = false;-			} else {-				warning ("Unknown control point type.");-				warning (@"$(b[i])\n");-			}-		}-		-		foreach (EditPoint e in smooth_points) {-			e.set_point_type (PointType.LINE_DOUBLE_CURVE);-			e.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);-			e.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE);-		}--		foreach (EditPoint e in smooth_points) {-			path.recalculate_linear_handles_for_point (e);-		}-		-		for (int i = 0; i < 3; i++) {-			foreach (EditPoint e in smooth_points) {-				e.set_tie_handle (true);-				e.process_tied_handle ();-			}-		}-				-		if (path.points.size > 0) {-			path_list.add (path);-		}-		-		foreach (Path p in path_list.paths) {-			p.remove_points_on_points ();-		}-		-		return path_list;-	}-	-	// TODO: implement a default svg parser--	static int parse_int (string? s) {-		if (is_null (s)) {-			warning ("null instead of string");-			return 0;-		}-		-		if (!is_point ((!) s)) {-			warning (@"Expecting an integer got: $((!) s)");-			return 0;-		}-		-		return int.parse ((!) s);-	}-	-	static double parse_double (string? s) {-		if (is_null (s)) {-			warning ("Got null instead of expected string.");-			return 0;-		}-		-		if (!is_point ((!) s)) {-			warning (@"Expecting a double got: $((!) s)");-			return 0;-		}-		-		return double.parse ((!) s);-	}-	-	static bool is_point (string? s) {-		if (s == null) {-			warning ("s is null");-			return false;-		}-		-		return double.try_parse ((!) s);-	}-	-	Path parse_poly_data (string polygon_points) {-		string data = add_separators (polygon_points);-		string[] c = data.split (" ");-		Path path;-		BezierPoints[] bezier_points = new BezierPoints[c.length + 1];-		int bi;-		Glyph g;-		EditPoint ep;-		-		bi = 0;-		for (int i = 0; i < c.length - 1; i += 2) {	-			if (i + 1 >= c.length) {-				warning ("No y value.");-				break;-			}--			if (bi >= bezier_points.length) {-				warning ("End of bezier_points");-				break;-			}--			bezier_points[bi] = new BezierPoints ();-			bezier_points[bi].type == 'L';-			bezier_points[bi].x0 = parse_double (c[i]);-			bezier_points[bi].y0 = -parse_double (c[i + 1]);-			bi++;-		}-			-		g = MainWindow.get_current_glyph ();-		move_and_resize (bezier_points, bi, false, 1, g);-		-		path = new Path ();-		for (int i = 0; i < bi; i++) {	-			ep = path.add (bezier_points[i].x0, bezier_points[i].y0);-			ep.set_point_type (PointType.LINE_CUBIC);-		}-		-		path.create_list ();-		path.recalculate_linear_handles ();-		-		return path;-	}-}--}diff --git a/libbirdfont/SvgStyle.vala b/libbirdfont/SvgStyle.valadeleted file mode 100644index 33a6cdc..0000000--- a/libbirdfont/SvgStyle.vala+++ /dev/null@@ -1,124 +0,0 @@-/*-	Copyright (C) 2015 Johan Mattsson--	This library is free software; you can redistribute it and/or modify -	it under the terms of the GNU Lesser General Public License as -	published by the Free Software Foundation; either version 3 of the -	License, or (at your option) any later version.--	This library 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 -	Lesser General Public License for more details.-*/--using B;-using Math;--namespace BirdFont {--public class SvgStyle {-	-	Gee.HashMap<string, string> style;-	-	public SvgStyle () {-		style = new Gee.HashMap<string, string> ();-	}-	-	public LineCap get_line_cap () {-		string l;-		-		if (!style.has_key ("stroke-linecap")) {-			return LineCap.BUTT;-		}-		-		l = style.get ("stroke-linecap");-		-		if (l == "round") {-			return LineCap.ROUND;-		} else if (l == "square") {-			return LineCap.SQUARE;-		}-		-		return LineCap.BUTT; 	-	}-	-	public bool has_stroke () {-		bool s = true;-		-		if (style.has_key ("stroke")) {-			s = style.get ("stroke") != "none";-		}-				-		return get_stroke_width () > 0 && s;-	}-		-	public double get_stroke_width () {-		if (!style.has_key ("stroke-width")) {-			return 0;-		}--		return double.parse (style.get ("stroke-width"));-	}-	-	-	public static SvgStyle parse (Attributes attributes) {-		SvgStyle s = new SvgStyle ();-		-		foreach (Attribute a in attributes) {-			if (a.get_name () == "style") {-				s.parse_key_value_pairs (a.get_content ());-			}-			-			if (a.get_name () == "stroke-width") {-				s.style.set ("stroke-width", a.get_content ());-			}--			if (a.get_name () == "stroke") {-				s.style.set ("stroke", a.get_content ());-			}--			if (a.get_name () == "fill") {-				s.style.set ("fill", a.get_content ());-			}-		}-		-		return s;-	}-	-	void parse_key_value_pairs (string svg_style) {-		string[] p = svg_style.split (";");-		string[] pair;-		string k, v;-		-		foreach (string kv in p) {-			pair = kv.split (":");-			-			if (pair.length != 2) {-				warning ("pair.length != 2");-				continue;-			}-			-			k = pair[0];-			v = pair[1];-			-			style.set (k, v);-		}-	}-	-	public void apply (PathList path_list) {-		foreach (Path p in path_list.paths) {-			if (has_stroke ()) {-				p.stroke = get_stroke_width ();-			} else {-				p.stroke = 0;-			}-			-			p.line_cap = get_line_cap ();-			p.reset_stroke ();-			p.update_region_boundaries ();		-		}-	}-}--}

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112