Clone in a terminal:
Commit d7653df
Johan Mattsson - 2015-09-27T13:41:14+00:00
d7653df4d75962a8b0f576d9637f13f0a1096268johan.mattsson.m@gmail.com

Generate stylistic alternates and fix PostScript names

Changed files (19)

Diff

diff --git a/libbirdfont/Font.vala b/libbirdfont/Font.valaindex 774606c..ea854dd 100644--- a/libbirdfont/Font.vala+++ b/libbirdfont/Font.vala@@ -35,6 +35,9 @@ public class Font : GLib.Object { 	/** Table with ligatures. */ 	public GlyphTable ligature; 	+	/** List of alternate glyphs. */+	public Gee.ArrayList<Alternate> alternates;+	 	public Gee.ArrayList<BackgroundImage> background_images; 	public string background_scale = "1"; 	@@ -63,7 +66,7 @@ public class Font : GLib.Object { 	 	bool modified = false; 	-	// name table descriptions+	// name table strings 	public string postscript_name; 	public string name; 	public string subfamily;@@ -175,12 +178,41 @@ public class Font : GLib.Object { 		 		settings = new FontSettings (); 		kerning_strings = new KerningStrings ();+		+		alternates = new Gee.ArrayList<Alternate> (); 	}  	~Font () { 		font_deleted (); 	} +	public Alternate? get_alternate (GlyphCollection gc) {+		foreach (Alternate a in alternates) {+			if (a.glyph == gc) {+				return a;+			}+		}+		+		return null;+	}++	public void add_new_alternate (GlyphCollection glyph,+		GlyphCollection alternate) {+	+		Alternate  a;+		Alternate? alt = get_alternate (alternate);+		+		if (alt == null) {+			a = new Alternate (glyph);+			alternates.add (a);+		} else {+			a = (!) alt;+		}+		+		a.add (alternate);+		glyph_name.insert (alternate.get_name (), alternate);+	}+ 	public bool has_compatible_format () { 		return !newer_format () && !older_format (); 	}@@ -540,6 +572,10 @@ public class Font : GLib.Object { 		glyph_name.remove (glyph.get_name ()); 		ligature.remove (glyph.get_current ().get_name ()); 		+		foreach (Alternate a in alternates) {+			a.remove (glyph);+		}+		 		foreach (Glyph g in glyph.glyphs) { 			deleted_glyphs.add (g); 		}diff --git a/libbirdfont/GlyphCollection.vala b/libbirdfont/GlyphCollection.valaindex 1a3fb08..df9fec4 100644--- a/libbirdfont/GlyphCollection.vala+++ b/libbirdfont/GlyphCollection.vala@@ -37,6 +37,7 @@ public class GlyphCollection : GLib.Object { 		 		g = new Glyph (name, unicode_character); 		glyphs.add (g);+		set_selected (g); 	} 	 	public void remove (int index) {diff --git a/libbirdfont/OpenFontFormat/Alternate.vala b/libbirdfont/OpenFontFormat/Alternate.valanew file mode 100644index 0000000..d3d92ff--- /dev/null+++ b/libbirdfont/OpenFontFormat/Alternate.vala@@ -0,0 +1,47 @@+/*+    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 Alternate : GLib.Object {+	+	public GlyphCollection glyph;+	public Gee.ArrayList<GlyphCollection> alternates;+	+	public Alternate (GlyphCollection glyph) {+		this.glyph = glyph;+		this.alternates = new Gee.ArrayList<GlyphCollection> ();+	}++	public void add (GlyphCollection g) {+		alternates.add (g);+	}+	+	public void remove (GlyphCollection g) {+		int i = 0;+		foreach (GlyphCollection a in alternates) {+			if (a.get_name () == g.get_name ()) {+				break;+			}+			i++;+		}+		+		if (i < alternates.size) {+			alternates.remove_at (i);+		}+	}+	+}++}diff --git a/libbirdfont/OpenFontFormat/AlternateFeature.vala b/libbirdfont/OpenFontFormat/AlternateFeature.valaindex 4c47493..f20ed00 100644--- a/libbirdfont/OpenFontFormat/AlternateFeature.vala+++ b/libbirdfont/OpenFontFormat/AlternateFeature.vala@@ -11,18 +11,84 @@     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      Lesser General Public License for more details. */-using Math;  namespace BirdFont {  public class AlternateFeature : GLib.Object {-	FontData font_data = new FontData ();+	GlyfTable glyf_table;+	+	public AlternateFeature (GlyfTable glyf_table) {	+		this.glyf_table = glyf_table;+	}+	+	public bool has_alternates () {+		Font font = OpenFontFormatWriter.get_current_font ();+		return font.alternates.size > 0;+	}+	+	public Lookups get_lookups () throws GLib.Error {+		Lookups lookups = new Lookups ();+		Lookup lookup = new Lookup (3, 0, Lookups.ALTERNATES);+		FontData fd = new FontData ();+		Font font = OpenFontFormatWriter.get_current_font ();+		+		font.alternates.sort ((a, b) => {+			Alternate alt1 = (Alternate) a;+			Alternate alt2 = (Alternate) b;+			return strcmp (alt1.glyph.get_name (), alt2.glyph.get_name ());+		});+		+		fd.add_ushort (1); // format identifier+		+		// offset to coverage+		int coverage_offset = 6;+		coverage_offset += 2 * font.alternates.size;+		coverage_offset += 2 + 2 * get_number_of_alternates (); +		fd.add_ushort ((uint16) coverage_offset);+		+		// number of alternate sets+		fd.add_ushort ((uint16) font.alternates.size); +		+		int offset = 6 + 2 * font.alternates.size;+		for (int i = 0; i < font.alternates.size; i++) {+			// offset to each alternate set+			fd.add_ushort ((uint16) offset);+			offset += 2;+			offset += 2 * font.alternates.size;+		}+		+		// alternates+		fd.add_ushort ((uint16) font.alternates.size);+		foreach (Alternate alternate in font.alternates) {+			foreach (GlyphCollection g in alternate.alternates) {+				string name = g.get_name ();+				fd.add_ushort ((uint16) glyf_table.get_gid (name));+			}+		}		 -	public AlternateFeature () {	+		// coverage  +		fd.add_ushort (1); // format+		fd.add_ushort ((uint16) font.alternates.size); // coverage array length+		foreach (Alternate alternate in font.alternates) {+			string glyph_name = alternate.glyph.get_name ();+			fd.add_ushort ((uint16) glyf_table.get_gid (glyph_name));+		}+		+		lookup.add_subtable (fd);+		lookups.add_lookup (lookup);+		+		return lookups; 	} 	-	public FontData get_font_data () {-		return font_data;+	int get_number_of_alternates () {+		int n = 0;+		Font font = OpenFontFormatWriter.get_current_font ();+		+		foreach (Alternate alternate in font.alternates) {+			n += alternate.alternates.size;+		}+		+		return n; 	} } diff --git a/libbirdfont/OpenFontFormat/CligFeature.vala b/libbirdfont/OpenFontFormat/CligFeature.valaindex 5b0394b..0f77c75 100644--- a/libbirdfont/OpenFontFormat/CligFeature.vala+++ b/libbirdfont/OpenFontFormat/CligFeature.vala@@ -26,6 +26,10 @@ public class CligFeature : GLib.Object { 		generate_feature (); 	} 	+	public bool has_regular_ligatures () {+		return clig.ligature_sets.size > 0;+	}+	 	public Lookups get_lookups () { 		return lookups; 	}diff --git a/libbirdfont/OpenFontFormat/Feature.vala b/libbirdfont/OpenFontFormat/Feature.valanew file mode 100644index 0000000..a9b7b37--- /dev/null+++ b/libbirdfont/OpenFontFormat/Feature.vala@@ -0,0 +1,39 @@+/*+    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 Feature : GLib.Object {+	+	public string tag;+	public Lookups lookups;+	public Gee.ArrayList<int> public_lookups = new Gee.ArrayList<int> ();+	+	public int lookup_offset = 0; // FIXME:DELETE+	+	public Feature (string tag, Lookups lookups) {+		this.tag = tag;+		this.lookups = lookups;+	}+	+	public void add_feature_lookup (int lookup_token) {+		public_lookups.add (lookup_token);+	}+	+	public int get_public_lookups () {+		return public_lookups.size;+	}+}++}diff --git a/libbirdfont/OpenFontFormat/FeatureList.vala b/libbirdfont/OpenFontFormat/FeatureList.valanew file mode 100644index 0000000..d40a523--- /dev/null+++ b/libbirdfont/OpenFontFormat/FeatureList.vala@@ -0,0 +1,58 @@+/*+    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 FeatureList : GLib.Object {+	+	public Gee.ArrayList<Feature> features = new Gee.ArrayList<Feature> ();+	+	public FeatureList () {+	}+		+	public void add (Feature f) {+		features.add (f);+	}+	+	public FontData generate_feature_tags () throws GLib.Error {+		FontData fd = new FontData ();++		fd.add_ushort ((uint16) features.size); // number of features+		+		uint offset = 2 + 6 * features.size;+		foreach (Feature feature in features) {+			fd.add_tag (feature.tag); // feature tag: aalt, clig etc.+			fd.add_ushort ((uint16) offset); // offset to feature+			+			offset += 4 + 2 * feature.get_public_lookups ();+		}++		foreach (Feature feature in features) {+			// feature prameters (null)+			fd.add_ushort (0);+			+			// number of lookups+			fd.add_ushort ((uint16) feature.public_lookups.size); +			+			foreach (int p in feature.public_lookups) {+				// reference to a lookup table (lookup index)+				fd.add_ushort (feature.lookups.find (p));+			}+		}+				+		return fd;+	}+}++}diff --git a/libbirdfont/OpenFontFormat/GlyfTable.vala b/libbirdfont/OpenFontFormat/GlyfTable.valaindex 59a93a0..2108cfc 100644--- a/libbirdfont/OpenFontFormat/GlyfTable.vala+++ b/libbirdfont/OpenFontFormat/GlyfTable.vala@@ -144,7 +144,7 @@ public class GlyfTable : OtfTable { 		Gee.ArrayList<GlyphCollection> unassigned_glyphs; 		bool unassigned; 		-		// add notdef character and other special chars first+		// add notdef character and other special characters first 		glyphs.add (font.get_not_def_character ()); 		glyphs.add (font.get_null_character ()); 		glyphs.add (font.get_nonmarking_return ());@@ -159,12 +159,10 @@ public class GlyfTable : OtfTable { 		// add glyphs 		for (indice = 0; (gcn = font.get_glyph_collection_indice (indice)) != null; indice++) {		 			gc = (!) gcn;-			g = gc.get_current ().copy ();+			gc = gc.copy_deep ();+			g = gc.get_current (); 			g.remove_empty_paths (); 			unassigned = gc.is_unassigned ();-			-			gc = new GlyphCollection (gc.get_unicode_character (), gc.get_name ());-			gc.add_glyph (g);  			if (unassigned) { 				unassigned_glyphs.add (gc);diff --git a/libbirdfont/OpenFontFormat/GsubTable.vala b/libbirdfont/OpenFontFormat/GsubTable.valaindex 6532d07..0ca1643 100644--- a/libbirdfont/OpenFontFormat/GsubTable.vala+++ b/libbirdfont/OpenFontFormat/GsubTable.vala@@ -32,12 +32,46 @@ public class GsubTable : OtfTable { 		 		fd = new FontData (); 		CligFeature clig_feature = new CligFeature (glyf_table);-		AlternateFeature alternate_feature = new AlternateFeature ();+		AlternateFeature alternate_feature = new AlternateFeature (glyf_table);++		Lookups lookups = new Lookups ();+		FeatureList features = new FeatureList ();++		if (alternate_feature.has_alternates ()) {			+			Lookups aalt_lookup = alternate_feature.get_lookups ();+			Feature aalt_feature_lookup = new Feature ("aalt", lookups);+			aalt_feature_lookup.add_feature_lookup (Lookups.ALTERNATES);+			features.add (aalt_feature_lookup);	+			lookups.append (aalt_lookup);+		}+	+		bool has_clig = clig_feature.contextual.has_ligatures ()+			|| clig_feature.has_regular_ligatures ();+			+		if (has_clig) {+			Lookups clig_lookups = clig_feature.get_lookups ();+			Feature clig_feature_lookup = new Feature ("clig", lookups);+			+			if (clig_feature.contextual.has_ligatures ()) {+				clig_feature_lookup.add_feature_lookup (Lookups.CHAINED_CONTEXT);+			}+				+			if (clig_feature.has_regular_ligatures ()) {+				clig_feature_lookup.add_feature_lookup (Lookups.LIGATURES);+			}+			+			features.add (clig_feature_lookup);+			lookups.append (clig_lookups);+		}++		FontData feature_tags = features.generate_feature_tags ();++		uint lookup_list_offset = 30 + feature_tags.length_with_padding (); 		 		fd.add_ulong (0x00010000); // table version 		fd.add_ushort (10); // offset to script list 		fd.add_ushort (30); // offset to feature list-		fd.add_ushort (clig_feature.contextual.has_ligatures () ? 46 : 44); // offset to lookup list+		fd.add_ushort ((uint16) lookup_list_offset); // offset to lookup list 		 		// script list 		fd.add_ushort (1); // number of items in script list@@ -53,40 +87,18 @@ public class GsubTable : OtfTable { 		fd.add_ushort (0); // required features (0xFFFF is none) 		fd.add_ushort (1); // number of features 		fd.add_ushort (0); // feature index-		-		// feature table-		fd.add_ushort (1); // number of features-		-		fd.add_tag ("clig"); // feature tag-		fd.add_ushort (8); // offset to feature-		// FIXME: Should it be liga and clig? -		Lookups lookups = new Lookups ();-		lookups.append (clig_feature.get_lookups ());-		-		// FIXME: refactor clig_feature -		uint16 feature_lookups = 1;-		-		if (clig_feature.contextual.has_ligatures ()) {-			feature_lookups++;-		}-		-		fd.add_ushort (0); // feature prameters (null)-		fd.add_ushort (feature_lookups); // number of lookups-		-		if (clig_feature.contextual.has_ligatures ()) {-			// The chained context tables are listed here but the actual-			// ligature table is only referenced in the context table-			fd.add_ushort (lookups.find (Lookups.CHAINED_CONTEXT));-			fd.add_ushort (lookups.find (Lookups.LIGATURES)); -		} else {-			fd.add_ushort (lookups.find (Lookups.LIGATURES)); // lookup clig_subtable+		// feature lookups with references to the lookup list+		fd.append (feature_tags);++		if (lookup_list_offset != fd.length_with_padding ()) {+			warning (@"Bad offset to lookup list: $(lookup_list_offset) != $(fd.length_with_padding ())"); 		}-		+ 		// lookup list-		fd.append (lookups.genrate_lookup_list ());-		-		// subtables+		fd.append (lookups.generate_lookup_list ());	++		// subtable data 		foreach (Lookup lookup in lookups.tables) { 			foreach (FontData subtable in lookup.subtables) { 				fd.append (subtable);@@ -100,4 +112,3 @@ public class GsubTable : OtfTable { }  }-diff --git a/libbirdfont/OpenFontFormat/HheaTable.vala b/libbirdfont/OpenFontFormat/HheaTable.valaindex 23b3e14..e929db1 100644--- a/libbirdfont/OpenFontFormat/HheaTable.vala+++ b/libbirdfont/OpenFontFormat/HheaTable.vala@@ -86,7 +86,7 @@ public class HheaTable : OtfTable { 		int16 ascender, descender; 		FontData fd = new FontData (); 		Fixed version = 1 << 16;-		Font font = BirdFont.get_current_font ();+		Font font = OpenFontFormatWriter.get_current_font (); 		 		fd.add_fixed (version); // table version 		diff --git a/libbirdfont/OpenFontFormat/LigatureCollection.vala b/libbirdfont/OpenFontFormat/LigatureCollection.valaindex c923235..a5f2556 100644--- a/libbirdfont/OpenFontFormat/LigatureCollection.vala+++ b/libbirdfont/OpenFontFormat/LigatureCollection.vala@@ -11,7 +11,6 @@     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU      Lesser General Public License for more details. */-using Math;  namespace BirdFont { diff --git a/libbirdfont/OpenFontFormat/Lookup.vala b/libbirdfont/OpenFontFormat/Lookup.valaindex 39bb0e9..978931b 100644--- a/libbirdfont/OpenFontFormat/Lookup.vala+++ b/libbirdfont/OpenFontFormat/Lookup.vala@@ -33,6 +33,10 @@ public class Lookup : GLib.Object { 	} 	 	public uint get_lookup_entry_size () throws GLib.Error {+		if (subtables.size == 0) {+			warning ("No subtables.");+		}+		 		return 6 + 2 * subtables.size; 	} 	diff --git a/libbirdfont/OpenFontFormat/Lookups.vala b/libbirdfont/OpenFontFormat/Lookups.valaindex 0168e44..2b6c827 100644--- a/libbirdfont/OpenFontFormat/Lookups.vala+++ b/libbirdfont/OpenFontFormat/Lookups.vala@@ -23,8 +23,9 @@ public class Lookups : GLib.Object {  	public static const int NONE = 0; 	public static const int CHAINED_CONTEXT = 1;-	public static const int LIGATURES = 1;-+	public static const int LIGATURES = 2;+	public static const int ALTERNATES = 2;+	 	public Lookups () {	 	} 	@@ -57,7 +58,7 @@ public class Lookups : GLib.Object { 		} 	} 	-	public FontData genrate_lookup_list () throws GLib.Error {+	public FontData generate_lookup_list () throws GLib.Error { 		FontData fd = new FontData (); 		uint lookup_offset; 		uint tables_size;diff --git a/libbirdfont/OpenFontFormat/NameTable.vala b/libbirdfont/OpenFontFormat/NameTable.valaindex 57e6d2d..6c4c438 100644--- a/libbirdfont/OpenFontFormat/NameTable.vala+++ b/libbirdfont/OpenFontFormat/NameTable.vala@@ -149,7 +149,9 @@ public class NameTable : OtfTable { 		return name_validation (s, true); 	} 		-	public string name_validation (string s, bool allow_space) {+	public static string name_validation (string s, bool allow_space,+		int max_length = 27) {+			 		string n; 		int ccount; 		unichar c;@@ -158,7 +160,7 @@ public class NameTable : OtfTable { 		n = s; 		ccount = n.char_count (); 		// truncate strings longer than 28 characters-		for (int i = 0; i < ccount && i < 27; i++) {+		for (int i = 0; i < ccount && i < max_length; i++) { 			c = n.get_char (n.index_of_nth_char (i)); 			 			if (allow_space && c == ' ') {@@ -173,7 +175,7 @@ public class NameTable : OtfTable { 		return name.str;	 	}		 	-	bool is_valid_ps_name_char (unichar c) {+	static bool is_valid_ps_name_char (unichar c) { 		switch (c) { 			case '[': 				return false;diff --git a/libbirdfont/OpenFontFormat/PostTable.vala b/libbirdfont/OpenFontFormat/PostTable.valaindex aa08dce..f0f2bdd 100644--- a/libbirdfont/OpenFontFormat/PostTable.vala+++ b/libbirdfont/OpenFontFormat/PostTable.vala@@ -20,125 +20,11 @@ public class PostTable : OtfTable { 	 	Gee.ArrayList<uint16> index = new Gee.ArrayList<uint16> (); 	Gee.ArrayList<string> names = new Gee.ArrayList<string> ();--	Gee.ArrayList<string> available_names = new Gee.ArrayList<string> (); 	 	public PostTable (GlyfTable g) { 		id = "post"; 		glyf_table = g; 	}-		-	public int get_gid (string name) { // FIXME: do fast lookup-		int i = 0;-		int j = 0;-		foreach (string n in names) {-			if (n == name) {				-				j = 0;-				foreach (uint16 k in index) {-					if (k == i) {-						return j;-					}-					j++;-				}-								-				return i;-			}-			i++;-		}-		return -1;-	}--	public string get_name (int gid) {-		int k;-		-		if (!(0 <= gid < index.size)) {-			warning ("gid is out of range.");-			return "";-		}-				-		k = index.get (gid);-		-		if (gid != 0 && k == 0) {-			warning (@"Glyph $gid is assigned to name .notdef, only gid 0 can be .notdef character.");-			return "";-		}-		-		if (!(0 <= k < names.size)) {-			warning ("k is out of range.");-			return "";-		}-				-		return names.get (k);-	}-	-	public override void parse (FontData dis) throws Error {-		dis.seek (offset);-		-		Fixed format = dis.read_fixed ();-		Fixed italic = dis.read_fixed ();-		-		int16 underlie_pos = dis.read_short ();-		int16 underlie_thickness = dis.read_short ();-		uint32 is_fixed_pitch  = dis.read_ulong ();-		-		uint32 mem_min42  = dis.read_ulong ();-		uint32 mem_max42  = dis.read_ulong ();-		uint32 mem_min1  = dis.read_ulong ();-		uint32 mem_max1  = dis.read_ulong ();-		-		uint16 nnames  = dis.read_ushort ();-		-		if (format != 0x00020000) {-			warning ("Only post tables of version 2 will be parsed found version $(format.get_string ())");-			return;-		}-		-		printd (@"format: $(format.get_string ())\n");-		printd (@"italic: $(italic.get_string ())\n");-		printd (@"underlie_pos: $(underlie_pos)\n");-		printd (@"underlie_thickness: $(underlie_thickness)\n");-		printd (@"is_fixed_pitch: $(is_fixed_pitch)\n");-		printd (@"mem_min42: $(mem_min42)\n");-		printd (@"mem_max42: $(mem_max42)\n");-		printd (@"mem_min1: $(mem_min1)\n");-		printd (@"mem_max1: $(mem_max1)\n");-		printd (@"\n");-		-		printd (@"Num names: $(nnames)\n");-		-		uint16 k;-		int non_standard_names = 0;-		for (uint16 i = 0; i < nnames; i++) {-			k = dis.read_ushort ();-			index.add (k);-			-			if (k >= 258) {-				non_standard_names++;-			}-		}-		-		add_standard_names ();-		-		// read non standard names-		for (int i = 0; i < non_standard_names; i++) {-			uint8 len = dis.read_byte ();-			StringBuilder name = new StringBuilder ();-			-			for (int j = 0; j < len; j++) {-				name.append_c (dis.read_char ());-			}--			names.add (name.str);-		}--		populate_available ();-	}--	void populate_available () {-		for (int i = 0; i < index.size; i++) {-			available_names.add (get_name (i));-		}-	} 	 	// the Macintosh standard order 	private void add_standard_names () {@@ -1188,7 +1074,8 @@ public class PostTable : OtfTable { 		int name_index; 		GlyphCollection gc; 		Glyph g;-				+		string ps_name;+			 		fd.add_fixed (0x00020000); // Version 		fd.add_fixed (0x00000000); // italicAngle 		@@ -1214,19 +1101,23 @@ public class PostTable : OtfTable { 		assert (names.size == 0); 		add_standard_names (); +		print ("Adding post names\n");+ 		for (int i = 1; i < glyf_table.glyphs.size; i++) { 			gc = glyf_table.glyphs.get (i); 			g = gc.get_current (); 			name_index = get_standard_index (g.unichar_code); 			-			if (name_index != 0) {+			if (name_index != 0 && !gc.is_unassigned ()) { 				fd.add_ushort ((uint16) name_index);  // use standard name 			} else {-				printd (@"Adding non standard postscript name $(g.get_name ())\n");+				printd (@"Adding non standard postscript name $(gc.get_name ())\n"); 				 				name_index = (int) names.size; // use font specific name 				fd.add_ushort ((uint16) name_index);-				names.add (g.get_name ());+				+				ps_name = create_ps_name (g.get_name ());+				names.add (ps_name); 			} 			 			this.index.add ((uint16) name_index);@@ -1237,6 +1128,7 @@ public class PostTable : OtfTable { 			 			if (n.length > 0xFF) { 				warning (@"too long name for glyph $n");+				continue; 			} 			 			fd.add ((uint8) n.length);@@ -1248,6 +1140,33 @@ public class PostTable : OtfTable { 		this.font_data = fd; 	} +	string create_ps_name (string name) {+		string valid_name = NameTable.name_validation (name, false, 0xFF);+		+		if (valid_name.char_count () == 1) {+			warning (@"Too short name: $valid_name generated from $name");+			valid_name = add_suffix (valid_name);+		}+		+		if (names.index_of (valid_name) > -1) {+			valid_name = add_suffix (valid_name);+		} +		+		return valid_name;+	}+	+	string add_suffix (string valid_name) {+		int i = 2;+		string s;+		+		s = valid_name + @"_$i";+		while (names.index_of (s) > -1) {+			i++;+			s = valid_name + @"_$i";+		}+		+		return s;+	} }  }diff --git a/libbirdfont/OverView.vala b/libbirdfont/OverView.valaindex 4946803..1c58ea3 100644--- a/libbirdfont/OverView.vala+++ b/libbirdfont/OverView.vala@@ -20,7 +20,7 @@ namespace BirdFont { public class OverView : FontDisplay { 	public WidgetAllocation allocation = new WidgetAllocation (); 	-	OverViewItem selected_item = new OverViewItem (null, '\0', 0, 0);+	public OverViewItem selected_item = new OverViewItem (null, '\0', 0, 0);  	public Gee.ArrayList<GlyphCollection> copied_glyphs = new Gee.ArrayList<GlyphCollection> (); 	public Gee.ArrayList<GlyphCollection> selected_items = new Gee.ArrayList<GlyphCollection> ();	@@ -1347,7 +1347,7 @@ public class OverView : FontDisplay { 		 		if (((!)character_info).is_ligature ()) { 			name = ((!)character_info).get_name ();-			draw_info_line (t_("Ligature") + ": " + name, cr, x, y, 0);+			draw_info_line (name, cr, x, y, 0); 		} else { 			i = 0; 			foreach (string line in lines) {diff --git a/libbirdfont/OverviewTools.vala b/libbirdfont/OverviewTools.valaindex 6fa16b8..9b3bf6f 100644--- a/libbirdfont/OverviewTools.vala+++ b/libbirdfont/OverviewTools.vala@@ -32,11 +32,14 @@ public class OverviewTools : ToolCollection  { 	public static SpinButton skew; 	public static SpinButton resize; 	+	private string alternate_name = "";+	 	public OverviewTools () { 		Expander font_name = new Expander (); 		Expander character_sets = new Expander (t_("Character Sets")); 		Expander zoom_expander = new Expander (t_("Zoom")); 		Expander transform_expander = new Expander (t_("Transform"));+		Expander glyph_expander = new Expander (t_("Glyph")); 		 		expanders = new Gee.ArrayList<Expander> (); 		custom_character_sets = new Gee.ArrayList<LabelTool> ();@@ -127,10 +130,59 @@ public class OverviewTools : ToolCollection  { 		transform.set_persistent (false); 		transform_expander.add_tool (transform); 		+		Tool alternate = new Tool ("alternate", t_("Create alternate"));+		alternate.select_action.connect (add_new_alternate);+		glyph_expander.add_tool (alternate);+		 		expanders.add (font_name); 		expanders.add (zoom_expander); 		expanders.add (character_sets); 		expanders.add (transform_expander);+		expanders.add (glyph_expander);+	}+	+	public void add_new_alternate (Tool tool) {+		TextListener listener;+		OverView o = MainWindow.get_overview ();+		OverViewItem oi = o.selected_item;+		GlyphCollection gc;+		+		if (oi.glyphs == null) {+			return;+		}+		+		gc = (!) oi.glyphs;+		+		listener = new TextListener (t_("Alternate"), "", t_("Add"));+		+		listener.signal_text_input.connect ((text) => {+			alternate_name = text;+		});+		+		listener.signal_submit.connect (() => {+			GlyphCollection alt;+			Font font;+			OverView overview = MainWindow.get_overview ();+			+			font = BirdFont.get_current_font ();+			+			if (alternate_name == "") {+				return;+			}+			+			if (font.glyph_name.has_key (alternate_name)) {+				MainWindow.show_message (t_("All glyphs must have unique names."));+			} else {+				alt = new GlyphCollection.with_glyph ('\0', alternate_name);+				alt.set_unassigned (true);+				font.add_new_alternate (gc, alt);+				MainWindow.get_overview ().update_item_list ();+				overview.open_glyph_signal (alt);+			}+		});+		+		tool.set_selected (false);+		TabContent.show_text_input (listener); 	} 	 	public void process_transform () {diff --git a/libbirdfont/StrokeTool.vala b/libbirdfont/StrokeTool.valaindex 8c276fc..b46ca1f 100644--- a/libbirdfont/StrokeTool.vala+++ b/libbirdfont/StrokeTool.vala@@ -124,6 +124,7 @@ public class StrokeTool : Tool { 				 		foreach (Path p in g.active_paths) { 			p.close ();+			p.remove_points_on_points (); 			o.add (p); 		} 		diff --git a/resources/icons.bf b/resources/icons.bfindex 52ea63c..fab581f 100644--- a/resources/icons.bf+++ b/resources/icons.bf@@ -1,6 +1,6 @@ <?xml version="1.0" encoding="utf-8" standalone="yes"?> <font>-<format>2.0</format>+<format>2.1</format>  <postscript_name>BirdfontIcons</postscript_name> <name>Birdfont Icons</name>@@ -13,8 +13,15 @@ <description>An icon font for the font editor Birdfont.</description> <copyright>Copyright 2015 GNU Lesser General Public License</copyright>+<license></license>+<license_url></license_url> <weight>400</weight> <units_per_em>1024</units_per_em>+<trademark></trademark>+<manufacturer></manufacturer>+<designer></designer>+<vendor_url></vendor_url>+<designer_url></designer_url>  <horizontal> 	<top_limit>84.0000000000</top_limit>@@ -292,6 +299,21 @@ GNU Lesser General Public License</copyright> 		</layer> 	</glyph> </collection>+<collection name="alternate">+	<selected id="0"/>+	<glyph id="0" left="-28" right="28">+		<layer name= "Layer" visible="true">+			<path data="B 3.6759014745,40.7567512767 C 3.6759014745,40.7567512767 3.6759014745,40.7567512767 3.6759014745,40.7567512767 C 3.6759014745,40.7567512767 3.2688257643,40.8457013235 3.0652879094,40.8901763469 C 2.8617500543,40.9346513703 2.6582121992,40.9791263937 2.4546743442,41.0236014172 C 1.5642251139,41.2181733328 0.6737758836,41.4127452485 -0.2166733467,41.6073171642 C -0.0994455563,42.1438046394 0.0177822341,42.6802921146 0.1350100246,43.2167795898 C 1.0254592549,43.0222076741 1.9159084853,42.8276357584 2.8063577155,42.6330638427 C 3.4169712807,42.4996387725 4.0275848458,42.3662137022 4.6381984109,42.2327886320 C 5.4654639795,42.0520229679 6.2927295481,41.8712573040 7.1199951168,41.6904916405 C 7.1582621678,41.4790581417 7.1965292188,41.2676246430 7.2347962697,41.0561911442 C 4.6535421192,39.3891160541 2.0722879687,37.7220409638 -0.5089661818,36.0549658736 C -2.0599617587,35.0532721462 -3.6109573357,34.0515784188 -5.1619529127,33.0498846913 C -6.3196453115,32.3022015700 -7.4773377103,31.5545184487 -8.6350301092,30.8068353274 C -8.9329576056,31.2681382352 -9.2308851020,31.7294411430 -9.5288125985,32.1907440508 C -8.3711201996,32.9384271721 -7.2134278008,33.6861102935 -6.0557354020,34.4337934149 C -4.5047398250,35.4354871422 -2.9537442480,36.4371808696 -1.4027486711,37.4388745971 C -0.3687516197,38.1066704153 0.6652454316,38.7744662336 1.6992424829,39.4422620519 C 3.3981499084,40.5394830478 2.7542954653,40.0795161653 3.6759014745,40.7567512767" />+			<path data="B 3.2646352148,35.0697188780 C 3.4529797567,35.5741584754 3.6413242987,36.0785980728 3.8296688407,36.5830376702 C 4.0819997291,37.2588506799 4.3343306176,37.9346636897 4.5866615060,38.6104766994 C 4.9546321149,39.5960053688 5.3226027239,40.5815340382 5.6905733328,41.5670627076 C 6.2050291379,41.3749783758 6.7194849431,41.1828940441 7.2339407481,40.9908097123 C 6.8659701392,40.0052810430 6.4979995302,39.0197523735 6.1300289212,38.0342237042 C 5.8776980328,37.3584106944 5.6253671444,36.6825976847 5.3730362559,36.0067846750 C 5.1846917140,35.5023450776 4.9963471720,34.9979054802 4.8080026300,34.4934658828 M 3.2646352148,35.0697188780" />+			<path data="B 2.2039994470,16.7446012982 C 1.1700023957,17.4123971165 0.1360053444,18.0801929348 -0.8979917070,18.7479887530 C -2.4489872839,19.7496824805 -3.9999828608,20.7513762078 -5.5509784378,21.7530699352 C -6.7086708366,22.5007530566 -7.8663632355,23.2484361780 -9.0240556343,23.9961192993 C -8.7261281379,24.4574222071 -8.4282006415,24.9187251149 -8.1302731450,25.3800280227 C -6.9725807462,24.6323449014 -5.8148883474,23.8846617800 -4.6571959485,23.1369786587 C -3.1062003716,22.1352849313 -1.5552047946,21.1335912039 -0.0042092177,20.1318974764 C 2.5770449328,18.4648223862 5.1582990833,16.7977472960 7.7395532338,15.1306722059 C 7.7012861829,14.9192387071 7.6630191319,14.7078052084 7.6247520809,14.4963717096 C 6.7974865122,14.3156060461 5.9702209436,14.1348403822 5.1429553751,13.9540747181 C 4.5323418099,13.8206496478 3.9217282448,13.6872245776 3.3111146797,13.5537995074 C 2.4206654494,13.3592275916 1.5302162190,13.1646556760 0.6397669887,12.9700837603 C 0.5225391983,13.5065712355 0.4053114078,14.0430587107 0.2880836174,14.5795461859 C 1.1785328477,14.7741181016 2.0689820780,14.9686900172 2.9594313083,15.1632619329 C 3.1629691634,15.2077369563 3.3665070184,15.2522119798 3.5700448735,15.2966870031 C 3.7735827285,15.3411620266 4.1806584386,15.4301120734 4.1806584386,15.4301120734 C 4.1806584386,15.4301120734 4.1806584386,15.4301120734 4.1806584386,15.4301120734 C 3.2590524294,16.1073471848 3.9029068725,15.6473803023 2.2039994470,16.7446012982" />+			<path data="B 5.3127595942,21.6933974673 C 5.5011041361,21.1889578699 5.6894486781,20.6845182725 5.8777932201,20.1800786751 C 6.1301241085,19.5042656654 6.3824549969,18.8284526557 6.6347858854,18.1526396459 C 7.0027564944,17.1671109765 7.3707271033,16.1815823071 7.7386977122,15.1960536378 C 7.2242419072,15.0039693059 6.7097861021,14.8118849742 6.1953302969,14.6198006425 C 5.8273596881,15.6053293119 5.4593890791,16.5908579813 5.0914184701,17.5763866507 C 4.8390875817,18.2521996604 4.5867566933,18.9280126702 4.3344258048,19.6038256798 C 4.1460812628,20.1082652772 3.9577367209,20.6127048746 3.7693921789,21.1171444720 M 5.3127595942,21.6933974673" />+			<path data="S 27.5084977672,39.1601233077 L 9.3282139024,39.1601233077 L 18.4183558348,54.3103598617 L 27.5084977672,39.1601233077" />+			<path data="S 12.6997545643,14.7606495448 L 26.0573543453,14.7606495448 L 26.0573543453,1.4030497638 L 12.6997545643,1.4030497638 L 12.6997545643,14.7606495448" />+			<path data="B -14.3764353493,31.3046892257 C -14.1272616411,31.0346434605 -14.3764353493,31.3046892257 -14.3764353493,31.3046892257 C -14.1272616411,31.0346434605 -14.0672089911,30.9837086223 -13.8623329216,30.7178020715 C -13.6065849730,30.3858694303 -13.3977455777,30.0306253113 -13.2027179830,29.6608065126 C -13.0834737539,29.4072882220 -13.0542515682,29.3558890569 -12.9517101422,29.0949722124 C -12.8473697454,28.8294778835 -12.7666783102,28.5595814714 -12.6911935158,28.2848694529 C -12.6139755421,27.9494662774 -12.5427105763,27.6104930915 -12.5213814882,27.2659421275 C -12.5110855591,27.0996212675 -12.5075550732,26.9329505830 -12.5006429073,26.7664547674 C -12.4741698843,26.1287895730 -12.6196005716,25.4801529704 -12.7976349746,24.8731900560 C -12.8925515717,24.5941502305 -12.9922946818,24.3201193128 -13.1161646890,24.0522817354 C -13.2260276858,23.8147307772 -13.2586845368,23.7634915666 -13.3835241233,23.5338107416 C -13.5142093436,23.3170031222 -13.5495490952,23.2498149588 -13.6951323087,23.0425093010 C -13.9014177387,22.7487657045 -14.1322563101,22.4723797944 -14.3861690503,22.2184713483 C -14.3861690503,22.2184713483 -14.3861690503,22.2184713483 -14.3861690503,22.2184713483 C -14.6586427044,21.9668135753 -14.7094597969,21.9065576513 -14.9770103728,21.7004148908 C -15.3089430141,21.4446669422 -15.6641871329,21.2358275469 -16.0340059317,21.0407999522 C -16.2875242223,20.9215557231 -16.3389233873,20.8923335374 -16.5998402319,20.7897921114 C -16.8653345608,20.6854517145 -17.1352309730,20.6047602794 -17.4099429913,20.5292754850 C -17.6420181068,20.4758461454 -17.6937924431,20.4601222088 -17.9284189764,20.4212356465 C -18.2661838671,20.3652551259 -18.6078402959,20.3387210585 -18.9503607179,20.3387251387 C -19.2383021519,20.3488920775 -19.5195034719,20.3606717249 -19.8046594476,20.4020676429 C -20.1511584759,20.4523686941 -20.4861238421,20.5373084875 -20.8216223882,20.6357169438 C -21.1006622137,20.7306335409 -21.3746931316,20.8303766510 -21.6425307088,20.9542466582 C -21.8800816670,21.0641096550 -21.9313208776,21.0967665060 -22.1610017027,21.2216060925 C -22.8657201499,21.6463895285 -23.4900758435,22.1605383637 -23.9943975534,22.8150923420 C -24.2501455021,23.1470249833 -24.4589848974,23.5022691021 -24.6540124921,23.8720879009 C -24.7732567212,24.1256061915 -24.8024789068,24.1770053565 -24.9050203329,24.4379222011 C -25.0093607298,24.7034165300 -25.0900521649,24.9733129422 -25.1655369593,25.2480249606 C -25.2427549329,25.5834281361 -25.3140198987,25.9224013221 -25.3353489869,26.2669522861 C -25.3456449160,26.4332731461 -25.3491754019,26.5999438306 -25.3560875677,26.7664396462 C -25.3825605908,27.4041048406 -25.2371299035,28.0527414431 -25.0590955006,28.6597043575 C -24.9641789034,28.9387441830 -24.8644357933,29.2127751008 -24.7405657860,29.4806126780 C -24.6307027893,29.7181636362 -24.5980459383,29.7694028468 -24.4732063518,29.9990836719 C -24.0484229157,30.7038021191 -23.5342740805,31.3281578127 -22.8797201023,31.8324795226 C -22.5477874611,32.0882274713 -22.1925433421,32.2970668666 -21.8227245434,32.4920944612 C -21.5692062528,32.6113386904 -21.5178070877,32.6405608760 -21.2568902432,32.7431023021 C -20.9913959142,32.8474426990 -20.7214995021,32.9281341340 -20.4467874838,33.0036189285 C -19.9444942582,33.1192590532 -19.4456317544,33.1941456522 -18.9281289485,33.1941695482 C -19.0615567624,33.1941616876 -18.7817245277,33.1941803462 -18.5290552687,33.1808466582 C -18.4492515689,33.1766353124 -18.3696554484,33.1688284483 -18.2901765298,33.1604937357 C -17.8615408487,33.1155440146 -17.4478902965,33.0182547753 -17.0351080868,32.8971774698 C -16.7560682612,32.8022608725 -16.4820373435,32.7025177625 -16.2141997662,32.5786477552 C -15.9766488081,32.4687847585 -15.9254095974,32.4361279075 -15.6957287724,32.3112883210 C -15.4789211530,32.1806031007 -15.4117329896,32.1452633491 -15.2044273318,31.9996801355 C -14.9090523118,31.7922490161 -14.6317498598,31.5600107261 -14.3764353493,31.3046892257" />+			<path data="B -18.9259276385,24.0104388377 C -18.8046174118,24.0135980089 -18.9259276385,24.0104388377 -18.9259276385,24.0104388377 C -18.8046174118,24.0135980089 -18.7895247346,24.0113370207 -18.6803238825,24.0224357941 C -18.5727282364,24.0333714204 -18.4676550533,24.0533874806 -18.3619012191,24.0754366886 C -18.2374201695,24.1070775771 -18.1152043773,24.1413046993 -17.9946933055,24.1862415298 C -17.8710993530,24.2323279219 -17.8450635053,24.2462044492 -17.7257894863,24.2995346995 C -17.5673564620,24.3789047134 -17.4140554414,24.4631561222 -17.2705058271,24.5677067054 C -17.1433733797,24.6603002773 -17.1298221759,24.6809132511 -16.9916660133,24.8055623986 C -16.8993966054,24.8978293907 -16.8140898319,24.9942820306 -16.7366029173,25.0994342600 C -16.6725650915,25.1863356443 -16.6568424804,25.2149165372 -16.5988440467,25.3067183927 C -16.5401191335,25.4099037221 -16.5247307878,25.4329811180 -16.4725372872,25.5409881308 C -16.4117993993,25.6666765357 -16.3622217592,25.7955026614 -16.3149699723,25.9266786714 C -16.2508930951,26.1311950863 -16.1938361129,26.3419004728 -16.1807670823,26.5570108897 C -16.1646931863,26.8215800497 -16.1832607650,27.0734623105 -16.2373547194,27.3329112251 C -16.2689956079,27.4573922748 -16.3032227301,27.5796080669 -16.3481595606,27.7001191387 C -16.3942459527,27.8237130913 -16.4081224800,27.8497489390 -16.4614527303,27.9690229580 C -16.5408227442,28.1274559822 -16.6250741530,28.2807570028 -16.7296247362,28.4243066171 C -16.8206048871,28.5492238119 -16.8410048697,28.5630887605 -16.9621223719,28.6977882466 C -16.9621223719,28.6977882466 -16.9621223719,28.6977882466 -16.9621223719,28.6977882466 C -17.0561984914,28.7918667568 -17.1541146194,28.8791858454 -17.2613522908,28.9582095270 C -17.3482536751,29.0222473528 -17.3768345680,29.0379699639 -17.4686364235,29.0959683975 C -17.5718217529,29.1546933109 -17.5948991488,29.1700816565 -17.7029061616,29.2222751571 C -17.8285945666,29.2830130450 -17.9574206922,29.3325906850 -18.0885967022,29.3798424720 C -18.2642832198,29.4348866767 -18.4402738831,29.4809525247 -18.6233123712,29.5039237226 C -18.7457715276,29.5192922582 -18.7648818498,29.5160165691 -18.9149831952,29.5224553501 C -18.9149831952,29.5224553501 -18.9149831952,29.5224553501 -18.9149831952,29.5224553501 C -19.0364241594,29.5224569827 -19.1567059786,29.5155674129 -19.2768909645,29.4981929740 C -19.3751994278,29.4839810957 -19.3974435550,29.4777622140 -19.4948292559,29.4574577249 C -19.6193103056,29.4258168363 -19.7415260977,29.3915897142 -19.8620371695,29.3466528836 C -19.9856311220,29.3005664916 -20.0116669698,29.2866899642 -20.1309409888,29.2333597139 C -20.2893740130,29.1539897001 -20.4426750336,29.0697382912 -20.5862246479,28.9651877080 C -20.7152618546,28.8712068550 -20.7286255721,28.8503308051 -20.8697642344,28.7226323597 C -20.8697642344,28.7226323597 -20.8697642344,28.7226323597 -20.8697642344,28.7226323597 C -20.9604360648,28.6319629710 -21.0439963691,28.5367726193 -21.1201275578,28.4334601534 C -21.1841653836,28.3465587692 -21.1998879947,28.3179778764 -21.2578864283,28.2261760208 C -21.3166113416,28.1229906914 -21.3319996874,28.0999132956 -21.3841931879,27.9919062827 C -21.4449310758,27.8662178777 -21.4945087158,27.7373917520 -21.5417605028,27.6062157420 C -21.6058373799,27.4016993272 -21.6628943621,27.1909939407 -21.6759633928,26.9758835238 C -21.6920372888,26.7113143638 -21.6734697101,26.4594321030 -21.6193757557,26.1999831883 C -21.5877348671,26.0755021387 -21.5535077450,25.9532863465 -21.5085709144,25.8327752747 C -21.4624845224,25.7091813222 -21.4486079950,25.6831454745 -21.3952777447,25.5638714555 C -21.2974394117,25.3685732284 -21.1912709053,25.1727778876 -21.0482280606,25.0059528978 C -20.9940830337,24.9428057785 -20.9364735939,24.8827136604 -20.8805963606,24.8210940417 C -20.8805963606,24.8210940417 -20.8805963606,24.8210940417 -20.8805963606,24.8210940417 C -20.7912819596,24.7317780594 -20.6971317251,24.6496672998 -20.5953781843,24.5746848865 C -20.5084768000,24.5106470607 -20.4798959072,24.4949244496 -20.3880940516,24.4369260159 C -20.2849087222,24.3782011027 -20.2618313263,24.3628127570 -20.1538243135,24.3106192564 C -20.0281359085,24.2498813685 -19.8993097828,24.2003037284 -19.7681337728,24.1530519415 C -19.6626218253,24.1199940762 -19.6417579038,24.1116518118 -19.5366087518,24.0855193231 C -19.3366033702,24.0358124232 -19.1321438606,24.0104426854 -18.9259276385,24.0104388377" />+		</layer>+	</glyph>+</collection> <collection name="apply_stroke"> 	<selected id="1"/> 	<glyph id="1" left="-26.53515625" right="29.796903565002076">@@ -1605,6 +1627,7 @@ GNU Lesser General Public License</copyright> <ligature sequence="i n f o _ i c o n" replacement="info_icon"/> <ligature sequence="s a v e _ f o n t" replacement="save_font"/> <ligature sequence="l o c k _ g r i d" replacement="lock_grid"/>+<ligature sequence="a l t e r n a t e" replacement="alternate"/> <ligature sequence="n e w _ f o n t" replacement="new_font"/> <ligature sequence="p r o g r e s s" replacement="progress"/> <ligature sequence="z o o m _ 1 _ 1" replacement="zoom_1_1"/>

Contact

Email: johan.mattsson.m@gmail.com
Mastodon: typo.social/@birdfont
GitHub: johanmattssonm
LinkedIn: johan-mattsson-2ab324112