Commit fcb8229
Apply style sheet in SVG files
Changed files (7)
modifiedlibbirdfont/SvgParser.valamodifiedlibsvgbird/Defs.valamodifiedlibsvgbird/Selector.valaaddedlibsvgbird/SelectorPattern.valamodifiedlibsvgbird/StyleSheet.valamodifiedlibsvgbird/SvgFile.valamodifiedlibsvgbird/SvgStyle.vala
Diff
@@ -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; } }@@ -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);@@ -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; } }new file mode 100644@@ -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;+ }+}++}@@ -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);@@ -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);@@ -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; }