Commit b7a4f7f
Embed SVG files in BF fonts This is a replacement for the rsvg code.
Changed files (16)
modifiedREADME.mdmodifieddodo.pymodifiedlibbirdfont/BirdFontFile.valaaddedlibbirdfont/EmbeddedSvg.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/MoveTool.valamodifiedlibbirdfont/OpenFontFormat/SvgTable.valamodifiedlibbirdfont/OverViewItem.valamodifiedlibbirdfont/PathObject.valamodifiedlibbirdfont/Svg/Defs.valamodifiedlibbirdfont/Svg/Object.valamodifiedlibbirdfont/Svg/Rectangle.valamodifiedlibbirdfont/Svg/SvgDrawing.valamodifiedlibbirdfont/Svg/SvgFile.valamodifiedlibbirdfont/Svg/SvgParser.valamodifiedlibbirdfont/Svg/SvgPath.vala
Diff
@@ -27,7 +27,6 @@ packages with a -dev or -devel affix: libwebkitgtk-3.0-dev libnotify-dev libsqlite3-dev- librsvg2-dev libxmlbird-dev XML Bird is available from [birdfont.org][xmlbird].@@ -78,7 +78,6 @@ def make_birdfont(target_binary, deps): --pkg webkitgtk-3.0 \ --pkg libnotify \ --pkg xmlbird \- --pkg librsvg-2.0 \ --pkg libbirdfont """ @@ -94,7 +93,6 @@ def make_birdfont(target_binary, deps): $(pkg-config --cflags gdk-pixbuf-2.0) \ $(pkg-config --cflags webkitgtk-3.0) \ $(pkg-config --cflags libnotify) \- $(pkg-config --cflags librsvg-2.0) \ -o OBJECT_FILE""" linker_command = config.CC + " " + config.LDFLAGS.get("birdfont", "") + """ \@@ -109,7 +107,6 @@ def make_birdfont(target_binary, deps): $(pkg-config --libs webkitgtk-3.0) \ $(pkg-config --libs xmlbird) \ $(pkg-config --libs libnotify) \- $(pkg-config --libs librsvg-2.0) \ -L./build -L./build/bin -l birdgems\ -o build/bin/""" + target_binary @@ -163,7 +160,6 @@ def make_birdfont_export(target_binary, deps): $(pkg-config --libs cairo) \ $(pkg-config --libs glib-2.0) \ $(pkg-config --libs xmlbird) \- $(pkg-config --libs librsvg-2.0) \ -L./build -L./build/bin -l birdgems\ -o ./build/bin/""" + target_binary @@ -217,7 +213,6 @@ def make_birdfont_import(target_binary, deps): $(pkg-config --libs cairo) \ $(pkg-config --libs glib-2.0) \ $(pkg-config --libs xmlbird) \- $(pkg-config --libs librsvg-2.0) \ -L./build -L./build/bin -l birdgems\ -o ./build/bin/""" + target_binary @@ -272,7 +267,6 @@ def make_birdfont_autotrace(target_binary, deps): $(pkg-config --libs cairo) \ $(pkg-config --libs glib-2.0) \ $(pkg-config --libs xmlbird) \- $(pkg-config --libs librsvg-2.0) \ -L./build -L./build/bin -l birdgems\ -o ./build/bin/""" + target_binary @@ -311,7 +305,6 @@ def make_libbirdfont(target_binary, deps): --pkg libbirdgems \ --pkg sqlite3 \ --pkg gdk-pixbuf-2.0 \- --pkg librsvg-2.0 \ """ cc_command = config.CC + " " + config.CFLAGS.get("libbirdfont", "") + """ \@@ -327,7 +320,6 @@ def make_libbirdfont(target_binary, deps): $(pkg-config --cflags cairo) \ $(pkg-config --cflags glib-2.0) \ $(pkg-config --cflags xmlbird) \- $(pkg-config --cflags librsvg-2.0) \ -o OBJECT_FILE""" linker_command = config.CC + " " + config.LDFLAGS.get("libbirdfont", "") + """ \@@ -474,7 +466,6 @@ def make_birdfont_test(target_binary, deps): $(pkg-config --libs cairo) \ $(pkg-config --libs glib-2.0) \ $(pkg-config --libs xmlbird) \- $(pkg-config --libs librsvg-2.0) \ -L./build -L./build/bin -l birdgems\ -o build/bin/""" + target_binary @@ -1,5 +1,5 @@ /*- Copyright (C) 2013 2014 2015 Johan Mattsson+ Copyright (C) 2013 2014 2015 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 @@ -436,48 +436,43 @@ class BirdFontFile : GLib.Object { write_layer (layer, os); } - write_embedded_svg (g, os);- write_glyph_background (g, os); os.put_string ("\t</glyph>\n"); } - void write_embedded_svg (Glyph g, DataOutputStream os) throws GLib.Error {+ void write_embedded_svg (EmbeddedSvg svg, DataOutputStream os) throws GLib.Error {+ XmlParser xml = new XmlParser ((!) svg.svg_data); - if (g.color_svg_data != null) {- XmlParser xml = new XmlParser ((!) g.color_svg_data);+ if (xml.validate ()) {+ os.put_string (@"<embedded ");+ os.put_string (@"type=\"svg\" ");+ os.put_string (@"x=\"$(round (svg.x))\"");+ os.put_string (@"y=\"$(round (svg.y))\"");+ os.put_string (@">\n"); - if (xml.validate ()) {- os.put_string (@"<embedded ");- os.put_string (@"type=\"svg\" ");- os.put_string (@"x=\"$(round (g.svg_x))\"");- os.put_string (@"y=\"$(round (g.svg_y))\"");- os.put_string (@">\n");- - Tag tag = xml.get_root_tag ();- - os.put_string ("<");- os.put_string (tag.get_name ());- - os.put_string (" ");- write_tag_attributes (os, tag);- - string content = tag.get_content ();- - if (content == "") {- os.put_string (" /");- }- - os.put_string (">");- - os.put_string (content);- - os.put_string ("</");- os.put_string (tag.get_name ());- os.put_string (">\n");- - os.put_string ("</embedded>");+ Tag tag = xml.get_root_tag ();+ + os.put_string ("<");+ os.put_string (tag.get_name ());+ + os.put_string (" ");+ write_tag_attributes (os, tag);+ + string content = tag.get_content ();+ + if (content == "") {+ os.put_string (" /"); }+ + os.put_string (">");+ + os.put_string (content);+ + os.put_string ("</");+ os.put_string (tag.get_name ());+ os.put_string (">\n");+ + os.put_string ("</embedded>\n"); } } @@ -507,39 +502,50 @@ class BirdFontFile : GLib.Object { } void write_layer (Layer layer, DataOutputStream os) throws GLib.Error {- string data;- - // FIXME: name etc. os.put_string (@"\t\t<layer name= \"$(layer.name)\" visible=\"$(layer.visible)\">\n"); - foreach (Path p in layer.get_all_paths ().paths) {- data = get_point_data (p);- if (data != "") {- os.put_string (@"\t\t\t<path ");- - if (p.stroke != 0) {- os.put_string (@"stroke=\"$(double_to_string (p.stroke))\" ");- }- - if (p.line_cap != LineCap.BUTT) {- if (p.line_cap == LineCap.ROUND) {- os.put_string (@"cap=\"round\" ");- } else if (p.line_cap == LineCap.SQUARE) {- os.put_string (@"cap=\"square\" ");- }- }- - if (p.skew != 0) {- os.put_string (@"skew=\"$(double_to_string (p.skew))\" ");- }- - os.put_string (@"data=\"$(data)\" />\n");+ foreach (Object o in layer.get_all_objects ().objects) {+ + if (o is EmbeddedSvg) {+ write_embedded_svg ((EmbeddedSvg) o, os); }+ + if (o is PathObject) {+ Path p = ((PathObject) o).get_path ();+ write_path_object (p, os);+ } } os.put_string ("\t\t</layer>\n"); } + void write_path_object (Path p, DataOutputStream os) throws GLib.Error {+ string data;+ + data = get_point_data (p);+ if (data != "") {+ os.put_string (@"\t\t\t<path ");+ + if (p.stroke != 0) {+ os.put_string (@"stroke=\"$(double_to_string (p.stroke))\" ");+ }+ + if (p.line_cap != LineCap.BUTT) {+ if (p.line_cap == LineCap.ROUND) {+ os.put_string (@"cap=\"round\" ");+ } else if (p.line_cap == LineCap.SQUARE) {+ os.put_string (@"cap=\"square\" ");+ }+ }+ + if (p.skew != 0) {+ os.put_string (@"skew=\"$(double_to_string (p.skew))\" ");+ }+ + os.put_string (@"data=\"$(data)\" />\n");+ }+ }+ public static string double_to_string (double n) { string d = @"$n"; return d.replace (",", ".");@@ -1447,11 +1453,7 @@ class BirdFontFile : GLib.Object { foreach (Tag t in tag) { if (t.get_name () == "background") { parse_background_scale (glyph, t);- }- - if (t.get_name () == "embedded") {- parse_embedded_svg (glyph, t);- }+ } } foreach (Path p in glyph.get_all_paths ()) {@@ -1464,10 +1466,11 @@ class BirdFontFile : GLib.Object { master.insert_glyph (glyph, selected || selected_id == id); } - void parse_embedded_svg (Glyph glyph, Tag tag) {+ void parse_embedded_svg (Layer layer, Tag tag) { string type = ""; double x = 0; double y = 0;+ EmbeddedSvg svg; foreach (Attribute attribute in tag.get_attributes ()) { if (attribute.get_name () == "x") {@@ -1484,9 +1487,9 @@ class BirdFontFile : GLib.Object { } if (type == "svg") {- glyph.svg_x = x;- glyph.svg_y = y;- glyph.color_svg_data = tag.get_content ();+ SvgFile svg_file = new SvgFile ();+ svg = svg_file.parse_data (tag.get_content ());+ layer.add_object (svg); } } @@ -1509,6 +1512,10 @@ class BirdFontFile : GLib.Object { path = parse_path (t); layer.add_path (path); }+ + if (t.get_name () == "embedded") {+ parse_embedded_svg (layer, t);+ } } return layer;@@ -1542,7 +1549,7 @@ class BirdFontFile : GLib.Object { } } - return path; + return path; } private static void line (Path path, string px, string py) {new file mode 100644@@ -0,0 +1,128 @@+/*+ 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;+using Cairo;++namespace BirdFont {++public class EmbeddedSvg : Object {+ public string svg_data = "";+ public SvgDrawing drawing = new SvgDrawing ();+ + public double x {+ get {+ return drawing.x;+ }++ set {+ drawing.x = value;+ }+ }++ public double y {+ get {+ return drawing.y;+ }+ + set {+ drawing.y = value;+ }+ }+ + // FIXME: boundaries for embedded SVG+ + public override double xmin {+ get {+ Glyph g = MainWindow.get_current_glyph ();+ return g.left_limit;+ }+ + set {+ }+ }++ public override double xmax {+ get {+ Glyph g = MainWindow.get_current_glyph ();+ return g.right_limit;+ }++ set {+ }+ }+ ++ public override double ymin {+ get {+ Font font = BirdFont.get_current_font ();+ return font.bottom_position;+ }++ set {+ }+ }++ public override double ymax {+ get {+ Font font = BirdFont.get_current_font ();+ return font.top_position;+ }++ set {+ }+ }+ + public EmbeddedSvg (SvgDrawing drawing) {+ this.drawing = drawing;+ }++ public override void update_region_boundaries () {+ drawing.update_region_boundaries ();+ }++ public override bool is_over (double x, double y) {+ return drawing.is_over (x, y);+ }+ + public override void draw (Context cr) {+ drawing.draw (cr);+ }+ + public override Object copy () {+ EmbeddedSvg svg = new EmbeddedSvg (drawing);+ svg.svg_data = svg_data;+ return svg;+ }+ + public override void move (double dx, double dy) {+ drawing.move (dx, dy);+ }+ + public override void rotate (double theta, double xc, double yc) {+ drawing.rotate (theta, xc, yc);+ }+ + public override bool is_empty () {+ return drawing.is_empty ();+ }+ + public override void resize (double ratio_x, double ratio_y) {+ drawing.resize (ratio_x, ratio_y);+ }++}++}@@ -141,40 +141,6 @@ public class Glyph : FontDisplay { public double bottom_limit = 0; public Surface? overview_thumbnail = null;- - public double svg_x = 0;- public double svg_y = 0;- private Rsvg.Handle? svg_drawing = null;-- public string? color_svg_data {- get {- return _color_svg_data;- }- - set {- try {- if (value != null) {- XmlParser xml = new XmlParser ((!) value);- - if (!xml.validate ()) {- warning("Invalid SVG data, skipping import.");- return;- }- - uint8[] svg_array = ((!) value).data;- svg_drawing = new Rsvg.Handle.from_data (svg_array);- } else {- svg_drawing = null;- }- - _color_svg_data = value; - } catch (GLib.Error e) {- warning (e.message);- }- }- }-- private string? _color_svg_data = null; public Glyph (string name, unichar unichar_code = 0) { this.name = name;@@ -1713,7 +1679,11 @@ public class Glyph : FontDisplay { cr.new_path (); foreach (Object o in get_visible_objects ()) {- o.draw (cr, c);+ if (o is PathObject) {+ ((PathObject) o).draw_path (cr, c);+ } else {+ o.draw (cr);+ } } cr.fill ();@@ -1891,10 +1861,8 @@ public class Glyph : FontDisplay { } draw_background_glyph (allocation, cmp);- - if (svg_drawing != null) {- juxtapose (allocation, cmp);- }++ juxtapose (allocation, cmp); if (BirdFont.show_coordinates) { draw_coordinate (cmp);@@ -1906,19 +1874,11 @@ public class Glyph : FontDisplay { cmp.restore (); } - if (svg_drawing != null) {- cmp.save ();- cmp.scale (view_zoom, view_zoom);- cmp.translate (-view_offset_x, -view_offset_y);- draw_svg (cmp);- cmp.restore ();- } else {- cmp.save ();- cmp.scale (view_zoom, view_zoom);- cmp.translate (-view_offset_x, -view_offset_y);- draw_path (cmp); - cmp.restore (); - }+ cmp.save ();+ cmp.scale (view_zoom, view_zoom);+ cmp.translate (-view_offset_x, -view_offset_y);+ draw_path (cmp); + cmp.restore (); cmp.save (); tool = MainWindow.get_toolbox ().get_current_tool ();@@ -1926,16 +1886,6 @@ public class Glyph : FontDisplay { cmp.restore (); } - public void draw_svg (Context cr) {- if (svg_drawing != null) {- cr.save ();- cr.translate (xc () + svg_x, yc () - svg_y);- Rsvg.Handle svg_handle = (!) svg_drawing;- svg_handle.render_cairo (cr);- cr.restore ();- }- }- private void zoom_in_at_point (double x, double y, double amount = 15) { int n = (int) (-amount); zoom_at_point (x, y, n);@@ -1,5 +1,5 @@ /*- Copyright (C) 2012 2013 2015 Johan Mattsson+ Copyright (C) 2012 2013 2015 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 @@ -127,25 +127,20 @@ public class MoveTool : Tool { delta_x = -dx; delta_y = -dy;- - if (glyph.color_svg_data != null) {- glyph.svg_x += delta_x;- glyph.svg_y += delta_y;- } else { - foreach (Layer group in glyph.selected_groups) {- if (group.gradient != null) {- Gradient g = (!) group.gradient;- g.x1 += delta_x;- g.x2 += delta_x;- g.y1 += delta_y;- g.y2 += delta_y;- }- }- - foreach (Object object in glyph.active_paths) {- object.move (delta_x, delta_y);+ + foreach (Layer group in glyph.selected_groups) {+ if (group.gradient != null) {+ Gradient g = (!) group.gradient;+ g.x1 += delta_x;+ g.x2 += delta_x;+ g.y1 += delta_y;+ g.y2 += delta_y; } }+ + foreach (Object object in glyph.active_paths) {+ object.move (delta_x, delta_y);+ } } last_x = x;@@ -208,35 +203,33 @@ public class MoveTool : Tool { glyph.store_undo_state (); group_selection = false;+ + group = glyph.get_path_at (x, y); - if (glyph.color_svg_data == null) {- group = glyph.get_path_at (x, y);+ if (group != null) {+ g = (!) group;+ return_if_fail (g.objects.objects.size > 0);+ object = g.objects.objects.get (0);+ selected = glyph.active_paths_contains (object); - if (group != null) {- g = (!) group;- return_if_fail (g.objects.objects.size > 0);- object = g.objects.objects.get (0);- selected = glyph.active_paths_contains (object);- - if (!selected && !KeyBindings.has_shift ()) {- glyph.clear_active_paths ();- } - - foreach (Object lp in g.objects) {- if (selected && KeyBindings.has_shift ()) {- glyph.selected_groups.remove ((!) group);- glyph.active_paths.remove (lp);- } else {- glyph.add_active_object ((!) group, lp);- }- }- } else if (!KeyBindings.has_shift ()) {+ if (!selected && !KeyBindings.has_shift ()) { glyph.clear_active_paths ();- }+ } - update_selection_boundaries ();+ foreach (Object lp in g.objects) {+ if (selected && KeyBindings.has_shift ()) {+ glyph.selected_groups.remove ((!) group);+ glyph.active_paths.remove (lp);+ } else {+ glyph.add_active_object ((!) group, lp);+ }+ }+ } else if (!KeyBindings.has_shift ()) {+ glyph.clear_active_paths (); } + update_selection_boundaries ();+ move_path = true; last_x = x;@@ -294,25 +287,6 @@ public class MoveTool : Tool { objects_moved (); GlyphCanvas.redraw (); }-- static void draw_selection_box (Context cr) {- double x = Math.fmin (selection_x, last_x);- double y = Math.fmin (selection_y, last_y);-- double w = Math.fabs (selection_x - last_x);- double h = Math.fabs (selection_y - last_y);- - Glyph glyph = MainWindow.get_current_glyph ();- - if (glyph.color_svg_data == null) {- cr.save (); - Theme.color (cr, "Foreground 1");- cr.set_line_width (2);- cr.rectangle (x, y, w, h);- cr.stroke ();- cr.restore ();- }- } public static void get_selection_box_boundaries (out double x, out double y, out double w, out double h) { double px, py, px2, py2;@@ -526,6 +500,23 @@ public class MoveTool : Tool { update_selection_boundaries (); objects_moved (); }++ static void draw_selection_box (Context cr) {+ double x = Math.fmin (selection_x, last_x);+ double y = Math.fmin (selection_y, last_y);++ double w = Math.fabs (selection_x - last_x);+ double h = Math.fabs (selection_y - last_y);+ + Glyph glyph = MainWindow.get_current_glyph ();+ + cr.save (); + Theme.color (cr, "Foreground 1");+ cr.set_line_width (2);+ cr.rectangle (x, y, w, h);+ cr.stroke ();+ cr.restore ();+ } } }@@ -36,17 +36,53 @@ public class SvgTable : OtfTable { GlyphCollection glyphs; string? svg_data; int gid;+ Gee.ArrayList<EmbeddedSvg> embedded_svg; for (int index = 0; index < font.length (); index++) { glyph_collection = font.get_glyph_collection_index (index); if (glyph_collection != null) { glyphs = (!) glyph_collection;- svg_data = glyphs.get_current ().color_svg_data;+ embedded_svg = get_embedded_svg (glyphs); - if (svg_data != null) {+ if (embedded_svg.size > 0) { gid = glyf_table.get_gid (glyphs.get_name ());- add_svg_glyph ((!) svg_data, gid, glyphs);+ + StringBuilder svg = new StringBuilder ();+ svg.append ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n");+ + foreach (EmbeddedSvg embedded in embedded_svg) {+ svg.append ("<svg>");+ svg.append ("\n\n");+ svg.append ("<g id=");+ svg.append ("\"");+ svg.append ("glyph");+ svg.append (@"$gid");+ svg.append ("\" ");+ + // scale the internal coordinates from 100 units per em to the + // number of units per em in this font and move the glyph+ // in to the em box+ Glyph glyph = glyphs.get_current ();+ double scale = HeadTable.UNITS;+ double x = embedded.x - glyph.left_limit;+ double y = font.base_line - embedded.y;+ svg.append (@"transform=\"scale($scale) translate($x, $y)\"");+ + svg.append (">");+ svg.append ("\n\n");++ append_svg_glyph (svg, embedded.svg_data, glyphs);++ svg.append ("\n\n");+ svg.append ("</g>\n");+ svg.append ("</svg>");+ }+ + SvgTableEntry entry;+ entry = new SvgTableEntry ((uint16) gid, svg.str);+ entries.add (entry);+ glyphs_in_table++; } }@@ -55,8 +91,19 @@ public class SvgTable : OtfTable { process_svg_data (); } - void add_svg_glyph (string svg_data, int glyph_id, GlyphCollection glyphs) {- SvgTableEntry entry;+ Gee.ArrayList<EmbeddedSvg> get_embedded_svg (GlyphCollection glyphs) {+ Gee.ArrayList<EmbeddedSvg> svg = new Gee.ArrayList<EmbeddedSvg> ();+ + foreach (Object object in glyphs.get_current ().get_visible_objects ()) {+ if (object is EmbeddedSvg) {+ svg.add ((EmbeddedSvg) object);+ }+ }+ + return svg;+ }+ + void append_svg_glyph (StringBuilder svg, string svg_data, GlyphCollection glyphs) { Gee.ArrayList<Tag> layer_content; Gee.ArrayList<Tag> svg_tags; Gee.ArrayList<Tag> meta;@@ -94,8 +141,6 @@ public class SvgTable : OtfTable { } } - StringBuilder svg = new StringBuilder ();- svg.append ("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"no\"?>\n"); svg.append ("<"); svg.append (svg_root_tag.get_name ()); svg.append (" ");@@ -105,40 +150,14 @@ public class SvgTable : OtfTable { foreach (Tag tag in svg_tags) { append_tag (svg, tag); }-- svg.append ("\n\n");- svg.append ("<g id=");- svg.append ("\"");- svg.append ("glyph");- svg.append (@"$glyph_id");- svg.append ("\" ");- - // scale the internal coordinates from 100 units per em to the - // number of units per em in this font and move the glyph- // in to the em box- Glyph glyph = glyphs.get_current ();- double scale = HeadTable.UNITS;- double x = glyph.svg_x - glyph.left_limit;- double y = font.base_line - glyph.svg_y;- svg.append (@"transform=\"scale($scale) translate($x, $y)\"");- - svg.append (">");- svg.append ("\n\n"); foreach (Tag tag in layer_content) { append_tag (svg, tag); }- - svg.append ("\n\n");- svg.append ("</g>");- svg.append ("\n\n");- + svg.append ("</"); svg.append (svg_root_tag.get_name ());- svg.append (">\n");- - entry = new SvgTableEntry ((uint16) glyph_id, svg.str);- entries.add (entry);+ svg.append (">\n"); } public void append_tag (StringBuilder svg, Tag tag) {@@ -127,31 +127,18 @@ public class OverViewItem : GLib.Object { c.save (); g.boundaries (out x1, out y1, out x2, out y2); - if (g.color_svg_data != null) {- font = BirdFont.get_current_font ();- glyph_width = g.right_limit - g.left_limit;- glyph_height = font.top_position - font.bottom_position;- } else {- glyph_width = x2 - x1;- glyph_height = y2 - y1;- }+ glyph_width = x2 - x1;+ glyph_height = y2 - y1; c.save (); c.scale (glyph_scale * Screen.get_scale (), glyph_scale * Screen.get_scale ()); g.add_help_lines (); - if (g.color_svg_data != null) {- gx = 10;- gy = (h / glyph_scale) - 25 / glyph_scale;- c.translate (gx - Glyph.xc () - g.get_lsb (), g.get_baseline () + gy - Glyph.yc ());- g.draw_svg (c);- } else {- gx = ((w / glyph_scale) - glyph_width) / 2 - g.get_left_side_bearing ();- gy = (h / glyph_scale) - 25 / glyph_scale;- c.translate (gx - Glyph.xc () - g.get_lsb (), g.get_baseline () + gy - Glyph.yc ());- g.draw_paths (c, color);- }+ gx = ((w / glyph_scale) - glyph_width) / 2 - g.get_left_side_bearing ();+ gy = (h / glyph_scale) - 25 / glyph_scale;+ c.translate (gx - Glyph.xc () - g.get_lsb (), g.get_baseline () + gy - Glyph.yc ());+ g.draw_paths (c, color); c.restore (); @@ -155,8 +155,12 @@ public class PathObject : Object { public override bool is_over (double x, double y) { return path.is_over (x, y); }- - public override void draw (Context cr, Color? c = null) {++ public override void draw (Context cr) {+ draw_path (cr);+ }+ + public void draw_path (Context cr, Color? c = null) { PathList path_stroke; Color path_color; bool open;@@ -80,6 +80,17 @@ public class Defs { return ((!) attribute).has_prefix ("url"); }++ public Defs copy () {+ Defs d = new Defs ();+ + foreach (Gradient g in gradients) {+ d.add (g);+ }+ + return d;+ }+ } }@@ -56,7 +56,7 @@ public abstract class Object : GLib.Object { 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 void draw (Context cr); public abstract Object copy (); public abstract void move (double dx, double dy); public abstract void rotate (double theta, double xc, double yc);@@ -126,11 +126,7 @@ public abstract class Object : GLib.Object { if (gradient != null) { g = (!) gradient; - pattern = new Cairo.Pattern.linear (- g.x1,- g.y1,- g.x2,- g.y2);+ pattern = new Cairo.Pattern.linear (g.x1, g.y1, g.x2, g.y2); Matrix gradient_matrix = g.get_matrix (); gradient_matrix.invert ();@@ -33,7 +33,7 @@ public class Rectangle : Object { return false; } - public override void draw (Context cr, Color? c = null) {+ public override void draw (Context cr) { cr.save (); apply_transform (cr); @@ -12,14 +12,57 @@ Lesser General Public License for more details. */ + using B;+using Cairo; using Math; namespace BirdFont { -public class SvgDrawing {+public class SvgDrawing : Object { public Layer root_layer = new Layer (); public Defs defs = new Defs ();++ public double x = 0;+ public double y = 0;+ public double width = 0;+ public double height = 0;+ + public override void update_region_boundaries () {+ }+ + public override bool is_over (double x, double y) {+ return (this.x <= x <= this.x + width) + && (this.y <= y <= this.y + height);+ }+ + public override void draw (Context cr) {+ foreach (Object o in root_layer.get_visible_objects ().objects) {+ o.draw (cr);+ }+ }+ + public override Object copy () {+ SvgDrawing drawing = new SvgDrawing ();+ drawing.root_layer = root_layer.copy ();+ drawing.defs = defs.copy ();+ return drawing;+ }+ + public override void move (double dx, double dy) {+ x += dx;+ y += dy;+ }+ + public override void rotate (double theta, double xc, double yc) {+ }+ + public override bool is_empty () {+ return false;+ }+ + public override void resize (double ratio_x, double ratio_y) {+ } } }@@ -13,6 +13,7 @@ */ using B;+using Cairo; namespace BirdFont { @@ -23,29 +24,50 @@ public class SvgFile : GLib.Object { public SvgFile () { } - public SvgDrawing parse (string path) {+ public EmbeddedSvg parse (string path) { string xml_data; try { FileUtils.get_contents (path, out xml_data);- XmlParser xmlparser = new XmlParser (xml_data);- - if (xmlparser.validate ()) {- Tag root = xmlparser.get_root_tag ();- return parse_svg_file (root);- } else {- warning ("Invalid xml file.");- }+ return parse_data (xml_data); } catch (GLib.Error error) { warning (error.message); } - return new SvgDrawing ();+ SvgDrawing drawing = new SvgDrawing ();+ return new EmbeddedSvg (drawing);+ }++ public EmbeddedSvg parse_data (string xml_data) {+ XmlParser xmlparser = new XmlParser (xml_data);+ SvgDrawing drawing = new SvgDrawing (); + + if (xmlparser.validate ()) {+ Tag root = xmlparser.get_root_tag ();+ drawing = 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); } private SvgDrawing parse_svg_file (Tag tag) { drawing = new SvgDrawing ();- ++ foreach (Attribute attr in tag.get_attributes ()) { + if (attr.get_name () == "width") {+ drawing.width = parse_number (attr.get_content ());+ }++ if (attr.get_name () == "height") {+ drawing.height = parse_number (attr.get_content ());+ }+ }+ foreach (Tag t in tag) { string name = t.get_name (); @@ -64,8 +64,15 @@ public class SvgParser { public static void import_color_svg (Glyph glyph, string path) { SvgFile svg_file = new SvgFile ();- SvgDrawing drawing = svg_file.parse (path);- glyph.add_layer (drawing.root_layer);+ EmbeddedSvg drawing = svg_file.parse (path);+ + Layer layer = new Layer ();+ layer.name = "SVG";+ layer.add_object (drawing);+ + glyph.add_layer (layer);+ + // FIXME: update GUI } public static void import_folder (SvgType type) {@@ -30,7 +30,7 @@ public class SvgPath : Object { return false; } - public override void draw (Context cr, Color? c = null) {+ public override void draw (Context cr) { cr.save (); cr.new_path ();