Clone in a terminal:
Commit 0402839
Johan Mattsson - 2013-03-04T10:50:43+00:00
040283936b14928b1e955da2c38de52d9b1eeeacjohan.mattsson.m@gmail.com

quadratic paths with two handles using a hidden point

Changed files (7)

Diff

diff --git a/libbirdfont/BirdFontFile.vala b/libbirdfont/BirdFontFile.valaindex 3478df5..daf3e5b 100644--- a/libbirdfont/BirdFontFile.vala+++ b/libbirdfont/BirdFontFile.vala@@ -187,7 +187,10 @@ class BirdFontFile { 	 * S - Start point for path  	 * L - Line 	 * Q - Quadratic Bézier path+	 * D - Two quadratic off curve points 	 * C - Cubic Bézier path+	 * +	 * T - Tie handles for previous curve 	 */ 	private string get_point_data (Path pl) { 		StringBuilder data = new StringBuilder ();@@ -213,12 +216,23 @@ class BirdFontFile { 			data.append (" "); 			add_next_point (m, e, data); 			n = e;+			+			if (e.tie_handles) {+				data.append (" ");+				data.append (@"T");+			}+			 			i++; 		}  		data.append (" "); 		m = pl.points.first ().data;	 		add_next_point ((!) n, m, data);++		if (m.tie_handles) {+			data.append (" ");+			data.append (@"T");+		} 		 		return data.str; 	}@@ -236,6 +250,12 @@ class BirdFontFile { 		data.append (@"Q $(h.x ()),$(h.y ()) $(end.x),$(end.y)"); 	} +	private void add_double (EditPoint start, EditPoint end, StringBuilder data) {+		EditPointHandle h1 = start.get_right_handle ();+		EditPointHandle h2 = end.get_left_handle ();+		data.append (@"D $(h1.x ()),$(h1.y ()) $(h2.x ()),$(h2.y ()) $(end.x),$(end.y)");+	}+ 	private void add_cubic (EditPoint start, EditPoint end, StringBuilder data) { 		EditPointHandle h1 = start.get_right_handle (); 		EditPointHandle h2 = end.get_left_handle ();@@ -247,6 +267,8 @@ class BirdFontFile { 			add_line_to (end, data); 		} else if (start.right_handle.type == PointType.LINE_CUBIC && end.left_handle.type == PointType.LINE_CUBIC) { 			add_line_to (end, data);+		} else if (end.left_handle.type == PointType.DOUBLE_CURVE || start.right_handle.type == PointType.DOUBLE_CURVE) {+			add_double (start, end, data); 		} else if (end.left_handle.type == PointType.QUADRATIC || start.right_handle.type == PointType.QUADRATIC) { 			add_quadratic (start, end, data); 		} else {@@ -736,6 +758,50 @@ class BirdFontFile { 		ep1.recalculate_linear_handles (); 	} 	+	/** Two quadratic off curve points. */+	private void double_curve (Path path, string px0, string py0, string px1, string py1, string px2, string py2) {+		EditPoint ep1, ep2;+		+		double x0 = parse_double (px0);+		double y0 = parse_double (py0);+		double x1 = parse_double (px1);+		double y1 = parse_double (py1);+		double x2 = parse_double (px2);+		double y2 = parse_double (py2);+		+		double lx, ly;+				+		if (is_null (path.points.last ().data)) {+			warning ("No point");+			return;+		}++		// start with line handles+		ep1 = path.points.last ().data;+		ep1.get_right_handle ().type = PointType.LINE_DOUBLE_CURVE;+		+		lx = ep1.x + ((x2 - ep1.x) / 4);+		ly = ep1.y + ((y2 - ep1.y) / 4);+						+		ep1.get_right_handle ().move_to_coordinate (lx, ly);+		ep1.recalculate_linear_handles ();+		+		// set curve handles+		ep1 = path.points.last ().data;+		ep1.recalculate_linear_handles ();+		ep1.get_right_handle ().type = PointType.DOUBLE_CURVE;+		ep1.get_right_handle ().move_to_coordinate (x0, y0);				++		path.add (x2, y2);+						+		ep2 = path.points.last ().data;+		ep2.recalculate_linear_handles ();+		ep2.get_left_handle ().type = PointType.DOUBLE_CURVE;+		ep2.get_left_handle ().move_to_coordinate (x1, y1);+	+		ep1.recalculate_linear_handles ();+	}+	 	private void close (Path path) { 		EditPoint ep1, ep2; 		@@ -744,6 +810,8 @@ class BirdFontFile { 		ep2 = path.points.first ().data; 		 		path.points.remove_link (path.points.last ());+		+		ep2.tie_handles = ep1.tie_handles; 		ep2.left_handle.angle = ep1.left_handle.angle; 		ep2.left_handle.length = ep1.left_handle.length; 		ep2.left_handle.type = ep1.left_handle.type;@@ -760,6 +828,7 @@ class BirdFontFile { 		 		if (d[0] != "S") { 			warning ("No start point.");+			return path; 		} 		 		if (d[i++] == "S") {@@ -791,6 +860,18 @@ class BirdFontFile { 				return_val_if_fail (p1.length == 2, path); 				 				quadratic (path, p[0], p[1], p1[0], p1[1]);+			} else if (instruction == "D") {+				return_val_if_fail (i + 2 < d.length, path);+				+				p = d[i++].split (",");+				p1 = d[i++].split (",");+				p2 = d[i++].split (",");++				return_val_if_fail (p.length == 2, path);+				return_val_if_fail (p1.length == 2, path);+				return_val_if_fail (p2.length == 2, path);+				+				double_curve (path, p[0], p[1], p1[0], p1[1], p2[0], p2[1]); 			} else if (instruction == "C") { 				return_val_if_fail (i + 2 < d.length, path); 				@@ -803,6 +884,8 @@ class BirdFontFile { 				return_val_if_fail (p2.length == 2, path); 				 				cubic (path, p[0], p[1], p1[0], p1[1], p2[0], p2[1]);+			} else if (instruction == "T") {+				path.points.last ().data.tie_handles = true; 			} else { 				warning (@"invalid instruction $instruction"); 				return path;diff --git a/libbirdfont/EditPoint.vala b/libbirdfont/EditPoint.valaindex 86fddf2..a7cbdbf 100644--- a/libbirdfont/EditPoint.vala+++ b/libbirdfont/EditPoint.vala@@ -21,12 +21,12 @@ namespace BirdFont {  public enum PointType { 	NONE,-	NORMAL,-	LINE_QUADRATIC,-	LINE_CUBIC,+	LINE_QUADRATIC,      // line with quadratic handles+	LINE_DOUBLE_CURVE,   // line with two quadratic handles+	LINE_CUBIC,          // line with cubic handles 	CUBIC,+	DOUBLE_CURVE,        // two quadratic points with a hidden point half way between the two line handles 	QUADRATIC,-	DOUBLE_CURVE, 	END, 	FLOATING }@@ -115,17 +115,28 @@ public class EditPoint { 			if (h.type == PointType.LINE_CUBIC) { 				nx = x + ((n.x - x) / 3); 				ny = y + ((n.y - y) / 3);-			 				h.move_to_coordinate (nx, ny); 			}-						++			if (h.type == PointType.LINE_DOUBLE_CURVE) {+				nx = x + ((n.x - x) / 4);+				ny = y + ((n.y - y) / 4);+				h.move_to_coordinate (nx, ny);+			}+									 			// on the other side 			h = n.get_right_handle (); 			+			if (h.type == PointType.LINE_DOUBLE_CURVE) {+				nx = n.x + ((x - n.x) / 4);+				ny = n.y + ((y - n.y) / 4);	+				h.move_to_coordinate (nx, ny);+				+			}+			 			if (h.type == PointType.LINE_CUBIC) { 				nx = n.x + ((x - n.x) / 3);-				ny = n.y + ((y - n.y) / 3);-			+				ny = n.y + ((y - n.y) / 3);	 				h.move_to_coordinate (nx, ny); 			} 		}@@ -142,6 +153,13 @@ public class EditPoint { 				h.move_to_coordinate (nx, ny); 			} +			if (h.type == PointType.LINE_DOUBLE_CURVE) {+				nx = x + ((n.x - x) / 4);+				ny = y + ((n.y - y) / 4);+				+				h.move_to_coordinate (nx, ny);+			}+ 			if (h.type == PointType.LINE_QUADRATIC) { 				nx = x + ((n.x - x) / 2); 				ny = y + ((n.y - y) / 2);@@ -157,6 +175,13 @@ public class EditPoint {  				h.move_to_coordinate (nx, ny); 			}+			+			if (h.type == PointType.LINE_DOUBLE_CURVE) {+				nx = n.x + ((x - n.x) / 4);+				ny = n.y + ((y - n.y) / 4);++				h.move_to_coordinate (nx, ny);+			} 		} 	} 	@@ -186,9 +211,14 @@ public class EditPoint { 			angle = -acos (a / length) + PI; 		} 		-		left_handle.type = PointType.CUBIC;-		right_handle.type = PointType.CUBIC;-		+		if (left_handle.type == PointType.LINE_DOUBLE_CURVE || left_handle.type == PointType.QUADRATIC) {+			left_handle.type = PointType.DOUBLE_CURVE;+			right_handle.type = PointType.DOUBLE_CURVE;			+		} else if (left_handle.type == PointType.LINE_CUBIC) {+			left_handle.type = PointType.CUBIC;+			right_handle.type = PointType.CUBIC;+		}+				 		right_handle.angle = angle; 		left_handle.angle = angle; diff --git a/libbirdfont/OpenFontFormatWriter.vala b/libbirdfont/OpenFontFormatWriter.valaindex 503845e..e026913 100644--- a/libbirdfont/OpenFontFormatWriter.vala+++ b/libbirdfont/OpenFontFormatWriter.vala@@ -853,7 +853,126 @@ class GlyfTable : Table { 		
 		return (uint16)g.unichar_code; 
 	}
+
+	public void process_glyph (Glyph g, FontData fd) throws GLib.Error {
+		uint16 end_point;
+		uint16 npoints;
+		int16 ncontours;
+		int16 nflags;
+		int glyph_offset;
+		uint len; 
+		uint coordinate_length;
+
+		fd.seek_end (); // append glyph
+		
+		glyph_offset = (int) fd.length ();
+		
+		printd (@"glyph_offset: $(glyph_offset)\n");
+		
+		g.remove_empty_paths ();
+		if (g.path_list.length () == 0) {
+			// location_offsets == location_offset + 1 to tell parser that this glyf does not have a body
+			return;
+		}
+		
+		non_zero_glyphs++;
+		
+		ncontours = (int16) g.path_list.length ();
+		fd.add_short (ncontours);
+		
+		GlyfData glyf_data = new GlyfData (g);
+				
+		// bounding box
+		fd.add_16 (glyf_data.bounding_box_xmin);
+		fd.add_16 (glyf_data.bounding_box_ymin);
+		fd.add_16 (glyf_data.bounding_box_xmax);
+		fd.add_16 (glyf_data.bounding_box_ymax);
+
+		// end points
+		foreach (uint16 end in glyf_data.end_points) {
+			fd.add_u16 (end);
+		}
+
+		fd.add_u16 (0); // instruction length 
+		
+		uint glyph_header = 12 + ncontours * 2;
+		
+		printd (@"next glyf: $(g.name) ($((uint32)g.unichar_code))\n");
+		printd (@"glyf header length: $(glyph_header)\n");
+				
+		end_point = glyf_data.get_end_point ();
+		ncontours = glyf_data.get_ncontours ();
+		npoints = (ncontours > 0) ? end_point : 0; // +1?
+		
+		if (npoints > max_points) {
+			max_points = npoints;
+		}
+		
+		if (ncontours > max_contours) {
+			max_contours = ncontours;
+		}
+		
+		// flags		
+		nflags = glyf_data.get_nflags ();
+		if (nflags != npoints) {
+			warning (@"(nflags != npoints)  ($nflags != $npoints) in glyph $(g.name). ncontours: $ncontours");
+		}
+		assert (nflags == npoints);
 	
+		foreach (uint8 flag in glyf_data.flags) {
+			fd.add_byte (flag);
+		}
+
+		printd (@"flags: $(nflags)\n");
+		
+		// x coordinates
+		foreach (int16 x in glyf_data.coordinate_x) {
+			fd.add_16 (x);
+		}	
+
+		// y coordinates
+		foreach (int16 y in glyf_data.coordinate_y) {
+			fd.add_16 (y);
+		}
+	
+		len = fd.length ();
+		coordinate_length = fd.length () - nflags - glyph_header;
+		printd (@"coordinate_length: $(coordinate_length)\n");
+		printd (@"fd.length (): $(fd.length ())\n");
+		assert (fd.length () > nflags + glyph_header);
+		
+		printd (@"glyph_offset: $(glyph_offset)\n");
+		printd (@"len: $(len)\n");
+
+		// save bounding box for head table
+		if (glyf_data.bounding_box_xmin < this.xmin) {
+			this.xmin = glyf_data.bounding_box_xmin;
+		}
+		
+		if (glyf_data.bounding_box_ymin < this.ymin) {
+			this.ymin = glyf_data.bounding_box_ymin;
+		}
+		
+		if (glyf_data.bounding_box_xmax > this.xmax) {
+			this.xmax = glyf_data.bounding_box_xmax;
+		}
+		
+		if (glyf_data.bounding_box_ymax > this.ymax) {
+			this.ymax = glyf_data.bounding_box_ymax;
+		}
+				
+		// part of average width calculation for OS/2 table
+		total_width += xmax - xmin;
+		
+		printd (@"length before padding: $(fd.length ())\n");
+		
+		// all glyphs needs padding for loca table to be correct
+		while (fd.length () % 4 != 0) {
+			fd.add (0);
+		}
+		printd (@"length after padding: $(fd.length ())\n");
+	}
+
 	public Glyph? read_glyph (string name) throws GLib.Error {
 		Glyph? glyph;
 		Glyph g;
@@ -1365,172 +1484,137 @@ class GlyfTable : Table { 		return glyph;
 	}
 
-	public void process_glyph (Glyph g, FontData fd) throws GLib.Error {
-		int16 txmin, tymin, txmax, tymax;
-
-		int16 end_point;
-		int16 last_end_point;
-		int16 npoints;
-		int16 ncontours;
-		int16 nflags;
+	/** Data for one entry in the glyf table. */
+	class GlyfData : GLib.Object {		
+		public List<Path> paths = new List<Path> ();
+		public List<uint16> end_points = new List<uint16> ();
+		public List<uint8> flags = new List<uint8> ();
+		public List<int16> coordinate_x = new List<int16> ();
+		public List<int16> coordinate_y = new List<int16> ();
 		
-		double x, y;
-
-		Font font = OpenFontFormatWriter.get_current_font ();
-		int glyph_offset;
-		
-		uint len; 
-		uint coordinate_length;
-		Path quadratic;
-		PointType pt;
-		
-		fd.seek_end (); // append glyph
+		uint16 end_point = 0;
+		int16 nflags = 0;
 		
-		glyph_offset = (int) fd.length ();
+		Glyph glyph;
 		
-		printd (@"glyph_offset: $(glyph_offset)\n");
+		public int16 bounding_box_xmin = 0;
+		public int16 bounding_box_ymin = 0;
+		public int16 bounding_box_xmax = 0;
+		public int16 bounding_box_ymax = 0;
 		
-		g.remove_empty_paths ();
-		if (g.path_list.length () == 0) {
-			// location_offsets == location_offset + 1 to tell parser that this glyf does not have a body
-			return;
+		public GlyfData (Glyph g) {	
+			glyph = g;
+			
+			foreach (Path p in g.path_list) {
+				paths.append (p.get_quadratic_points ());
+			}
+			
+			process_end_points ();
+			process_flags ();
+			process_x ();
+			process_y ();
+			process_bounding_box ();			
+		}
+	
+		public uint16 get_end_point () {
+			return end_point;
+		}
+				
+		public int16 get_ncontours () {
+			return (int16) paths.length ();
+		}
+	
+		public int16 get_nflags () {
+			return nflags;
 		}
 		
-		non_zero_glyphs++;
-		
-		ncontours = (int16) g.path_list.length ();
-		fd.add_short (ncontours);
-		
-		txmin = int16.MAX;
-		tymin = int16.MAX;
-		txmax = int16.MIN;
-		tymax = int16.MIN;
-		
-		// bounding box will be set again after coordinate arrays have been created
-		fd.add_16 (0);
-		fd.add_16 (0);
-		fd.add_16 (0);
-		fd.add_16 (0);
-		
-		// end points
-		end_point = 0;
-		last_end_point = 0;
-		foreach (Path p in g.path_list) {
-			quadratic = p.get_quadratic_points ();
+		void process_end_points () {	
+			uint16 last_end_point = 0;
+			PointType type;
 			
-			if (quadratic.points.length () == 0) {
-				warning (@"No points in path (quadratic points $(quadratic.points.length ())) (before conversion $(p.points.length ()))");
-				continue;
-			}
+			end_point = 0;
 			
-			foreach (EditPoint e in quadratic.points) {
-				end_point++;
-				pt = e.get_right_handle ().type;
+			foreach (Path quadratic in paths) {
+				if (quadratic.points.length () == 0) {
+					warning (@"No points in path (before conversion $(quadratic.points.length ()))");
+					continue;
+				}
 				
-				if (pt == PointType.CUBIC || pt == PointType.QUADRATIC) {
+				foreach (EditPoint e in quadratic.points) {
+					end_point++;
+					type = e.get_right_handle ().type;
+					
+					// off curve
 					end_point++;
+					
+					if (end_point == 0xFFFF) {
+						warning ("Too many points");
+					}
 				}
+				end_points.append (end_point - 1);
 				
-				if (end_point == 0xFFFF) {
-					warning ("Too many points");
+				if (end_point - 1 < last_end_point) {
+					warning (@"Next endpoint has bad value. (end_point - 1 < last_end_point)  ($(end_point - 1) < $last_end_point)");
 				}
-			}
-			fd.add_u16 (end_point - 1);
-			
-			if (end_point - 1 < last_end_point) {
-				warning (@"Next endpoint has bad value. (end_point - 1 < last_end_point)  ($(end_point - 1) < $last_end_point)");
+				
+				last_end_point = end_point - 1;
 			}
 			
-			last_end_point = end_point - 1;
+			assert (end_point > 0);			
 		}
-		
-		fd.add_u16 (0); // instruction length 
-		
-		uint glyph_header = 12 + ncontours * 2;
-		
-		printd (@"next glyf: $(g.name) ($((uint32)g.unichar_code))\n");
-		printd (@"glyf header length: $(glyph_header)\n");
-		
-		// instructions should go here 
-		
-		npoints = (ncontours > 0) ? end_point : 0; // +1?
-		
-		if (npoints > max_points) {
-			max_points = npoints;
-		}
-		
-		if (ncontours > max_contours) {
-			max_contours = ncontours;
-		}
-		
-		// flags
-		nflags = 0;
-		List<uint8> flags = new List<uint8> ();
-		foreach (Path p in g.path_list) {
-			p = p.get_quadratic_points ();
-			foreach (EditPoint e in p.points) {
-				fd.add_byte (Coordinate.ON_PATH);
-				flags.append (Coordinate.ON_PATH);
-				nflags++;
+
+		void process_flags () {
+			flags = new List<uint8> ();
+			nflags = 0;
+			
+			foreach (Path p in paths) {
+				p = p.get_quadratic_points ();
 				
-				if (e.get_right_handle ().type == PointType.CUBIC) {
-					fd.add_byte (Coordinate.NONE);
+				foreach (EditPoint e in p.points) {
+					flags.append (Coordinate.ON_PATH);
+					nflags++;
+					
+					// off curve
 					flags.append (Coordinate.NONE);
 					nflags++;
 				}
 			}
 		}
 		
-		if (nflags != npoints) {
-			warning (@"(nflags != npoints)  ($nflags != $npoints) in glyph $(g.name). ncontours: $ncontours");
-		}
-		assert (nflags == npoints);
-
-		printd (@"flags: $(nflags)\n");
-		
-		// x coordinates
-		List<int16> coordinate_x = new List<int16> ();
-		List<int16> coordinate_y = new List<int16> ();
-		double prev = 0;
-		
-		foreach (Path p in g.path_list) {
-			p = p.get_quadratic_points ();
-
-			foreach (EditPoint e in p.points) {
-				x = rint (e.x * UNITS - prev - g.left_limit * UNITS);
-
-				fd.add_16 ((int16) x);
-				coordinate_x.append ((int16) x);
-				-				prev = rint (e.x * UNITS - g.left_limit * UNITS);
-				-				if (e.get_right_handle ().type == PointType.CUBIC) {
-					x = rint (e.get_right_handle ().x () * UNITS - prev - g.left_limit * UNITS);
+		void process_x () {
+			double prev = 0;
+			double x;
+			
+			foreach (Path p in paths) {
+				foreach (EditPoint e in p.points) {
+					x = rint (e.x * UNITS - prev - glyph.left_limit * UNITS);
+					coordinate_x.append ((int16) x);
+					
+					prev = rint (e.x * UNITS - glyph.left_limit * UNITS);
 
-					fd.add_16 ((int16) x);
+					// off curve
+					x = rint (e.get_right_handle ().x () * UNITS - prev - glyph.left_limit * UNITS);
 					coordinate_x.append ((int16) x);
 					
-					prev = rint (e.get_right_handle ().x () * UNITS - g.left_limit * UNITS);
+					prev = rint (e.get_right_handle ().x () * UNITS - glyph.left_limit * UNITS);
 				}
 			}
 		}
+		
+		void process_y () {
+			double prev = 0;
+			double y;
+			Font font = OpenFontFormatWriter.get_current_font ();
+			
+			foreach (Path p in paths) {
+				foreach (EditPoint e in p.points) {
+					y = rint (e.y * UNITS - prev + font.base_line  * UNITS);
+					coordinate_y.append ((int16) y);
+					
+					prev = rint (e.y * UNITS + font.base_line * UNITS);
 
-		// y coordinates
-		prev = 0;
-		foreach (Path p in g.path_list) {
-			p = p.get_quadratic_points ();
-			foreach (EditPoint e in p.points) {
-				y = rint (e.y * UNITS - prev + font.base_line  * UNITS);
-				fd.add_16 ((int16) y);
-				-				coordinate_y.append ((int16) y);-				
-				prev = rint (e.y * UNITS + font.base_line * UNITS);
-
-				if (e.get_right_handle ().type == PointType.CUBIC) {
+					// off curve
 					y = rint (e.get_right_handle ().y () * UNITS - prev + font.base_line * UNITS);
-					
-					fd.add_16 ((int16) y);
 					coordinate_y.append ((int16) y);
 					
 					prev = rint (e.get_right_handle ().y () * UNITS + font.base_line  * UNITS);
@@ -1538,89 +1622,52 @@ class GlyfTable : Table { 			}
 		}
 		
-		len = fd.length ();
-		printd (@"fd.length (): $(fd.length ())\n");
-		coordinate_length = fd.length () - nflags - glyph_header;
-		printd (@"coordinate_length: $(coordinate_length)\n");
-		assert (fd.length () > nflags + glyph_header);
-				
-		// bounding box	
-		int16 last = 0;
-			
-		int i = 0;
-		foreach (int16 c in coordinate_x) {
-			c += last;
-			
-			// Only on curve points are good for calculating bounding box
-			if ((flags.nth (i).data & Coordinate.ON_PATH) > 0) { 
-				if (c < txmin) txmin = c;
-				if (c > txmax) txmax = c;
+		void process_bounding_box () {
+			int16 last = 0;			
+			int i = 0;
+
+			bounding_box_xmin = int16.MAX;
+			bounding_box_ymin = int16.MAX;
+			bounding_box_xmax = int16.MIN;
+			bounding_box_ymax = int16.MIN;
+					
+			if (coordinate_x.length () == 0) {
+				warning ("no points in coordinate_y");
 			}
+			
+			foreach (int16 c in coordinate_x) {
+				c += last;
 				
-			last = c;
-			i++;
-		}
+				// Only on curve points are good for calculating bounding box
+				if ((flags.nth (i).data & Coordinate.ON_PATH) > 0) { 
+					if (c < bounding_box_xmin) bounding_box_xmin = c;
+					if (c > bounding_box_xmax) bounding_box_xmax = c;
+				}
+					
+				last = c;
+				i++;
+			}
 
-		last = 0;
-		i = 0;
-		foreach (int16 c in coordinate_y) {
-			c += last;
-			
-			if ((flags.nth (i).data & Coordinate.ON_PATH) > 0) {
-				if (c < tymin) tymin = c;
-				if (c > tymax) tymax = c;			
+			if (coordinate_y.length () == 0) {
+				warning ("no points in coordinate_y");
 			}
 			
-			last = c;
-			i++;
-		}
-		
-		fd.seek_end ();
-		
-		printd (@"glyph_offset: $(glyph_offset)\n");
-		printd (@"len: $(len)\n");
-		
-		fd.seek (glyph_offset + 2); // go to box boundries for this glyf
-		// assert (fd.read_short () == int16.MAX);
-
-		// add bounding box
-		fd.add_16 (txmin);
-		fd.add_16 (tymin);
-		fd.add_16 (txmax);
-		fd.add_16 (tymax);
-		fd.seek_end ();
-	
-		assert (len == fd.length ());
-		
-		fd.seek (glyph_offset + 2);
-		assert (fd.read_int16 () == txmin);
-		assert (fd.read_int16 () == tymin);
-		assert (fd.read_int16 () == txmax);
-		assert (fd.read_int16 () == tymax);
-		fd.seek_end ();
-
-		printd (@"\n");
-		printd (@"txmin: $txmin\n");
-		printd (@"tymin: $tymin\n");
-		printd (@"txmax: $txmax\n");
-		printd (@"tymax: $tymax\n");
-
-		// save this for head table
-		if (txmin < this.xmin) this.xmin = txmin;
-		if (tymin < this.ymin) this.ymin = tymin;
-		if (txmax > this.xmax) this.xmax = txmax;
-		if (tymax > this.ymax) this.ymax = tymax;
+			last = 0;
+			i = 0;
+			foreach (int16 c in coordinate_y) {
+				c += last;
 				
-		// part of average width calculation for OS/2 table
-		total_width += xmax - xmin;
-		
-		printd (@"length before padding: $(fd.length ())\n");
-		
-		// all glyphs needs padding for loca table to be correct
-		while (fd.length () % 4 != 0) {
-			fd.add (0);
+				if ((flags.nth (i).data & Coordinate.ON_PATH) > 0) {
+					if (c < bounding_box_ymin) bounding_box_ymin = c;
+					if (c > bounding_box_ymax) bounding_box_ymax = c;			
+				}
+				
+				last = c;
+				i++;
+			}
+			
+			printd (@"Bounding box: $bounding_box_xmin,$bounding_box_ymin  $bounding_box_xmax,$bounding_box_ymax\n");
 		}
-		printd (@"length after padding: $(fd.length ())\n");
 	}
 
 	// necessary in order to have glyphs sorted according to ttf specification
@@ -2872,7 +2919,7 @@ class Os2Table : Table { 		fd.add_16 (200); // SHORT yStrikeoutPosition
 		fd.add_16 (40); // SHORT sFamilyClass
 
-		// PANOSE
+		// FIXME: PANOSE
 		fd.add (0); 
 		fd.add (0); 
 		fd.add (0); 
@@ -2884,7 +2931,7 @@ class Os2Table : Table { 		fd.add (0); 
 		fd.add (0); 
 
-		// FIXA:
+		// FIXME:
 		fd.add_u32 (0); // ulUnicodeRange1 Bits 0-31
 		fd.add_u32 (0); // ULONG ulUnicodeRange2 Bits 32-63
 		fd.add_u32 (0); // ULONG ulUnicodeRange3 Bits 64-95
@@ -4616,7 +4663,7 @@ class GposTable : Table { 			warning ("No kerning to add to gpos table.");
 		}
 		
-		printd (@"Adding $num_kerning_values kerning pairs to gpos table.");
+		printd (@"Adding $num_kerning_values kerning pairs to gpos table.\n");
 		
 		fd.add_ulong (0x00010000); // table version
 		fd.add_ushort (10); // offset to script list
@@ -4776,6 +4823,10 @@ class DirectoryTable : Table { 			tables.append (this);
 			
 			if (kern_table.kerning_pairs > 0) {
+				// FIXME: Firefox will ignore the Kern table of GPOS is present 
+				// but not adjust the values according to the GPOS table.
+				// 
+				// Maybe there is a problem with gpos_table that I am not aware of.
 				tables.append (gpos_table);
 			}
 			
diff --git a/libbirdfont/Path.vala b/libbirdfont/Path.valaindex 0875afa..f06eb09 100644--- a/libbirdfont/Path.vala+++ b/libbirdfont/Path.vala@@ -133,7 +133,6 @@ public class Path { 		if (!is_open () && n != null) { 			en = (!) n; 			em = ep.first ().data;-			 			draw_next (en, em, cr); 		} @@ -196,19 +195,38 @@ public class Path { 	}  	private void draw_next (EditPoint e, EditPoint en, Context cr) {-		PointType t = e.get_right_handle ().type;+		PointType r = e.get_right_handle ().type;+		PointType l = en.get_left_handle ().type; 		-		if (t == PointType.DOUBLE_CURVE) {-			+		if (r == PointType.DOUBLE_CURVE || l == PointType.DOUBLE_CURVE) {+			draw_double_curve (e, en, cr); 		} else { 			draw_curve (e, en, cr); 		} 	} 	+	private static void draw_double_curve (EditPoint e, EditPoint en, Context cr) {+		EditPoint middle;+		double x, y;+		+		x = e.get_right_handle ().x () + (en.get_left_handle ().x () - e.get_right_handle ().x ()) / 2;+		y = e.get_right_handle ().y () + (en.get_left_handle ().y () - e.get_right_handle ().y ()) / 2;+		+		middle = new EditPoint (x, y, PointType.DOUBLE_CURVE);+		middle.right_handle = en.get_left_handle ().copy ();+		+		middle.right_handle.type = PointType.DOUBLE_CURVE;+		middle.left_handle.type = PointType.DOUBLE_CURVE;+		+		draw_curve (e, middle, cr);+		draw_curve (middle, en, cr);		+	}+		 	private static void draw_curve (EditPoint e, EditPoint en, Context cr, double alpha = 1) { 		Glyph g = MainWindow.get_current_glyph (); 		double xa, ya, xb, yb, xc, yc, xd, yd;-		PointType t = en.get_right_handle ().type;+		PointType t = e.get_right_handle ().type;+		PointType u = en.get_left_handle ().type; 		 		get_bezier_points (e, en, out xa, out ya, out xb, out yb, out xc, out yc, out xd, out yd); @@ -217,7 +235,7 @@ public class Path { 		 		cr.line_to (xa, ya); // this point makes sense only if it is the first or last position, the other points are meaningless don't export them -		if (t == PointType.QUADRATIC || t == PointType.LINE_QUADRATIC) {+		if (t == PointType.QUADRATIC || t == PointType.LINE_QUADRATIC || t == PointType.DOUBLE_CURVE || u == PointType.QUADRATIC || u == PointType.LINE_QUADRATIC || u == PointType.DOUBLE_CURVE) { 			cr.curve_to ((xa + 2 * xb) / 3, (ya + 2 * yb) / 3, (xd + 2 * xb) / 3, (yd + 2 * yb) / 3, xd, yd);		 		} else { 			cr.curve_to (xb, yb, xc, yc, xd, yd);@@ -763,7 +781,9 @@ public class Path { 			points.delete_link ((!) previous_point); 		} -		if (unlikely (previous_point == null && points.length () != 0)) warning ("previous_point == null");+		if (unlikely (previous_point == null && points.length () != 0)) {+			warning ("previous_point == null");+		}  		if (points.length () == 0) { 			points.append (p);@@ -788,10 +808,14 @@ public class Path { 		if (p.prev != null && p.get_prev ().data.right_handle.type == PointType.QUADRATIC) { 			p.left_handle.type = PointType.QUADRATIC; 			p.right_handle.type = PointType.LINE_QUADRATIC;-		} else if (Toolbox.use_quadratic_points ()) {+		} else if (Toolbox.get_selected_point_type () == PointType.QUADRATIC) { 			p.left_handle.type = PointType.LINE_QUADRATIC; 			p.right_handle.type = PointType.LINE_QUADRATIC; 			p.type = PointType.LINE_QUADRATIC;+		} else if (Toolbox.get_selected_point_type () == PointType.DOUBLE_CURVE) {+			p.left_handle.type = PointType.LINE_DOUBLE_CURVE;+			p.right_handle.type = PointType.LINE_DOUBLE_CURVE;+			p.type = PointType.DOUBLE_CURVE; 		} 		 		return np;@@ -962,10 +986,18 @@ public class Path { 		EditPoint middle = new EditPoint (); 		unowned List<EditPoint> e; 		EditPointHandle eh;+		EditPointHandle last;+		EditPoint first; 		 		quadratic_path = copy ();+		+		last = quadratic_path.points.last ().data.get_right_handle ();+		if (last.type == PointType.QUADRATIC) {+			first = quadratic_path.points.first ().data;+			quadratic_path.points.append (first);+		} 		quadratic_path.close ();-				+/*				 		if (quadratic_path.points.length () < 2) { 			return quadratic_path; 		}@@ -983,9 +1015,9 @@ public class Path { 		while (e != quadratic_path.points.last ().prev) { 			middle.prev = e; 			middle.next = e.next;-							-			convert_to_quadratic (quadratic_path, middle);	 			+			convert_to_quadratic (quadratic_path, middle);	+ 			e = (!) e.next; 		} 		@@ -996,7 +1028,7 @@ public class Path { 		eh = ((!)quadratic_path.points.last ().prev).data.get_right_handle (); 		eh.set_point_type (PointType.CUBIC); 		eh.length *= 1.6;-+*/ 		return quadratic_path; 	} @@ -1061,6 +1093,7 @@ public class Path { 			} else { 				e = (!) e.next; 			}+ 		} 				 		return need_split;	@@ -1077,9 +1110,11 @@ public class Path { 		EditPoint stop; 		PointType rt = middle.get_right_handle ().type; 		+		/* // FIXME: DELETE 		if (rt == PointType.QUADRATIC || rt == PointType.LINE_CUBIC || rt == PointType.LINE_QUADRATIC) { 			return false; 		}+		*/ 		 		start = middle.get_prev ().data; 		stop = middle.get_next ().data;diff --git a/libbirdfont/PenTool.vala b/libbirdfont/PenTool.valaindex b1909ed..0663d52 100644--- a/libbirdfont/PenTool.vala+++ b/libbirdfont/PenTool.vala@@ -178,7 +178,11 @@ public class PenTool : Tool { 			if (selected_handle.type == PointType.LINE_QUADRATIC) { 				selected_handle.set_point_type (PointType.QUADRATIC); 			}-				++			if (selected_handle.type == PointType.LINE_DOUBLE_CURVE) {+				selected_handle.set_point_type (PointType.DOUBLE_CURVE);+			}+							 			if (GridTool.is_visible ()) { 				coordinate_x = Glyph.path_coordinate_x (x); 				coordinate_y = Glyph.path_coordinate_y (y);diff --git a/libbirdfont/Svg.vala b/libbirdfont/Svg.valaindex 797952a..1ecbeb2 100644--- a/libbirdfont/Svg.vala+++ b/libbirdfont/Svg.vala@@ -84,6 +84,8 @@ class Svg { 			add_abs_line_to (start, end, svg, g, do_glyph); 		} else if (end.left_handle.type == PointType.QUADRATIC || start.right_handle.type == PointType.QUADRATIC) { 			add_quadratic_abs_path (start, end, svg, g, do_glyph);+		} else if (end.left_handle.type == PointType.DOUBLE_CURVE || start.right_handle.type == PointType.DOUBLE_CURVE) {+			add_double_quadratic_abs_path (start, end, svg, g, do_glyph); 		} else { 			add_cubic_abs_path (start, end, svg, g, do_glyph); 		}@@ -133,6 +135,20 @@ class Svg { 		} 	} 	+	private static void add_double_quadratic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) {+		EditPoint middle;+		double x, y;+		+		x = start.get_right_handle ().x () + (end.get_left_handle ().x () - start.get_right_handle ().x ()) / 2;+		y = start.get_right_handle ().y () + (end.get_left_handle ().y () - start.get_right_handle ().y ()) / 2;+		+		middle = new EditPoint (x, y, PointType.QUADRATIC);+		middle.right_handle = end.get_left_handle ().copy ();+		+		add_quadratic_abs_path (start, middle, svg, g, to_glyph);+		add_quadratic_abs_path (middle, end, svg, g, to_glyph);+	}+		 	private static void add_quadratic_abs_path (EditPoint start, EditPoint end, StringBuilder svg, Glyph g,  bool to_glyph) { 		double left = g.left_limit; 		double baseline = BirdFont.get_current_font ().base_line;diff --git a/libbirdfont/Toolbox.vala b/libbirdfont/Toolbox.valaindex 4d00162..2695eca 100644--- a/libbirdfont/Toolbox.vala+++ b/libbirdfont/Toolbox.vala@@ -47,7 +47,7 @@ public class Toolbox : GLib.Object  { 	 	ImageSurface? toolbox_background = null; 	-	public static bool use_quadratic_bezierpoints = false;+	public static PointType point_type = PointType.CUBIC; 	 	public Toolbox (GlyphCanvas main_glyph_canvas) { 		glyph_canvas = main_glyph_canvas;@@ -134,16 +134,23 @@ public class Toolbox : GLib.Object  { 		// quadratic Bézier points 		Tool quadratic_points = new Tool ("quadratic_points", _("Create quadratic Bézier curves")); 		quadratic_points.select_action.connect ((self) => {-			Toolbox.use_quadratic_bezierpoints = true;+			point_type = PointType.QUADRATIC; 		}); 		draw_tool_modifiers.add_tool (quadratic_points);		 		 		// cubic Bézier points 		Tool cubic_points = new Tool ("cubic_points", _("Create cubic Bézier curves")); 		cubic_points.select_action.connect ((self) => {-			Toolbox.use_quadratic_bezierpoints = false;+			point_type = PointType.CUBIC; 		}); 		draw_tool_modifiers.add_tool (cubic_points);++		// two quadratic points off curve for each quadratic control point+		Tool double_points = new Tool ("double_points", _("Quadratic double point"));+		double_points.select_action.connect ((self) => {+			point_type = PointType.DOUBLE_CURVE;+		});+		draw_tool_modifiers.add_tool (double_points); 		 		// path tools 		Tool union_paths_tool = new MergeTool ("union_paths");@@ -598,11 +605,9 @@ public class Toolbox : GLib.Object  { 		idle.attach (null); 	} -	/**-	 * @return true if new points should be quadratic instead of cubic.-	 */-	public static bool use_quadratic_points () {-		return use_quadratic_bezierpoints;+	/** Insert new points of this type. */+	public static PointType get_selected_point_type () {+		return point_type; 	} 	 	public void key_press (uint keyval) {

Contact

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