Clone in a terminal:
Commit bf23771
Johan Mattsson - 2013-08-20T19:57:34+00:00
bf237715dd562ef160393c24041bdba968c5201bjohan.mattsson.m@gmail.com

store kerning in hash table (using libgee)

Changed files (12)

Diff

diff --git a/README b/READMEindex 6d65d7f..4bf2e76 100644--- a/README+++ b/README@@ -18,6 +18,7 @@ with a -dev or -devel affix. 
 Install the following packages:
 valac
+libgee-dev
 libglib2.0-dev 
 libgtk2.0-dev 
 libxml2-dev 
diff --git a/dodo.py b/dodo.pyindex e8d4aae..d20e4ed 100644--- a/dodo.py+++ b/dodo.py@@ -45,6 +45,7 @@ LIBS = [     'cairo',     'gdk-pixbuf-2.0',     'webkit-1.0',+    'gee-1.0'     ]  def task_build ():diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex 9021356..7279cff 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -65,6 +65,8 @@ class BirdFontFile { 		Xml.Doc* doc; 		Xml.Node* root; 		+		print (xml_data);+		 		Parser.init (); 		 		font.font_file = "typeface.bf"; // FIXME@@ -89,6 +91,7 @@ class BirdFontFile { 	public bool write_font_file (string path, bool backup = false) { 		try { 			File file = File.new_for_path (path);+			uint num_kerning_pairs; 			 			if (file.query_file_type (0) == FileType.DIRECTORY) { 				stderr.printf (@"Can not save font. $path is a directory.");@@ -199,15 +202,15 @@ class BirdFontFile { 				} 			}); 			-			uint num_kerning_pairs = KerningClasses.get_instance ().classes_first.length ();+			num_kerning_pairs = KerningClasses.get_instance ().classes_first.length (); 			for (uint i = 0; i < num_kerning_pairs; i++) { 				os.put_string ("<kerning "); 				os.put_string ("left=\"");-				os.put_string (KerningClasses.get_instance ().classes_first.nth (i).data.get_all_ranges ());+				os.put_string (KerningClasses.get_instance ().classes_first.nth (i).data.get_all_ranges ().replace ("\"", "quote")); 				os.put_string ("\" "); 				 				os.put_string ("right=\"");-				os.put_string (KerningClasses.get_instance ().classes_last.nth (i).data.get_all_ranges ());+				os.put_string (KerningClasses.get_instance ().classes_last.nth (i).data.get_all_ranges ().replace ("\"", "quote")); 				os.put_string ("\" "); 				 				os.put_string ("hadjustment=\"");@@ -498,11 +501,25 @@ class BirdFontFile { 		} 	} +	private string unserialize (string s) {+		StringBuilder b;+		string r;+		r = s.replace ("quote", "\"");+		+		if (s.has_prefix ("U+")) {+			b = new StringBuilder ();+			b.append_unichar (Font.to_unichar (s));+			r = @"$(b.str)";+		}+		+		return r;+	}+	 	private void parse_kerning (Xml.Node* node) { 		string attr_name; 		string attr_content; 		GlyphRange range_left, range_right;-		double hadjusment = 0;+		double hadjustment = 0; 		KerningRange kerning_range; 		 		try {@@ -514,16 +531,22 @@ class BirdFontFile { 				attr_content = prop->children->content; 				 				if (attr_name == "left") {-					range_left.parse_ranges (attr_content);+					range_left.parse_ranges (unserialize (attr_content)); 				}  				if (attr_name == "right") {-					range_right.parse_ranges (attr_content);+					range_right.parse_ranges (unserialize (attr_content)); 				}  				if (attr_name == "hadjustment") {-					hadjusment = double.parse (attr_content);+					hadjustment = double.parse (attr_content);+					print (@"$hadjustment"); 				}+				+				print (attr_name);+				print (" ");+				print (attr_content);+				print ("\n"); 			} 			 			if (range_left.get_length () > 1) {@@ -538,7 +561,8 @@ class BirdFontFile { 				KerningTools.add_unique_class (kerning_range); 			} -			KerningClasses.get_instance ().set_kerning (range_left, range_right, hadjusment);+			print (@"kern: $(range_left.get_all_ranges ())   $(range_right.get_all_ranges ()),    $hadjustment\n");+			KerningClasses.get_instance ().set_kerning (range_left, range_right, hadjustment); 			 		} catch (MarkupError e) { 			warning (e.message);diff --git a/libbirdfont/DrawingTools.vala b/libbirdfont/DrawingTools.valaindex fbe7076..3b6914b 100644--- a/libbirdfont/DrawingTools.vala+++ b/libbirdfont/DrawingTools.vala@@ -198,33 +198,6 @@ public class DrawingTools : ToolCollection  { 		}); 		path_tool_modifiers.add_tool (flip_horizontal); 		-		// adjust precision-		string precision_value = Preferences.get ("precision");-		-		precision = new SpinButton ("precision", _("Set precision"));-		-		if (precision_value != "") {-			precision.set_value (precision_value);-		} else {-			precision.set_value_round (1);-		}-		-		precision.new_value_action.connect ((self) => {-			MainWindow.get_toolbox ().select_tool (precision);-			-			Preferences.set ("precision", self.get_display_value ());-			MainWindow.get_toolbox ().redraw ((int) precision.x, (int) precision.y, 70, 70);-		});--		precision.select_action.connect((self) => {-			pen_tool.set_precision (((SpinButton)self).get_value ());-		});-		-		precision.set_min (0.001);-		precision.set_max (1);-		-		path_tool_modifiers.add_tool (precision);-		 		// Character set tools 		Tool full_unicode = new Tool ("utf_8", _("Show full unicode characters set"), 'f', CTRL); 		full_unicode.select_action.connect ((self) => {@@ -438,7 +411,34 @@ public class DrawingTools : ToolCollection  { 		 		Tool rectangle = new RectangleTool ("rectangle"); 		shape_tools.add_tool (rectangle);-				++		// adjust precision+		string precision_value = Preferences.get ("precision");+		+		precision = new SpinButton ("precision", _("Set precision"));+		+		if (precision_value != "") {+			precision.set_value (precision_value);+		} else {+			precision.set_value_round (1);+		}+		+		precision.new_value_action.connect ((self) => {+			MainWindow.get_toolbox ().select_tool (precision);+			+			Preferences.set ("precision", self.get_display_value ());+			MainWindow.get_toolbox ().redraw ((int) precision.x, (int) precision.y, 70, 70);+		});++		precision.select_action.connect((self) => {+			pen_tool.set_precision (((SpinButton)self).get_value ());+		});+		+		precision.set_min (0.001);+		precision.set_max (1);+		+		shape_tools.add_tool (precision);+								 		// background tools 		background_scale = new SpinButton ("scale_background", _("Set size for background image")); 		background_scale.set_int_value ("1.000");@@ -648,9 +648,10 @@ public class DrawingTools : ToolCollection  { 		foreach (Tool t in draw_tools.tool) { 			t.persistent = true; 		}+		 		move_background.persistent = true; 		cut_background.persistent = true;-+		 		foreach (Tool t in shape_tools.tool) { 			t.persistent = true; 		}diff --git a/libbirdfont/GlyphRange.vala b/libbirdfont/GlyphRange.valaindex e216030..47f7a79 100644--- a/libbirdfont/GlyphRange.vala+++ b/libbirdfont/GlyphRange.vala@@ -148,18 +148,23 @@ public class GlyphRange { 	 * this string. This function is used for storing ranges in th .bf format. 	 */ 	public string get_all_ranges () {+		bool first = true; 		StringBuilder s = new StringBuilder (); 		foreach (UniRange u in ranges) { 			+			if (!first) {+				s.append (" ");+			}+			 			if (u.start == u.stop) { 				s.append (get_serialized_char (u.start));-				s.append (" "); 			} else { 				s.append (get_serialized_char (u.start)); 				s.append ("-"); 				s.append (get_serialized_char (u.stop));-				s.append (" "); 			}+			+			first = false; 		} 		return s.str; 	}@@ -174,7 +179,7 @@ public class GlyphRange { 		if (c == '-') { 			return "divis"; 		}-	+		 		s.append_unichar (c);	 		return s.str;	 	}@@ -187,7 +192,7 @@ public class GlyphRange { 		if (c == "divis") { 			return "-"; 		}-	+		 		return c; 	} 	@@ -278,9 +283,12 @@ public class GlyphRange { 		return len; 	} -	public bool has_character (string c) -		requires (c.char_count () == 1) {-		unichar s = c.get_char ();+	public bool has_character (string c) {+		unichar s;+		if (c.char_count () != 1) {+			warning (@"Expecting a single character got $c");+		}+		s = c.get_char (); 		return !unique (s, s); 	} @@ -316,20 +324,6 @@ public class GlyphRange { 		stdout.printf ("Ranges:\n"); 		stdout.printf (get_all_ranges ()); 	}-	-	// FIXME: DELETE-	/*-	public string get_all_ranges () {-		StringBuilder s = new StringBuilder ();-		foreach (UniRange u in ranges) {-			s.append (Font.to_hex_code (u.start));-			s.append (" - ");-			s.append (Font.to_hex_code (u.stop));-			s.append (" ");-		}-		return s.str;-	}-	*/ }  }diff --git a/libbirdfont/KerningClasses.vala b/libbirdfont/KerningClasses.valaindex 8361db6..01c6e6a 100644--- a/libbirdfont/KerningClasses.vala+++ b/libbirdfont/KerningClasses.vala@@ -15,106 +15,83 @@ using Cairo; using Xml; using Math;+using Gee;  namespace BirdFont {  public class KerningClasses : GLib.Object { 	 	// kerning for classes-	public List<GlyphRange> classes_first;-	public List<GlyphRange> classes_last;-	public List<Kerning> classes_kerning;+	public GLib.List<GlyphRange> classes_first;+	public GLib.List<GlyphRange> classes_last;+	public GLib.List<Kerning> classes_kerning; +	// kerning for single glyphs+	Gee.HashMap<string, double?> single_kerning;+	 	public delegate void KerningIterator (string left, string right, double kerning);  	public KerningClasses () {-		classes_first = new List<GlyphRange> ();-		classes_last = new List<GlyphRange> ();-		classes_kerning = new List<Kerning> ();+		classes_first = new GLib.List<GlyphRange> ();+		classes_last = new GLib.List<GlyphRange> ();+		classes_kerning = new GLib.List<Kerning> ();+		+		single_kerning = new HashMap<string, double?> ();+		+		KerningTools.remove_all_kerning_classes (); // TODO: move to menu tab 	} 	 	public static KerningClasses get_instance () { 		return BirdFont.get_current_font ().get_kerning_classes (); 	} 	+	public double? get_kerning_for_single_glyphs (string l, string r) {+		return single_kerning.get (@"$l$r");+	} ++	public void set_kerning_for_single_glyphs (string l, string r, double k) {+		single_kerning.set (@"$l$r", k);+	} + 	public void set_kerning (GlyphRange left_range, GlyphRange right_range, double k) {-		int index = get_kerning_item_index (left_range, right_range);+		int index;+		+		if (left_range.get_length () == 1 && right_range.get_length () == 1) {+			set_kerning_for_single_glyphs (left_range.get_all_ranges (), right_range.get_all_ranges (), k);+			return;+		}+		+		index = get_kerning_item_index (left_range, right_range); 		 		// keep the list sorted (classes first then single glyphs) 		if (index == -1) { 			classes_first.append (left_range); 			classes_last.append (right_range); 			classes_kerning.append (new Kerning (k));-			update_order (classes_first.length () - 1); 		} else { 			return_if_fail (0 <= index <= classes_first.length ()); 			classes_kerning.nth (index).data.val = k;-			update_order (index);-		}-	}-	-	void update_order (uint i) {-		unowned List<GlyphRange> l;-		unowned List<GlyphRange> r;-		unowned List<Kerning> k;-		int first;-		-		if (!(0 <= i < classes_first.length ())) {-			warning (@"Index is out of range. Index: $i  Length: $(classes_first.length ())");-			return;-		}--		l = classes_first.nth (i);-		r = classes_last.nth (i);-		k = classes_kerning.nth (i);-		first = get_first_non_class ();--		if (first < 0) {-			return;-		}-				-		if (first > classes_first.length ()) {-			warning (@"Index is out of range. Index: $first  Length: $(classes_first.length ())");-			return;-		}-		-		if (l.data.is_class () || r.data.is_class ()) {-			classes_first.insert_before (classes_first.nth (first), l.data);-			classes_last.insert_before (classes_last.nth (first), r.data);-			classes_kerning.insert_before (classes_kerning.nth (first), k.data);--			classes_first.remove_link (l);-			classes_last.remove_link (r);-			classes_kerning.remove_link (k);-		} else {-			classes_first.append (l.data);-			classes_last.append (r.data);-			classes_kerning.append (k.data);--			classes_first.remove_link (l);-			classes_last.remove_link (r);-			classes_kerning.remove_link (k); 		} 	}  	public double get_kerning_for_range (GlyphRange range_first, GlyphRange range_last) {-		unowned List<GlyphRange> r;-		unowned List<GlyphRange> l;+		unowned GLib.List<GlyphRange> r;+		unowned GLib.List<GlyphRange> l; 		int len = (int) classes_first.length ();-		bool search_range_is_class = range_first.is_class () || range_last.is_class ();-+		 		len = (int) classes_first.length (); 		return_val_if_fail (len == classes_last.length (), 0); 		return_val_if_fail (len == classes_kerning.length (), 0);++		if (!(range_first.is_class () || range_last.is_class ())) {+			warning ("Expecting a class");+			return 0;+		} 		 		for (int i = len - 1; i >= 0; i--) { 			l = classes_first.nth (i); 			r = classes_last.nth (i);--			if (search_range_is_class && !l.data.is_class () && !r.data.is_class ()) {-				continue;-			}-				+	 			if (l.data.get_all_ranges () == range_first.get_all_ranges () 				&& r.data.get_all_ranges () == range_last.get_all_ranges ()) { 				return classes_kerning.nth (i).data.val;@@ -124,47 +101,24 @@ public class KerningClasses : GLib.Object { 		return 0; 	} -	public int get_first_non_class () {-		unowned List<GlyphRange> r;-		unowned List<GlyphRange> l;-		int len = (int) classes_first.length ();-		-		len = (int)classes_first.length ();-		return_val_if_fail (len == classes_last.length (), 0);-		return_val_if_fail (len == classes_kerning.length (), 0);-		-		for (int i = 0; i < len; i++) {-			l = classes_first.nth (i);-			r = classes_last.nth (i);-			-			if (!l.data.is_class () && !r.data.is_class ()) {-				return i;-			}-		}--		return -1;-	}- 	public int get_kerning_item_index (GlyphRange range_first, GlyphRange range_last) {-		unowned List<GlyphRange> r;-		unowned List<GlyphRange> l;+		unowned GLib.List<GlyphRange> r;+		unowned GLib.List<GlyphRange> l; 		int len = (int) classes_first.length ();-		bool search_range_is_class; 		 		len = (int)classes_first.length (); 		return_val_if_fail (len == classes_last.length (), 0); 		return_val_if_fail (len == classes_kerning.length (), 0);-		-		search_range_is_class = range_first.is_class () || range_last.is_class ();++		if (!(range_first.is_class () || range_last.is_class ())) {+			warning ("Expecting a class");+			return -1;+		} 		 		for (int i = len - 1; i >= 0; i--) { 			l = classes_first.nth (i); 			r = classes_last.nth (i); 			-			if (!l.data.is_class () && !r.data.is_class () && search_range_is_class) {-				continue;-			}-			 			if (l.data.get_all_ranges () == range_first.get_all_ranges () 				&& r.data.get_all_ranges () == range_last.get_all_ranges ()) { 				return i;@@ -175,9 +129,15 @@ public class KerningClasses : GLib.Object { 	} 		 	public double get_kerning (string left_glyph, string right_glyph) {-		unowned List<GlyphRange> r;-		unowned List<GlyphRange> l;+		unowned GLib.List<GlyphRange> r;+		unowned GLib.List<GlyphRange> l; 		int len = (int) classes_first.length ();+		double? d;+		+		d = get_kerning_for_single_glyphs (left_glyph, right_glyph);+		if (d != null) {+			return (!)d;+		}  		len = (int)classes_first.length (); 		return_val_if_fail (len == classes_last.length (), 0);@@ -197,22 +157,22 @@ public class KerningClasses : GLib.Object { 	}  	public double get_kern_for_range_to_char (GlyphRange left_range, string right_char) {-		unowned List<GlyphRange> r;-		unowned List<GlyphRange> l;+		unowned GLib.List<GlyphRange> r;+		unowned GLib.List<GlyphRange> l; 		int len = (int) classes_first.length ();-		bool search_range_is_class = left_range.is_class (); 		 		len = (int)classes_first.length (); 		return_val_if_fail (len == classes_last.length (), 0); 		return_val_if_fail (len == classes_kerning.length (), 0); 		+		if (!left_range.is_class ()) {+			warning ("Expecting a class");+			return -1;+		}+		 		for (int i = len - 1; i >= 0; i--) { 			l = classes_first.nth (i); 			r = classes_last.nth (i);--			if (!l.data.is_class () && !r.data.is_class () && search_range_is_class) {-				continue;-			} 			 			if (l.data.get_all_ranges () == left_range.get_all_ranges () 				&& r.data.has_character (right_char)) {@@ -224,22 +184,22 @@ public class KerningClasses : GLib.Object { 	}  	public double get_kern_for_char_to_range (string left_char, GlyphRange right_range) {-		unowned List<GlyphRange> r;-		unowned List<GlyphRange> l;+		unowned GLib.List<GlyphRange> r;+		unowned GLib.List<GlyphRange> l; 		int len = (int) classes_first.length ();-		bool search_range_is_class = right_range.is_class ();  		len = (int)classes_first.length (); 		return_val_if_fail (len == classes_last.length (), 0); 		return_val_if_fail (len == classes_kerning.length (), 0); 		+		if (!right_range.is_class ()) {+			warning ("Expecting a class");+			return 0;+		}+		 		for (int i = len - 1; i >= 0; i--) { 			l = classes_first.nth (i); 			r = classes_last.nth (i);--			if (search_range_is_class && !l.data.is_class () && !r.data.is_class ()) {-				continue;-			} 			 			if (l.data.has_character (left_char) 				&& r.data.get_all_ranges () == right_range.get_all_ranges ()) {@@ -254,7 +214,7 @@ public class KerningClasses : GLib.Object { 		print ("Kernings:\n"); 		for (int i = 0; i < classes_first.length (); i++) { 			print (classes_first.nth (i).data.get_all_ranges ());-			print (@"\t\t");+			print ("\t\t"); 			print (classes_last.nth (i).data.get_all_ranges ()); 			print ("\t\t"); 			print (@"$(classes_kerning.nth (i).data.val)");@@ -266,6 +226,12 @@ public class KerningClasses : GLib.Object { 			 			print ("\n"); 		}+		+		foreach (string key in single_kerning.keys) {+			print (key);+			print ("\t\t");+			print (@"$((!) single_kerning.get (key))\n");+		} 	} 	 	public void all_pairs (KerningIterator kerningIterator) {diff --git a/libbirdfont/KerningDisplay.vala b/libbirdfont/KerningDisplay.valaindex a89d617..af455c2 100644--- a/libbirdfont/KerningDisplay.vala+++ b/libbirdfont/KerningDisplay.vala@@ -66,7 +66,7 @@ public class KerningDisplay : FontDisplay { 	public void draw_error_message (WidgetAllocation allocation, Context cr) { 		string line1 = _("The current kerning class is malformed."); 		string line2 = _("Add single characters separated by space and ranges on the form A-Z.");-		string line3 = _("Type “space” to kern the space character.");+		string line3 = _("Type “space” to kern the space character and “divis” to kern -."); 		 		cr.save (); 		cr.set_source_rgba (1, 1, 1, 1);@@ -237,7 +237,7 @@ public class KerningDisplay : FontDisplay { 					return_if_fail (wi - 1 >= 0); 					 					if (word_with_ligatures.ranges.length () != word_with_ligatures.glyph.length ()) {-						warning ("ranges and glyphs does not match.");+						warning (@"ranges and glyphs does not match. $(word_with_ligatures.ranges.length ()) != $(word_with_ligatures.glyph.length ())"); 					} 					 					gr_left = word_with_ligatures.ranges.nth (wi - 1).data;@@ -416,7 +416,7 @@ public class KerningDisplay : FontDisplay { 				y = ((Math.fabs (ey - begin_handle_y) / 100) + 1); 			} 			-			k = (ex - last_handle_x) / y; // y-axis is variable precision+			k = (ex - last_handle_x) / y; // y-axis is for variable precision 			set_kerning (selected_handle, k); 			MainWindow.get_glyph_canvas ().redraw (); 		}diff --git a/libbirdfont/OpenFontFormat/load_font.c b/libbirdfont/OpenFontFormat/load_font.cindex 8b6d609..b80d08e 100644--- a/libbirdfont/OpenFontFormat/load_font.c+++ b/libbirdfont/OpenFontFormat/load_font.c@@ -576,13 +576,14 @@ FT_ULong get_charcode (FT_Face face, FT_UInt gid) { /** Obtain kerning data in .bf format for one glyph.  * @param gid glyph id  */-GString* get_kerning_data (FT_Face face, FT_Long gid) {+GString* get_kerning_data (FT_Face face, FT_Long gid, double units) { 	FT_Error error; 	FT_Vector kerning; 	GString* bf = g_string_new (""); 	FT_ULong char_left; 	FT_ULong char_right; 	FT_Long right;+	gchar kern[80]; 	 	char_left = get_charcode (face, gid); 	@@ -609,8 +610,9 @@ GString* get_kerning_data (FT_Face face, FT_Long gid) { 			return bf; 		} -		if (kerning.x > 0 && char_left > 31) {-			g_string_append_printf (bf, "<hkern left=\"U+%x\" right=\"U+%x\" kerning=\"%d\"/>\n", char_left, char_right, kerning.x);+		if (kerning.x != 0 && char_left > 31 && char_right > 31) {+			g_ascii_formatd (&kern, 80, "%f", kerning.x * units);+			g_string_append_printf (bf, "<kerning left=\"U+%x\" right=\"U+%x\" hadjustment=\"%s\"/>\n", char_left, char_right, kern); 		} 	} 	@@ -796,7 +798,7 @@ GString* get_bf_font (FT_Face face, char* file, int* err) {  	// kerning 	for (i = 0; i < face->num_glyphs; i++) {-		hkern = get_kerning_data (face, i);+		hkern = get_kerning_data (face, i, units); 		g_string_append (bf, hkern->str); 		g_string_free (hkern, 0); 		bird_font_progress_bar_set_progress ((double)(face->num_glyphs - i) / face->num_glyphs);diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex a47f408..1297928 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -1243,6 +1243,7 @@ public class Path { 		if (right == PointType.LINE_QUADRATIC && left == PointType.LINE_QUADRATIC) { 			ep.get_right_handle ().set_point_type (PointType.LINE_QUADRATIC); 			ep.get_left_handle ().set_point_type (PointType.LINE_QUADRATIC);+			ep.type = PointType.QUADRATIC; 			ep.recalculate_linear_handles (); 		} else if (right == PointType.LINE_CUBIC && left == PointType.LINE_CUBIC) { 			ep.get_right_handle ().set_point_type (PointType.LINE_CUBIC);@@ -1253,6 +1254,7 @@ public class Path { 			ep.get_right_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE); 			ep.get_left_handle ().set_point_type (PointType.LINE_DOUBLE_CURVE); 			ep.recalculate_linear_handles ();+			ep.type = PointType.DOUBLE_CURVE; 		} else if (right == PointType.DOUBLE_CURVE || left == PointType.DOUBLE_CURVE) { 			double_bezier_vector (position, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x, out x0, out x1); 			double_bezier_vector (position, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y, out y0, out y1);@@ -1262,6 +1264,7 @@ public class Path {  			ep.get_left_handle ().set_point_type (PointType.DOUBLE_CURVE);	 			ep.get_right_handle ().set_point_type (PointType.DOUBLE_CURVE);+			ep.type = PointType.DOUBLE_CURVE; 		} else if (right == PointType.QUADRATIC) {		 			x0 = quadratic_bezier_vector (1 - position, stop.x, start.get_right_handle ().x (), start.x); 			y0 = quadratic_bezier_vector (1 - position, stop.y, start.get_right_handle ().y (), start.y);@@ -1270,7 +1273,9 @@ public class Path { 			ep.get_left_handle ().set_point_type (PointType.QUADRATIC);	 			ep.get_right_handle ().set_point_type (PointType.QUADRATIC); 			-			ep.get_left_handle ().move_to_coordinate_internal (0, 0);				+			ep.get_left_handle ().move_to_coordinate_internal (0, 0);+			+			ep.type = PointType.QUADRATIC;				 		} else { 			bezier_vector (position, start.x, start.get_right_handle ().x (), stop.get_left_handle ().x (), stop.x, out x0, out x1); 			bezier_vector (position, start.y, start.get_right_handle ().y (), stop.get_left_handle ().y (), stop.y, out y0, out y1);@@ -1746,11 +1751,13 @@ public class Path { 				ep.set_tie_handle (false); 				ep.set_reflective_handles (false); 				ep.get_left_handle ().type = PenTool.to_line (ep.type);+				ep.type = PenTool.to_curve (ep.type); 				path_list.paths.append (current_path); 				 				if (!is_null (current_path.points.last ())) { 					ep = current_path.points.last ().data; 					ep.get_right_handle ().type = PenTool.to_line (ep.type);+					ep.type = PenTool.to_curve (ep.get_right_handle ().type); 				} 			} 		} else {@@ -1759,25 +1766,28 @@ public class Path { 				ep.set_tie_handle (false); 				ep.set_reflective_handles (false); 				ep.get_left_handle ().type = PenTool.to_line (ep.type);+				ep.type = PenTool.to_curve (ep.type); 				set_new_start (current_path.points.first ().data); 				path_list.paths.append (current_path); 				 				if (!is_null (current_path.points.last ())) { 					ep = current_path.points.last ().data; 					ep.get_right_handle ().type = PenTool.to_line (ep.type);+					ep.type = PenTool.to_curve (ep.get_right_handle ().type); 				} 			} 			 			if (remaining_points.points.length () > 0) { 				remaining_points.points.first ().data.set_tie_handle (false); 				remaining_points.points.first ().data.set_reflective_handles (false);-				remaining_points.points.first ().data.type = PenTool.to_line (remaining_points.points.first ().data.type);+				remaining_points.points.first ().data.type = remaining_points.points.first ().data.type; 				set_new_start (remaining_points.points.first ().data); 				path_list.paths.append (remaining_points); 				 				if (!is_null (current_path.points.last ())) { 					ep = current_path.points.last ().data; 					ep.get_right_handle ().type = PenTool.to_line (ep.type);+					ep.type = PenTool.to_curve (ep.get_right_handle ().type); 				} 			} 		}@@ -1877,7 +1887,6 @@ public class Path { 			e = new EditPoint (); 			p1.get_closest_point_on_path (e, inter.x, inter.y); 			inter.editpoint_b = e;-			 			inter.editpoint_b.x = inter.editpoint_a.x; 			inter.editpoint_b.y = inter.editpoint_a.y; 			@@ -1885,6 +1894,9 @@ public class Path { 			if (!p1.has_edit_point (e)) { 				p1.insert_new_point_on_path (e); 			}+			+			inter.editpoint_a.type = PenTool.to_curve (inter.editpoint_a.get_right_handle ().type);+			inter.editpoint_b.type = PenTool.to_curve (inter.editpoint_b.get_right_handle ().type); 		} 			 		if (il.points.length () < 2) {diff --git a/libbirdfont/PenTool.vala b/libbirdfont/PenTool.valaindex e69d1be..c0130ae 100644--- a/libbirdfont/PenTool.vala+++ b/libbirdfont/PenTool.vala@@ -1413,6 +1413,20 @@ public class PenTool : Tool { 		} 		return t; 	}++	public static PointType to_curve (PointType t) {+		switch (DrawingTools.point_type) {+			case PointType.LINE_QUADRATIC:+				return PointType.QUADRATIC;+			case PointType.LINE_DOUBLE_CURVE:+				return PointType.DOUBLE_CURVE;+			case PointType.LINE_CUBIC:+				return PointType.CUBIC;+			default:+				break;+		}+		return t;+	} 	 	public static void set_converted_handle_length (EditPointHandle e) { 		if (e.type == PointType.QUADRATIC  && DrawingTools.point_type == PointType.DOUBLE_CURVE) {diff --git a/libbirdfont/SpinButton.vala b/libbirdfont/SpinButton.valaindex 7d45b33..de4ab0a 100644--- a/libbirdfont/SpinButton.vala+++ b/libbirdfont/SpinButton.vala@@ -49,8 +49,8 @@ public class SpinButton : Tool { 				n = (button == 3) ? 10 : 1; 					 				for (int i = 0; i < n; i++) {-					if (py < 28) increase ();-					if (py > 35) decrease ();+					if (py < 51) increase ();+					if (py > 60) decrease (); 				} 			} 			diff --git a/libbirdfont/TestCases.vala b/libbirdfont/TestCases.valaindex 119a4ae..e2d9442 100644--- a/libbirdfont/TestCases.vala+++ b/libbirdfont/TestCases.vala@@ -44,6 +44,7 @@ class TestCases { 		add (test_parse_quadratic_paths, "Quadratic paths"); 		add (test_freetype, "Freetype"); 		add (test_preview, "Preview");+		add (test_kerning, "Kerning"); 	} 	 	private void add (Callback callback, string name) {@@ -1449,6 +1450,35 @@ class TestCases { 	private static void add_point_on_path (Path p, int x, int y) { 		p.add (Glyph.path_coordinate_x (x), Glyph.path_coordinate_y (y)); 	}+	+	private static void test_kerning () {+		MenuTab.show_kerning_context ();+		Font font = BirdFont.get_current_font ();+		KerningDisplay kerning_display = KerningDisplay.get_singleton ();+		unichar a, b;+		StringBuilder sb1, sb2;+		string sa, sb;+		GlyphRange? r, l;+		+		for (int i = 0; i < 100; i++) {+			l = null;+			r = null;+		+			// kern single glyph+			sb1 = new StringBuilder ();+			sb2 = new StringBuilder ();+			+			a = (unichar)Random.int_range ((int)'a', (int)'ʙ');+			b = (unichar)Random.int_range ((int)'a', (int)'ʙ');+			+			sb1.append_unichar (a);+			sb2.append_unichar (b);+			sa = (!)sb1.str;+			sb = (!)sb2.str;+			+			kerning_display.set_kerning_pair (sa, sb, ref r, ref l, Random.int_range (0, 300));+		}+	} }  }

Contact

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