The Birdfont Source Code


All Repositories / birdfont.git / commit – RSS feed

Create versions of glyphs in order to support multi-master fonts

These changes was commited to the Birdfont repository Sun, 15 Nov 2015 17:15:47 +0000.

Contributing

Send patches or pull requests to johan.mattsson.m@gmail.com.
Clone this repository: git clone https://github.com/johanmattssonm/birdfont.git
author Johan Mattsson <johan.mattsson.m@gmail.com>
Sun, 15 Nov 2015 17:15:47 +0000 (18:15 +0100)
committer Johan Mattsson <johan.mattsson.m@gmail.com>
Sun, 15 Nov 2015 17:15:47 +0000 (18:15 +0100)
commit 84c0fa79cdd4bf190592707b4dcf6917d3d8d127
tree 27db1ad2390dc531a3307bd86d9509906d7ebf2f
parent 3ed3dda2762c672722fdd9e33d739013d467406f
Create versions of glyphs in order to support multi-master fonts

12 files changed:
libbirdfont/BackgroundTab.vala
libbirdfont/BirdFontFile.vala
libbirdfont/BirdFontPart.vala
libbirdfont/ClipTool.vala
libbirdfont/Font.vala
libbirdfont/GlyphCollection.vala
libbirdfont/MainWindow.vala
libbirdfont/OverView.vala
libbirdfont/OverViewItem.vala
libbirdfont/OverviewTools.vala
libbirdfont/VersionList.vala
--- a/libbirdfont/BackgroundTab.vala +++ b/libbirdfont/BackgroundTab.vala @@ -52,7 +52,11 @@ GlyphCanvas canvas = MainWindow.get_glyph_canvas (); GlyphCollection gc = new GlyphCollection ('\0', ""); - gc.add_glyph (this); + + GlyphMaster master = new GlyphMaster (); + master.add_glyph (this); + gc.add_master (master); + canvas.set_current_glyph_collection (gc, false); DrawingTools.background_scale.set_tool_visibility (true); ZoomTool.zoom_full_background_image ();
--- a/libbirdfont/BirdFontFile.vala +++ b/libbirdfont/BirdFontFile.vala @@ -152,7 +152,7 @@ try { string data; - foreach (Glyph g in gc.glyphs) { + foreach (Glyph g in gc.get_all_glyph_masters ()) { if (g.get_background_image () != null) { bg = (!) g.get_background_image (); data = bg.get_png_base64 (); @@ -383,33 +383,50 @@ os.put_string ("</horizontal>\n"); } - public void write_glyph_collection_start (GlyphCollection gc, DataOutputStream os) throws GLib.Error { + public void write_glyph_collection_start (GlyphCollection gc, GlyphMaster master, DataOutputStream os) throws GLib.Error { os.put_string ("<collection "); if (gc.is_unassigned ()) { - os.put_string (@"name=\"$(gc.get_current ().get_name ())\""); + os.put_string (@"name=\"$(gc.get_name ())\""); } else { - os.put_string (@"unicode=\"$(Font.to_hex (gc.get_current ().unichar_code))\""); + os.put_string (@"unicode=\"$(Font.to_hex (gc.get_unicode_character ()))\""); + } + + if (gc.is_multimaster ()) { + os.put_string (" "); + os.put_string (@"master=\"$(master.get_id ())\""); } os.put_string (">\n"); } public void write_glyph_collection_end (DataOutputStream os) throws GLib.Error { - os.put_string ("</collection>\n"); + os.put_string ("</collection>\n\n"); } - public void write_selected (GlyphCollection gc, DataOutputStream os) throws GLib.Error { - os.put_string (@"\t<selected id=\"$(gc.get_current ().version_id)\"/>\n"); + public void write_selected (GlyphMaster master, DataOutputStream os) throws GLib.Error { + Glyph? g = master.get_current (); + Glyph glyph; + + if (g != null) { + glyph = (!) g; + os.put_string (@"\t<selected id=\"$(glyph.version_id)\"/>\n"); + } } public void write_glyph_collection (GlyphCollection gc, DataOutputStream os) throws GLib.Error { - write_glyph_collection_start (gc, os); - write_selected (gc, os); - foreach (Glyph g in gc.glyphs) { + foreach (GlyphMaster master in gc.glyph_masters) { + write_glyph_collection_start (gc, master, os); + write_selected (master, os); + write_glyph_master (master, os); + write_glyph_collection_end (os); + } + } + + public void write_glyph_master (GlyphMaster master, DataOutputStream os) throws GLib.Error { + foreach (Glyph g in master.glyphs) { write_glyph (g, os); } - write_glyph_collection_end (os); } public void write_glyph (Glyph g, DataOutputStream os) throws GLib.Error { @@ -1234,6 +1251,8 @@ string name = ""; int selected_id = -1; bool unassigned = false; + string master_id = ""; + GlyphMaster master; foreach (Attribute attribute in tag.get_attributes ()) { if (attribute.get_name () == "unicode") { @@ -1249,10 +1268,15 @@ unassigned = false; } - if (attribute.get_name () == "name") { + // set name because either name or unicode is set in the bf file + if (attribute.get_name () == "name") { unicode = '\0'; name = attribute.get_content (); unassigned = true; + } + + if (attribute.get_name () == "master") { + master_id = attribute.get_content (); } } @@ -1264,17 +1288,24 @@ } else { gc = new GlyphCollection (unicode, name); } - + + if (gc.has_master (master_id)) { + master = gc.get_master (master_id); + } else { + master = new GlyphMaster.for_id (master_id); + gc.add_master (master); + } + foreach (Tag t in tag) { if (t.get_name () == "selected") { selected_id = parse_selected (t); - gc.set_selected_version (selected_id); + master.set_selected_version (selected_id); } } foreach (Tag t in tag) { if (t.get_name () == "glyph") { - parse_glyph (t, gc, name, unicode, selected_id, unassigned); + parse_glyph (t, gc, master, name, unicode, selected_id, unassigned); } } @@ -1302,8 +1333,8 @@ return id; } - public void parse_glyph (Tag tag, GlyphCollection gc, string name, - unichar unicode, int selected_id, bool unassigned) { + public void parse_glyph (Tag tag, GlyphCollection gc, GlyphMaster master, + string name, unichar unicode, int selected_id, bool unassigned) { Glyph glyph = new Glyph (name, unicode); Path path; bool selected = false; @@ -1360,8 +1391,7 @@ glyph.version_id = (has_id) ? id : (int) gc.length () + 1; gc.set_unassigned (unassigned); - gc.insert_glyph (glyph, selected || selected_id == id); - glyph = new Glyph.no_lines (""); + master.insert_glyph (glyph, selected || selected_id == id); } Layer parse_layer (Tag tag) {
--- a/libbirdfont/BirdFontPart.vala +++ b/libbirdfont/BirdFontPart.vala @@ -92,8 +92,8 @@ try { // remove deleted glyphs - foreach (Glyph g in font.deleted_glyphs) { - file_name = get_glyph_base_file_name (g) + ".bfp"; + foreach (string deleted_glyph in font.deleted_glyphs) { + file_name = deleted_glyph; glyph_dir_name = get_subdir_name (file_name); glyph_file = get_destination_file (file_name, "glyphs", glyph_dir_name); @@ -156,21 +156,27 @@ selected_file_name = get_first_number_in_unicode (((!)gc).get_current ()); dir_name = get_subdir_name (selected_file_name); - - os = create_file (@"selected_$(selected_file_name).bfp", "glyphs", dir_name); - bf.write_root_tag (os); - bf.write_glyph_collection_start (gc, os); - bf.write_selected ((!) gc, os); - bf.write_glyph_collection_end (os); - bf.write_closing_root_tag (os); - os.close (); - - foreach (Glyph g in gc.glyphs) { - try { - write_glyph (bf, gc, g); - write_glyph_background_image (bf, gc, g); - } catch (GLib.Error e) { - warning (e.message); + + // selected glyph + foreach (GlyphMaster master in gc.glyph_masters) { + os = create_file (@"selected_$(selected_file_name)_$(master.get_id ()).bfp", "glyphs", dir_name); + bf.write_root_tag (os); + bf.write_glyph_collection_start (gc, master, os); + bf.write_selected ((!) master, os); + bf.write_glyph_collection_end (os); + bf.write_closing_root_tag (os); + os.close (); + } + + + foreach (GlyphMaster master in gc.glyph_masters) { + foreach (Glyph g in master.glyphs) { + try { + write_glyph (bf, gc, master, g); + write_glyph_background_image (bf, gc, g); + } catch (GLib.Error e) { + warning (e.message); + } } } } catch (GLib.Error e) { @@ -243,15 +249,15 @@ } } - string get_first_number_in_unicode (Glyph g) throws GLib.Error { + static string get_first_number_in_unicode (Glyph g) { string s = Font.to_hex (g.unichar_code); s = s.replace ("U+", ""); return s; } - string get_glyph_base_file_name (Glyph g) throws GLib.Error { + public static string get_glyph_base_file_name (Glyph g, GlyphMaster master) { string s = get_first_number_in_unicode (g); - s = @"U+$(s)_$(g.version_id)"; + s = @"U+$(s)_$(g.version_id)_$(master.get_id ())"; return s; } @@ -265,17 +271,17 @@ return (!) d.get_char ().to_string (); } - void write_glyph (BirdFontFile bf, GlyphCollection gc, Glyph g) throws GLib.Error { + void write_glyph (BirdFontFile bf, GlyphCollection gc, GlyphMaster master, Glyph g) throws GLib.Error { string file_name; string dir_name; DataOutputStream os; - file_name = get_glyph_base_file_name (g); + file_name = get_glyph_base_file_name (g, master); dir_name = get_subdir_name (file_name); os = create_file (@"$(file_name).bfp", "glyphs", dir_name); bf.write_root_tag (os); - bf.write_glyph_collection_start (gc, os); + bf.write_glyph_collection_start (gc, master, os); bf.write_glyph (g, os); bf.write_glyph_collection_end (os); bf.write_closing_root_tag (os);
--- a/libbirdfont/ClipTool.vala +++ b/libbirdfont/ClipTool.vala @@ -361,7 +361,9 @@ glyphs.add (glyph_collection); glyph = new Glyph ((!) c.to_string (), c); - glyph_collection.add_glyph (glyph); + GlyphMaster master = new GlyphMaster (); + master.add_glyph (glyph); + glyph_collection.add_master (master); } if (p.has_prefix ("unassigned:")) {
--- a/libbirdfont/Font.vala +++ b/libbirdfont/Font.vala @@ -106,7 +106,8 @@ bool bfp = false; BirdFontPart bfp_file; - public Gee.ArrayList<Glyph> deleted_glyphs; + /** File names of deleted glyphs in bfp directories. */ + public Gee.ArrayList<string> deleted_glyphs; public Ligatures ligature_substitution; @@ -171,7 +172,7 @@ bfp_file = new BirdFontPart (this); - deleted_glyphs = new Gee.ArrayList<Glyph> (); + deleted_glyphs = new Gee.ArrayList<string> (); ligature_substitution = new Ligatures (this); background_images = new Gee.ArrayList<BackgroundImage> (); @@ -445,7 +446,10 @@ g.remove_empty_paths (); gc.set_unassigned (false); - gc.add_glyph (g); + + GlyphMaster master = new GlyphMaster (); + master.add_glyph (g); + gc.add_master (master); return gc; } @@ -461,7 +465,10 @@ gc = new GlyphCollection ('\0', "null"); n = new Glyph ("null", '\0'); - gc.add_glyph (n); + GlyphMaster master = new GlyphMaster (); + master.add_glyph (n); + gc.add_master (master); + gc.set_unassigned (false); n.left_limit = 0; @@ -490,7 +497,10 @@ n.right_limit = 27; n.remove_empty_paths (); - gc.add_glyph (n); + GlyphMaster master = new GlyphMaster (); + master.add_glyph (n); + gc.add_master (master); + gc.set_unassigned (false); return gc; @@ -513,7 +523,10 @@ i = new Path (); gc.set_unassigned (true); - gc.add_glyph (g); + + GlyphMaster master = new GlyphMaster (); + master.add_glyph (g); + gc.add_master (master); g.left_limit = -20; g.right_limit = 33; @@ -595,9 +608,17 @@ a.remove (glyph); } - foreach (Glyph g in glyph.glyphs) { - deleted_glyphs.add (g); + foreach (GlyphMaster master in glyph.glyph_masters) { + foreach (Glyph g in master.glyphs) { + add_deleted_glyph (g, master); + } } + } + + public void add_deleted_glyph (Glyph g, GlyphMaster master) { + string file_name; + file_name = BirdFontPart.get_glyph_base_file_name (g, master) + ".bfp"; + deleted_glyphs.add (file_name); } // FIXME: the order of ligature substitutions
--- a/libbirdfont/GlyphCollection.vala +++ b/libbirdfont/GlyphCollection.vala @@ -21,52 +21,85 @@ unichar unicode_character; string name; bool unassigned; - Gee.ArrayList<GlyphMaster> glyph_masters; - + public Gee.ArrayList<GlyphMaster> glyph_masters; + + // FIXME: move this somewhere + static int current_master = 0; + public GlyphCollection (unichar unicode_character, string name) { this.unicode_character = unicode_character; this.name = name; glyph_masters = new Gee.ArrayList<GlyphMaster> (); - unassigned = false + unassigned = false; } public GlyphCollection.with_glyph (unichar unicode_character, string name) { Glyph g; + GlyphMaster master; glyph_masters = new Gee.ArrayList<GlyphMaster> (); - unassigned = false + master = new GlyphMaster (); + glyph_masters.add (master); + + unassigned = false; this.unicode_character = unicode_character; this.name = name; g = new Glyph (name, unicode_character); - glyphs.add (g); - set_selected (g); + master.glyphs.add (g); + master.set_selected (g); + } + + public bool has_masters () { + return glyph_masters.size > 0; } - public void remove (int index) { - return_if_fail (0 <= index < glyphs.size); + /** This method returns the current master, it has global state. */ + public GlyphMaster get_current_master () { + int i = current_master; - if (selected >= index) { - selected--; + if (i >= glyph_masters.size) { + warning("No master is set for glyph."); + i = glyph_masters.size - 1; } - glyphs.remove_at (index); + return_val_if_fail (0 <= i < glyph_masters.size, new GlyphMaster ()); + + return glyph_masters.get (i); + } + + public bool has_master (string id) { + foreach (GlyphMaster m in glyph_masters) { + if (m.get_id () == id) { + return true; + } + } + + return false; } - - public void set_selected (Glyph g) { - int i = 0; - foreach (Glyph gl in glyphs) { - if (gl == g) { - selected = i; - return; + public GlyphMaster get_master (string id) { + foreach (GlyphMaster m in glyph_masters) { + if (m.get_id () == id) { + return m; } - i++; } - selected = 0; - warning ("Glyph is not a part of the collection."); + warning ("Master not found for id $(id)."); + return new GlyphMaster (); + } + + public bool is_multimaster() { + return glyph_masters.size > 1; + } + + public void remove (int index) { + get_current_master ().remove (index); + } + + public void set_selected (Glyph g) { + get_current_master ().set_selected (g); } public void set_unassigned (bool a) { @@ -77,30 +110,35 @@ return unassigned; } - public void add_glyph (Glyph g) { - glyphs.add (g); + public void add_master (GlyphMaster master) { + glyph_masters.add (master); } public Glyph get_current () { - if (likely (0 <= selected < glyphs.size)) { - return glyphs.get (selected); + Glyph? g = get_current_master ().get_current (); + + if (likely (g != null)) { + return (!) g; } - warning (@"No glyph selected for $(name): $selected glyphs.size: $(glyphs.size)"); - + warning (@"No glyph selected for $(name)"); return new Glyph ("", '\0'); + } + + public Glyph get_interpolated (double weight) { + return get_current (); } public void insert_glyph (Glyph g, bool selected_glyph) { - glyphs.add (g); - - if (selected_glyph) { - selected = glyphs.size - 1; - } + get_current_master ().insert_glyph (g, selected_glyph); } public uint length () { - return glyphs.size; + if (!has_masters ()) { + return 0; + } + + return get_current_master ().glyphs.size; } public string get_unicode () { @@ -124,18 +162,7 @@ public void set_name (string n) { name = n; } - - public void set_selected_version (int version_id) { - int i = 0; - foreach (Glyph g in glyphs) { - if (g.version_id == version_id) { - selected = i; - break; - } - i++; - } - } - + /** Create a copy of this list. This method will copy the list data but * keep pointers to the original glyphs. * @return a new list with copies of pointers to the glyphs @@ -143,11 +170,10 @@ public GlyphCollection copy () { GlyphCollection n = new GlyphCollection (unicode_character, name); - foreach (Glyph g in glyphs) { - n.insert_glyph (g, false); + foreach (GlyphMaster g in glyph_masters) { + n.glyph_masters.add (g.copy ()); } - n.selected = selected; n.unassigned = unassigned; return n; @@ -156,21 +182,32 @@ public GlyphCollection copy_deep () { GlyphCollection n = new GlyphCollection (unicode_character, name); - foreach (Glyph g in glyphs) { - n.insert_glyph (g.copy (), false); + foreach (GlyphMaster g in glyph_masters) { + n.glyph_masters.add (g.copy_deep ()); } - n.selected = selected; n.unassigned = unassigned; return n; } public int get_last_id () { - return_val_if_fail (glyphs.size > 0, 0); - return glyphs.get (glyphs.size - 1).version_id; + return get_current_master ().get_last_id (); + } + + /** @return all versions of all masters */ + public Gee.ArrayList<Glyph> get_all_glyph_masters () { + Gee.ArrayList<Glyph> glyphs = new Gee.ArrayList<Glyph> (); + + foreach (GlyphMaster master in glyph_masters) { + foreach (Glyph g in master.glyphs) { + glyphs.add (g); + } + } + + return glyphs; } } }
--- a/libbirdfont/MainWindow.vala +++ b/libbirdfont/MainWindow.vala @@ -183,8 +183,7 @@ GlyphCollection gc; warning ("No default glyph have been set yet.\n"); - gc = new GlyphCollection ('\0', ""); - gc.add_glyph (new Glyph ("", '\0')); + gc = new GlyphCollection.with_glyph ('\0', ""); return gc; }
--- a/libbirdfont/OverView.vala +++ b/libbirdfont/OverView.vala @@ -164,9 +164,10 @@ TabBar tabs = MainWindow.get_tab_bar (); bool selected; Glyph glyph; - GlyphCollection glyph_collection = MainWindow.get_current_glyph_collection (); + GlyphCollection glyph_collection; GlyphCanvas canvas; - + + glyph_collection = MainWindow.get_current_glyph_collection (); name.append_unichar (character); selected = tabs.select_char (name.str); @@ -221,7 +222,8 @@ glyph_collection = new GlyphCollection (character, name.str); if (!empty) { - glyph = new Glyph (name.str, (!unassigned) ? character : '\0'); + glyph = new Glyph (name.str, !unassigned ? character : '\0'); + glyph_collection.add_master (new GlyphMaster ()); glyph_collection.insert_glyph (glyph, true); }
--- a/libbirdfont/OverViewItem.vala +++ b/libbirdfont/OverViewItem.vala @@ -211,7 +211,7 @@ if (gl != null) { font = BirdFont.get_current_font (); - g = ((!) gl).get_current (); + g = ((!) gl).get_interpolated (OverviewTools.current_master_size); c.save (); g.boundaries (out x1, out y1, out x2, out y2);
--- a/libbirdfont/OverviewTools.vala +++ b/libbirdfont/OverviewTools.vala @@ -31,6 +31,8 @@ public static SpinButton skew; public static SpinButton resize; + + public static double current_master_size; public OverviewTools () { Expander font_name = new Expander (); @@ -38,6 +40,7 @@ Expander zoom_expander = new Expander (t_("Zoom")); Expander transform_expander = new Expander (t_("Transform")); Expander glyph_expander = new Expander (t_("Glyph")); + Expander multi_master = new Expander (t_("Multi-Master")); expanders = new Gee.ArrayList<Expander> (); custom_character_sets = new Gee.ArrayList<LabelTool> (); @@ -147,12 +150,31 @@ idle.attach (null); }); glyph_expander.add_tool (curve_orientation); + + SpinButton master_size; + current_master_size = 1 + master_size = new SpinButton ("master_size", t_("Master Size")); /// master refers to a master in a multi-master font + master_size.set_big_number (false); + master_size.set_int_value ("1.000"); + master_size.set_int_step (1); + master_size.set_min (0.001); + master_size.set_max (9); + master_size.show_icon (true); + master_size.set_persistent (false); + master_size.new_value_action.connect ((self) => { + current_master_size = self.get_value (); + }); + multi_master.add_tool (master_size); expanders.add (font_name); expanders.add (zoom_expander); expanders.add (character_sets); expanders.add (transform_expander); expanders.add (glyph_expander); + + if (BirdFont.has_argument ("--test")) { + expanders.add (multi_master); + } } void fix_curve_orientation () {
--- a/libbirdfont/VersionList.vala +++ b/libbirdfont/VersionList.vala @@ -70,8 +70,10 @@ glyphs = new Gee.ArrayList<Glyph> (); - foreach (Glyph g in gc.glyphs) { - add_glyph (g, false); + if (gc.has_masters ()) { + foreach (Glyph g in gc.get_current_master ().glyphs) { + add_glyph (g, false); + } } if (gc.length () > 0) { @@ -96,8 +98,11 @@ } return_if_fail (0 <= index < glyphs.size); + + Glyph g = glyph_collection.get_current (); + GlyphMaster m = glyph_collection.get_current_master (); + font.add_deleted_glyph (g, m); - font.deleted_glyphs.add (glyph_collection.get_current ()); over_view.store_undo_state (glyph_collection.copy ()); current_version = get_current_version_index ();