The Birdfont Source Code


All Repositories / birdfont.git / commitdiff – RSS feed

Use SVG transform, parse opacity and gradients

These changes was commited to the Birdfont repository Thu, 07 Jan 2016 23:32:56 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
[Thu, 07 Jan 2016 23:32:56 +0000]

Updated Files

libbirdfont/Color.vala
libbirdfont/Doubles.vala
libbirdfont/Glyph.vala
libbirdfont/Gradient.vala
libbirdfont/Object.vala
libbirdfont/Stop.vala
libbirdfont/Svg/Color.vala
libbirdfont/Svg/Gradient.vala
libbirdfont/Svg/Object.vala
libbirdfont/Svg/Points.vala
libbirdfont/Svg/Rectangle.vala
libbirdfont/Svg/Stop.vala
libbirdfont/Svg/SvgDrawing.vala
libbirdfont/Svg/SvgFile.vala
libbirdfont/Svg/SvgParser.vala
libbirdfont/Svg/SvgPath.vala
libbirdfont/Svg/SvgStyle.vala
diff --git libbirdfont/Color.vala(deleted)
--- a/libbirdfont/Color.vala +++ /dev/null @@ -1,282 +1,1 @@ - /* Copyright (C) 1999 The Free Software Foundation - * - * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code) - * Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+) - * Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+) - * - * 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 2 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. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ - - namespace BirdFont { - - public class Color { - public double r; - public double g; - public double b; - public double a; - - public Color (double r, double g, double b, double a) { - this.r = r; - this.g = g; - this.b = b; - this.a = a; - } - - public Color.hsba (double h, double s, double v, double a) { - double hue, saturation, value; - double f, p, q, t; - - this.a = a; - - if (s == 0.0) { - r = v; - g = v; - b = v; - } else { - hue = h * 6.0; - saturation = s; - value = v; - - if (hue == 6.0) { - hue = 0.0; - } - - f = hue - (int) hue; - p = value * (1.0 - saturation); - q = value * (1.0 - saturation * f); - t = value * (1.0 - saturation * (1.0 - f)); - - switch ((int) hue) { - case 0: - r = value; - g = t; - b = p; - break; - - case 1: - r = q; - g = value; - b = p; - break; - - case 2: - r = p; - g = value; - b = t; - break; - - case 3: - r = p; - g = q; - b = value; - break; - - case 4: - r = t; - g = p; - b = value; - break; - - case 5: - r = value; - g = p; - b = q; - break; - - default: - assert_not_reached (); - } - } - } - - public static Color? parse (string? svg_color) { - if (svg_color == null) { - return null; - } - - string color = ((!) svg_color).replace ("#", ""); - uint32 c; - string[] arguments; - Color parsed = black (); - - if (color.char_count () == 6) { - color.scanf ("%x", out c); - parsed.r = (uint8)((c & 0xFF0000) >> 16) / 254.0; - parsed.g = (uint8)((c & 0x00FF00) >> 8)/ 254.0; - parsed.b = (uint8)(c & 0x0000FF) / 254.0; - } else if (color.char_count () == 3) { - color.scanf ("%x", out c); - parsed.r = (uint8)(((c & 0xF00) >> 4) | ((c & 0xF00) >> 8)) / 254.0; - parsed.g = (uint8)((c & 0x0F0) | ((c & 0x0F0) >> 4)) / 254.0; - parsed.b = (uint8)(((c & 0x00F) << 4) | (c & 0x00F)) / 254.0; - } else if (color.index_of ("%") > -1) { - color = color.replace ("rgb", ""); - color = color.replace (" ", ""); - color = color.replace ("\t", ""); - color = color.replace ("%", ""); - arguments = color.split (","); - - return_val_if_fail (arguments.length == 3, parsed); - arguments[0].scanf ("%lf", out parsed.r); - arguments[1].scanf ("%lf", out parsed.g); - arguments[2].scanf ("%lf", out parsed.b); - } else if (color.index_of ("rgb") > -1) { - color = color.replace ("rgb", ""); - color = color.replace (" ", ""); - color = color.replace ("\t", ""); - arguments = color.split (","); - - return_val_if_fail (arguments.length == 3, parsed); - - int r, g, b; - arguments[0].scanf ("%d", out r); - parsed.r = r / 254.0; - - arguments[1].scanf ("%d", out g); - parsed.g = g / 254.0; - - arguments[2].scanf ("%d", out b); - parsed.b = b / 254.0; - } else { - warning ("Unknown color type: " + color); - } - - - return parsed; - } - - public void to_hsva (out double h, out double s, out double v, out double a) { - double red, green, blue; - double min, max; - double delta; - - a = this.a; - - red = r; - green = g; - blue = b; - - h = 0.0; - - if (red > green) { - if (red > blue) - max = red; - else - max = blue; - - if (green < blue) - min = green; - else - min = blue; - } else { - if (green > blue) - max = green; - else - max = blue; - - if (red < blue) - min = red; - else - min = blue; - } - - v = max; - - if (max != 0.0) - s = (max - min) / max; - else - s = 0.0; - - if (s == 0.0) - h = 0.0; - else { - delta = max - min; - - if (red == max) - h = (green - blue) / delta; - else if (green == max) - h = 2 + (blue - red) / delta; - else if (blue == max) - h = 4 + (red - green) / delta; - - h /= 6.0; - - if (h < 0.0) - h += 1.0; - else if (h > 1.0) - h -= 1.0; - } - } - - public static Color black () { - return new Color (0, 0, 0, 1); - } - - public static Color red () { - return new Color (1, 0, 0, 1); - } - - public static Color green () { - return new Color (0, 1, 0, 1); - } - - public static Color blue () { - return new Color (0, 0, 1, 1); - } - - public static Color yellow () { - return new Color (222.0 / 255, 203.0 / 255, 43 / 255.0, 1); - } - - public static Color brown () { - return new Color (160.0 / 255, 90.0 / 255, 44.0 / 255, 1); - } - - public static Color pink () { - return new Color (247.0 / 255, 27.0 / 255, 113 / 255.0, 1); - } - - public static Color white () { - return new Color (1, 1, 1, 1); - } - - public static Color grey () { - return new Color (0.5, 0.5, 0.5, 1); - } - - public static Color magenta () { - return new Color (103.0 / 255, 33.0 / 255, 120.0 / 255, 1); - } - - public string to_string () { - return @"r: $r, g: $g, b: $b, a: $a"; - } - - public Color copy () { - return new Color (r, g, b, a); - } - - public string to_rgb_hex () { - string s = "#"; - s += Font.to_hex_code ((unichar) Math.rint (r * 254)); - s += Font.to_hex_code ((unichar) Math.rint (g * 254)); - s += Font.to_hex_code ((unichar) Math.rint (b * 254)); - return s; - } - } - - }
--- a/libbirdfont/Doubles.vala +++ b/libbirdfont/Doubles.vala @@ -47,9 +47,23 @@ data[size] = d; size++; + } + + public double get_double (int index) { + if (unlikely (index < 0)) { + warning ("index < 0"); + return 0; + } + + if (unlikely (index >= size)) { + warning ("index >= size"); + return 0; + } + + return data[index]; } } }
--- a/libbirdfont/Glyph.vala +++ b/libbirdfont/Glyph.vala @@ -1793,6 +1793,7 @@ cr.save (); cr.new_path (); + // FIXME: layer transforms foreach (Object o in get_visible_objects ()) { if (o is PathObject) { Path p = ((PathObject) o).get_path ();
diff --git libbirdfont/Gradient.vala(deleted)
--- a/libbirdfont/Gradient.vala +++ /dev/null @@ -1,54 +1,1 @@ - /* - Copyright (C) 2015 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; - using Math; - - namespace BirdFont { - - public class Gradient : GLib.Object { - public double x1; - public double y1; - public double x2; - public double y2; - - public Gee.ArrayList<Stop> stops; - - public int id = -1; - - public Gradient () { - x1 = 0; - y1 = 0; - x2 = 0; - y2 = 0; - stops = new Gee.ArrayList<Stop> (); - } - - public Gradient copy () { - Gradient g = new Gradient (); - g.x1 = x1; - g.y1 = y1; - g.x2 = x2; - g.y2 = y2; - - foreach (Stop s in stops) { - g.stops.add (s.copy ()); - } - - return g; - } - } - - }
diff --git libbirdfont/Object.vala(deleted)
--- a/libbirdfont/Object.vala +++ /dev/null @@ -1,111 +1,1 @@ - /* - Copyright (C) 2015 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; - using Math; - - namespace BirdFont { - - public abstract class Object : GLib.Object { - bool open = false; - - public bool visible = true; - public SvgStyle style = new SvgStyle (); - public Gee.ArrayList<SvgTransform> transforms = new Gee.ArrayList<SvgTransform> (); - - public virtual Color? color { get; set; } // FIXME: keep this in svg style - public virtual Color? stroke_color { get; set; } - public virtual Gradient? gradient { get; set; } - - /** Path boundaries */ - public virtual double xmax { get; set; } - public virtual double xmin { get; set; } - public virtual double ymax { get; set; } - public virtual double ymin { get; set; } - - public virtual double rotation { get; set; } - public virtual double stroke { get; set; } - public virtual LineCap line_cap { get; set; default = LineCap.BUTT; } - public virtual bool fill { get; set; } - - public Object () { - } - - public Object.create_copy (Object o) { - open = o.open; - } - - public void set_open (bool open) { - this.open = open; - } - - public bool is_open () { - return open; - } - - public abstract void update_region_boundaries (); - public abstract bool is_over (double x, double y); - public abstract void draw (Context cr, Color? c = null); - public abstract Object copy (); - public abstract void move (double dx, double dy); - public abstract void rotate (double theta, double xc, double yc); - public abstract bool is_empty (); - public abstract void resize (double ratio_x, double ratio_y); - - public static void copy_attributes (Object from, Object to) { - to.open = from.open; - - to.color = from.color; - to.stroke_color = from.stroke_color; - to.gradient = from.gradient; - - to.xmax = from.xmax; - to.xmin = from.xmin; - to.ymax = from.ymax; - to.ymin = from.ymin; - - to.rotation = from.rotation; - to.stroke = from.stroke; - to.line_cap = from.line_cap; - to.fill = from.fill; - } - - public virtual string to_string () { - return "Object"; - } - - public void fill_and_stroke (Context cr) { - Color fill, stroke; - - if (style.fill != null) { - fill = (!) style.fill; - cr.set_source_rgba (fill.r, fill.g, fill.b, fill.a); - - if (style.stroke != null) { - cr.fill_preserve (); - } else { - cr.fill (); - } - } - - if (style.stroke != null) { - stroke = (!) style.stroke; - cr.set_source_rgba (stroke.r, stroke.g, stroke.b, stroke.a); - cr.stroke (); - } - } - } - - }
diff --git libbirdfont/Stop.vala(deleted)
--- a/libbirdfont/Stop.vala +++ /dev/null @@ -1,36 +1,1 @@ - /* - Copyright (C) 2015 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; - using Math; - - namespace BirdFont { - - public class Stop : GLib.Object { - public Color color = Color.black (); - public double offset = 0; - - public Stop () { - } - - public Stop copy () { - Stop s = new Stop (); - s.color = color.copy (); - s.offset = offset; - return s; - } - } - - }
diff --git libbirdfont/Svg/Color.vala(new)
--- /dev/null +++ b/libbirdfont/Svg/Color.vala @@ -1,1 +1,286 @@ + /* Copyright (C) 1999 The Free Software Foundation + * + * Authors: Simon Budig <Simon.Budig@unix-ag.org> (original code) + * Federico Mena-Quintero <federico@gimp.org> (cleanup for GTK+) + * Jonathan Blandford <jrb@redhat.com> (cleanup for GTK+) + * + * 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 2 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. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + + namespace BirdFont { + + public class Color { + public double r; + public double g; + public double b; + public double a; + + public Color (double r, double g, double b, double a) { + this.r = r; + this.g = g; + this.b = b; + this.a = a; + } + + public Color.hsba (double h, double s, double v, double a) { + double hue, saturation, value; + double f, p, q, t; + + this.a = a; + + if (s == 0.0) { + r = v; + g = v; + b = v; + } else { + hue = h * 6.0; + saturation = s; + value = v; + + if (hue == 6.0) { + hue = 0.0; + } + + f = hue - (int) hue; + p = value * (1.0 - saturation); + q = value * (1.0 - saturation * f); + t = value * (1.0 - saturation * (1.0 - f)); + + switch ((int) hue) { + case 0: + r = value; + g = t; + b = p; + break; + + case 1: + r = q; + g = value; + b = p; + break; + + case 2: + r = p; + g = value; + b = t; + break; + + case 3: + r = p; + g = q; + b = value; + break; + + case 4: + r = t; + g = p; + b = value; + break; + + case 5: + r = value; + g = p; + b = q; + break; + + default: + assert_not_reached (); + } + } + } + + public static Color? parse (string? svg_color) { + if (svg_color == null) { + return null; + } + + string color = ((!) svg_color).replace ("#", ""); + uint32 c; + string[] arguments; + Color parsed = black (); + + if (color == "none") { + return null; + } + + if (color.char_count () == 6) { + color.scanf ("%x", out c); + parsed.r = (uint8)((c & 0xFF0000) >> 16) / 254.0; + parsed.g = (uint8)((c & 0x00FF00) >> 8)/ 254.0; + parsed.b = (uint8)(c & 0x0000FF) / 254.0; + } else if (color.char_count () == 3) { + color.scanf ("%x", out c); + parsed.r = (uint8)(((c & 0xF00) >> 4) | ((c & 0xF00) >> 8)) / 254.0; + parsed.g = (uint8)((c & 0x0F0) | ((c & 0x0F0) >> 4)) / 254.0; + parsed.b = (uint8)(((c & 0x00F) << 4) | (c & 0x00F)) / 254.0; + } else if (color.index_of ("%") > -1) { + color = color.replace ("rgb", ""); + color = color.replace (" ", ""); + color = color.replace ("\t", ""); + color = color.replace ("%", ""); + arguments = color.split (","); + + return_val_if_fail (arguments.length == 3, parsed); + arguments[0].scanf ("%lf", out parsed.r); + arguments[1].scanf ("%lf", out parsed.g); + arguments[2].scanf ("%lf", out parsed.b); + } else if (color.index_of ("rgb") > -1) { + color = color.replace ("rgb", ""); + color = color.replace (" ", ""); + color = color.replace ("\t", ""); + arguments = color.split (","); + + return_val_if_fail (arguments.length == 3, parsed); + + int r, g, b; + arguments[0].scanf ("%d", out r); + parsed.r = r / 254.0; + + arguments[1].scanf ("%d", out g); + parsed.g = g / 254.0; + + arguments[2].scanf ("%d", out b); + parsed.b = b / 254.0; + } else { + warning ("Unknown color type: " + color); + } + + + return parsed; + } + + public void to_hsva (out double h, out double s, out double v, out double a) { + double red, green, blue; + double min, max; + double delta; + + a = this.a; + + red = r; + green = g; + blue = b; + + h = 0.0; + + if (red > green) { + if (red > blue) + max = red; + else + max = blue; + + if (green < blue) + min = green; + else + min = blue; + } else { + if (green > blue) + max = green; + else + max = blue; + + if (red < blue) + min = red; + else + min = blue; + } + + v = max; + + if (max != 0.0) + s = (max - min) / max; + else + s = 0.0; + + if (s == 0.0) + h = 0.0; + else { + delta = max - min; + + if (red == max) + h = (green - blue) / delta; + else if (green == max) + h = 2 + (blue - red) / delta; + else if (blue == max) + h = 4 + (red - green) / delta; + + h /= 6.0; + + if (h < 0.0) + h += 1.0; + else if (h > 1.0) + h -= 1.0; + } + } + + public static Color black () { + return new Color (0, 0, 0, 1); + } + + public static Color red () { + return new Color (1, 0, 0, 1); + } + + public static Color green () { + return new Color (0, 1, 0, 1); + } + + public static Color blue () { + return new Color (0, 0, 1, 1); + } + + public static Color yellow () { + return new Color (222.0 / 255, 203.0 / 255, 43 / 255.0, 1); + } + + public static Color brown () { + return new Color (160.0 / 255, 90.0 / 255, 44.0 / 255, 1); + } + + public static Color pink () { + return new Color (247.0 / 255, 27.0 / 255, 113 / 255.0, 1); + } + + public static Color white () { + return new Color (1, 1, 1, 1); + } + + public static Color grey () { + return new Color (0.5, 0.5, 0.5, 1); + } + + public static Color magenta () { + return new Color (103.0 / 255, 33.0 / 255, 120.0 / 255, 1); + } + + public string to_string () { + return @"r: $r, g: $g, b: $b, a: $a"; + } + + public Color copy () { + return new Color (r, g, b, a); + } + + public string to_rgb_hex () { + string s = "#"; + s += Font.to_hex_code ((unichar) Math.rint (r * 254)); + s += Font.to_hex_code ((unichar) Math.rint (g * 254)); + s += Font.to_hex_code ((unichar) Math.rint (b * 254)); + return s; + } + } + + }
--- /dev/null +++ b/libbirdfont/Svg/Gradient.vala @@ -1,1 +1,54 @@ + /* + Copyright (C) 2015 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; + using Math; + + namespace BirdFont { + + public class Gradient : GLib.Object { + public double x1; + public double y1; + public double x2; + public double y2; + + public Gee.ArrayList<Stop> stops; + + public int id = -1; + + public Gradient () { + x1 = 0; + y1 = 0; + x2 = 0; + y2 = 0; + stops = new Gee.ArrayList<Stop> (); + } + + public Gradient copy () { + Gradient g = new Gradient (); + g.x1 = x1; + g.y1 = y1; + g.x2 = x2; + g.y2 = y2; + + foreach (Stop s in stops) { + g.stops.add (s.copy ()); + } + + return g; + } + } + + }
diff --git libbirdfont/Svg/Object.vala(new)
--- /dev/null +++ b/libbirdfont/Svg/Object.vala @@ -1,1 +1,186 @@ + /* + 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; + using Math; + + namespace BirdFont { + + public abstract class Object : GLib.Object { + bool open = false; + + public bool visible = true; + public SvgStyle style = new SvgStyle (); + public Gee.ArrayList<SvgTransform> transforms = new Gee.ArrayList<SvgTransform> (); + + public virtual Color? color { get; set; } // FIXME: keep this in svg style + public virtual Color? stroke_color { get; set; } + public virtual Gradient? gradient { get; set; } + + /** Path boundaries */ + public virtual double xmax { get; set; } + public virtual double xmin { get; set; } + public virtual double ymax { get; set; } + public virtual double ymin { get; set; } + + public virtual double rotation { get; set; } + public virtual double stroke { get; set; } + public virtual LineCap line_cap { get; set; default = LineCap.BUTT; } + public virtual bool fill { get; set; } + + public Object () { + } + + public Object.create_copy (Object o) { + open = o.open; + } + + public void set_open (bool open) { + this.open = open; + } + + public bool is_open () { + return open; + } + + public abstract void update_region_boundaries (); + public abstract bool is_over (double x, double y); + public abstract void draw (Context cr, Color? c = null); + public abstract Object copy (); + public abstract void move (double dx, double dy); + public abstract void rotate (double theta, double xc, double yc); + public abstract bool is_empty (); + public abstract void resize (double ratio_x, double ratio_y); + + public static void copy_attributes (Object from, Object to) { + to.open = from.open; + + to.color = from.color; + to.stroke_color = from.stroke_color; + to.gradient = from.gradient; + + to.xmax = from.xmax; + to.xmin = from.xmin; + to.ymax = from.ymax; + to.ymin = from.ymin; + + to.rotation = from.rotation; + to.stroke = from.stroke; + to.line_cap = from.line_cap; + to.fill = from.fill; + } + + public virtual string to_string () { + return "Object"; + } + + public void fill_and_stroke (Context cr) { + Color fill, stroke; + bool need_fill = style.fill_gradient != null || style.fill != null; + bool need_stroke = style.stroke_gradient != null || style.stroke != null; + + cr.set_line_width (style.stroke_width); + + if (style.fill_gradient != null) { + apply_gradient (cr, (!) style.fill_gradient); + } + + if (style.fill != null) { + fill = (!) style.fill; + cr.set_source_rgba (fill.r, fill.g, fill.b, fill.a); + } + + if (need_fill) { + if (need_stroke) { + cr.fill_preserve (); + } else { + cr.fill (); + } + } + + if (style.stroke_gradient != null) { + apply_gradient (cr, (!) style.stroke_gradient); + } + + if (style.stroke != null) { + stroke = (!) style.stroke; + cr.set_source_rgba (stroke.r, stroke.g, stroke.b, stroke.a); + } + + if (need_stroke) { + cr.stroke (); + } + } + + public void apply_gradient (Context cr, Gradient? gradient) { + Cairo.Pattern pattern; + Gradient g; + + if (gradient != null) { + g = (!) gradient; + + pattern = new Cairo.Pattern.linear ( + g.x1, + g.y1, + g.x2, + g.y2); + + foreach (Stop s in g.stops) { + Color c = s.color; + pattern.add_color_stop_rgba (s.offset, c.r, c.g, c.b, c.a); + } + + 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 = Matrix (s0, s1, s2, s3, s4, s5); + cr.set_matrix (matrix); + } + } + } + } + } + + }
--- a/libbirdfont/Svg/Points.vala +++ b/libbirdfont/Svg/Points.vala @@ -20,6 +20,7 @@ public Doubles point_data = new Doubles.for_capacity (100); public double x = 0; public double y = 0; + public bool closed = false; public void add (double p) { point_data.add (p);
--- a/libbirdfont/Svg/Rectangle.vala +++ b/libbirdfont/Svg/Rectangle.vala @@ -35,6 +35,8 @@ public override void draw (Context cr, Color? c = null) { cr.save (); + + apply_transform (cr); if (rx == 0 && ry == 0) { cr.rectangle (x, y, width, height);
diff --git libbirdfont/Svg/Stop.vala(new)
--- /dev/null +++ b/libbirdfont/Svg/Stop.vala @@ -1,1 +1,36 @@ + /* + Copyright (C) 2015 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; + using Math; + + namespace BirdFont { + + public class Stop : GLib.Object { + public Color color = Color.black (); + public double offset = 0; + + public Stop () { + } + + public Stop copy () { + Stop s = new Stop (); + s.color = color.copy (); + s.offset = offset; + return s; + } + } + + }
--- /dev/null +++ b/libbirdfont/Svg/SvgDrawing.vala @@ -1,1 +1,26 @@ + /* + 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 SvgDrawing { + public Layer root_layer = new Layer (); + public Gee.ArrayList<Gradient> gradients = new Gee.ArrayList<Gradient> (); + } + + }
--- a/libbirdfont/Svg/SvgFile.vala +++ b/libbirdfont/Svg/SvgFile.vala @@ -21,7 +21,7 @@ public SvgFile () { } - public Layer parse (string path) { + public SvgDrawing parse (string path) { string xml_data; try { @@ -38,23 +38,27 @@ warning (error.message); } - return new Layer (); + return new SvgDrawing (); } - private Layer parse_svg_file (Tag tag) { - Layer layer = new Layer (); - + private SvgDrawing parse_svg_file (Tag tag) { + SvgDrawing drawing = new SvgDrawing (); + foreach (Tag t in tag) { string name = t.get_name (); if (name == "g") { - parse_layer (layer, t); + parse_layer (drawing.root_layer, t); + } + + if (name == "defs") { + parse_defs (drawing, t); } - parse_object (layer, t); + parse_object (drawing.root_layer, t); } - return layer; + return drawing; } private void parse_layer (Layer layer, Tag tag) { @@ -77,12 +81,14 @@ } foreach (Tag t in tag) { - if (t.get_name () == "g") { + string name = t.get_name (); + + if (name == "g") { Layer sublayer = new Layer (); parse_layer (layer, t); layer.subgroups.add (sublayer); } - + parse_object (layer, t); } @@ -93,6 +99,89 @@ } } + void parse_defs (SvgDrawing drawing, Tag tag) { + foreach (Tag t in tag) { + // FIXME: radial + string name = t.get_name (); + + if (name == "linearGradient") { + parse_linear_gradient (drawing, t); + } + } + } + + void parse_linear_gradient (SvgDrawing drawing, Tag tag) { + Gradient gradient = new Gradient (); + + foreach (Attribute attr in tag.get_attributes ()) { + string name = attr.get_name (); + + if (name == "href") { + } + + if (name == "x1") { + gradient.x1 = parse_number (attr.get_content ()); + } + + if (name == "y1") { + gradient.y1 = parse_number (attr.get_content ()); + } + + if (name == "x2") { + gradient.x2 = parse_number (attr.get_content ()); + } + + if (name == "y2") { + gradient.y2 = parse_number (attr.get_content ()); + } + } + + foreach (Tag t in tag) { + // FIXME: radial + string name = t.get_name (); + + if (name == "stop") { + parse_stop (gradient, tag); + } + } + } + + void parse_stop (Gradient gradient, Tag tag) { + SvgStyle style = SvgStyle.parse (tag.get_attributes ()); + Stop stop = new Stop (); + + foreach (Attribute attr in tag.get_attributes ()) { + string name = attr.get_name (); + + if (name == "offset") { + string stop_offset = attr.get_content (); + + if (stop_offset.index_of ("%") > -1) { + stop_offset = stop_offset.replace ("%", ""); + stop.offset = parse_number (stop_offset) / 100.0; + } else { + stop.offset = parse_number (stop_offset); + } + } + } + + string? stop_color = style.style.get ("stop-color"); + string? stop_opacity = style.style.get ("stop-opacity"); + Color? color = Color.black (); + + if (stop_color != null) { + color = Color.parse (stop_color); + + if (color != null) { + stop.color = (!) color; + } + } + + if (stop_opacity != null && color != null) { + ((!) color).a = parse_number (stop_opacity); + } + } + void parse_object (Layer layer, Tag tag) { string name = tag.get_name (); @@ -243,16 +332,22 @@ return transform; } - private string remove_unit (string d) { + private static string remove_unit (string d) { string s = d.replace ("pt", ""); s = s.replace ("pc", ""); s = s.replace ("mm", ""); s = s.replace ("cm", ""); s = s.replace ("in", ""); + s = s.replace ("px", ""); return s; } - private double parse_number (string d) { + public static double parse_number (string? number_with_unit) { + if (number_with_unit == null) { + return 0; + } + + string d = (!) number_with_unit; string s = remove_unit (d); double n = SvgParser.parse_double (s); @@ -397,12 +492,17 @@ points.add (bezier_points[i].x0); points.add (bezier_points[i].y0); } else if (bezier_points[i].type == 'z') { + points.closed = true; path_data.add (points); points = new Points (); } else { string type = (!) bezier_points[i].type.to_string (); warning (@"SVG conversion not implemented for $type"); } + } + + if (points.point_data.size > 0) { + path_data.add (points); } return path_data;
--- a/libbirdfont/Svg/SvgParser.vala +++ b/libbirdfont/Svg/SvgParser.vala @@ -64,8 +64,8 @@ public static void import_color_svg (Glyph glyph, string path) { SvgFile svg_file = new SvgFile (); - Layer layer = svg_file.parse (path); - glyph.add_layer (layer); + SvgDrawing drawing = svg_file.parse (path); + glyph.add_layer (drawing.root_layer); } public static void import_folder (SvgType type) {
--- a/libbirdfont/Svg/SvgPath.vala +++ b/libbirdfont/Svg/SvgPath.vala @@ -32,15 +32,19 @@ public override void draw (Context cr, Color? c = null) { cr.save (); + apply_transform (cr); + cr.new_path (); foreach (Points p in points) { - cr.new_path (); - cr.move_to (p.x, p.y); + cr.move_to (p.x, p.y); draw_points (cr, p); + + if (p.closed) { + cr.close_path (); + } } - + fill_and_stroke (cr); - cr.restore (); }
--- a/libbirdfont/Svg/SvgStyle.vala +++ b/libbirdfont/Svg/SvgStyle.vala @@ -19,10 +19,14 @@ public class SvgStyle { - Gee.HashMap<string, string> style; + public Gee.HashMap<string, string> style; public Color? stroke = null; public Color? fill = null; + public Gradient? stroke_gradient = null; + public Gradient? fill_gradient = null; + + public double stroke_width = 0; public SvgStyle () { style = new Gee.HashMap<string, string> (); @@ -63,10 +67,11 @@ return double.parse (style.get ("stroke-width")); } - public static SvgStyle parse (Attributes attributes) { SvgStyle s = new SvgStyle (); + double fill_opacity = 1; + double stroke_opacity = 1; foreach (Attribute a in attributes) { if (a.get_name () == "style") { @@ -83,10 +88,30 @@ if (a.get_name () == "fill") { s.style.set ("fill", a.get_content ()); + } + + if (a.get_name () == "fill-opacity") { + fill_opacity = SvgFile.parse_number (a.get_content ()); + } + + if (a.get_name () == "stroke-opacity") { + stroke_opacity = SvgFile.parse_number (a.get_content ()); } } s.stroke = Color.parse (s.style.get ("stroke")); + + if (s.fill != null) { + Color color = (!) s.fill; + color.a = fill_opacity; + } + + if (s.stroke != null) { + 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;