The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Style sheets for SVG files

These changes was commited to the Birdfont repository Mon, 11 Jan 2016 17:51:41 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
author Johan Mattsson <johan.mattsson.m@gmail.com>
Mon, 11 Jan 2016 17:51:41 +0000 (18:51 +0100)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Mon, 11 Jan 2016 21:36:25 +0000 (22:36 +0100)
commit 0496f4deb093ae5be1d4958b17eaf9265453ba14
tree fba7826e0636fad35c12b6212c3108fec844fdbc
parent 4431915b0597afe81bdef75bdae99aa45c30582e
Style sheets for SVG files

12 files changed:
configure
libbirdfont/Glyph.vala
libbirdfont/OpenFontFormat/SvgTable.vala
libbirdfont/Path.vala
libsvgbird/AttributePattern.vala [new ]
libsvgbird/Defs.vala
libsvgbird/Selector.vala [new ]
libsvgbird/SelectorTag.vala [new ]
libsvgbird/StyleSheet.vala [new ]
libsvgbird/SvgFile.vala
libsvgbird/SvgStyle.vala
--- a/configure +++ b/configure @@ -114,7 +114,7 @@ '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)
--- a/libbirdfont/Glyph.vala +++ b/libbirdfont/Glyph.vala @@ -278,7 +278,6 @@ // FIXME: delete group public void add_active_object (Layer? group, SvgBird.Object? o) { SvgBird.Object object; - Layer g; if (o != null) { object = (!) o;
--- a/libbirdfont/OpenFontFormat/SvgTable.vala +++ b/libbirdfont/OpenFontFormat/SvgTable.vala @@ -34,7 +34,6 @@ Font font = OpenFontFormatWriter.get_current_font (); GlyphCollection? glyph_collection; GlyphCollection glyphs; - string? svg_data; int gid; Gee.ArrayList<EmbeddedSvg> embedded_svg;
--- a/libbirdfont/Path.vala +++ b/libbirdfont/Path.vala @@ -967,6 +967,7 @@ points.add (p); p.prev = previous_point; p.next = previous_point.next; + previous_point.next = p; } last_point = p;
--- /dev/null +++ b/libsvgbird/AttributePattern.vala @@ -1,1 +1,113 @@ + /* + 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; + } + } + + }
--- a/libsvgbird/Defs.vala +++ b/libsvgbird/Defs.vala @@ -32,7 +32,6 @@ string tag_id = (!) url; if (unlikely (!is_url (tag_id))) { - warning ("Not an URL: " + tag_id); return null; }
diff --git libsvgbird/Selector.vala(new)
--- /dev/null +++ b/libsvgbird/Selector.vala @@ -1,1 +1,42 @@ + /* + 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 libsvgbird/SelectorTag.vala(new)
--- /dev/null +++ b/libsvgbird/SelectorTag.vala @@ -1,1 +1,139 @@ + /* + 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 libsvgbird/StyleSheet.vala(new)
--- /dev/null +++ b/libsvgbird/StyleSheet.vala @@ -1,1 +1,113 @@ + /* + 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; + } + } + + }
--- a/libsvgbird/SvgFile.vala +++ b/libsvgbird/SvgFile.vala @@ -24,7 +24,9 @@ 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 @@ } } - foreach (Tag t in tag) { + foreach (XmlElement t in tag) { string name = t.get_name (); if (name == "g") { @@ -61,7 +63,7 @@ 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 @@ 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 @@ } } - 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 @@ } } - 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 @@ } } - foreach (Tag t in tag) { + foreach (XmlElement t in tag) { // FIXME: radial string name = t.get_name (); @@ -178,7 +180,7 @@ } } - 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 @@ } // 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 @@ } } - 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 @@ } - 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 ()) {
--- a/libsvgbird/SvgStyle.vala +++ b/libsvgbird/SvgStyle.vala @@ -17,7 +17,7 @@ namespace SvgBird { - public class SvgStyle { + public class SvgStyle : GLib.Object { public Gee.HashMap<string, string> style; @@ -31,7 +31,12 @@ 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 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 @@ } } + 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 @@ if (s.stroke != null) { Color color = (!) s.stroke; color.a = stroke_opacity; - } - - return s; + } } void parse_key_value_pairs (string svg_style) {