The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

Linear gradients and matrix tranform on gradients

These changes was commited to the Birdfont repository Sat, 09 Jan 2016 14:21:26 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Sat, 09 Jan 2016 14:21:26 +0000]

Updated Files

libbirdfont/Layer.vala
libbirdfont/Svg/Color.vala
libbirdfont/Svg/Defs.vala
libbirdfont/Svg/Gradient.vala
libbirdfont/Svg/Object.vala
libbirdfont/Svg/Stop.vala
libbirdfont/Svg/SvgDrawing.vala
libbirdfont/Svg/SvgFile.vala
libbirdfont/Svg/SvgParser.vala
libbirdfont/Svg/SvgStyle.vala
libbirdfont/Svg/SvgTransform.vala
libbirdfont/Svg/SvgTransforms.vala
--- a/libbirdfont/Layer.vala +++ b/libbirdfont/Layer.vala @@ -25,12 +25,12 @@ public Gradient? gradient = null; public bool single_path = false; - public Gee.ArrayList<SvgTransform> transforms; + public SvgTransforms transforms; public Layer () { objects = new ObjectGroup (); subgroups = new Gee.ArrayList<Layer> (); - transforms = new Gee.ArrayList<SvgTransform> (); + transforms = new SvgTransforms (); } public int index_of (Layer sublayer) {
--- a/libbirdfont/Svg/Color.vala +++ b/libbirdfont/Svg/Color.vala @@ -266,7 +266,8 @@ } public string to_string () { - return @"r: $r, g: $g, b: $b, a: $a"; + string alpha = Font.to_hex_code ((unichar) Math.rint (a * 254)); + return @"$(to_rgb_hex ())" + alpha; } public Color copy () {
diff --git libbirdfont/Svg/Defs.vala(new)
--- /dev/null +++ b/libbirdfont/Svg/Defs.vala @@ -1,1 +1,86 @@ + /* + 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 BirdFont { + + public class Defs { + public Gee.ArrayList<Gradient> gradients = new Gee.ArrayList<Gradient> (); + + public void add (Gradient g) { + gradients.add (g); + } + + public Gradient? get_gradient_for_url (string? url) { + if (url == null) { + return null; + } + + string tag_id = (!) url; + + if (unlikely (!is_url (tag_id))) { + warning ("Not an URL: " + tag_id); + return null; + } + + int p1 = tag_id.index_of ("("); + if (unlikely (p1 == -1)) { + warning ("Not an URL: " + tag_id); + return null; + } + + int p2 = tag_id.index_of (")"); + if (unlikely (p2 == -1 || p2 < p1)) { + warning ("Not an URL: " + tag_id); + return null; + } + + p1 += "(".length; + int length = p2 - p1; + tag_id = tag_id.substring (p1, length); + + return get_gradient_for_id (tag_id); + } + + public Gradient? get_gradient_for_id (string id) { + string tag_id; + + if (id.has_prefix ("#")) { + tag_id = id.substring ("#".length); + } else { + tag_id = id; + } + + foreach (Gradient gradient in gradients) { + if (gradient.id == tag_id) { + return gradient; + } + } + + return null; + } + + public static bool is_url (string? attribute) { + if (attribute == null) { + return false; + } + + return ((!) attribute).has_prefix ("url"); + } + } + + }
--- a/libbirdfont/Svg/Gradient.vala +++ b/libbirdfont/Svg/Gradient.vala @@ -25,7 +25,9 @@ public Gee.ArrayList<Stop> stops; - public int id = -1; + public string id = ""; + public string? href = null; + public SvgTransforms transforms; public Gradient () { x1 = 0; @@ -33,6 +35,7 @@ x2 = 0; y2 = 0; stops = new Gee.ArrayList<Stop> (); + transforms = new SvgTransforms (); } public Gradient copy () { @@ -47,8 +50,31 @@ } return g; + } + + public void copy_stops (Gradient g) { + foreach (Stop stop in g.stops) { + stops.add (stop.copy ()); + } + } + + public string to_string () { + StringBuilder description = new StringBuilder (); + description.append ("Gradient: "); + description.append (@"x1=$x1, y1=$y1, x2=$x2, y2=$y2"); + + foreach (Stop stop in stops) { + description.append (" "); + description.append (stop.to_string ()); + } + + return description.str; + } + + public Matrix get_matrix () { + return transforms.get_matrix (); } } }
--- a/libbirdfont/Svg/Object.vala +++ b/libbirdfont/Svg/Object.vala @@ -22,7 +22,7 @@ public bool visible = true; public SvgStyle style = new SvgStyle (); - public Gee.ArrayList<SvgTransform> transforms = new Gee.ArrayList<SvgTransform> (); + public SvgTransforms transforms = new SvgTransforms (); public virtual Color? color { get; set; } // FIXME: keep this in svg style public virtual Color? stroke_color { get; set; } @@ -94,9 +94,7 @@ if (style.fill_gradient != null) { apply_gradient (cr, (!) style.fill_gradient); - } - - if (style.fill != null) { + } else if (style.fill != null) { fill = (!) style.fill; cr.set_source_rgba (fill.r, fill.g, fill.b, fill.a); } @@ -111,9 +109,7 @@ if (style.stroke_gradient != null) { apply_gradient (cr, (!) style.stroke_gradient); - } - - if (style.stroke != null) { + } else if (style.stroke != null) { stroke = (!) style.stroke; cr.set_source_rgba (stroke.r, stroke.g, stroke.b, stroke.a); } @@ -140,47 +136,19 @@ Color c = s.color; pattern.add_color_stop_rgba (s.offset, c.r, c.g, c.b, c.a); } + + pattern.set_matrix (g.get_matrix ()); cr.set_source (pattern); } } public void apply_transform (Context cr) { - foreach (SvgTransform transform in transforms) { - if (transform.type == TransformType.SCALE) { - if (transform.arguments.size == 1) { - double s = transform.arguments.get_double (0); - cr.scale (s, s); - } else if (transform.arguments.size == 2) { - double s0 = transform.arguments.get_double (0); - double s1 = transform.arguments.get_double (1); - cr.scale (s0, s1); - } - } else if (transform.type == TransformType.TRANSLATE) { - if (transform.arguments.size == 1) { - double s = transform.arguments.get_double (0); - cr.translate (s, 0); - } else if (transform.arguments.size == 2) { - double s0 = transform.arguments.get_double (0); - double s1 = transform.arguments.get_double (1); - cr.translate (s0, s1); - } - } else if (transform.type == TransformType.MATRIX) { - if (transform.arguments.size == 1) { - double s0 = transform.arguments.get_double (0); - double s1 = transform.arguments.get_double (1); - double s2 = transform.arguments.get_double (2); - double s3 = transform.arguments.get_double (3); - double s4 = transform.arguments.get_double (4); - double s5 = transform.arguments.get_double (5); + Matrix matrix = transforms.get_matrix (); + cr.set_matrix (matrix); + } - Matrix matrix = Matrix (s0, s1, s2, s3, s4, s5); - cr.set_matrix (matrix); - } - } - } - } } }
--- a/libbirdfont/Svg/Stop.vala +++ b/libbirdfont/Svg/Stop.vala @@ -29,8 +29,12 @@ s.color = color.copy (); s.offset = offset; return s; + } + + public string to_string () { + return @"Stop: $(offset), " + color.to_string (); } } }
--- a/libbirdfont/Svg/SvgDrawing.vala +++ b/libbirdfont/Svg/SvgDrawing.vala @@ -19,8 +19,8 @@ public class SvgDrawing { public Layer root_layer = new Layer (); - public Gee.ArrayList<Gradient> gradients = new Gee.ArrayList<Gradient> (); + public Defs defs = new Defs (); } }
--- a/libbirdfont/Svg/SvgFile.vala +++ b/libbirdfont/Svg/SvgFile.vala @@ -17,6 +17,8 @@ namespace BirdFont { public class SvgFile : GLib.Object { + + SvgDrawing drawing; public SvgFile () { } @@ -42,7 +44,7 @@ } private SvgDrawing parse_svg_file (Tag tag) { - SvgDrawing drawing = new SvgDrawing (); + drawing = new SvgDrawing (); foreach (Tag t in tag) { string name = t.get_name (); @@ -106,17 +108,39 @@ if (name == "linearGradient") { parse_linear_gradient (drawing, t); + } + } + + foreach (Gradient gradient in drawing.defs.gradients) { + if (gradient.href != null) { + Gradient? referenced; + referenced = drawing.defs.get_gradient_for_id ((!) gradient.href); + + if (referenced != null) { + gradient.copy_stops ((!) referenced); + } + + gradient.href = null; } } } void parse_linear_gradient (SvgDrawing drawing, Tag tag) { Gradient gradient = new Gradient (); + + drawing.defs.add (gradient); foreach (Attribute attr in tag.get_attributes ()) { string name = attr.get_name (); - if (name == "href") { + // FIXME: gradientUnits + + if (name == "gradientTransform") { + gradient.transforms = parse_transform (attr.get_content ()); + } + + if (name == "href") { + gradient.href = attr.get_content (); } if (name == "x1") { @@ -133,6 +157,10 @@ if (name == "y2") { gradient.y2 = parse_number (attr.get_content ()); + } + + if (name == "id") { + gradient.id = attr.get_content (); } } @@ -141,14 +169,16 @@ string name = t.get_name (); if (name == "stop") { - parse_stop (gradient, tag); + parse_stop (gradient, t); } } } void parse_stop (Gradient gradient, Tag tag) { - SvgStyle style = SvgStyle.parse (tag.get_attributes ()); + SvgStyle style = SvgStyle.parse (drawing.defs, tag.get_attributes ()); Stop stop = new Stop (); + + gradient.stops.add (stop); foreach (Attribute attr in tag.get_attributes ()) { string name = attr.get_name (); @@ -252,7 +282,7 @@ } rectangle.transforms = get_transform (tag.get_attributes ()); - rectangle.style = SvgStyle.parse (tag.get_attributes ()); + rectangle.style = SvgStyle.parse (drawing.defs,tag.get_attributes ()); rectangle.visible = is_visible (tag); layer.add_object (rectangle); @@ -268,12 +298,12 @@ } // FIXME: reverse order? - public Gee.ArrayList<SvgTransform> parse_transform (string transforms) { + public SvgTransforms parse_transform (string transforms) { string[] functions; string transform = transforms; - Gee.ArrayList<SvgTransform> transform_functions; + SvgTransforms transform_functions; - transform_functions = new Gee.ArrayList<SvgTransform> (); + transform_functions = new SvgTransforms (); transform = transform.replace ("\t", " "); transform = transform.replace ("\n", " "); @@ -438,14 +468,14 @@ return !hidden; } - private Gee.ArrayList<SvgTransform> get_transform (Attributes attributes) { + private SvgTransforms get_transform (Attributes attributes) { foreach (Attribute attr in attributes) { if (attr.get_name () == "transform") { return parse_transform (attr.get_content ()); } } - return new Gee.ArrayList<SvgTransform> (); + return new SvgTransforms (); } private void parse_path (Layer layer, Tag tag) { @@ -458,7 +488,7 @@ } path.transforms = get_transform (tag.get_attributes ()); - path.style = SvgStyle.parse (tag.get_attributes ()); + path.style = SvgStyle.parse (drawing.defs, tag.get_attributes ()); path.visible = is_visible (tag); layer.add_object (path);
--- a/libbirdfont/Svg/SvgParser.vala +++ b/libbirdfont/Svg/SvgParser.vala @@ -508,7 +508,7 @@ } } - style = SvgStyle.parse (tag.get_attributes ()); + style = SvgStyle.parse (null, tag.get_attributes ()); if (hidden) { return; @@ -576,7 +576,7 @@ } } - style = SvgStyle.parse (tag.get_attributes ()); + style = SvgStyle.parse (null, tag.get_attributes ()); if (hidden) { return; @@ -642,7 +642,7 @@ } } - style = SvgStyle.parse (tag.get_attributes ()); + style = SvgStyle.parse (null, tag.get_attributes ()); if (hidden) { return; @@ -720,7 +720,7 @@ } } - style = SvgStyle.parse (tag.get_attributes ()); + style = SvgStyle.parse (null, tag.get_attributes ()); if (hidden) { return; @@ -815,7 +815,7 @@ } } - style = SvgStyle.parse (tag.get_attributes ()); + style = SvgStyle.parse (null, tag.get_attributes ()); if (hidden) { return path_list; @@ -855,7 +855,7 @@ } } - style = SvgStyle.parse (tag.get_attributes ()); + style = SvgStyle.parse (null, tag.get_attributes ()); if (hidden) { return;
--- a/libbirdfont/Svg/SvgStyle.vala +++ b/libbirdfont/Svg/SvgStyle.vala @@ -68,7 +68,7 @@ return double.parse (style.get ("stroke-width")); } - public static SvgStyle parse (Attributes attributes) { + public static SvgStyle parse (Defs? d, Attributes attributes) { SvgStyle s = new SvgStyle (); double fill_opacity = 1; double stroke_opacity = 1; @@ -99,8 +99,17 @@ } } + 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")); + if (d != null) { + Defs defs = (!) d; + + s.stroke_gradient = defs.get_gradient_for_url (s.style.get ("stroke")); + s.fill_gradient = defs.get_gradient_for_url (s.style.get ("fill")); + } + if (s.fill != null) { Color color = (!) s.fill; color.a = fill_opacity; @@ -110,9 +119,6 @@ Color color = (!) s.stroke; color.a = stroke_opacity; } - - s.stroke_width = SvgFile.parse_number (s.style.get ("stroke-width")); - s.fill = Color.parse (s.style.get ("fill")); return s; }
--- a/libbirdfont/Svg/SvgTransform.vala +++ b/libbirdfont/Svg/SvgTransform.vala @@ -13,6 +13,7 @@ */ using B; + using Cairo; namespace BirdFont { @@ -28,8 +29,48 @@ public Doubles arguments = new Doubles.for_capacity (10); public SvgTransform () { + } + + public Matrix get_matrix () { + Matrix matrix; + + matrix = Matrix.identity (); + + if (type == TransformType.SCALE) { + if (arguments.size == 1) { + double s = arguments.get_double (0); + matrix.scale (s, s); + return matrix; + } else if (arguments.size == 2) { + double s0 = arguments.get_double (0); + double s1 = arguments.get_double (1); + matrix.scale (s0, s1); + } + } else if (type == TransformType.TRANSLATE) { + if (arguments.size == 1) { + double s = arguments.get_double (0); + matrix.translate (s, 0); + } else if (arguments.size == 2) { + double s0 = arguments.get_double (0); + double s1 = arguments.get_double (1); + matrix.translate (s0, s1); + } + } else if (type == TransformType.MATRIX) { + if (arguments.size == 6) { + double s0 = arguments.get_double (0); + double s1 = arguments.get_double (1); + double s2 = arguments.get_double (2); + double s3 = arguments.get_double (3); + double s4 = arguments.get_double (4); + double s5 = arguments.get_double (5); + + matrix = Matrix (s0, s1, s2, s3, s4, s5); + } + } + + return matrix; } } }
--- /dev/null +++ b/libbirdfont/Svg/SvgTransforms.vala @@ -1,1 +1,48 @@ + /* + 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 Cairo; + + namespace BirdFont { + + public class SvgTransforms : GLib.Object { + public Gee.ArrayList<SvgTransform> transforms; + + public SvgTransforms () { + transforms = new Gee.ArrayList<SvgTransform> (); + } + + public void add (SvgTransform transform) { + transforms.add (transform); + } + + public Matrix get_matrix () { + Matrix matrix = Matrix.identity (); + + if (transforms.size == 0) { + return Matrix.identity (); + } + + matrix = transforms.get (0).get_matrix (); + + for (int i = 1; i < transforms.size; i++) { + matrix.multiply (matrix, transforms.get (i).get_matrix ()); + } + + return matrix; + } + } + + }