Commit 3da8a54
Use SVG transform, parse opacity and gradients
Changed files (17)
deletedlibbirdfont/Color.valamodifiedlibbirdfont/Doubles.valamodifiedlibbirdfont/Glyph.valadeletedlibbirdfont/Gradient.valadeletedlibbirdfont/Object.valadeletedlibbirdfont/Stop.valaaddedlibbirdfont/Svg/Color.valaaddedlibbirdfont/Svg/Gradient.valaaddedlibbirdfont/Svg/Object.valamodifiedlibbirdfont/Svg/Points.valamodifiedlibbirdfont/Svg/Rectangle.valaaddedlibbirdfont/Svg/Stop.valaaddedlibbirdfont/Svg/SvgDrawing.valamodifiedlibbirdfont/Svg/SvgFile.valamodifiedlibbirdfont/Svg/SvgParser.valamodifiedlibbirdfont/Svg/SvgPath.valamodifiedlibbirdfont/Svg/SvgStyle.vala
Diff
deleted file mode 100644@@ -1,281 +0,0 @@-/* 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;- }-}--}@@ -48,6 +48,20 @@ public class Doubles : GLib.Object { 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];+ } } }@@ -1793,6 +1793,7 @@ public class Glyph : FontDisplay { 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 ();deleted file mode 100644@@ -1,53 +0,0 @@-/*- 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;- }-}--}deleted file mode 100644@@ -1,110 +0,0 @@-/*- 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 ();- }- }-}--}deleted file mode 100644@@ -1,35 +0,0 @@-/*- 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;- }-}--}new file mode 100644@@ -0,0 +1,285 @@+/* 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;+ }+}++}new file mode 100644@@ -0,0 +1,53 @@+/*+ 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;+ }+}++}new file mode 100644@@ -0,0 +1,185 @@+/*+ 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);+ }+ }+ }+ }+}++}@@ -20,6 +20,7 @@ public class Points : GLib.Object { 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);@@ -36,6 +36,8 @@ public class Rectangle : Object { 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); } else {new file mode 100644@@ -0,0 +1,35 @@+/*+ 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;+ }+}++}new file mode 100644@@ -0,0 +1,25 @@+/*+ 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> ();+}++}@@ -21,7 +21,7 @@ public class SvgFile : GLib.Object { public SvgFile () { } - public Layer parse (string path) {+ public SvgDrawing parse (string path) { string xml_data; try {@@ -38,23 +38,27 @@ public class SvgFile : GLib.Object { 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 @@ public class SvgFile : GLib.Object { } 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 @@ public class SvgFile : GLib.Object { } } + 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 @@ public class SvgFile : GLib.Object { 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,6 +492,7 @@ public class SvgFile : GLib.Object { 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 {@@ -405,6 +501,10 @@ public class SvgFile : GLib.Object { } } + if (points.point_data.size > 0) {+ path_data.add (points);+ }+ return path_data; } }@@ -64,8 +64,8 @@ public class SvgParser { 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) {@@ -32,15 +32,19 @@ public class SvgPath : Object { 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 (); } @@ -19,10 +19,14 @@ namespace BirdFont { 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> ();@@ -64,9 +68,10 @@ public class SvgStyle { 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") {@@ -84,9 +89,29 @@ public class SvgStyle { 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;