Clone in a terminal:
Commit fcb8229
Johan Mattsson - 2016-01-11T23:20:07+00:00
fcb82294a05e378be90d5f1ff29af240389fa1adjohan.mattsson.m@gmail.com

Apply style sheet in SVG files

Changed files (7)

Diff

diff --git a/libbirdfont/SvgParser.vala b/libbirdfont/SvgParser.valaindex 6db92df..322cd20 100644--- a/libbirdfont/SvgParser.vala+++ b/libbirdfont/SvgParser.vala@@ -125,7 +125,6 @@ public class SvgParser { 		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) {@@ -148,13 +147,8 @@ public class SvgParser { 			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 ());+		XmlTree xml_tree = new XmlTree (xml_data);+		path_list = parser.parse_svg_file (xml_tree.get_root ()); 	 		glyph = MainWindow.get_current_glyph (); 		foreach (Path p in path_list.paths) {@@ -193,10 +187,10 @@ public class SvgParser { 		import_svg_data (svg_data); 	} 	-	private PathList parse_svg_file (Tag tag) {+	private PathList parse_svg_file (XmlElement tag) { 		Layer pl = new Layer (); 	-		foreach (Tag t in tag) {+		foreach (XmlElement t in tag) { 			 			if (t.get_name () == "g") { 				parse_layer (t, pl);@@ -234,7 +228,7 @@ public class SvgParser { 		return LayerUtils.get_all_paths (pl); 	} 	-	private void parse_layer (Tag tag, Layer pl) {+	private void parse_layer (XmlElement tag, Layer pl) { 		Layer layer; 		bool hidden = false; @@ -254,7 +248,7 @@ public class SvgParser { 			return; 		} 					-		foreach (Tag t in tag) {+		foreach (XmlElement t in tag) { 			if (t.get_name () == "path") { 				parse_path (t, pl); 			}@@ -482,7 +476,7 @@ public class SvgParser { 		return param.strip();			 	} 	-	private void parse_circle (Tag tag, Layer pl) {+	private void parse_circle (XmlElement tag, Layer pl) { 		Path p; 		double x, y, r; 		Glyph g;@@ -515,7 +509,7 @@ public class SvgParser { 			} 		} 		-		style = SvgStyle.parse (null, style, tag.get_attributes ());+		style = SvgStyle.parse (null, style, tag); 		 		if (hidden) { 			return;@@ -545,7 +539,7 @@ public class SvgParser { 		append_paths (pl, npl); 	} -	private void parse_ellipse (Tag tag, Layer pl) {+	private void parse_ellipse (XmlElement tag, Layer pl) { 		Path p; 		double x, y, rx, ry; 		Glyph g;@@ -583,7 +577,7 @@ public class SvgParser { 			} 		} 		-		style = SvgStyle.parse (null, style, tag.get_attributes ());+		style = SvgStyle.parse (null, style, tag); 		 		if (hidden) { 			return;@@ -613,7 +607,7 @@ public class SvgParser { 		append_paths (pl, npl); 	} -	private void parse_line (Tag tag, Layer pl) {+	private void parse_line (XmlElement tag, Layer pl) { 		Path p; 		double x1, y1, x2, y2; 		BezierPoints[] bezier_points;@@ -649,7 +643,7 @@ public class SvgParser { 			} 		} 		-		style = SvgStyle.parse (null, style, tag.get_attributes ());+		style = SvgStyle.parse (null, style, tag); 		 		if (hidden) { 			return;@@ -690,7 +684,7 @@ public class SvgParser { 		append_paths (pl, npl); 	} 		-	private void parse_rect (Tag tag, Layer layer) {+	private void parse_rect (XmlElement tag, Layer layer) { 		Path p; 		double x, y, x2, y2; 		BezierPoints[] bezier_points;@@ -727,7 +721,7 @@ public class SvgParser { 			} 		} 		-		style = SvgStyle.parse (null, style, tag.get_attributes ());+		style = SvgStyle.parse (null, style, tag); 		 		if (hidden) { 			return;@@ -791,7 +785,7 @@ public class SvgParser { 		append_paths (layer, npl); 	} 	-	private void parse_polygon (Tag tag, Layer layer) {+	private void parse_polygon (XmlElement tag, Layer layer) { 		PathList path_list = get_polyline (tag); 		 		foreach (Path p in path_list.paths) {@@ -805,11 +799,11 @@ public class SvgParser { 		LayerUtils.append_paths (layer, pl); 	} 	-	private void parse_polyline (Tag tag, Layer layer) {	+	private void parse_polyline (XmlElement tag, Layer layer) {	 		append_paths (layer, get_polyline (tag)); 	} 	-	private PathList get_polyline (Tag tag) {+	private PathList get_polyline (XmlElement tag) { 		Path p = new Path (); 		bool hidden = false; 		PathList path_list = new PathList ();@@ -825,7 +819,7 @@ public class SvgParser { 			} 		} -		style = SvgStyle.parse (null, style, tag.get_attributes ());+		style = SvgStyle.parse (null, style, tag); 		 		if (hidden) { 			return path_list;@@ -843,7 +837,7 @@ public class SvgParser { 		return path_list; 	} 	-	private void parse_path (Tag tag, Layer layer) {+	private void parse_path (XmlElement tag, Layer layer) { 		Glyph glyph = MainWindow.get_current_glyph (); 		PathList path_list = new PathList (); 		SvgStyle style = new SvgStyle ();@@ -865,7 +859,7 @@ public class SvgParser { 			} 		} 		-		style = SvgStyle.parse (null, style, tag.get_attributes ());+		style = SvgStyle.parse (null, style, tag); 		 		if (hidden) { 			return;@@ -1537,21 +1531,16 @@ public class SvgParser { 	}  	public static EmbeddedSvg parse_embedded_svg_data (string xml_data) {-		XmlParser xmlparser = new XmlParser (xml_data);+		XmlTree tree = new XmlTree (xml_data);+		XmlElement tag = tree.get_root (); 		SvgDrawing drawing = new SvgDrawing ();	 		SvgFile svg_file = new SvgFile (); -		-		if (xmlparser.validate ()) {-			Tag root = xmlparser.get_root_tag ();-			drawing = svg_file.parse_svg_file (root);-			EmbeddedSvg svg = new EmbeddedSvg (drawing);-			svg.svg_data = xml_data;-			return svg;-		} else {-			warning ("Invalid xml file.");-		}-	-		return new EmbeddedSvg (drawing);++		XmlElement root = tree.get_root ();+		drawing = svg_file.parse_svg_file (root);+		EmbeddedSvg svg = new EmbeddedSvg (drawing);+		svg.svg_data = xml_data;+		return svg; 	}  }diff --git a/libsvgbird/Defs.vala b/libsvgbird/Defs.valaindex 233f3a2..6bc730c 100644--- a/libsvgbird/Defs.vala+++ b/libsvgbird/Defs.vala@@ -19,6 +19,7 @@ namespace SvgBird {  public class Defs { 	public Gee.ArrayList<Gradient> gradients = new Gee.ArrayList<Gradient> ();+	public StyleSheet style_sheet = new StyleSheet ();  	public void add (Gradient g) { 		gradients.add (g);diff --git a/libsvgbird/Selector.vala b/libsvgbird/Selector.valaindex 6f00e2f..927f4a7 100644--- a/libsvgbird/Selector.vala+++ b/libsvgbird/Selector.vala@@ -33,7 +33,13 @@ public class Selector : GLib.Object { 		this.style = style; 	} 	-	public bool match (string tag, string? id, string? css_class) {+	public bool match (XmlElement tag, string? id, string? css_class) {+		foreach (SelectorPattern pattern in patterns) {+			if (pattern.match (tag, id, css_class)) {+				return true;+			}+		}+		 		return false; 	} }diff --git a/libsvgbird/SelectorPattern.vala b/libsvgbird/SelectorPattern.valanew file mode 100644index 0000000..328802d--- /dev/null+++ b/libsvgbird/SelectorPattern.vala@@ -0,0 +1,110 @@+/*+	Copyright (C) 2016 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 SvgBird {++/** A CSS selector pattern. */+public class SelectorPattern : GLib.Object {+	Gee.ArrayList<SelectorTag> tags;++	public SelectorPattern (string pattern) {+		string p = pattern.strip ();+		string[] elements = p.split (" ");+		tags = new Gee.ArrayList<SelectorTag> ();+		+		foreach (string element in elements) {+			if (element != "") {+				tags.add (new SelectorTag (element));+			}+		}+	}+	+	public bool match (XmlElement tag, string? id, string? css_class) {+		for (int i = tags.size - 1; i >= 0; i--) {+			SelectorTag pattern = tags.get (i);+			+			if (pattern.name == ">") {+				if (i - 1 < 0) {+					return false;+				}+				+				string parent = tags.get (i - 1).name;+				+				if (!has_parent (tag, parent)) {+					return false;+				}+			} else if (pattern.name == "+") {+				if (i - 1 < 0) {+					return false;+				}+				+				string previous = tags.get (i - 1).name;+				+				if (!is_immediately_following (tag, previous)) {+					return false;+				}+			} else if (!pattern.match (tag, id, css_class)) {+				return false;+			}+		}+		+		return true;+	}+	+	public bool is_immediately_following (XmlElement tag, string previous) {+		return get_previous (tag) == tag;+	}+	+	XmlElement? get_previous (XmlElement? xml_parent) {+		if (xml_parent == null) {+			return null;+		}+		+		XmlElement element = (!) xml_parent;+		XmlElement? parent = element.get_parent ();+		+		if (parent != null) {+			XmlElement? previous = null;+			+			foreach (XmlElement e in (!) parent) {+				if (e == xml_parent) {+					return previous;+				}+				+				previous = e;+			}+		}+		+		return null;+	}+	+	public bool has_parent (XmlElement tag, string parent) {+		XmlElement? xml_parent = tag.get_parent ();+		+		while (xml_parent != null) {+			if (((!) xml_parent).get_name () == parent) {+				return true;+			}+			+			xml_parent = tag.get_parent ();+		}+		+		return false;+	}+}++}diff --git a/libsvgbird/StyleSheet.vala b/libsvgbird/StyleSheet.valaindex 5efff29..cd7fc59 100644--- a/libsvgbird/StyleSheet.vala+++ b/libsvgbird/StyleSheet.vala@@ -25,7 +25,28 @@ public class StyleSheet : GLib.Object { 		styles = new Gee.ArrayList<Selector> (); 	} 	-	public static StyleSheet parse (Defs defs, Tag style_tag) {+	public void inherit_style (XmlElement tag, SvgStyle style) {+		string? id = null;+		string? css_class = null;+		+		foreach (Attribute attribute in tag.get_attributes ()) {+			string name = attribute.get_name ();+			+			if (name == "id") {+				id = attribute.get_content ();+			} else if (name == "class") {+				css_class = attribute.get_content ();+			}+		}+		+		foreach (Selector selector in styles) {+			if (selector.match (tag, id, css_class)) {+				style.inherit (selector.style);+			}+		}+	}+	+	public static StyleSheet parse (Defs defs, XmlElement style_tag) { 		StyleSheet style_sheet = new StyleSheet (); 		string css = style_tag.get_content (); 		css = get_cdata (css);diff --git a/libsvgbird/SvgFile.vala b/libsvgbird/SvgFile.valaindex c3bb83d..b00eb30 100644--- a/libsvgbird/SvgFile.vala+++ b/libsvgbird/SvgFile.vala@@ -24,15 +24,13 @@ public class SvgFile : GLib.Object { 	public SvgFile () {		 	} 	-	public SvgDrawing parse_svg_file (Tag svg_tag) {-		XmlTree tree = new XmlTree.for_tag (svg_tag);-		XmlElement tag = tree.get_root ();+	public SvgDrawing parse_svg_file (XmlElement svg_tag) { 		drawing = new SvgDrawing ();  		SvgStyle style = new SvgStyle ();-		SvgStyle.parse (drawing.defs, style, tag.get_attributes ());+		SvgStyle.parse (drawing.defs, style, svg_tag); -		foreach (Attribute attr in tag.get_attributes ()) {	+		foreach (Attribute attr in svg_tag.get_attributes ()) {	 			if (attr.get_name () == "width") { 				drawing.width = parse_number (attr.get_content ()); 			}@@ -42,7 +40,7 @@ public class SvgFile : GLib.Object { 			} 		} 				-		foreach (XmlElement t in tag) {+		foreach (XmlElement t in svg_tag) { 			string name = t.get_name (); 			 			if (name == "g") {@@ -54,7 +52,7 @@ public class SvgFile : GLib.Object { 			} 			 			if (name == "a") {-				parse_link (drawing.root_layer, style, tag);+				parse_link (drawing.root_layer, style, svg_tag); 			} 			 			parse_object (drawing.root_layer, style, t);@@ -82,7 +80,7 @@ public class SvgFile : GLib.Object { 			layer.visible = !hidden; 		} 		-		SvgStyle style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		SvgStyle style = SvgStyle.parse (drawing.defs, parent_style, tag); 		 		foreach (XmlElement t in tag) { 			string name = t.get_name ();@@ -129,6 +127,16 @@ public class SvgFile : GLib.Object { 				gradient.href = null; 			} 		}+		+		foreach (XmlElement t in tag) {+			// FIXME: radial+			string name = t.get_name ();+			+			if (name == "style") {+				drawing.defs.style_sheet = StyleSheet.parse (drawing.defs, t);+			}+		}+		 	}  	void parse_linear_gradient (SvgDrawing drawing, XmlElement tag) {@@ -182,7 +190,7 @@ public class SvgFile : GLib.Object {  	void parse_stop (Gradient gradient, XmlElement tag) { 		SvgStyle parent_style = new SvgStyle (); // not inherited-		SvgStyle style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		SvgStyle style = SvgStyle.parse (drawing.defs, parent_style, tag); 		Stop stop = new Stop (); 		 		gradient.stops.add (stop);@@ -271,7 +279,7 @@ public class SvgFile : GLib.Object { 		} 		 		polygon.transforms = get_transform (tag.get_attributes ());-		polygon.style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		polygon.style = SvgStyle.parse (drawing.defs, parent_style, tag); 		polygon.visible = is_visible (tag);	 		 		layer.add_object (polygon);@@ -293,7 +301,7 @@ public class SvgFile : GLib.Object { 		} 		 		polyline.transforms = get_transform (tag.get_attributes ());-		polyline.style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		polyline.style = SvgStyle.parse (drawing.defs, parent_style, tag); 		polyline.visible = is_visible (tag);	 		 		layer.add_object (polyline);@@ -331,7 +339,7 @@ public class SvgFile : GLib.Object { 		} 		 		rectangle.transforms = get_transform (tag.get_attributes ());-		rectangle.style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		rectangle.style = SvgStyle.parse (drawing.defs, parent_style, tag); 		rectangle.visible = is_visible (tag);	 		 		layer.add_object (rectangle);@@ -357,7 +365,7 @@ public class SvgFile : GLib.Object { 		} 		 		circle.transforms = get_transform (tag.get_attributes ());-		circle.style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		circle.style = SvgStyle.parse (drawing.defs, parent_style, tag); 		circle.visible = is_visible (tag);	 		 		layer.add_object (circle);@@ -387,7 +395,7 @@ public class SvgFile : GLib.Object { 		} 		 		ellipse.transforms = get_transform (tag.get_attributes ());-		ellipse.style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		ellipse.style = SvgStyle.parse (drawing.defs, parent_style, tag); 		ellipse.visible = is_visible (tag);	 		 		layer.add_object (ellipse);@@ -417,7 +425,7 @@ public class SvgFile : GLib.Object { 		} 		 		line.transforms = get_transform (tag.get_attributes ());-		line.style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		line.style = SvgStyle.parse (drawing.defs, parent_style, tag); 		line.visible = is_visible (tag);	 		 		layer.add_object (line);@@ -614,7 +622,7 @@ public class SvgFile : GLib.Object { 		} 		 		path.transforms = get_transform (tag.get_attributes ());-		path.style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ());+		path.style = SvgStyle.parse (drawing.defs, parent_style, tag); 		path.visible = is_visible (tag);	 		 		layer.add_object (path);diff --git a/libsvgbird/SvgStyle.vala b/libsvgbird/SvgStyle.valaindex 76cd8b6..377780b 100644--- a/libsvgbird/SvgStyle.vala+++ b/libsvgbird/SvgStyle.vala@@ -19,7 +19,7 @@ namespace SvgBird {  public class SvgStyle : GLib.Object { 	-	public Gee.HashMap<string, string> style;+	public Gee.HashMap<string, string> style = new Gee.HashMap<string, string> (); 	 	public Color? stroke = null; 	public Color? fill = null;@@ -29,7 +29,6 @@ public class SvgStyle : GLib.Object { 	public double stroke_width = 0; 	 	public SvgStyle () {-		style = new Gee.HashMap<string, string> (); 	}  	public SvgStyle.for_properties (Defs? defs, string style) {@@ -69,14 +68,22 @@ public class SvgStyle : GLib.Object { 		return stroke_width; 	} 	-	public static SvgStyle parse (Defs? d, SvgStyle inherited, Attributes attributes) {+	public void inherit (SvgStyle inherited) {+		foreach (string key in inherited.style.keys) {+			style.set (key, inherited.style.get (key));+		}+	}+	+	public static SvgStyle parse (Defs? d, SvgStyle inherited, XmlElement tag) { 		SvgStyle s = new SvgStyle ();+		Attributes attributes = tag.get_attributes (); -		s.style.set ("fill", "#000000"); // default fill value-				-		// inherit-		foreach (string key in inherited.style.keys) {-			s.style.set (key, inherited.style.get (key));+		s.style.set ("fill", "#000000"); // default fill value		+		s.inherit (inherited);+		+		if (d != null) {+			StyleSheet style_sheet = ((!) d).style_sheet;+			style_sheet.inherit_style (tag, s); 		}  		foreach (Attribute a in attributes) {@@ -146,7 +153,7 @@ public class SvgStyle : GLib.Object { 	} 	 	void parse_key_value_pairs (string svg_style) {-		string[] p = svg_style.split (";");+		string[] p = svg_style.strip ().split (";"); 		string[] pair; 		string k, v; 		@@ -154,7 +161,7 @@ public class SvgStyle : GLib.Object { 			pair = kv.split (":"); 			 			if (pair.length != 2) {-				warning ("pair.length != 2");+				warning ("pair.length != 2 in " + svg_style); 				continue; 			} 			

Contact

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