Clone in a terminal:
Commit 0496f4d
Johan Mattsson - 2016-01-11T21:36:25+00:00
0496f4deb093ae5be1d4958b17eaf9265453ba14johan.mattsson.m@gmail.com

Style sheets for SVG files

Changed files (11)

Diff

diff --git a/configure b/configureindex ac5fd92..b0a9277 100755--- a/configure+++ b/configure@@ -114,7 +114,7 @@ def configure(gtk, libbgee): 				'fontconfig', 				] -	test_library_version ('xmlbird', True, '1.1.0')+	test_library_version ('xmlbird', True, '1.2.0')  	for lib in libs: 		test_library_version (lib)diff --git a/libbirdfont/Glyph.vala b/libbirdfont/Glyph.valaindex c560033..f0731eb 100644--- a/libbirdfont/Glyph.vala+++ b/libbirdfont/Glyph.vala@@ -278,7 +278,6 @@ public class Glyph : FontDisplay { 	// FIXME: delete group 	public void add_active_object (Layer? group, SvgBird.Object? o) { 		SvgBird.Object object;-		Layer g;  		if (o != null) { 			object = (!) o;diff --git a/libbirdfont/OpenFontFormat/SvgTable.vala b/libbirdfont/OpenFontFormat/SvgTable.valaindex 45aa35a..61f93a3 100644--- a/libbirdfont/OpenFontFormat/SvgTable.vala+++ b/libbirdfont/OpenFontFormat/SvgTable.vala@@ -34,7 +34,6 @@ public class SvgTable : OtfTable { 		Font font = OpenFontFormatWriter.get_current_font (); 		GlyphCollection? glyph_collection; 		GlyphCollection glyphs;-		string? svg_data; 		int gid; 		Gee.ArrayList<EmbeddedSvg> embedded_svg; 		diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 606f4f8..f10a611 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -967,6 +967,7 @@ public class Path : GLib.Object { 			points.add (p); 			p.prev = previous_point; 			p.next = previous_point.next;+			previous_point.next = p; 		} 		 		last_point = p;diff --git a/libsvgbird/AttributePattern.vala b/libsvgbird/AttributePattern.valanew file mode 100644index 0000000..72d1550--- /dev/null+++ b/libsvgbird/AttributePattern.vala@@ -0,0 +1,112 @@+/*+	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 {++public enum AttributePatternType {+	NONE,+	ANYTHING,+	LIST,+	EQUALS,+	STARTS_WITH+}++public class AttributePattern : GLib.Object {+	public string name = "";+	public string? content = null;+	public AttributePatternType type = AttributePatternType.NONE;+	+	public bool match (Attributes attributes) {+		switch (type) {+		case AttributePatternType.ANYTHING:+			return match_attribute_name (attributes);+		case AttributePatternType.LIST:+			return match_list (attributes);+		case AttributePatternType.EQUALS:+			return attribute_equals (attributes);+		case AttributePatternType.STARTS_WITH:+			return attribute_start_with (attributes);+		}+		+		return false;+	}++	string remove_hypen (string content) {+		int hyphen = content.index_of ("-");+		+		if (hyphen == -1) {+			return content;+		}+		+		return content.substring (0, hyphen);+	}++	bool attribute_start_with (Attributes attributes) {+		foreach (Attribute attribute in attributes) {+			if (attribute.get_name () == name +				&& remove_hypen (attribute.get_content ()) == content) {+				return true;+			}+		}+		+		return false;+	}++	bool attribute_equals (Attributes attributes) {+		foreach (Attribute attribute in attributes) {+			if (attribute.get_name () == name +				&& attribute.get_content () == content) {+				return true;+			}+		}+		+		return false;+	}+	+	bool match_attribute_name (Attributes attributes) {+		foreach (Attribute attribute in attributes) {+			if (attribute.get_name () == name) {+				return true;+			}+		}+		+		return false;+	}+	+	bool match_list (Attributes attributes) {+		if (content == null) {+			return false;+		}+		+		string[] list = ((!) content).split (" ");+		foreach (Attribute attribute in attributes) {+			if (attribute.get_name () == name) {+				+				string attribute_content = attribute.get_content ();+				foreach (string list_item in list) {+					if (attribute_content == list_item) {+						return true;+					}+				}+			}+		}+		+		return false;+	}+}++}diff --git a/libsvgbird/Defs.vala b/libsvgbird/Defs.valaindex a1a022f..233f3a2 100644--- a/libsvgbird/Defs.vala+++ b/libsvgbird/Defs.vala@@ -32,7 +32,6 @@ public class Defs { 		string tag_id = (!) url;  		if (unlikely (!is_url (tag_id))) {-			warning ("Not an URL: " + tag_id); 			return null; 		} diff --git a/libsvgbird/Selector.vala b/libsvgbird/Selector.valanew file mode 100644index 0000000..6f00e2f--- /dev/null+++ b/libsvgbird/Selector.vala@@ -0,0 +1,41 @@+/*+	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 {++public class Selector : GLib.Object {+	+	Gee.ArrayList<SelectorPattern> patterns;+	public SvgStyle style { get; set; }++	public Selector (string pattern, SvgStyle style) {+		this.patterns = new Gee.ArrayList<SelectorPattern> ();+		string[] selector_patterns = pattern.split (",");+		+		for (int i = 0; i < selector_patterns.length; i++) {+			patterns.add (new SelectorPattern (selector_patterns[i]));+		}++		this.style = style;+	}+	+	public bool match (string tag, string? id, string? css_class) {+		return false;+	}+}++}diff --git a/libsvgbird/SelectorTag.vala b/libsvgbird/SelectorTag.valanew file mode 100644index 0000000..90bcbc9--- /dev/null+++ b/libsvgbird/SelectorTag.vala@@ -0,0 +1,138 @@+/*+	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 part of a CSS selector pattern. */+public class SelectorTag : GLib.Object {+	public string name;+	string? id = null;+	string? css_class = null;+	Gee.ArrayList<AttributePattern>? attribute_patterns = null;++	public SelectorTag (string pattern) {+		string tag_pattern = pattern.strip ();+		int id_separator = tag_pattern.index_of ("#");+		int class_separator = tag_pattern.index_of (".");+		int attribute_separator = tag_pattern.index_of ("[");+		+		if (id_separator != -1) {+			name = tag_pattern.substring (0, id_separator);+			id = tag_pattern.substring (id_separator + "#".length);+		} else if (class_separator != -1) {+			name = tag_pattern.substring (0, class_separator);+			css_class = tag_pattern.substring (class_separator + ".".length);+		} else if (attribute_separator != -1) {+			parse_attributes (tag_pattern.substring (attribute_separator));+		} else {+			name = tag_pattern;+		}+	}++	void parse_attributes (string attributes) {+		int index = 0;+		Gee.ArrayList<AttributePattern> patterns = new Gee.ArrayList<AttributePattern> ();+		+		while (index != -1) {+			int start = attributes.index_of ("[", index);+			+			if (start == -1) {+				return;+			}+			+			int stop = attributes.index_of ("]", start);+			+			if (stop == -1) {+				return;+			}+			+			AttributePattern pattern;+			pattern = parse_attribute (attributes.substring (start, stop));+			patterns.add (pattern);+			+			index = stop + "]".length;+		}+		+		attribute_patterns = patterns;+	}+	+	AttributePattern parse_attribute (string attribute) {+		int starts_with = attribute.index_of ("|=");+		int in_list = attribute.index_of ("~=");+		int equals = attribute.index_of ("=");+		AttributePattern pattern = new AttributePattern ();++		if (starts_with != -1) {+			pattern.name = attribute.substring (0, starts_with);+			pattern.type = AttributePatternType.STARTS_WITH;+			pattern.content = attribute.substring (0, equals + "~=".length);+		} else if (in_list != -1) {+			pattern.name = attribute.substring (0, in_list);+			pattern.type = AttributePatternType.LIST;+			pattern.content = attribute.substring (0, equals + "~=".length);+		} else if (equals != -1) {+			pattern.name = attribute.substring (0, equals);+			pattern.type = AttributePatternType.EQUALS;+			pattern.content = attribute.substring (0, equals + "=".length);+		} else {+			pattern.name = attribute;+			pattern.type = AttributePatternType.ANYTHING;+		}+		+		return pattern;+	}++	public bool match (XmlElement tag, string? id, string? css_class) {+		string tag_name = tag.get_name ();+		+		if (this.name != "*" && this.name != "" && this.name != tag_name) {+			return false;+		}+		+		if (this.id != null) {+			if (id == null) {+				return false;+			} +			+			if (this.id != id) {+				return false;+			}+		}+		+		if (this.css_class != null) {+			if (css_class == null) {+				return false;+			} +			+			if (this.css_class != css_class) {+				return false;+			}+		}+		+		if (attribute_patterns != null) {+			foreach (AttributePattern pattern in (!) attribute_patterns) {+				if (!pattern.match (tag.get_attributes ())) {+					return false;+				}+			}+		}+		+		return true;+	}+}++}diff --git a/libsvgbird/StyleSheet.vala b/libsvgbird/StyleSheet.valanew file mode 100644index 0000000..5efff29--- /dev/null+++ b/libsvgbird/StyleSheet.vala@@ -0,0 +1,112 @@+/*+	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 {++public class StyleSheet : GLib.Object {+	+	public Gee.ArrayList<Selector> styles;+	+	public StyleSheet () {+		styles = new Gee.ArrayList<Selector> ();+	}+	+	public static StyleSheet parse (Defs defs, Tag style_tag) {+		StyleSheet style_sheet = new StyleSheet ();+		string css = style_tag.get_content ();+		css = get_cdata (css);+		css = add_separators (css);+		css = replace_whitespace (css);+		+		int index = 0;+		int start_bracket_length = "{".length;+		int end_bracket_length = "}".length;+		int css_length = css.length;+		+		while (index < css_length) {+			int style_rules_start = css.index_of ("{", index);+			int style_rules_end = css.index_of ("}", style_rules_start);+			+			if (style_rules_start == -1 || style_rules_end == -1) {+				break;+			}+			+			int selector_end = style_rules_start - start_bracket_length;+			string selectors = css.substring (index, selector_end - index);+			+			int style_start = style_rules_start + start_bracket_length;+			int style_end = style_rules_end;+			string style_rules = css.substring (style_start, style_end - style_start);+			+			index = style_rules_end + end_bracket_length;+			SvgStyle style = new SvgStyle.for_properties (defs, style_rules);+			+			Selector selector = new Selector (selectors, style);+			style_sheet.styles.add (selector);+		}+		+		return style_sheet;+	}+	+	public static string get_cdata (string tag_content) {+		StringBuilder data = new StringBuilder ();+		+		int index = 0;+		int cdata_tag_length = "<![CDATA[".length;+		int cdata_end_tag_length = "]]>".length;+		int content_length = tag_content.length;+		+		while (index < content_length) {+			int cdata_start = tag_content.index_of ("<![CDATA[", index);+			int cdata_end = tag_content.index_of ("]]>", cdata_start);+			+			if (cdata_start == -1 || cdata_end == -1) {+				break;+			}+			+			cdata_start += cdata_tag_length;+			data.append (tag_content.substring (cdata_start, cdata_end - cdata_start));+			index = cdata_end + cdata_end_tag_length;+		}+		+		if (index < tag_content.length) {+			data.append (tag_content.substring (index));+		}+		+		return data.str;+	}++	public static string add_separators (string data) {+		string style_data = data.replace (">", " > ");+		style_data = data.replace ("+", " + ");+		return style_data;+	}+	+	public static string replace_whitespace (string data) {+		string style_data = data.replace ("\n", " ");+		style_data = style_data.replace ("\r", " ");+		style_data = style_data.replace ("\t", " ");+		+		while (style_data.index_of ("  ") != -1) {+			style_data = style_data.replace ("  ", " ");+		}+		+		return style_data;+	}+}++}diff --git a/libsvgbird/SvgFile.vala b/libsvgbird/SvgFile.valaindex 42bee53..c3bb83d 100644--- a/libsvgbird/SvgFile.vala+++ b/libsvgbird/SvgFile.vala@@ -24,7 +24,9 @@ public class SvgFile : GLib.Object { 	public SvgFile () {		 	} 	-	public SvgDrawing parse_svg_file (Tag tag) {+	public SvgDrawing parse_svg_file (Tag svg_tag) {+		XmlTree tree = new XmlTree.for_tag (svg_tag);+		XmlElement tag = tree.get_root (); 		drawing = new SvgDrawing ();  		SvgStyle style = new SvgStyle ();@@ -40,7 +42,7 @@ public class SvgFile : GLib.Object { 			} 		} 				-		foreach (Tag t in tag) {+		foreach (XmlElement t in tag) { 			string name = t.get_name (); 			 			if (name == "g") {@@ -61,7 +63,7 @@ public class SvgFile : GLib.Object { 		return drawing; 	} -	private void parse_layer (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_layer (Layer layer, SvgStyle parent_style, XmlElement tag) { 		bool hidden = false;  		foreach (Attribute attr in tag.get_attributes ()) {	@@ -82,7 +84,7 @@ public class SvgFile : GLib.Object { 		 		SvgStyle style = SvgStyle.parse (drawing.defs, parent_style, tag.get_attributes ()); 		-		foreach (Tag t in tag) {+		foreach (XmlElement t in tag) { 			string name = t.get_name ();  			if (name == "g") {@@ -105,8 +107,8 @@ public class SvgFile : GLib.Object { 		} 	} -	void parse_defs (SvgDrawing drawing, Tag tag) {-		foreach (Tag t in tag) {+	void parse_defs (SvgDrawing drawing, XmlElement tag) {+		foreach (XmlElement t in tag) { 			// FIXME: radial 			string name = t.get_name (); 			@@ -129,7 +131,7 @@ public class SvgFile : GLib.Object { 		} 	} -	void parse_linear_gradient (SvgDrawing drawing, Tag tag) {+	void parse_linear_gradient (SvgDrawing drawing, XmlElement tag) { 		Gradient gradient = new Gradient (); 		 		drawing.defs.add (gradient);@@ -168,7 +170,7 @@ public class SvgFile : GLib.Object { 			} 		} 		-		foreach (Tag t in tag) {+		foreach (XmlElement t in tag) { 			// FIXME: radial 			string name = t.get_name (); 			@@ -178,7 +180,7 @@ public class SvgFile : GLib.Object { 		} 	} -	void parse_stop (Gradient gradient, Tag tag) {+	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 ()); 		Stop stop = new Stop ();@@ -218,11 +220,11 @@ public class SvgFile : GLib.Object { 	} 	 	// links are ignored, add the content to the layer-	void parse_link (Layer layer, SvgStyle parent_style, Tag tag) {+	void parse_link (Layer layer, SvgStyle parent_style, XmlElement tag) { 		parse_layer (layer, parent_style, tag); 	} 	-	void parse_object (Layer layer, SvgStyle parent_style, Tag tag) {+	void parse_object (Layer layer, SvgStyle parent_style, XmlElement tag) { 		string name = tag.get_name (); 		 		if (name == "path") {@@ -254,7 +256,7 @@ public class SvgFile : GLib.Object { 		} 	} -	private void parse_polygon (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_polygon (Layer layer, SvgStyle parent_style, XmlElement tag) { 		Polygon polygon = new Polygon ();  		foreach (Attribute attr in tag.get_attributes ()) {@@ -276,7 +278,7 @@ public class SvgFile : GLib.Object {  	} 	-	private void parse_polyline (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_polyline (Layer layer, SvgStyle parent_style, XmlElement tag) { 		Polyline polyline = new Polyline ();  		foreach (Attribute attr in tag.get_attributes ()) {@@ -297,7 +299,7 @@ public class SvgFile : GLib.Object { 		layer.add_object (polyline); 	} 	-	private void parse_rect (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_rect (Layer layer, SvgStyle parent_style, XmlElement tag) { 		Rectangle rectangle = new Rectangle ();  		foreach (Attribute attr in tag.get_attributes ()) {@@ -335,7 +337,7 @@ public class SvgFile : GLib.Object { 		layer.add_object (rectangle); 	} 	-	private void parse_circle (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_circle (Layer layer, SvgStyle parent_style, XmlElement tag) { 		Circle circle = new Circle (); 		 		foreach (Attribute attr in tag.get_attributes ()) {@@ -361,7 +363,7 @@ public class SvgFile : GLib.Object { 		layer.add_object (circle); 	} 	-	private void parse_ellipse (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_ellipse (Layer layer, SvgStyle parent_style, XmlElement tag) { 		Ellipse ellipse = new Ellipse (); 		 		foreach (Attribute attr in tag.get_attributes ()) {@@ -391,7 +393,7 @@ public class SvgFile : GLib.Object { 		layer.add_object (ellipse); 	} 	-	private void parse_line (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_line (Layer layer, SvgStyle parent_style, XmlElement tag) { 		Line line = new Line (); 		 		foreach (Attribute attr in tag.get_attributes ()) {@@ -574,7 +576,7 @@ public class SvgFile : GLib.Object { 		return param.strip();			 	} -	private bool is_visible (Tag tag) {+	private bool is_visible (XmlElement tag) { 		bool hidden = false;  		foreach (Attribute attr in tag.get_attributes ()) {@@ -602,7 +604,7 @@ public class SvgFile : GLib.Object { 		return new SvgTransforms (); 	} 	-	private void parse_path (Layer layer, SvgStyle parent_style, Tag tag) {+	private void parse_path (Layer layer, SvgStyle parent_style, XmlElement tag) { 		SvgPath path = new SvgPath ();  		foreach (Attribute attr in tag.get_attributes ()) {diff --git a/libsvgbird/SvgStyle.vala b/libsvgbird/SvgStyle.valaindex 59890c5..76cd8b6 100644--- a/libsvgbird/SvgStyle.vala+++ b/libsvgbird/SvgStyle.vala@@ -17,7 +17,7 @@ using Math;  namespace SvgBird { -public class SvgStyle {+public class SvgStyle : GLib.Object { 	 	public Gee.HashMap<string, string> style; 	@@ -31,7 +31,12 @@ public class SvgStyle { 	public SvgStyle () { 		style = new Gee.HashMap<string, string> (); 	}-	++	public SvgStyle.for_properties (Defs? defs, string style) {+		parse_key_value_pairs (style);+		set_style_properties (defs, this);+	}+ 	public LineCap get_line_cap () { 		string l; 		@@ -66,8 +71,6 @@ public class SvgStyle { 	 	public static SvgStyle parse (Defs? d, SvgStyle inherited, Attributes attributes) { 		SvgStyle s = new SvgStyle ();-		double fill_opacity = 1;-		double stroke_opacity = 1;  		s.style.set ("fill", "#000000"); // default fill value 				@@ -102,6 +105,14 @@ public class SvgStyle { 			} 		} 	+		set_style_properties (d, s);+		return s;+	}+	+	static void set_style_properties (Defs? d, SvgStyle s) {+		double fill_opacity = 1;+		double stroke_opacity = 1;+ 		s.stroke_width = SvgFile.parse_number (s.style.get ("stroke-width")); 		s.stroke = Color.parse (s.style.get ("stroke")); 		s.fill = Color.parse (s.style.get ("fill"));@@ -131,9 +142,7 @@ public class SvgStyle { 		if (s.stroke != null) { 			Color color = (!) s.stroke; 			color.a = stroke_opacity;-		}-		-		return s;+		}		 	} 	 	void parse_key_value_pairs (string svg_style) {

Contact

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