Commit 30e31d8
Use other types of graphical objects The previous version uses only simple paths this commit makes it possible to add other objects like circles, rectangles and text. The refactoring is the first part of the full SVG implementation.
Changed files (28)
modifieddodo.pymodifiedlibbirdfont/ClipTool.valamodifiedlibbirdfont/DrawingTools.valamodifiedlibbirdfont/ExportTool.valaaddedlibbirdfont/FastPath.valamodifiedlibbirdfont/Glyph.valamodifiedlibbirdfont/Layer.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/MoveTool.valaaddedlibbirdfont/Object.valaaddedlibbirdfont/ObjectGroup.valamodifiedlibbirdfont/OpenFontFormat/FontData.valamodifiedlibbirdfont/OpenFontFormat/GlyfData.valamodifiedlibbirdfont/OpenFontFormat/GlyfTable.valamodifiedlibbirdfont/OpenFontFormat/OpenFontFormatReader.valamodifiedlibbirdfont/OpenFontFormat/OpenFontFormatWriter.valamodifiedlibbirdfont/OpenFontFormat/OtfInputStream.valamodifiedlibbirdfont/OpenFontFormat/OtfTable.valamodifiedlibbirdfont/OrientationTool.valamodifiedlibbirdfont/OtfFeatureTable.valamodifiedlibbirdfont/Path.valamodifiedlibbirdfont/PenTool.valamodifiedlibbirdfont/ResizeTool.valamodifiedlibbirdfont/StrokeTool.valamodifiedlibbirdfont/SvgFontFormatWriter.valamodifiedlibbirdfont/SvgParser.valamodifiedlibbirdfont/Test.valamodifiedlibbirdfont/TrackTool.vala
Diff
@@ -301,7 +301,7 @@ def make_libbirdfont(target_binary, deps): -H build/libbirdfont/birdfont.h \ libbirdfont/*.vala \ libbirdfont/OpenFontFormat/*.vala \- libbirdfont/Renderer/*.vala \+ libbirdfont/TextRendering/*.vala \ --pkg """ + config.GEE + """ \ --pkg gio-2.0 \ --pkg cairo \@@ -95,7 +95,7 @@ public class ClipTool : Tool { dx = g.motion_x - x - w / 2.0; dy = g.motion_y - y + h / 2.0; - foreach (Path path in g.active_paths) {+ foreach (Object path in g.active_paths) { path.move (dx, dy); } } else if (fd is KerningDisplay) {@@ -260,7 +260,7 @@ public class ClipTool : Tool { } } } else if (glyph.get_visible_paths ().size > 0) {- foreach (Path path in glyph.active_paths) {+ foreach (Path path in glyph.get_active_paths ()) { // FIXME: other objects s.append ("BF path: "); s.append (BirdFontFile.get_point_data (path)); s.append ("\n");@@ -447,13 +447,13 @@ public class ClipTool : Tool { if (path.points.size > 0) { PenTool.clear_directions (); glyph.add_path (path);- glyph.active_paths.add (path);+ glyph.add_active_path (null, path); path.update_region_boundaries (); } PenTool.remove_all_selected_points (); - foreach (Path p in glyph.active_paths) {+ foreach (Path p in glyph.get_active_paths ()) { if (p.is_open ()) { foreach (EditPoint e in p.points) { e.set_selected (true);@@ -292,7 +292,7 @@ public class DrawingTools : ToolCollection { glyph.selection_boundaries (out x, out y, out w, out h); delta = x_coordinate.get_value () - x + glyph.left_limit; - foreach (Path path in glyph.active_paths) {+ foreach (Object path in glyph.active_paths) { path.move (delta, 0); } @@ -335,7 +335,7 @@ public class DrawingTools : ToolCollection { glyph.selection_boundaries (out x, out y, out w, out h); - foreach (Path path in glyph.active_paths) {+ foreach (Path path in glyph.get_active_paths ()) { path.move (0, y_coordinate.get_value () - (y - h) - font.base_line); } @@ -375,7 +375,7 @@ public class DrawingTools : ToolCollection { double x, y, w, h; Glyph glyph = MainWindow.get_current_glyph (); double angle = (self.get_value () / 360) * 2 * PI;- Path last_path;+ Object last_path; glyph.selection_boundaries (out x, out y, out w, out h); x += w / 2;@@ -480,7 +480,7 @@ public class DrawingTools : ToolCollection { tie = !p.tie_handles; // don't tie end points- foreach (Path path in MainWindow.get_current_glyph ().active_paths) {+ foreach (Path path in MainWindow.get_current_glyph ().get_active_paths ()) { if (path.is_open ()) { if (p == path.get_first_point () || p == path.get_last_point ()) { tie = false;@@ -598,9 +598,9 @@ public class DrawingTools : ToolCollection { Glyph g = MainWindow.get_current_glyph (); Layer layer = g.get_current_layer (); - foreach (Path p in g.active_paths) {- layer.paths.remove (p);- layer.paths.paths.insert (0, p);+ foreach (Object p in g.active_paths) {+ layer.remove (p);+ layer.objects.objects.insert (0, p); } GlyphCanvas.redraw ();@@ -798,12 +798,12 @@ public class DrawingTools : ToolCollection { g.store_undo_state (); if (StrokeTool.add_stroke) {- foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { p.stroke = StrokeTool.stroke_width; p.line_cap = StrokeTool.line_cap; } } else {- foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { p.stroke = 0; } }@@ -838,9 +838,13 @@ public class DrawingTools : ToolCollection { StrokeTool.stroke_width = object_stroke.get_value (); if (tool && StrokeTool.add_stroke) {- foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { p.stroke = StrokeTool.stroke_width;- p.reset_stroke ();+ + if (p is FastPath) {+ Path path = ((FastPath) p).get_path ();+ path.reset_stroke ();+ } } } @@ -876,9 +880,12 @@ public class DrawingTools : ToolCollection { g = MainWindow.get_current_glyph (); g.store_undo_state (); - foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { p.line_cap = LineCap.BUTT;- p.reset_stroke ();+ + if (p is FastPath) {+ ((FastPath) p).get_path ().reset_stroke ();+ } } StrokeTool.line_cap = LineCap.BUTT;@@ -900,9 +907,12 @@ public class DrawingTools : ToolCollection { g = MainWindow.get_current_glyph (); g.store_undo_state (); - foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { p.line_cap = LineCap.ROUND;- p.reset_stroke ();+ + if (p is FastPath) {+ ((FastPath) p).get_path ().reset_stroke ();+ } } StrokeTool.line_cap = LineCap.ROUND;@@ -925,9 +935,12 @@ public class DrawingTools : ToolCollection { g = MainWindow.get_current_glyph (); g.store_undo_state (); - foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { p.line_cap = LineCap.SQUARE;- p.reset_stroke ();++ if (p is FastPath) {+ ((FastPath) p).get_path ().reset_stroke ();+ } } StrokeTool.line_cap = LineCap.SQUARE;@@ -1249,7 +1262,7 @@ public class DrawingTools : ToolCollection { bool stroke = false; Glyph g = MainWindow.get_current_glyph (); - foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { if (p.stroke > 0) { stroke = true; }@@ -95,37 +95,50 @@ public class ExportTool : GLib.Object { name = glyph.get_name (); - Gee.ArrayList<Path> pl;+ Gee.ArrayList<Object> pl; s = new StringBuilder (); glyph_svg = ""; - pl = only_selected_paths ? glyph.active_paths : glyph.get_visible_paths ();- foreach (Path p in pl) {- if (p.stroke > 0) {- s.append (@"<path ");- s.append (@"style=\"");- s.append (@"fill:none;");- s.append (@"stroke:#000000;");- s.append (@"stroke-width:$(p.stroke)px;");- - if (p.line_cap == LineCap.ROUND) {- s.append (@"stroke-linecap:round;");- } else if (p.line_cap == LineCap.SQUARE) {- s.append (@"stroke-linecap:square;");+ pl = only_selected_paths ? glyph.active_paths : glyph.get_visible_objects ();+ + foreach (Object o in pl) {+ + if (o is FastPath) {+ Path p = ((FastPath) o).get_path ();++ if (p.stroke > 0) {+ s.append (@"<path ");+ s.append (@"style=\"");+ s.append (@"fill:none;");+ s.append (@"stroke:#000000;");+ s.append (@"stroke-width:$(p.stroke)px;");+ + if (p.line_cap == LineCap.ROUND) {+ s.append (@"stroke-linecap:round;");+ } else if (p.line_cap == LineCap.SQUARE) {+ s.append (@"stroke-linecap:square;");+ }+ + s.append (@"\" ");+ + s.append (@"d=\"$(Svg.to_svg_path (p, glyph))\" id=\"path_$(name)_$(id)\" />\n");+ id++; }- - s.append (@"\" ");- - s.append (@"d=\"$(Svg.to_svg_path (p, glyph))\" id=\"path_$(name)_$(id)\" />\n");- id++;+ } else {+ warning ("Copy and paste for other objects not implemented."); } } if (only_selected_paths) {- foreach (Path p in glyph.active_paths) {- if (p.stroke == 0) {- glyph_svg += Svg.to_svg_path (p, glyph);+ foreach (Object p in glyph.active_paths) {+ if (p is FastPath) {+ Path path = ((FastPath) p).get_path ();+ if (path.stroke == 0) {+ glyph_svg += Svg.to_svg_path (path, glyph);+ }+ } else {+ warning ("Not implemented"); } } } else {new file mode 100644@@ -0,0 +1,81 @@+/*+ 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;++namespace BirdFont {++public class FastPath : Object {++ Path path;++ public FastPath () {+ path = new Path ();+ update_region_boundaries ();+ }++ public FastPath.create_copy (FastPath p) {+ base.create_copy (p);+ path = p.path.copy ();+ }++ public FastPath.for_path (Path path) {+ this.path = path;+ }++ public override bool is_over (double x, double y) {+ return path.is_over (x, y);+ }+ + public override void draw (Context cr) {+ }+ + public override void move (double dx, double dy) {+ path.move (dx, dy);+ path.reset_stroke ();+ }+ + public Path get_path () {+ return path;+ }++ public override void update_region_boundaries () {+ path.update_region_boundaries ();+ xmax = path.xmax;+ xmin = path.xmin;+ ymax = path.ymax;+ ymin = path.ymin; + }++ public override void rotate (double theta, double xc, double yc) {+ path.rotate (theta, xc, yc);+ rotation += theta;+ rotation %= 2 * Math.PI;+ }+ + public override bool is_empty () {+ return path.points.size == 0;+ }+ + public override void resize (double ratio_x, double ratio_y) {+ path.resize (ratio_x, ratio_y);+ path.reset_stroke ();+ }+ + public override Object copy () {+ return new FastPath.create_copy (this);+ }+}++}@@ -132,7 +132,7 @@ public class Glyph : FontDisplay { public Layer layers = new Layer (); public int current_layer = 0;- public Gee.ArrayList<Path> active_paths = new Gee.ArrayList<Path> ();+ public Gee.ArrayList<Object> active_paths = new Gee.ArrayList<Object> (); public Gee.ArrayList<Layer> selected_groups = new Gee.ArrayList<Layer> (); // used if this glyph originates from a fallback font@@ -191,12 +191,12 @@ public class Glyph : FontDisplay { this.unichar_code = unichar_code; } - public Gee.ArrayList<Path> get_active_paths () {- return active_paths;- }- public Layer get_current_layer () {- return_val_if_fail (0 <= current_layer < layers.subgroups.size, new Layer ());+ if (unlikely (!(0 <= current_layer < layers.subgroups.size))) {+ warning ("Layer index out of bounds.");+ return new Layer ();+ }+ return layers.subgroups.get (current_layer); } @@ -213,6 +213,10 @@ public class Glyph : FontDisplay { warning ("Layer is not added to glyph."); } + public Gee.ArrayList<Object> get_visible_objects () {+ return layers.get_visible_objects ().objects;+ }+ public Gee.ArrayList<Path> get_visible_paths () { return layers.get_visible_paths ().paths; }@@ -221,6 +225,10 @@ public class Glyph : FontDisplay { return layers.get_visible_paths (); } + public Gee.ArrayList<Object> get_objects_in_current_layer () {+ return get_current_layer ().get_all_objects ().objects;+ }+ public Gee.ArrayList<Path> get_paths_in_current_layer () { return get_current_layer ().get_all_paths ().paths; }@@ -289,22 +297,35 @@ public class Glyph : FontDisplay { } public void add_active_path (Layer? group, Path? p) {- Path path;+ if (p != null) {+ FastPath path = new FastPath.for_path ((!) p);+ add_active_object (group, path);+ } else {+ add_active_object (group, null);+ }+ }+ + public void add_active_object (Layer? group, Object? o) {+ Object object; Layer g; - if (p != null) {- path = (!) p;+ if (o != null) {+ object = (!) o; - if (Toolbox.get_move_tool ().is_selected ()) {- if (path.stroke > 0) {- Toolbox.set_object_stroke (path.stroke);- }+ if (!active_paths.contains (object)) {+ active_paths.add (object); }-- if (!active_paths.contains (path)) {- active_paths.add (path);+ + if (object is FastPath) {+ FastPath path = (FastPath) object;+ if (Toolbox.get_move_tool ().is_selected ()) {+ if (path.get_path ().stroke > 0) {+ Toolbox.set_object_stroke (path.get_path ().stroke);+ }+ }+ + PenTool.active_path = path.get_path (); }- PenTool.active_path = path; } if (group != null) {@@ -321,11 +342,6 @@ public class Glyph : FontDisplay { GlyphCanvas.redraw (); } - public Path? get_active_path () {- return_val_if_fail (active_paths.size > 0, null);- return active_paths.get (active_paths.size - 1);- }- public bool boundaries (out double x1, out double y1, out double x2, out double y2) { var paths = get_all_paths (); @@ -375,7 +391,7 @@ public class Glyph : FontDisplay { px2 = -10000; py2 = -10000; - foreach (Path p in active_paths) {+ foreach (Object p in active_paths) { if (p.xmin < px) { px = p.xmin; }@@ -487,6 +503,14 @@ public class Glyph : FontDisplay { get_current_layer ().add_path (p); } + public void add_object (Object object) {+ if (layers.subgroups.size == 0) {+ layers.add_layer (new Layer ());+ }++ get_current_layer ().add_object (object); + }+ public override void selected_canvas () { TimeoutSource input_delay; @@ -926,8 +950,9 @@ public class Glyph : FontDisplay { add_path (path); path.reopen (); path.create_list ();-- add_active_path (null, path);+ + FastPath object = new FastPath.for_path (path);+ add_active_object (null, object); } if (remaining_points.paths.size > 0) {@@ -1040,7 +1065,7 @@ public class Glyph : FontDisplay { public void set_active_path (Path p) { p.reopen (); clear_active_paths ();- add_active_path (null, p);+ add_active_object (null, new FastPath.for_path (p)); } /** Move view port centrum to this coordinate. */@@ -1189,8 +1214,8 @@ public class Glyph : FontDisplay { bool found = false; foreach (Layer layer in get_current_layer ().subgroups) {- foreach (Path pt in layer.paths.paths) {- if (pt.is_over (x, y)) {+ foreach (Object o in layer.objects) {+ if (o.is_over (x, y)) { found = true; group = layer; }@@ -1233,8 +1258,8 @@ public class Glyph : FontDisplay { } public bool is_over_selected_path (double x, double y) {- foreach (Path pt in active_paths) {- if (pt.is_over (x, y)) {+ foreach (Object p in active_paths) {+ if (p.is_over (x, y)) { return true; } }@@ -1349,8 +1374,9 @@ public class Glyph : FontDisplay { return; } - foreach (Path path in active_paths) {+ foreach (Object object in active_paths) { EditPoint p;+ Path path = ((FastPath) object).get_path (); EditPoint pl = path.get_last_point (); if (pl.prev != null) {@@ -1364,7 +1390,6 @@ public class Glyph : FontDisplay { if (px > x) px -= tw + 60; if (py > y) py -= th + 60;- } else { px = x - 60; py = y - 60;@@ -1678,7 +1703,7 @@ public class Glyph : FontDisplay { p.recalculate_linear_handles (); } - p.draw_path (cr, this, color);+ p.draw_path (cr, color); if (open) { p.reopen ();@@ -1718,11 +1743,14 @@ public class Glyph : FontDisplay { && !(MainWindow.get_toolbox ().get_current_tool () is BezierTool)) { cr.save (); cr.new_path ();- foreach (Path p in active_paths) {- if (p.stroke > 0) {- stroke = p.get_stroke_fast ();- color = Theme.get_color ("Selected Objects");- draw_path_list (stroke, cr, color);+ foreach (Object o in active_paths) {+ if (o is FastPath) {+ Path p = ((FastPath) o).get_path ();+ if (p.stroke > 0) {+ stroke = p.get_stroke_fast ();+ color = Theme.get_color ("Selected Objects");+ draw_path_list (stroke, cr, color);+ } } } cr.fill ();@@ -1735,7 +1763,7 @@ public class Glyph : FontDisplay { foreach (Path p in get_visible_paths ()) { if (p.stroke == 0) { color = p.color == null ? get_path_fill_color () : (!) p.color;- p.draw_path (cr, this, color);+ p.draw_path (cr, color); } } cr.fill ();@@ -1761,22 +1789,25 @@ public class Glyph : FontDisplay { foreach (Path p in get_visible_paths ()) { if (p.stroke == 0) { color = p.color == null ? Color.black () : (!) p.color;- p.draw_path (cr, this, color);+ p.draw_path (cr, color); } } cr.close_path (); cr.fill (); cr.restore (); - foreach (Path p in active_paths) {- cr.save ();- cr.new_path ();- if (p.stroke == 0) {- p.draw_path (cr, this);+ foreach (Object o in active_paths) {+ if (o is FastPath) {+ Path p = ((FastPath) o).get_path ();+ cr.save ();+ cr.new_path ();+ if (p.stroke == 0) {+ p.draw_path (cr);+ }+ cr.close_path ();+ cr.fill ();+ cr.restore (); }- cr.close_path ();- cr.fill ();- cr.restore (); } } @@ -1800,7 +1831,7 @@ public class Glyph : FontDisplay { public void draw_path_list (PathList pl, Context cr, Color? c = null) { foreach (Path p in pl.paths) {- p.draw_path (cr, this, c);+ p.draw_path (cr, c); } } @@ -1961,8 +1992,8 @@ public class Glyph : FontDisplay { g.layers = layers.copy (); - foreach (Path p in active_paths) {- g.active_paths.add (p);+ foreach (Object o in active_paths) {+ g.active_paths.add (o); } if (background_image != null) {@@ -2049,8 +2080,8 @@ public class Glyph : FontDisplay { } clear_active_paths ();- foreach (Path p in g.active_paths) {- add_active_path (null, p);+ foreach (Object p in g.active_paths) {+ add_active_object (null, p); } redraw_area (0, 0, allocation.width, allocation.height);@@ -2543,6 +2574,20 @@ public class Glyph : FontDisplay { return g2; }+ + // FIXME: convert everything to the new Object code+ public Gee.ArrayList<Path> get_active_paths () {+ Gee.ArrayList<Path> paths = new Gee.ArrayList<Path> ();+ + foreach (Object object in active_paths) {+ if (object is FastPath) {+ paths.add (((FastPath) object).get_path ());+ }+ }+ + return paths;+ }+ } }@@ -15,7 +15,8 @@ namespace BirdFont { public class Layer : GLib.Object {- public PathList paths;+ public ObjectGroup objects;+ public Gee.ArrayList<Layer> subgroups; public bool visible = true; public string name = "Layer";@@ -25,40 +26,80 @@ public class Layer : GLib.Object { public bool single_path = false; public Layer () {- paths = new PathList ();+ objects = new ObjectGroup (); subgroups = new Gee.ArrayList<Layer> (); } public int index_of (Layer sublayer) { return subgroups.index_of (sublayer); }- ++ public ObjectGroup get_all_objects () {+ ObjectGroup o = new ObjectGroup ();+ + o.append (objects);+ + foreach (Layer sublayer in subgroups) {+ o.append (sublayer.get_all_objects ());+ }+ + return o;+ }+ public PathList get_all_paths () {- PathList p = new PathList ();+ PathList paths = new PathList (); - p.append (paths);+ foreach (Object o in objects) {+ if (o is FastPath) {+ FastPath p = (FastPath) o;+ paths.add (p.get_path ());+ }+ } foreach (Layer sublayer in subgroups) {- p.append (sublayer.get_all_paths ());+ paths.append (sublayer.get_all_paths ()); } - return p;+ return paths;+ }++ public ObjectGroup get_visible_objects () {+ ObjectGroup paths = new ObjectGroup ();+ + if (visible) {+ foreach (Object o in objects) {+ paths.add (o);+ }+ }+ + foreach (Layer sublayer in subgroups) {+ if (sublayer.visible) {+ paths.append (sublayer.get_visible_objects ());+ }+ }+ + return paths; } public PathList get_visible_paths () {- PathList p = new PathList ();+ PathList paths = new PathList (); if (visible) {- p.append (paths);+ foreach (Object o in objects) {+ if (o is FastPath) {+ FastPath p = (FastPath) o;+ paths.add (p.get_path ());+ }+ } } foreach (Layer sublayer in subgroups) { if (sublayer.visible) {- p.append (sublayer.get_all_paths ());+ paths.append (sublayer.get_visible_paths ()); } } - return p;+ return paths; } public void add_layer (Layer layer) {@@ -66,18 +107,52 @@ public class Layer : GLib.Object { } public void add_path (Path path) {- paths.add (path);+ FastPath p = new FastPath.for_path (path);+ objects.add (p);+ }++ public void add_object (Object object) {+ objects.add (object); } + public void append_paths (PathList path_list) {+ foreach (Path p in path_list.paths) {+ add_path (p);+ }+ }++ private FastPath? get_fast_path (Path path) {+ foreach (Object o in objects) {+ if (o is FastPath) {+ FastPath p = (FastPath) o;+ if (p.get_path () == path) {+ return p;+ }+ }+ }+ + return null;+ }+ public void remove_path (Path path) {- paths.remove (path);+ FastPath? p = get_fast_path (path);+ + if (p != null) {+ objects.remove ((!) p);+ }+ foreach (Layer sublayer in subgroups) { sublayer.remove_path (path); } } + public void remove (Object o) {+ objects.remove (o);+ }+ public void remove_layer (Layer layer) { subgroups.remove (layer);+ foreach (Layer sublayer in subgroups) { sublayer.remove_layer (layer); }@@ -87,7 +162,7 @@ public class Layer : GLib.Object { Layer layer = new Layer (); layer.name = name;- layer.paths = paths.copy ();+ layer.objects = objects.copy (); layer.visible = visible; foreach (Layer l in subgroups) {@@ -111,7 +186,7 @@ public class Layer : GLib.Object { px2 = Glyph.CANVAS_MIN; py2 = Glyph.CANVAS_MIN; - foreach (Path p in get_all_paths ().paths) {+ foreach (Object p in get_all_objects ().objects) { if (px > p.xmin) { px = p.xmin; } @@ -136,14 +211,14 @@ public class Layer : GLib.Object { } public void print (int indent = 0) {- foreach (Path p in paths.paths) {+ foreach (Object o in objects) { for (int i = 0; i < indent; i++) { stdout.printf ("\t"); }- stdout.printf (@"Path open: $(p.is_open ())");+ stdout.printf (@"Path open: $(o.is_open ())"); - if (p.color != null) {- stdout.printf (" %s", ((!) p.color).to_rgb_hex ());+ if (o.color != null) {+ stdout.printf (" %s", ((!) o.color).to_rgb_hex ()); } stdout.printf ("\n");@@ -645,28 +645,28 @@ public class MenuTab : FontDisplay { Gee.ArrayList<Path> paths = new Gee.ArrayList<Path> (); // selected objects- foreach (Path p in g.active_paths) {+ foreach (Path p in g.get_active_paths ()) { paths.add (PenTool.simplify (p, false, PenTool.simplification_threshold)); } // selected segments if (paths.size == 0) {- foreach (Path p in g.get_all_paths ()) {+ foreach (Path p in g.get_active_paths ()) { g.add_active_path (null, p); } - foreach (Path p in g.active_paths) {+ foreach (Path p in g.get_active_paths ()) { paths.add (PenTool.simplify (p, true, PenTool.simplification_threshold)); } } g.store_undo_state (); - foreach (Path p in g.active_paths) {- g.layers.remove_path (p);+ foreach (Object o in g.active_paths) {+ g.layers.remove (o); } - foreach (Path p in g.active_paths) {+ foreach (Path p in g.get_active_paths ()) { g.layers.remove_path (p); } @@ -94,8 +94,8 @@ public class MoveTool : Tool { g.store_undo_state (); } - foreach (Path p in g.active_paths) {- g.layers.remove_path (p);+ foreach (Object p in g.active_paths) {+ g.layers.remove (p); g.update_view (); } @@ -138,7 +138,7 @@ public class MoveTool : Tool { } } - foreach (Path path in glyph.active_paths) {+ foreach (Object path in glyph.active_paths) { path.move (delta_x, delta_y); } }@@ -167,7 +167,7 @@ public class MoveTool : Tool { if (GridTool.is_visible () && moved) { tie_paths_to_grid (glyph); } else if (GridTool.has_ttf_grid ()) {- foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { tie_path_to_ttf_grid (p); } } @@ -184,8 +184,11 @@ public class MoveTool : Tool { objects_moved (); DrawingTools.resize_tool.signal_objects_rotated (); - foreach (Path p in glyph.active_paths) {- p.create_full_stroke ();+ foreach (Object o in glyph.active_paths) {+ if (o is FastPath) {+ FastPath path = (FastPath) o;+ path.get_path ().create_full_stroke ();+ } } } else { objects_deselected ();@@ -194,7 +197,7 @@ public class MoveTool : Tool { public void press (int b, int x, int y) { Glyph glyph = MainWindow.get_current_glyph ();- Path p;+ Object object; bool selected = false; Layer? group; Layer g;@@ -207,20 +210,20 @@ public class MoveTool : Tool { if (group != null) { g = (!) group;- return_if_fail (g.paths.paths.size > 0);- p = g.paths.paths.get (0);- selected = glyph.active_paths.contains (p);+ 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 (Path lp in g.paths.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_path ((!) group, lp);+ glyph.add_active_object ((!) group, lp); } } } else if (!KeyBindings.has_shift ()) {@@ -256,10 +259,10 @@ public class MoveTool : Tool { glyph.clear_active_paths (); - foreach (Path p in glyph.get_paths_in_current_layer ()) {+ foreach (Object p in glyph.get_objects_in_current_layer ()) { if (p.xmin > x1 && p.xmax < x2 && p.ymin < y1 && p.ymax > y2) {- if (p.points.size > 0) {- glyph.add_active_path (null, p);+ if (!p.is_empty ()) {+ glyph.add_active_object (null, p); } } }@@ -280,7 +283,7 @@ public class MoveTool : Tool { get_selection_box_boundaries (out x, out y, out w, out h); - foreach (Path path in glyph.active_paths) {+ foreach (Object path in glyph.active_paths) { path.move (glyph.left_limit - x + w / 2, font.base_line - y + h / 2); } @@ -317,23 +320,26 @@ public class MoveTool : Tool { px2 = -10000; py2 = -10000; - foreach (Path p in glyph.active_paths) {- p.update_region_boundaries ();- - if (px > p.xmin) {- px = p.xmin;- } + foreach (Object o in glyph.active_paths) {+ if (o is FastPath) {+ Path p = ((FastPath) o).get_path ();+ p.update_region_boundaries ();+ + if (px > p.xmin) {+ px = p.xmin;+ } - if (py > p.ymin) {- py = p.ymin;- }+ if (py > p.ymin) {+ py = p.ymin;+ } - if (px2 < p.xmax) {- px2 = p.xmax;- }- - if (py2 < p.ymax) {- py2 = p.ymax;+ if (px2 < p.xmax) {+ px2 = p.xmax;+ }+ + if (py2 < p.ymax) {+ py2 = p.ymax;+ } } } @@ -367,7 +373,7 @@ public class MoveTool : Tool { break; } - foreach (Path path in glyph.active_paths) {+ foreach (Object path in glyph.active_paths) { path.move (x * Glyph.ivz (), y * Glyph.ivz ()); } @@ -378,7 +384,7 @@ public class MoveTool : Tool { glyph.redraw_area (0, 0, glyph.allocation.width, glyph.allocation.height); } - static void tie_path_to_ttf_grid (Path p) {+ static void tie_path_to_ttf_grid (Object p) { double sx, sy, qx, qy; sx = p.xmax;@@ -428,7 +434,7 @@ public class MoveTool : Tool { dx_min = Math.fabs (qx - minx); dx_max = Math.fabs (sx - maxx); - foreach (Path p in g.active_paths) {+ foreach (Object p in g.active_paths) { if (dy_min < dy_max) { p.move (0, qy - miny); } else {@@ -447,8 +453,10 @@ public class MoveTool : Tool { public static void update_boundaries_for_selection () { Glyph glyph = MainWindow.get_current_glyph ();- foreach (Path p in glyph.active_paths) {- p.update_region_boundaries ();+ foreach (Object o in glyph.active_paths) {+ if (o is FastPath) {+ ((FastPath)o).get_path ().update_region_boundaries ();+ } } } @@ -470,14 +478,19 @@ public class MoveTool : Tool { xc = selection_box_center_x; yc = selection_box_center_y; - foreach (Path p in glyph.active_paths) {- if (vertical) {- p.flip_vertical ();- } else {- p.flip_horizontal ();+ foreach (Object p in glyph.active_paths) {+ if (p is FastPath) {+ Path path = ((FastPath) p).get_path ();+ + // FIXME: move to object+ if (vertical) {+ path.flip_vertical ();+ } else {+ path.flip_horizontal ();+ }+ + path.reverse (); }- - p.reverse (); } get_selection_box_boundaries (out xc2, out yc2, out w, out h); @@ -485,7 +498,7 @@ public class MoveTool : Tool { dx = -(xc2 - xc); dy = -(yc2 - yc); - foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { p.move (dx, dy); } @@ -499,9 +512,9 @@ public class MoveTool : Tool { Glyph g = MainWindow.get_current_glyph (); g.clear_active_paths ();- foreach (Path p in g.get_paths_in_current_layer ()) {- if (p.points.size > 0) {- g.add_active_path (null, p);+ foreach (Object p in g.get_objects_in_current_layer ()) {+ if (!p.is_empty ()) {+ g.add_active_object (null, p); } } new file mode 100644@@ -0,0 +1,88 @@+/*+ 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 Color? color = null;+ public Color? stroke_color = null;+ public Gradient? gradient = null;++ /** Path boundaries */+ public double xmax = Glyph.CANVAS_MIN;+ public double xmin = Glyph.CANVAS_MAX;+ public double ymax = Glyph.CANVAS_MIN;+ public double ymin = Glyph.CANVAS_MAX;+ + public double rotation = 0;+ public double stroke = 0;+ public LineCap line_cap = LineCap.BUTT;+ + public Object () { + }++ public Object.create_copy (Object o) { + open = o.open;+ + if (color != null) {+ color = ((!) color).copy ();+ } else {+ color = null;+ }++ if (stroke_color != null) {+ stroke_color = ((!) stroke_color).copy ();+ } else {+ stroke_color = null;+ }++ if (gradient != null) {+ gradient = ((!) gradient).copy ();+ } else {+ gradient = null;+ }+ + xmax = o.xmax;+ xmin = o.xmin;+ ymax = o.ymax;+ ymin = o.ymin;+ + rotation = o.rotation;+ stroke = o.stroke;+ }+ + 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);+ 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);+}++}new file mode 100644@@ -0,0 +1,57 @@+/*+ 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.+*/++namespace BirdFont {++public class ObjectGroup : GLib.Object {+ public Gee.ArrayList<Object> objects;+ + public ObjectGroup () {+ objects = new Gee.ArrayList<Object> ();+ }++ public Gee.Iterator<Object> iterator () {+ return objects.iterator ();+ }++ public void remove (Object p) {+ objects.remove (p);+ }+ + public void add (Object p) {+ objects.add (p);+ }+ + public void clear () {+ objects.clear ();+ }++ public void append (ObjectGroup group) {+ foreach (Object o in group.objects) {+ objects.add (o);+ }+ }+ + public ObjectGroup copy () {+ ObjectGroup objects_copy = new ObjectGroup ();+ + foreach (Object o in objects) {+ objects_copy.add (o.copy ());+ }+ + return objects_copy;+ }+}++}@@ -14,7 +14,7 @@ namespace BirdFont { -public class FontData : Object {+public class FontData : GLib.Object { // Read pointer uint rp = 0;@@ -16,7 +16,7 @@ using Math; namespace BirdFont { -public class CoordinateFlags {+public class CoordinateFlags : GLib.Object { /** TTF coordinate flags. */ public static const uint8 NONE = 0;@@ -1,5 +1,5 @@ /*- Copyright (C) 2012, 2013, 2014 Johan Mattsson+ Copyright (C) 2012 2013 2014 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 @@ -478,7 +478,7 @@ public class GlyfTable : OtfTable { end_points = new uint16[ncontours + 1]; for (int i = 0; i < ncontours; i++) {- end_points[i] = dis.read_ushort (); // FIXA: mind shot vector is negative+ end_points[i] = dis.read_ushort (); // FIXME: mind shot vector is negative if (i > 0 && end_points[i] < end_points[i -1]) { warning (@"Next endpoint has bad value in $(name.str). (end_points[i] > end_points[i -1]) ($(end_points[i]) > $(end_points[i -1])) i: $i ncontours: $ncontours");@@ -58,7 +58,7 @@ errordomain BadFormat { PARSE } -public class OpenFontFormatReader : Object {+public class OpenFontFormatReader : GLib.Object { public DirectoryTable directory_table; public FontData font_data = new FontData ();@@ -14,7 +14,7 @@ namespace BirdFont { -public class OpenFontFormatWriter : Object {+public class OpenFontFormatWriter : GLib.Object { DataOutputStream os; DataOutputStream os_mac;@@ -15,7 +15,7 @@ namespace BirdFont { /** Reader for otf data types. */-public class OtfInputStream : Object {+public class OtfInputStream : GLib.Object { public FileInputStream fin; public DataInputStream din;@@ -14,7 +14,7 @@ namespace BirdFont { -public class OtfTable : Object {+public class OtfTable : GLib.Object { public string id = "NO_ID"; @@ -30,8 +30,11 @@ public class OrientationTool : Tool { select_action.connect ((self) => { Glyph g = MainWindow.get_current_glyph (); - foreach (Path p in g.active_paths) {- p.reverse ();+ foreach (Object o in g.active_paths) {+ if (o is FastPath) {+ FastPath p = (FastPath) o;+ p.get_path ().reverse ();+ } } count_down = true;@@ -54,13 +57,17 @@ public class OrientationTool : Tool { bool has_clockwise_paths = false; bool has_counter_clockwise_paths = false; - foreach (Path p in glyph.active_paths) {- if (p.is_clockwise ()) {- has_clockwise_paths = true;- }- - if (!p.is_clockwise ()) {- has_counter_clockwise_paths = true;+ foreach (Object o in glyph.active_paths) {+ if (o is FastPath) {+ Path p = ((FastPath) o).get_path ();+ + if (p.is_clockwise ()) {+ has_clockwise_paths = true;+ }+ + if (!p.is_clockwise ()) {+ has_counter_clockwise_paths = true;+ } } } @@ -45,7 +45,7 @@ public class OtfFeatureTable : Table { public override void selected_row (Row row, int column, bool delete_button) { int row_index = row.get_index ();- Object o;+ GLib.Object o; String s; AlternateItem a; @@ -99,13 +99,12 @@ public class Path : GLib.Object { public bool highlight_last_segment = false; public string point_data = "";+ + private static Text? arrow = null; public Color? color = null; public Color? stroke_color = null;- public Gradient? gradient = null;- - private static Text? arrow = null; public Path () { string width;@@ -262,7 +261,7 @@ public class Path : GLib.Object { * Call Context.new_path (); before this method and Context.fill () * to show the path. */- public void draw_path (Context cr, Glyph glyph, Color? color = null) {+ public void draw_path (Context cr, Color? color = null) { unowned EditPoint? n = null; unowned EditPoint en; unowned EditPoint em;@@ -274,8 +273,8 @@ public class Path : GLib.Object { return; } - center_x = glyph.allocation.width / 2.0;- center_y = glyph.allocation.height / 2.0;+ center_x = Glyph.xc ();+ center_y = Glyph.yc (); ex = center_x + points.get (0).x; ey = center_y - points.get (0).y;@@ -2266,12 +2265,6 @@ public class Path : GLib.Object { lines = pl; - /** // FIXME: Check automatic orientation.- foreach (Path p in pl.paths) {- lines.add (SvgParser.get_lines (p));- }- */- foreach (Path p in lines.paths) { if (p.points.size > 1 && p != path && path.boundaries_intersecting (p)) {@@ -765,8 +765,11 @@ public class PenTool : Tool { p.path.reset_stroke (); } - foreach (Path path in g.active_paths) {- path.reset_stroke ();+ foreach (Object path in g.active_paths) {+ if (path is FastPath) {+ FastPath p = (FastPath) path;+ p.get_path ().reset_stroke ();+ } } } @@ -1055,10 +1058,11 @@ public class PenTool : Tool { // don't use set point to reflective to on open ends reflective = true;- foreach (Path path in MainWindow.get_current_glyph ().active_paths) {- if (path.is_open () && path.points.size > 0) {- if (selected_handle.parent == path.get_first_point () - || selected_handle.parent == path.get_last_point ()) {+ foreach (Object path in MainWindow.get_current_glyph ().active_paths) {+ if (path.is_open () && !path.is_empty () && path is FastPath) {+ Path p = ((FastPath) path).get_path ();+ if (selected_handle.parent == p.get_first_point () + || selected_handle.parent == p.get_last_point ()) { reflective = false; } }@@ -1229,7 +1233,10 @@ public class PenTool : Tool { if (active_edit_point != null) { glyph.clear_active_paths ();- glyph.add_active_path (null, active_path);+ + FastPath path = new FastPath.for_path (active_path);+ glyph.add_active_object (null, path);+ DrawingTools.update_stroke_settings (); if (KeyBindings.modifier != SHIFT) {@@ -1408,8 +1415,10 @@ public class PenTool : Tool { foreach (Path merge in paths) { if (merge.points.size > 0) {- if (is_close_to_point (merge.points.get (merge.points.size - 1), px, py)) {- glyph.add_active_path (null, merge);+ FastPath merged_path = new FastPath.for_path (merge);+ + if (is_close_to_point (merge.points.get (merge.points.size - 1), px, py)) { + glyph.add_active_object (null, merged_path); active_path = merge; merge.reopen (); glyph.open_path ();@@ -1417,7 +1426,7 @@ public class PenTool : Tool { } if (is_close_to_point (merge.points.get (0), px, py)) {- glyph.add_active_path (null, merge);+ glyph.add_active_object (null, merged_path); active_path = merge; clear_directions (); merge.reopen ();@@ -1453,7 +1462,9 @@ public class PenTool : Tool { force_direction (); glyph.clear_active_paths ();- glyph.add_active_path (null, path);+ + FastPath closed_path = new FastPath.for_path (path);+ glyph.add_active_object (null, closed_path); if (direction_changed) { path.reverse ();@@ -1492,11 +1503,12 @@ public class PenTool : Tool { } else { union = merge_open_paths (path, merge); + FastPath union_path = new FastPath.for_path (union); glyph.add_path (union); glyph.delete_path (path); glyph.delete_path (merge); glyph.clear_active_paths ();- glyph.add_active_path (null, union);+ glyph.add_active_object (null, union_path); union.reopen (); union.create_list ();@@ -1777,13 +1789,19 @@ public class PenTool : Tool { active_edit_point = new_point.point; return_val_if_fail (glyph.active_paths.size > 0, new PointSelection.empty ());- add_selected_point (selected_point, glyph.active_paths.get (glyph.active_paths.size - 1));-- active_path = new_point.path;- glyph.clear_active_paths ();- glyph.add_active_path (null, new_point.path);+ Object object = glyph.active_paths.get (glyph.active_paths.size - 1);+ + if (object is FastPath) { + Path path = ((FastPath) object).get_path ();+ + add_selected_point (selected_point, path); - move_selected = true;+ active_path = new_point.path;+ glyph.clear_active_paths ();+ glyph.add_active_object (null, object);+ + move_selected = true;+ } return new_point; }@@ -1819,6 +1837,7 @@ public class PenTool : Tool { EditPoint inserted; bool stroke = StrokeTool.add_stroke; Glyph g = MainWindow.get_current_glyph ();+ FastPath path; if (g.active_paths.size == 0) { np = new Path ();@@ -1826,7 +1845,8 @@ public class PenTool : Tool { np.stroke = stroke ? StrokeTool.stroke_width : 0; np.line_cap = StrokeTool.line_cap; - g.add_active_path (null, np);+ path = new FastPath.for_path (np);+ g.add_active_object (null, path); active_path = np; selected_path = np;@@ -1852,7 +1872,8 @@ public class PenTool : Tool { } g.clear_active_paths ();- g.add_active_path (null, np);+ path = new FastPath.for_path (np);+ g.add_active_object (null, path); active_path = np; selected_path = np; @@ -2062,7 +2083,8 @@ public class PenTool : Tool { selected_handle.selected = true; active_path = p.path;- g.add_active_path (null, active_path);+ FastPath path = new FastPath.for_path (active_path);+ g.add_active_object (null, path); } public static void add_selected_point (EditPoint p, Path path) {@@ -21,7 +21,7 @@ public class ResizeTool : Tool { bool resize_path_proportional = false; bool resize_width = false; - Path? resized_path = null;+ Object? resized_path = null; double last_resize_y; double last_resize_x; @@ -63,13 +63,13 @@ public class ResizeTool : Tool { }); press_action.connect((self, b, x, y) => {- Path last_path;+ Object last_path; Glyph glyph; glyph = MainWindow.get_current_glyph (); glyph.store_undo_state (); - foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { if (is_over_resize_handle (p, x, y)) { resize_path_proportional = true; resized_path = p;@@ -87,7 +87,7 @@ public class ResizeTool : Tool { } } - foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { if (is_over_rotate_handle (p, x, y)) { rotate_path = true; return;@@ -121,8 +121,11 @@ public class ResizeTool : Tool { update_selection_box (); GlyphCanvas.redraw (); - foreach (Path p in MainWindow.get_current_glyph ().active_paths) {- p.create_full_stroke ();+ foreach (Object p in MainWindow.get_current_glyph ().active_paths) {+ if (p is FastPath) {+ FastPath path = (FastPath) p;+ path.get_path ().create_full_stroke ();+ } } }); @@ -151,10 +154,6 @@ public class ResizeTool : Tool { glyph = MainWindow.get_current_glyph (); - foreach (Path selected_path in glyph.active_paths) {- selected_path.reset_stroke ();- }- GlyphCanvas.redraw (); } @@ -234,9 +233,9 @@ public class ResizeTool : Tool { public void rotate_selected_paths (double angle, double cx, double cy) { Glyph glyph = MainWindow.get_current_glyph (); double dx, dy, xc2, yc2, w, h;- Path last_path;+ Object last_path; - foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { p.rotate (angle, cx, cy); } @@ -245,7 +244,7 @@ public class ResizeTool : Tool { dx = -(xc2 - cx); dy = -(yc2 - cy); - foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { p.move (dx, dy); } @@ -287,7 +286,7 @@ public class ResizeTool : Tool { rotate_selected_paths (rotation - last_rotate, selection_box_center_x, selection_box_center_y); } - static bool is_over_rotate_handle (Path p, double x, double y) {+ static bool is_over_rotate_handle (Object p, double x, double y) { double cx, cy, hx, hy; double size = 10; bool inx, iny;@@ -364,17 +363,16 @@ public class ResizeTool : Tool { if (!selected) { glyph.clear_active_paths (); - foreach (Path path in glyph.get_visible_paths ()) {- glyph.add_active_path (null, path);+ foreach (Object path in glyph.get_visible_objects ()) {+ glyph.add_active_object (null, path); } } get_selection_min (out resize_pos_x, out resize_pos_y); // resize paths- foreach (Path selected_path in glyph.active_paths) {+ foreach (Object selected_path in glyph.active_paths) { selected_path.resize (ratio_x, ratio_y);- selected_path.reset_stroke (); } // move paths relative to the updated xmin and xmax@@ -382,7 +380,7 @@ public class ResizeTool : Tool { dx = resize_pos_x - selection_minx; dy = resize_pos_y - selection_miny; - foreach (Path selected_path in glyph.active_paths) {+ foreach (Object selected_path in glyph.active_paths) { selected_path.move (dx, dy); } @@ -470,7 +468,7 @@ public class ResizeTool : Tool { DrawingTools.move_tool.move_to_baseline (); - foreach (Path path in glyph.active_paths) {+ foreach (Object path in glyph.active_paths) { path.move (0, -descender * scale); } @@ -481,7 +479,7 @@ public class ResizeTool : Tool { Glyph glyph = MainWindow.get_current_glyph (); x = double.MAX; y = double.MAX;- foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { if (p.xmin < x) { x = p.xmin; }@@ -497,11 +495,11 @@ public class ResizeTool : Tool { double h, w; double ratio = get_resize_ratio (x, y); - foreach (Path selected_path in glyph.active_paths) {+ foreach (Object selected_path in glyph.active_paths) { h = selected_path.ymax - selected_path.ymin; w = selected_path.xmax - selected_path.xmin; - if (selected_path.points.size <= 1) {+ if (selected_path.is_empty ()) { // FIXME: test with one point continue; } @@ -513,13 +511,13 @@ public class ResizeTool : Tool { return true; } - bool is_over_resize_handle (Path p, double x, double y) {+ bool is_over_resize_handle (Object p, double x, double y) { double handle_x, handle_y; get_resize_handle_position (out handle_x, out handle_y); return Path.distance (handle_x, x, handle_y, y) < 12 * MainWindow.units; } - bool is_over_horizontal_resize_handle (Path p, double x, double y) {+ bool is_over_horizontal_resize_handle (Object p, double x, double y) { double handle_x, handle_y; get_horizontal_reseize_handle_position (out handle_x, out handle_y); return Path.distance (handle_x, x, handle_y, y) < 12 * MainWindow.units; @@ -540,26 +538,28 @@ public class ResizeTool : Tool { if (!selected_paths) { glyph.clear_active_paths (); - foreach (Path path in glyph.get_visible_paths ()) {- glyph.add_active_path (null, path);+ foreach (Object path in glyph.get_visible_objects ()) {+ glyph.add_active_object (null, path); } } glyph.selection_boundaries (out x, out y, out w, out h); - foreach (Path path in glyph.active_paths) {- SvgParser.apply_matrix (path, 1, 0, s, 1, 0, 0);- path.skew = skew;- path.update_region_boundaries ();+ foreach (Object path in glyph.active_paths) {+ if (path is FastPath) { // FIXME: other objects+ Path p = ((FastPath) path).get_path ();+ SvgParser.apply_matrix (p, 1, 0, s, 1, 0, 0);+ p.skew = skew;+ path.update_region_boundaries ();+ } } glyph.selection_boundaries (out nx, out y, out nw, out h); dx = -(nx - x); - foreach (Path p in glyph.active_paths) {+ foreach (Object p in glyph.active_paths) { p.move (dx, 0);- p.reset_stroke (); } dw = (nw - w);@@ -51,22 +51,27 @@ public class StrokeTool : GLib.Object { convert_stroke = true; g.store_undo_state (); - foreach (Path p in g.active_paths) {- if (p.stroke > 0) {- paths.append (p.get_completed_stroke ());+ foreach (Object o in g.active_paths) {+ if (o is FastPath) {+ FastPath path = (FastPath) o;+ Path p = path.get_path ();+ + if (p.stroke > 0) {+ paths.append (p.get_completed_stroke ());+ } } } if (paths.paths.size > 0) {- foreach (Path p in g.active_paths) {- g.layers.remove_path (p);+ foreach (Object o in g.active_paths) {+ g.layers.remove (o); } g.active_paths.clear (); foreach (Path np in paths.paths) { g.add_path (np);- g.active_paths.add (np);+ g.active_paths.add (new FastPath.for_path (np)); } PenTool.update_orientation ();@@ -134,11 +139,15 @@ public class StrokeTool : GLib.Object { g.store_undo_state (); - foreach (Path p in g.active_paths) {- if (p.stroke == 0) {- o.add (p);- } else {- o.append (p.get_completed_stroke ());+ foreach (Object object in g.active_paths) {+ if (object is FastPath) {+ Path p = ((FastPath) object).get_path ();+ + if (p.stroke == 0) {+ o.add (p);+ } else {+ o.append (p.get_completed_stroke ());+ } } } @@ -217,8 +226,8 @@ public class StrokeTool : GLib.Object { return; } - foreach (Path p in g.active_paths) {- g.delete_path (p);+ foreach (Object object in g.active_paths) {+ g.layers.remove (object); } g.clear_active_paths ();@@ -226,8 +235,9 @@ public class StrokeTool : GLib.Object { remove_merged_curve_parts (new_paths); foreach (Path p in new_paths.paths) {- g.add_path (p);- g.add_active_path (null, p);+ FastPath path = new FastPath.for_path (p);+ g.add_object (path);+ g.add_active_object (null, path); } PenTool.update_orientation ();@@ -14,7 +14,7 @@ namespace BirdFont { -class SvgFontFormatWriter : Object {+class SvgFontFormatWriter : GLib.Object { DataOutputStream os; @@ -160,12 +160,10 @@ public class SvgParser { glyph = MainWindow.get_current_glyph (); foreach (Path p in path_list.paths) {- glyph.add_path (p);- }- - foreach (Path p in path_list.paths) {- glyph.add_active_path (null, p); // FIXME: groups- p.update_region_boundaries ();+ FastPath path = new FastPath.for_path (p);+ glyph.add_object (path);+ glyph.add_active_object (null, path); // FIXME: groups+ path.update_region_boundaries (); } glyph.close_path (); @@ -302,7 +300,15 @@ public class SvgParser { } private void transform (string transform_functions, Layer layer) {- transform_paths (transform_functions, layer.paths);+ PathList path_list = new PathList ();+ + foreach (Object o in layer.objects) {+ if (o is FastPath) {+ path_list.add (((FastPath) o).get_path ());+ }+ }+ + transform_paths (transform_functions, path_list); transform_subgroups (transform_functions, layer); } @@ -315,7 +321,7 @@ public class SvgParser { private void transform_paths (string transform_functions, PathList pl) { string data = transform_functions.dup (); string[] functions;- + // use only a single space as separator while (data.index_of (" ") > -1) { data = data.replace (" ", " ");@@ -538,7 +544,7 @@ public class SvgParser { } style.apply (npl);- pl.paths.append (npl);+ pl.append_paths (npl); } private void parse_ellipse (Tag tag, Layer pl) {@@ -606,7 +612,7 @@ public class SvgParser { } style.apply (npl);- pl.paths.append (npl);+ pl.append_paths (npl); } private void parse_line (Tag tag, Layer pl) {@@ -683,10 +689,10 @@ public class SvgParser { } style.apply (npl);- pl.paths.append (npl);+ pl.append_paths (npl); } - private void parse_rect (Tag tag, Layer pl) {+ private void parse_rect (Tag tag, Layer layer) { Path p; double x, y, x2, y2; BezierPoints[] bezier_points;@@ -784,22 +790,22 @@ public class SvgParser { } style.apply (npl);- pl.paths.append (npl);+ layer.append_paths (npl); } - private void parse_polygon (Tag tag, Layer pl) {+ private void parse_polygon (Tag tag, Layer layer) { PathList path_list = get_polyline (tag); foreach (Path p in path_list.paths) { p.close (); } - pl.paths.append (path_list);+ layer.append_paths (path_list); } - private void parse_polyline (Tag tag, Layer pl) { - pl.paths.append (get_polyline (tag));+ private void parse_polyline (Tag tag, Layer layer) { + layer.append_paths (get_polyline (tag)); } private PathList get_polyline (Tag tag) {@@ -836,7 +842,7 @@ public class SvgParser { return path_list; } - private void parse_path (Tag tag, Layer pl) {+ private void parse_path (Tag tag, Layer layer) { Glyph glyph = MainWindow.get_current_glyph (); PathList path_list = new PathList (); SvgStyle style = new SvgStyle ();@@ -863,37 +869,47 @@ public class SvgParser { if (hidden) { return; }- - pl.paths.append (path_list);+ + foreach (Path path in path_list.paths) {+ layer.add_path (path);+ }+ style.apply (path_list); // assume the even odd rule is applied and convert the path // to a path using the non-zero rule int inside_count; bool inside;- foreach (Path p1 in pl.paths.paths) {- inside_count = 0;- - foreach (Path p2 in pl.paths.paths) {- if (p1 != p2) {- inside = true;+ foreach (Object o1 in layer.objects) {+ if (o1 is FastPath) {+ Path p1 = ((FastPath) o1).get_path ();+ inside_count = 0;+ + foreach (Object o2 in layer.objects) {+ if (o2 is FastPath) {+ Path p2 = ((FastPath) o2).get_path (); - foreach (EditPoint ep in p1.points) {- if (!is_inside (ep, p2)) {- inside = false;+ if (p1 != p2) {+ inside = true;+ + foreach (EditPoint ep in p1.points) {+ if (!is_inside (ep, p2)) {+ inside = false;+ }+ }++ if (inside) {+ inside_count++; + } } }-- if (inside) {- inside_count++; - } }- }-- if (inside_count % 2 == 0) {- p1.force_direction (Direction.CLOCKWISE);- } else {- p1.force_direction (Direction.COUNTER_CLOCKWISE);+ + if (inside_count % 2 == 0) {+ p1.force_direction (Direction.CLOCKWISE);+ } else {+ p1.force_direction (Direction.COUNTER_CLOCKWISE);+ } } } @@ -14,7 +14,7 @@ namespace BirdFont { -public class Test : Object {+public class Test : GLib.Object { public Callback callback; public string name; double time_stamp;@@ -121,8 +121,11 @@ public class TrackTool : Tool { start_update_timer (); drawing = true; - foreach (Path path in glyph.active_paths) {- path.create_full_stroke (); // cache merged stroke parts+ foreach (Object path in glyph.active_paths) {+ if (path is FastPath) {+ // cache merged stroke parts+ ((FastPath) path).get_path ().create_full_stroke ();+ } } } });@@ -146,8 +149,9 @@ public class TrackTool : Tool { g = MainWindow.get_current_glyph (); if (g.active_paths.size > 0) { // set type for last point- p = g.active_paths.get (g.active_paths.size - 1);- + Object o = g.active_paths.get (g.active_paths.size - 1);+ p = ((FastPath) o).get_path ();+ if (p.points.size > 1) { previous = p.points.get (p.points.size - 1); previous.type = DrawingTools.point_type;@@ -164,8 +168,10 @@ public class TrackTool : Tool { add_endpoint_and_merge (x, y); } - foreach (Path path in g.active_paths) {- convert_hidden_points (path);+ foreach (Object path in g.active_paths) {+ if (path is FastPath) {+ convert_hidden_points (((FastPath) path).get_path ());+ } } g.clear_active_paths ();@@ -403,7 +409,14 @@ public class TrackTool : Tool { return; } - p = glyph.active_paths.get (glyph.active_paths.size - 1);+ Object o = glyph.active_paths.get (glyph.active_paths.size - 1);+ + if (o is FastPath) {+ warning ("Object is not a path");+ return;+ }+ + p = ((FastPath) o).get_path (); p.reopen (); px = Glyph.path_coordinate_x (x); py = Glyph.path_coordinate_y (y);@@ -488,7 +501,15 @@ public class TrackTool : Tool { return new Path (); } - return glyph.active_paths.get (glyph.active_paths.size - 1); + Object o = glyph.active_paths.get (glyph.active_paths.size - 1);+ + if (likely (o is FastPath)) {+ return ((FastPath) o).get_path ();+ }+ + warning ("Active object is a path.");+ + return new Path (); } /** Delete all points close to the pixel at x,y. */