Commit effb52a
Merge branch 'master' of github.com:johanmattssonm/birdfont
Changed files (17)
modifieddodo.pymodifiedlibbirdfont/EmbeddedSvg.valamodifiedlibbirdfont/ExportTool.valamodifiedlibbirdfont/KerningDisplay.valamodifiedlibbirdfont/MainWindow.valamodifiedlibbirdfont/Menu.valamodifiedlibbirdfont/MenuTab.valamodifiedlibbirdfont/OpenFontFormat/GlyfData.valamodifiedlibbirdfont/OpenFontFormat/GlyfTable.valamodifiedlibbirdfont/Preferences.valamodifiedlibbirdfont/PreviewTools.valamodifiedlibbirdfont/SpacingClass.valamodifiedlibbirdfont/SvgFontFormatWriter.valamodifiedlibbirdfont/SvgParser.valamodifiedlibsvgbird/SvgFile.valamodifiedlibsvgbird/SvgTransforms.valamodifiedscripts/version.py
Diff
@@ -567,6 +567,7 @@ def make_birdfont_test(target_binary, deps): $(pkg-config --cflags gio-2.0) \ $(pkg-config --cflags cairo) \ $(pkg-config --cflags glib-2.0) \+ $(pkg-config --cflags xmlbird) \ -o OBJECT_FILE""" linker_command = config.CC + " " + config.LDFLAGS.get("birdfont-test", "") + """ \@@ -90,7 +90,7 @@ public class EmbeddedSvg : SvgBird.Object { svg.append ("""<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">"""); svg.append ("\n"); - string transforms = transforms.get_xml ();+ string transforms = drawing.transforms.get_xml (); if (transforms != "") { svg.append ("<g");@@ -1,5 +1,5 @@ /*- Copyright (C) 2012 2014 2015 Johan Mattsson+ Copyright (C) 2012 - 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 @@ -18,6 +18,8 @@ using SvgBird; namespace BirdFont { public class ExportTool : GLib.Object {++ public static string? error_message = null; public ExportTool (string n) { }@@ -420,8 +422,7 @@ os.put_string ( <p class="big"> <span class="capstosmallcaps">OTF</span> features, <span class="swashes">like swashes </span>- <span class="alternates">alternates & </span>- small caps, can be added + <span class="alternates">alternates & </span> small caps, can be added to the font.</span> </p> </div>@@ -581,16 +582,19 @@ os.put_string ( OpenFontFormatWriter fo = new OpenFontFormatWriter (f.units_per_em); File file = (!) File.new_for_path (ttf);- File file_mac = (!) File.new_for_path (ttf_mac);+ File file_mac = (!) File.new_for_path (ttf_mac); ++ error_message = null; try { fo.open (file, file_mac); fo.write_ttf_font (f); fo.close (); } catch (Error e) {- warning (@"Can't write TTF font to $ttf");+ warning (@"Can't create TTF font to $ttf"); critical (@"$(e.message)");- }+ error_message = e.message; + } } static void write_eot (string ttf, string eot) {@@ -46,7 +46,7 @@ public class KerningDisplay : FontDisplay { public bool adjust_side_bearings = false; public bool right_side_bearing = true; - public bool right_to_left = false; + public static bool right_to_left = false; WidgetAllocation allocation = new WidgetAllocation (); @@ -202,7 +202,7 @@ public class KerningDisplay : FontDisplay { glyph.add_help_lines (); if (right_to_left) {- cr.translate (x - kern - glyph.get_lsb () - glyph.get_width () - Glyph.xc (), glyph.get_baseline () + y - Glyph.yc ());+ cr.translate (-kern + x - glyph.get_lsb () - glyph.get_width () - Glyph.xc (), glyph.get_baseline () + y - Glyph.yc ()); } else { cr.translate (kern + x - glyph.get_lsb () - Glyph.xc (), glyph.get_baseline () + y - Glyph.yc ()); }@@ -112,7 +112,14 @@ public class MainWindow : GLib.Object { } } - public static void show_message (string text) { + public static void show_message (string text) {+ Tab t = MainWindow.get_tab_bar ().get_selected_tab (); + string tab_name = t.get_display ().get_name ();+ + if (tab_name == "Preview") {+ MenuTab.select_overview (); + }+ MessageDialog md = new MessageDialog (text); show_dialog (md); } @@ -396,7 +396,12 @@ public class Menu : AbstractMenu { MenuItem next_kerning_pair = add_menu_item (t_("Select Next Kerning Pair"), "select next kerning pair"); next_kerning_pair.action.connect (() => {- KerningDisplay.next_pair ();+ if (KerningDisplay.right_to_left) {+ KerningDisplay.previous_pair (); + } else {+ KerningDisplay.next_pair ();+ }+ show_menu = false; }); next_kerning_pair.add_display("Kerning");@@ -405,7 +410,12 @@ public class Menu : AbstractMenu { MenuItem previous_kerning_pair = add_menu_item (t_("Select Previous Kerning Pair"), "select previous kerning pair"); previous_kerning_pair.action.connect (() => {- KerningDisplay.previous_pair ();+ if (KerningDisplay.right_to_left) {+ KerningDisplay.next_pair (); + } else {+ KerningDisplay.previous_pair ();+ }+ show_menu = false; }); previous_kerning_pair.add_display("Kerning");@@ -211,7 +211,12 @@ public class MenuTab : FontDisplay { public static void signal_file_exported () { IdleSource idle = new IdleSource (); idle.set_callback (() => {- export_callback.file_exported ();+ export_callback.file_exported (); + + if (ExportTool.error_message != null) {+ MainWindow.show_message (t_("Can't create TTF font.") + "\n" + (!) ExportTool.error_message);+ } + return false; }); idle.attach (null);@@ -436,6 +441,8 @@ public class MenuTab : FontDisplay { } else { MainWindow.show_dialog (new SaveDialog (dialog)); }+ + MainWindow.native_window.update_window_size (); } public static void show_export_settings_tab () {@@ -43,7 +43,7 @@ public class GlyfData : GLib.Object { public Gee.ArrayList<int16> coordinate_y = new Gee.ArrayList<int16> (); uint16 end_point = 0;- int16 nflags = 0;+ uint16 nflags = 0; Glyph glyph; @@ -58,53 +58,48 @@ public class GlyfData : GLib.Object { public GlyfData (Glyph g) { bool process;- PathList qp = g.get_quadratic_paths (); + PathList all_quadratic = g.get_quadratic_paths (); + PathList qp = new PathList (); glyph = g; - foreach (Path p in qp.paths) {+ int i = 0;+ foreach (Path p in all_quadratic.paths) { if (p.points.size > 0) {- if (!is_empty (p)) {+ if (likely (!is_empty (p))) { // Add points at extrema p.add_extrema ();+ qp.add (p);+ } else {+ warning (@"Path number $i is empty in $(glyph.get_name ())"); }+ i++; } } - process = true;- - while (process) {- points.clear ();- paths.clear ();- foreach (Path p in qp.paths) {- if (!is_empty (p)) {- paths.add (p);- foreach (EditPoint ep in p.points) {- points.add (ep);- }- }- }- - if (paths.size == 0) {- break;+ points.clear ();+ paths.clear ();+ foreach (Path p in qp.paths) {+ paths.add (p);++ foreach (EditPoint ep in p.points) {+ points.add (ep); }+ } + if (paths.size > 0) { process_end_points (); process_flags (); process_x ();- - // error checking is done here- process = !process_y (); - + process_y (); process_bounding_box ();- }+ } } bool is_empty (Path p) { EditPoint? last = null; if (unlikely (p.points.size < 2)) {- warning (@"A path in $(glyph.get_name ()) has less than three points, it will not be exported."); return true; } @@ -114,8 +109,7 @@ public class GlyfData : GLib.Object { } last = ep; }- - warning (@"A path in $(glyph.get_name ()) ($(glyph.get_hex ())) has no area but $(p.points.size) points at $(p.get_first_point ().x),$(p.get_first_point ().y).");+ return true; } @@ -127,9 +121,26 @@ public class GlyfData : GLib.Object { return (int16) paths.size; } - public int16 get_nflags () {+ public uint16 get_nflags () { return nflags; }++ /** Count off curve points and on curve points.+ * @return the number of points or uint16.MAX if more than uint16.MAX points where found. + */ + public int get_num_points () {+ int points = 0;+ + foreach (Path quadratic in paths) {+ points += 2 * quadratic.points.size;+ + if (points >= uint16.MAX) {+ return uint16.MAX; + }+ }+ + return points;+ } void process_end_points () { uint16 last_end_point = 0;@@ -138,6 +149,7 @@ public class GlyfData : GLib.Object { end_points.clear (); end_point = 0; + int path_number = 0; foreach (Path quadratic in paths) { if (unlikely (quadratic.points.size == 0)) { warning (@"No points in path (before conversion $(quadratic.points.size))");@@ -145,20 +157,26 @@ public class GlyfData : GLib.Object { } if (unlikely (quadratic.points.size < 2)) {- warning ("A path contains less than three points, it will not be exported.");+ warning ("A path contains less than three points, it will not be exported. Path number: $path_number"); continue; } foreach (EditPoint e in quadratic.points) {+ if (unlikely (nflags == uint16.MAX - 1)) {+ warning (@"Too many end points in $(glyph.get_name ())");+ break; + }+ end_point++; type = e.get_right_handle ().type; // off curve- end_point++;- - if (end_point >= 0xFFFF) {- warning ("Too many points");+ if (unlikely (nflags == uint16.MAX - 1)) {+ warning (@"Too many end points in $(glyph.get_name ())");+ break; }+ + end_point++; } end_points.add (end_point - 1); @@ -189,7 +207,13 @@ public class GlyfData : GLib.Object { // off curve flags.add (CoordinateFlags.NONE);- nflags++;+ + if (unlikely (nflags == uint16.MAX)) {+ warning (@"Too many flags in $(glyph.get_name ())");+ return; + } + + nflags++; } } }@@ -230,7 +254,7 @@ public class GlyfData : GLib.Object { } } - bool process_y () {+ void process_y () { double prev = 0; double y; Font font = OpenFontFormatWriter.get_current_font ();@@ -238,6 +262,8 @@ public class GlyfData : GLib.Object { int epi = 0; coordinate_y.clear ();++ int path_number = 0; foreach (Path p in paths) { foreach (EditPoint e in p.points) {@@ -245,17 +271,8 @@ public class GlyfData : GLib.Object { coordinate_y.add ((int16) y); if ((int16) y == 0 && (int16) coordinate_x.get (coordinate_y.size - 1) == 0) {- warning (@"Point on point in TTF. Index $(coordinate_y.size - 1)");- - // FIXME: distorted shape- /*- if (BirdFont.has_argument ("--test")) {- print (glyph.get_name () + "\n");- print (points.get (epi).to_string ());- PenTool.remove_point_simplify (new PointSelection (points.get (epi), p));- return false;- }- */+ warning (@"Point on point in TTF. Index $(coordinate_y.size - 1) "+ + @"Path: $path_number in $(glyph.get_name ())"); } prev = rint (e.y * UNITS - font.base_line * UNITS);@@ -265,25 +282,13 @@ public class GlyfData : GLib.Object { // off curve y = rint (e.get_right_handle ().y * UNITS - prev - font.base_line * UNITS); coordinate_y.add ((int16) y);-- if ((int16) y == 0 && (int16) coordinate_x.get (coordinate_y.size - 1) == 0) {- warning (@"Point on point in TTF (off curve) Index: $(coordinate_y.size - 1) ");- if (BirdFont.has_argument ("--test")) {- print (glyph.get_name () + "\n");- print (points.get (epi).to_string ());- - // FIXME: distorted shape- PenTool.remove_point_simplify (new PointSelection (points.get (epi), p));- return false;- }- } prev = rint (e.get_right_handle ().y * UNITS - font.base_line * UNITS); epi++; }+ + path_number++; }- - return true; } void process_bounding_box () {@@ -209,7 +209,7 @@ public class GlyfTable : OtfTable { uint16 end_point; uint16 npoints; int16 ncontours;- int16 nflags;+ uint16 nflags; int glyph_offset; uint len; uint coordinate_length;@@ -223,6 +223,12 @@ public class GlyfTable : OtfTable { g.remove_empty_paths (); glyf_data = g.get_ttf_data ();+ + int points = glyf_data.get_num_points ();+ if (unlikely (points >= uint16.MAX)) {+ warning (@"Too many points in glyph $(g.get_name ()) ($points)");+ throw new FileError.FAILED (t_("Too many control points") + " " + t_("in") + @" $(g.get_name ())");+ } this.glyf_data.add (glyf_data); @@ -77,6 +77,25 @@ public class Preferences { set ("recent_files", @"$(recent.str)"); } + public static void set_window_size (int x, int y, int width, int height) {+ set ("window_x", @"$x");+ set ("window_y", @"$y");+ set ("window_width", @"$width");+ set ("window_height", @"$height");+ }++ public static int get_window_x () {+ string wp = get ("window_x");+ int x = int.parse (wp);+ return x;+ }++ public static int get_window_y () {+ string wp = get ("window_y");+ int y = int.parse (wp);+ return y;+ }+ public static int get_window_width() { string wp = get ("window_width"); int w = int.parse (wp);@@ -62,7 +62,10 @@ public class PreviewTools : ToolCollection { Preview.generate_html_document (); } - MainWindow.tabs.select_tab_name ("Preview");+ if (ExportTool.error_message == null) {+ MainWindow.tabs.select_tab_name ("Preview");+ }+ return false; }); @@ -53,7 +53,7 @@ public class SpacingClass : GLib.Object { string v = text; if (v.has_prefix ("U+") || v.has_prefix ("u+")) {- v = ((!) Font.to_unichar (val).to_string ()).dup ();+ v = ((!) Font.to_unichar (v).to_string ()).dup (); } if (update_first) {@@ -59,9 +59,19 @@ class SvgFontFormatWriter : GLib.Object { put ("<defs>"); - put (@"<font id=\"$font_name\" horiz-adv-x=\"250\" >");+ string font_id = font_name.replace (" ", "-");+ font_id = B.XmlParser.encode (font_id); + + Glyph space = font.get_space ().get_current ();+ double space_width = space.get_width ();+ + put (@"<font id=\"$font_id\" horiz-adv-x=\"$(to_float (space_width))\" >"); put (@"<font-face units-per-em=\"$(to_float (units_per_em))\" ascent=\"$(to_float (ascent))\" descent=\"$(to_float (descent))\" />"); + put (@"<font-src>");+ put (@"\t<font-face-name=\"XmlParser.encode ($font_name)\">");+ put (@"</font-src>");+ // (missing-glyph goes here) // regular glyphs @@ -162,6 +162,7 @@ public class SvgParser { // parse the file if (!has_format) {+ parser.set_format (SvgFormat.ILLUSTRATOR); warn_if_test ("No format identifier found in SVG parser.\n"); } @@ -226,7 +227,6 @@ public class SvgParser { } foreach (XmlElement t in tag) {- if (t.get_name () == "g") { parse_layer (t, pl); }@@ -269,13 +269,11 @@ public class SvgParser { } PathList paths = LayerUtils.get_all_paths (pl);- ViewBox? box = SvgFile.parse_view_box (tag);+ if (box != null) { ViewBox view_box = (!) box;- Cairo.Matrix matrix = Cairo.Matrix.identity ();- Cairo.Matrix view_box_matrix = view_box.get_matrix (width, height);- view_box_matrix.multiply (view_box_matrix, matrix);+ Matrix view_box_matrix = view_box.get_matrix (width, height); SvgTransform t = new SvgTransform.for_matrix (view_box_matrix); SvgTransforms transforms = new SvgTransforms (); transforms.add (t);@@ -347,14 +345,7 @@ public class SvgParser { } } - PathList paths = new PathList ();- - foreach (SvgBird.Object object in pl.objects) {- if (object is Path) {- paths.add ((Path) object);- }- }- + PathList paths = LayerUtils.get_all_paths (pl); SvgTransforms transforms = SvgFile.get_transform (tag.get_attributes ()); transform_paths (transforms, paths); }@@ -101,8 +101,14 @@ public class SvgFile : GLib.Object { bool slice = true; bool preserve_aspect_ratio = true; + if (tag.get_name () != "svg") {+ warning (@"viewBox is not the svg tag: $(tag.get_name ())");+ return null;+ }+ foreach (Attribute attribute in tag.get_attributes ()) { if (attribute.get_name () == "viewBox") {+ print (@"$(attribute.get_name ()): $(attribute.get_content ())\n"); parameters = attribute.get_content (); } @@ -123,6 +129,7 @@ public class SvgFile : GLib.Object { } } + print (@"parameters: $parameters\n"); arguments = parameters.replace (",", " "); while (arguments.index_of (" ") > -1) {@@ -131,8 +138,9 @@ public class SvgFile : GLib.Object { string[] view_box_parameters = arguments.split (" "); - if (view_box_parameters.length != 4) {+ if (unlikely (view_box_parameters.length != 4)) { warning ("Expecting four arguments in view box.");+ warning (@"Content: $arguments ($parameters)"); return null; } @@ -134,6 +134,10 @@ public class SvgTransforms : GLib.Object { return copy_transforms; } + public void insert (int position, SvgTransform transform) {+ transforms.insert (position, transform);+ }+ public void add (SvgTransform transform) { transforms.add (transform); }@@ -13,7 +13,7 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. """ -VERSION = '2.17.1'+VERSION = '2.18.3' SO_VERSION_MAJOR = '36' SO_VERSION_MINOR = '0' SO_VERSION = SO_VERSION_MAJOR + '.' + SO_VERSION_MINOR