The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Apply style sheet in SVG files

These changes was commited to the Birdfont repository Mon, 11 Jan 2016 23:06:45 +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 23:06:45 +0000 (00:06 +0100)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Mon, 11 Jan 2016 23:20:07 +0000 (00:20 +0100)
commit fcb82294a05e378be90d5f1ff29af240389fa1ad
tree 156d96325b742186fad4adf838d2e02c58416d9b
parent 0496f4deb093ae5be1d4958b17eaf9265453ba14
Apply style sheet in SVG files

libbirdfont/SvgParser.vala
libsvgbird/Defs.vala
libsvgbird/Selector.vala
libsvgbird/SelectorPattern.vala [new ]
libsvgbird/StyleSheet.vala
libsvgbird/SvgFile.vala
libsvgbird/SvgStyle.vala
--- a/libbirdfont/SvgParser.vala +++ b/libbirdfont/SvgParser.vala @@ -125,7 +125,6 @@ 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 @@ 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 @@ 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 @@ 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 @@ return; } - foreach (Tag t in tag) { + foreach (XmlElement t in tag) { if (t.get_name () == "path") { parse_path (t, pl); } @@ -482,7 +476,7 @@ 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 @@ } } - style = SvgStyle.parse (null, style, tag.get_attributes ()); + style = SvgStyle.parse (null, style, tag); if (hidden) { return; @@ -545,7 +539,7 @@ 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 @@ } } - style = SvgStyle.parse (null, style, tag.get_attributes ()); + style = SvgStyle.parse (null, style, tag); if (hidden) { return; @@ -613,7 +607,7 @@ 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 @@ } } - style = SvgStyle.parse (null, style, tag.get_attributes ()); + style = SvgStyle.parse (null, style, tag); if (hidden) { return; @@ -690,7 +684,7 @@ 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 @@ } } - style = SvgStyle.parse (null, style, tag.get_attributes ()); + style = SvgStyle.parse (null, style, tag); if (hidden) { return; @@ -791,7 +785,7 @@ 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 @@ 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 @@ } } - style = SvgStyle.parse (null, style, tag.get_attributes ()); + style = SvgStyle.parse (null, style, tag); if (hidden) { return path_list; @@ -843,7 +837,7 @@ 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 @@ } } - style = SvgStyle.parse (null, style, tag.get_attributes ()); + style = SvgStyle.parse (null, style, tag); if (hidden) { return; @@ -1537,24 +1531,19 @@ } 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; } } }
--- a/libsvgbird/Defs.vala +++ b/libsvgbird/Defs.vala @@ -19,6 +19,7 @@ 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);
--- a/libsvgbird/Selector.vala +++ b/libsvgbird/Selector.vala @@ -33,10 +33,16 @@ 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; } } }
--- /dev/null +++ b/libsvgbird/SelectorPattern.vala @@ -1,1 +1,111 @@ + /* + 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; + } + } + + }
--- a/libsvgbird/StyleSheet.vala +++ b/libsvgbird/StyleSheet.vala @@ -25,7 +25,28 @@ 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);
--- a/libsvgbird/SvgFile.vala +++ b/libsvgbird/SvgFile.vala @@ -24,15 +24,13 @@ 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 @@ } } - foreach (XmlElement t in tag) { + foreach (XmlElement t in svg_tag) { string name = t.get_name (); if (name == "g") { @@ -54,7 +52,7 @@ } 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 @@ 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 @@ 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 @@ 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 @@ } 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 @@ } 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 @@ } 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 @@ } 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 @@ } 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 @@ } 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 @@ } 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);
--- a/libsvgbird/SvgStyle.vala +++ b/libsvgbird/SvgStyle.vala @@ -19,7 +19,7 @@ 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 double stroke_width = 0; public SvgStyle () { - style = new Gee.HashMap<string, string> (); } public SvgStyle.for_properties (Defs? defs, string style) { @@ -69,14 +68,22 @@ 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 @@ } 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 @@ pair = kv.split (":"); if (pair.length != 2) { - warning ("pair.length != 2"); + warning ("pair.length != 2 in " + svg_style); continue; }