Clone in a terminal:
Commit 1ea7c01
Johan Mattsson - 2012-08-11T19:25:59+00:00
1ea7c019a4ac250af6ea32f53eca2af2f7bb9c67johan.mattsson.m@gmail.com

load file argument

Changed files (8)

Diff

diff --git a/src/ExportTool.vala b/src/ExportTool.valaindex 79d3c68..5ce901c 100644--- a/src/ExportTool.vala+++ b/src/ExportTool.vala@@ -109,7 +109,7 @@ class ExportTool : Tool { 				os.put_string (@"d=\"$(glyph_svg)\" id=\"path_$(name)$(pid++)\" />\n"); 				 			}-+			 			os.put_string ("""</g> 			 </svg>""");diff --git a/src/Font.vala b/src/Font.valaindex b71f93d..2f8c5f9 100644--- a/src/Font.vala+++ b/src/Font.vala@@ -64,8 +64,8 @@ class Font : GLib.Object { 	bool ttf_export = true; 	bool svg_export = true; -	bool loading = false; 	OpenFontFormatReader otf;+	bool otf_font = false; 	 	public Font () { 		// positions in pixels at first zoom level@@ -229,7 +229,7 @@ class Font : GLib.Object { 			return (!) get_glyph ("nonmarkingreturn"); 		} 				-		ret = new Glyph ("nonmarkingreturn");+		ret = new Glyph ("nonmarkingreturn", '\r'); 		ret.set_unassigned (true); 		ret.left_limit = 0; 		ret.right_limit = 0;@@ -247,7 +247,7 @@ class Font : GLib.Object { 			return (!) get_glyph ("null"); 		} 		-		n = new Glyph ("null");+		n = new Glyph ("null", '\0'); 		n.set_unassigned (true); 		n.left_limit = 0; 		n.right_limit = 0;@@ -269,7 +269,7 @@ class Font : GLib.Object { 			return (!) get_glyph ("space"); 		} 				-		n = new Glyph ("space");+		n = new Glyph ("space", ' '); 		n.set_unassigned (false); 		n.left_limit = 0; 		n.right_limit = 27;@@ -373,7 +373,7 @@ class Font : GLib.Object { 		GlyphCollection? gc = get_cached_glyph_collection (glyph); 		Glyph? g; 		-		if (gc == null) {+		if (gc == null && otf_font) { 			// load it from otf file if we need to 			g = otf.read_glyph (glyph); 			@@ -676,6 +676,8 @@ class Font : GLib.Object { 	public bool load (string path) { 		bool loaded = false; +		otf_font = false;+ 		while (glyph_names.length () > 0) { 			glyph_names.remove_link (glyph_names.first ()); 		}@@ -743,8 +745,6 @@ class Font : GLib.Object { 	public void loading_finished_callback () { 		add_thumbnail (); 		Preferences.add_recent_files (get_path ());-		loading = false;-		print ("Done Loading.\n"); 	}  	/** Callback function for loading glyph in a separate thread. */@@ -786,41 +786,17 @@ class Font : GLib.Object {  	public bool parse_otf_file (string path) { 		otf = new OpenFontFormatReader ();-		loading = true;+		otf_font = true; 		 		otf.parse_index (path); 		 		foreach (string n in otf.get_all_names ()) { 			glyph_names.append (n); 		}-				-		/*-		ThreadFunc<void*> run = () => {-			string file = (!) font_file;--			try {-				parse_otf_async ((!) font_file);-			} catch (GLib.Error e) {-				stderr.printf (e.message);-			}--			return null;-		}; 		-		try {-			Thread.create<void*> (run, false);-			yield;-		} catch (ThreadError e) {-			stderr.printf ("Thread error: %s\n", e.message);-		}-		*/ 		return true; 	} 	-	void parse_otf_async (string fn) {-		// otf.parse (fn);-	}-	 	/** Measure height of x or other lower case letter. */ 	private double estimate_xheight () { 		Glyph? g;diff --git a/src/Glyph.vala b/src/Glyph.valaindex fd3c1d9..12150c3 100644--- a/src/Glyph.vala+++ b/src/Glyph.vala@@ -89,7 +89,7 @@ class Glyph : FontDisplay { 	 	bool editable = true; 	-	private static List <Glyph> undo_list = new List <Glyph> ();+	private static List<Glyph> undo_list = new List<Glyph> ();  	public Glyph (string name, unichar unichar_code = 0) { 		this.name = name;@@ -1327,7 +1327,7 @@ class Glyph : FontDisplay {  		if (new_point_on_path != null) { 			Path.draw_edit_point_center ((!) new_point_on_path, cr);-		}			+		}  		cr.restore (); 	}diff --git a/src/OpenFontFormatReader.vala b/src/OpenFontFormatReader.valaindex 7268a85..5fea974 100644--- a/src/OpenFontFormatReader.vala+++ b/src/OpenFontFormatReader.vala@@ -106,22 +106,14 @@ class OpenFontFormatReader : Object { 	}  	public void set_limits () {-		IdleSource idle = new IdleSource ();--		idle.set_callback (() => {-			Font f = Supplement.get_current_font ();-			-			f.base_line = 0;-			f.top_position = -get_ascender ();-			f.top_limit = f.top_position - 5;-			f.xheight_position = f.top_position - 5;-			f.bottom_position = -get_descender ();-			f.bottom_limit = f.bottom_position + 5;	--			return false;-		});--		idle.attach (null);+		Font f = Supplement.get_current_font ();+		+		f.base_line = 0;+		f.top_position = -get_ascender ();+		f.top_limit = f.top_position - 5;+		f.xheight_position = f.top_position - 5;+		f.bottom_position = -get_descender ();+		f.bottom_limit = f.bottom_position + 5;	 	}  	public double get_ascender () {diff --git a/src/OpenFontFormatWriter.vala b/src/OpenFontFormatWriter.valaindex 28b6823..7b2ffe1 100644--- a/src/OpenFontFormatWriter.vala+++ b/src/OpenFontFormatWriter.vala@@ -128,12 +128,20 @@ class FontData : Object { 	{		
 		if (unlikely (pos >= len)) {
 			warning ("end of table reached");
-			throw new GLib.FileError.FAILED ("End of table");
+			assert (false);
 		}
 		
 		table_data[pos]= new_data;
 	}
 	
+	public void write_table_data (FontData fd, uint32 offset, uint32 length) {
+		fd.seek (offset);
+		for (uint32 i = 0; i < length; i++) {
+			add (table_data [rp++]);
+		}
+		fd.seek (0);
+	}
+	
 	public void write_table (OtfInputStream dis, uint32 offset, uint32 length) throws Error {
 		uint32 l = length + (length % 4);  // padding after end of table
 		uint8 b;
@@ -192,6 +200,8 @@ class FontData : Object { 		}
 		
 		rp = trp;
+		
+		return;
 	}
 
 	public uint32 check_sum () {
@@ -212,6 +222,7 @@ class FontData : Object { 	public uint8 read () {
 		if (unlikely (rp >= len)) {
 			warning ("end of table reached");
+			//assert (false);
 			return 0;
 		}
 		
@@ -610,7 +621,10 @@ class LocaTable : Table { 		uint32 last = 0;
 		
 		foreach (uint32 o in glyf_table.location_offsets) {
-			warn_if_fail (o % 2 == 0);
+			if (o % 4 != 0) {
+				warning ("glyph is not on a four byte boundry");
+				assert_not_reached ();
+			}
 		}
 	
 		if (head_table.loca_offset_size == 0) {
@@ -648,39 +662,12 @@ class LocaTable : Table { 	}
 }
 
-class Glyf : GLib.Object {
-	
-	public int16 xmin = 0;
-	public int16 ymin = 0;
-	public int16 xmax = 0;
-	public int16 ymax = 0;	
-	
-	List<uint16> end_points = new List<uint16> ();
-	List<uint8> instructions = new List<uint8> ();
-	List<uint8> flags = new List<uint8> ();
-	List<uint16> xcoordinates = new List<uint16> ();
-	List<uint16> ycoordinates = new List<uint16> ();
-		
-	int npoints = 0;
-		
-	int16 ncontours;	
-	uint16 ninstructions;	
-	int nflags;
-	
-	public Glyf () {
-	}
-	
-	public Glyf.process (Glyph g) {
-	
-	}
-
-			
-}
-
 class GlyfTable : Table {
 	
 	// Flags for composite glyph
 	static const uint16 BOTH_ARE_WORDS = 1 << 0;
+	static const uint16 BOTH_ARE_XY_VALUES = 1 << 1;
+	static const uint16 ROUND_TO_GRID = 1 << 2;
 	static const uint16 SCALE = 1 << 3;
 	static const uint16 RESERVED = 1 << 4;
 	static const uint16 MORE_COMPONENTS = 1 << 5;
@@ -716,7 +703,6 @@ class GlyfTable : Table { 
 	Mutex read_lock;
 	int64 next_index = -1;
-	List<int> loca_index = new List<int> ();
 	
 	public GlyfTable (LocaTable l) {
 		id = "glyf";
@@ -823,51 +809,6 @@ class GlyfTable : Table { 		this.dis = dis;
 		
 		// post_table.print_all ();
-		
-		// create a list of indices since we might read them in a different order
-		for (i = 0; i < loca.size; i++) {
-			loca_index.append (i);
-		}
-		// read_lock.unlock ();
-/*				
-		while (true) {
-			read_lock.lock ();
-			
-			if (loca_index.length () == 0) {
-				break;
-			}
-
-			ind = loca_index.first ();
-			i = ind.data;
-
-			try {
-				glyph = parse_index (i, dis, loca, hmtx_table, head_table, post_table);
-				add_glyph (glyph);
-				
-				if (next_index != -1) {
-					i = (int) next_index;
-				}
-				
-				glyph = parse_index (i, dis, loca, hmtx_table, head_table, post_table);
-				add_glyph (glyph);				
-			} catch (Error e) {
-				stderr.printf (@"Cmap length $(cmap_table.get_length ()) glyfs\n");
-				stderr.printf (@"Loca size: $(loca.size)\n");
-				stderr.printf (@"Glyph name: $(post_table.get_name (i))\n");
-				stderr.printf (@"\n");
-				stderr.printf (@"Falied to parse glyf: $(e.message)\n");
-				
-				break;
-			}
-
-			if (i == next_index) {
-				next_index = -1;
-			}
-			
-			loca_index.remove_all (i);
-			read_lock.unlock ();
-		}
-		*/
 	}
 	
 	Glyph parse_index (int index, FontData dis, LocaTable loca, HmtxTable hmtx_table, HeadTable head_table, PostTable post_table) throws GLib.Error {
@@ -877,6 +818,7 @@ class GlyfTable : Table { 		double units_per_em = head_table.get_units_per_em ();
 		unichar character = 0;
 		string name;	
+		uint32 end;
 		
 		character = cmap_table.get_char (index);
 		name = post_table.get_name (index);
@@ -890,22 +832,17 @@ class GlyfTable : Table { 		printd (@"name: $(name)\n");
 
 		if (!loca.is_empty (index)) {	
-			glyph_offset = loca.get_offset(index);
-			
-			glyph = parse_next_glyf (dis, character, glyph_offset, out xmin, out xmax, units_per_em);
+			glyph = parse_next_glyf (dis, character, index, out xmin, out xmax, units_per_em);
 			
 			glyph.left_limit = xmin - hmtx_table.get_lsb (index);
 			glyph.left_limit = 0;
 			glyph.right_limit = glyph.left_limit + hmtx_table.get_advance (index);
 			
-			// DEL: printd (@"$(glyph.right_limit) = $(glyph.left_limit) + $(hmtx_table.get_advance (i))\n");
-			
 			if (xmin > glyph.right_limit || xmax < glyph.left_limit) {
 				warning (@"Glyph $(name) is outside of it's box.");
 				glyph.left_limit = xmin;
 				glyph.right_limit = xmax;
 			}
-			
 		} else {
 			// add empty glyph
 			glyph = new Glyph (name, character);
@@ -932,8 +869,8 @@ class GlyfTable : Table { 	Glyph parse_next_composite_glyf (FontData dis, unichar character) throws Error {
 		uint16 component_flags = 0;
 		uint16 glyph_index;
-		int16 arg1;
-		int16 arg2;
+		int16 arg1 = 0;
+		int16 arg2 = 0;
 		uint16 arg1and2;
 		F2Dot14 scale;
 		
@@ -944,34 +881,47 @@ class GlyfTable : Table { 		F2Dot14 scale10;
 		
 		uint16 num_instructions;
+
+		Glyph glyph, linked_glyph;
+		string link_name;
+		List<int> x = new List<int> ();
+		List<int> y = new List<int> ();
+		List<int> gid = new List<int> ();
+		
+		double xmin, xmax;
+		double units_per_em = head_table.get_units_per_em ();
+		
+		int glid;
 		
-		Glyph glyph;
 		StringBuilder name = new StringBuilder ();
 		name.append_unichar (character);
-
+		
+		glyph = new Glyph (name.str, character);
+		
 		do {
 			component_flags = dis.read_ushort ();
 			glyph_index = dis.read_ushort ();
-
+			
 			if ((component_flags & BOTH_ARE_WORDS) > 0) {
 				arg1 = dis.read_short ();
-				arg1 = dis.read_short ();			
-			} else {
-				arg1and2 = dis.read_ushort ();
+				arg2 = dis.read_short ();			
+			} else if ((component_flags & BOTH_ARE_XY_VALUES) > 0) {
+				arg1 = dis.read_byte ();
+				arg2 = dis.read_byte ();
 			}
 			
+			gid.append (glyph_index);
+			x.append (arg1);
+			y.append (arg2);
+
 			// if ((component_flags & RESERVED) > 0)
 			
 			if ((component_flags & SCALE) > 0) {
 				scale = dis.read_f2dot14 ();
-			}
-
-			if ((component_flags & SCALE_X_Y) > 0) {
+			} else if ((component_flags & SCALE_X_Y) > 0) {
 				scalex = dis.read_f2dot14 ();
 				scaley = dis.read_f2dot14 ();
-			}
-
-			if ((component_flags & SCALE_WITH_ROTATTION) > 0) {
+			} else if ((component_flags & SCALE_WITH_ROTATTION) > 0) {
 				scalex = dis.read_f2dot14 ();
 				scale01 = dis.read_f2dot14 ();
 				scale10 = dis.read_f2dot14 ();
@@ -979,7 +929,16 @@ class GlyfTable : Table { 			}
 			
 		} while ((component_flags & MORE_COMPONENTS) > 0);
+	
 		
+		for (int i = 0; i < gid.length (); i++) {
+			// compensate xmax ymax with coordinate
+			glid = gid.nth (i).data;
+			linked_glyph = parse_next_glyf (dis, character, glid, out xmin, out xmax, units_per_em);
+		}
+
+		
+		/*
 		if ((component_flags & INSTRUCTIONS) > 0) {
 			num_instructions = dis.read_ushort ();
 			
@@ -987,14 +946,13 @@ class GlyfTable : Table { 				dis.read_byte ();
 			}
 		}
-
-		glyph = new Glyph (name.str, character);
+		*/
 		
 		return glyph;
 	}
 	
-	Glyph parse_next_glyf (FontData dis, unichar character, uint32 glyph_offset,
-		out double xmin, out double xmax, double units_per_em) throws Error {
+	Glyph parse_next_glyf (FontData dis, unichar character, int gid, out double xmin, out double xmax, double units_per_em) throws Error 
+	{
 
 		uint16* end_points = null;
 		uint8* instructions = null;
@@ -1015,13 +973,22 @@ class GlyfTable : Table { 		
 		Error? error = null;
 		
+		uint start, end, len;
+		
 		StringBuilder name = new StringBuilder ();
 		name.append_unichar (character);
 
-		dis.seek (offset + glyph_offset);
+		start = loca_table.get_offset (gid);
+		end = loca_table.get_offset (gid + 1);
+		len = start - end;
+
+		dis.seek (offset + start);
 		
 		ncontours = dis.read_short ();
 		
+		return_val_if_fail (start < end, new Glyph.no_lines (""));
+		return_val_if_fail (ncontours < len, new Glyph.no_lines (""));
+		
 		if (ncontours == 0) {
 			warning (@"Got zero contours in glyph $(name.str).");
 
@@ -1058,8 +1025,13 @@ class GlyfTable : Table { 			npoints = 0;
 		}
 		
+		return_val_if_fail (npoints < len, new Glyph.no_lines (""));
+		
 		// FIXA: implement instructions (maybe)
-		ninstructions = dis.read_ushort ();		
+		ninstructions = dis.read_ushort ();
+		
+		return_val_if_fail (ninstructions < len, new Glyph.no_lines (""));
+		
 		instructions = new uint8[ninstructions + 1];
 		uint8 repeat;
 		for (int i = 0; i < ninstructions; i++) {
@@ -1313,7 +1285,7 @@ class GlyfTable : Table { 		
 		g.remove_empty_paths ();
 		if (g.path_list.length () == 0) {
-			// ensure that location_offsets == location_offset + 1 to tell parser that this glyf does not have a body
+			// location_offsets == location_offset + 1 to tell parser that this glyf does not have a body
 			return;
 		}
 		
@@ -1409,6 +1381,7 @@ class GlyfTable : Table { 		
 		fd.seek (glyph_offset + 2); // go to box boundries for this glyf
 		assert (fd.read_short () == 0);
+
 		fd.add_16 (txmin);
 		fd.add_16 (tymin);
 		fd.add_16 (txmax);
@@ -1431,7 +1404,7 @@ class GlyfTable : Table { 		total_width += xmax - xmin;
 		
 		// glyph need padding too for loca table to be correct
-		if (fd.length () % 4 != 0) {
+		while (fd.length () % 4 != 0) {
 			fd.add (0);
 		}
 	}
@@ -1447,7 +1420,7 @@ class GlyfTable : Table { 		glyphs.append (font.get_not_def_character ());
 		//glyphs.append (font.get_null_character ());
 		//glyphs.append (font.get_nonmarking_return ());
-		glyphs.append (font.get_space ());
+		//glyphs.append (font.get_space ());
 			
 		// add glyphs, first all assigned then the unassigned ones
 		for (indice = 0; (gl = font.get_glyph_indice (indice)) != null; indice++) {		
@@ -1466,12 +1439,14 @@ class GlyfTable : Table { 		FontData fd = new FontData ();
 		
 		create_glyph_table ();
-		
+		int i = 0;
 		foreach (Glyph g in glyphs) {
 			// set values for loca table
+			assert (fd.length () % 4 == 0);
 			location_offsets.append (fd.length ());
-			
 			process_glyph (g, fd);
+			
+			print (@"loca fd.length (): $(fd.length ())\n");
 		}
 
 		location_offsets.append (fd.length ()); // last entry in loca table is special
@@ -2004,6 +1979,8 @@ class HeadTable : Table { 		requires (offset > 0 && length > 0) {
 
 		dis.seek (offset);
+		
+		font_data = new FontData ();		
 	
 		version = dis.read_fixed ();
 
@@ -2023,11 +2000,11 @@ class HeadTable : Table { 		flags = dis.read_ushort ();
 		
 		if ((flags & BASELINE_AT_ZERO) > 0) {
-			warning ("Expected flag BASELINE_AT_ZERO  has not been set.");
+			printd ("Flag BASELINE_AT_ZERO has been set.\n");
 		}
 
 		if ((flags & LSB_AT_ZERO) > 0) {
-			warning ("Flags LSB_AT_ZERO has been set.");
+			printd ("Flags LSB_AT_ZERO has been set.\n");
 		}
 		
 		units_per_em = dis.read_ushort ();
@@ -2123,8 +2100,6 @@ class HeadTable : Table { 		font_data.pad ();
 		
 		this.font_data = font_data;
-		
-		printd (@"loca_offset_size: $loca_offset_size\n");
 	}
 }
 
@@ -4550,29 +4525,19 @@ class DirectoryTable : Table { 	
 	public bool validate_tables (FontData dis, File file) {
 		bool valid = true;
-		uint p = head_table.get_checksum_position ();
-		uint32 checksum;
 		
 		try {
 			dis.seek (0);
 			
 			if (!validate_checksum_for_entire_font (dis, file)) {
 				warning ("file has invalid checksum");
+			} else {
+				printd ("Font file has valid checksum.\n");
 			}
-							
-			// zero out checksum entry in head table before validating it
-			dis.write_at (p + 0, 0);
-			dis.write_at (p + 1, 0);
-			dis.write_at (p + 2, 0);
-			dis.write_at (p + 3, 0);	
 
-			checksum = (uint32) dis.check_sum ();	
-			
-			if (checksum != head_table.checksum) {
-				warning ("head_table has is invalid checksum");
-				valid = false;				
-			}
-			
+			// Skip validation of head table for now it should be realy simple but seems to
+			// be broken in some funny way.
+
 			if (!glyf_table.validate (dis)) {
 				warning ("glyf_table has invalid checksum");
 				valid = false;
@@ -4626,7 +4591,6 @@ class DirectoryTable : Table { 	}
 	
 	bool validate_checksum_for_entire_font (FontData dis, File f) {
-		FontData fd = new FontData ();
 		uint p = head_table.offset + head_table.get_checksum_position ();
 		uint32 checksum_font, checksum_head;
 
@@ -4640,7 +4604,7 @@ class DirectoryTable : Table { 		dis.write_at (p + 2, 0);
 		dis.write_at (p + 3, 0);
 		
-		checksum_font = (uint32) (0xB1B0AFBA - fd.check_sum ());
+		checksum_font = (uint32) (0xB1B0AFBA - dis.check_sum ());
 
 		if (checksum_font != checksum_head) {
 			warning (@"Fontfile checksum in head table does not match calculated checksum. checksum_font: $checksum_font checksum_head: $checksum_head");
@@ -4735,11 +4699,11 @@ class DirectoryTable : Table { 	
 }
 
-// users could benifit from error detection and validation at a fine grained level in
+// developers could benifit from error detection and validation at a fine grained level in
 // this class. At some later point should this code present meaningfull info to the user but 
 // for now is the approach just to put a lot of info in the console if we need to do some debugging.
 void printd (string s) {
-	//print (s);
+	print (s);
 }
 
 }
diff --git a/src/OverView.vala b/src/OverView.valaindex a1e4ed5..880be3b 100644--- a/src/OverView.vala+++ b/src/OverView.vala@@ -60,8 +60,6 @@ class OverView : FontDisplay { 		 		if (range == null) { 			gr = new GlyphRange ();-			gr.use_default_range ();-			 			set_glyph_range (gr); 		} 		@@ -97,9 +95,6 @@ class OverView : FontDisplay { 			int64 adjustement = (int64) (-delta_last * get_height ()); 			int64 pixels = (int64) (-5.0 * delta_last * nail_height); 			-			// print (@"(int64) $(-delta_last) * $(over_view.get_height ()) = $adjustement \n");-			// print (@"$delta\n");-	 			if (absolute <= 0.002) { 				first_character = 0; 				first_visible = 0;@@ -978,7 +973,6 @@ class OverView : FontDisplay { 		 		if (all_avail) { 			f = Supplement.get_current_font ();-			print (@"$t >= $(f.length ())\n"); 			return t >= f.length (); 		} 		diff --git a/src/Path.vala b/src/Path.valaindex 38d5084..fbb01d2 100644--- a/src/Path.vala+++ b/src/Path.vala@@ -980,6 +980,7 @@ class Path { 		 	/** Test if @param path is a valid outline for this object. */	 	public bool test_is_outline (Path path) {+		assert (false); 		return this.test_is_outline_of_path (path) && path.test_is_outline_of_path (this); 	} 	diff --git a/src/Svg.vala b/src/Svg.valaindex b19efa7..3cd0fd0 100644--- a/src/Svg.vala+++ b/src/Svg.vala@@ -24,14 +24,9 @@ class Svg { 	/** Export to svg glyph data. */ 	public static string to_svg_glyph (Glyph g, double scale = 1) {	 		StringBuilder svg = new StringBuilder ();+		Glyph gl; 			 		foreach (Path pl in g.path_list) {-			if (pl.points.length () <= 2) {-				continue;-			}-			-			pl.create_list ();-			 			write_path_as_glyph (pl, svg, g, scale); 		} 		@@ -46,19 +41,21 @@ class Svg { 		return svg.str; 	} -	private static void write_path_as_glyph (Path pl, StringBuilder svg, Glyph g, double scale = 1) -		requires (pl.points.length () > 2)-	{+	private static void write_path_as_glyph (Path pl, StringBuilder svg, Glyph g, double scale = 1) { 		write_path (pl, svg, g, true, scale); 	} -	private static void write_path (Path pl, StringBuilder svg, Glyph g, bool do_glyph, double scale = 1) -		requires (pl.points.length () > 2)-	{+	private static void write_path (Path pl, StringBuilder svg, Glyph g, bool do_glyph, double scale = 1) { 		int i = 0; 		EditPoint? n = null; 		EditPoint m; 		+		if (pl.points.length () <= 2) {+			return;+		}+		+		pl.create_list ();+		 		foreach (var e in pl.points) { 			if (i == 0) { 				add_abs_start (e, svg, g, do_glyph, scale);

Contact

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