Clone in a terminal:
Commit 42d3ddb
Johan Mattsson - 2017-06-28T14:49:40+00:00
42d3ddb8d9232bce3cc424a9a1f9d9472bae1359johan.mattsson.m@gmail.com

More kerning pairs in GPOS extension subtable

Changed files (4)

Diff

diff --git a/libbirdfont/OpenFontFormat/GposTable.vala b/libbirdfont/OpenFontFormat/GposTable.valaindex 31ed992..fa1f223 100644--- a/libbirdfont/OpenFontFormat/GposTable.vala+++ b/libbirdfont/OpenFontFormat/GposTable.vala@@ -1,5 +1,5 @@ /*-	Copyright (C) 2012, 2013, 2014 Johan Mattsson+	Copyright (C) 2012 2013 2014 2017 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 @@ -34,14 +34,14 @@ public class GposTable : OtfTable { 		this.glyf_table = glyf_table; 		this.pairs = new KernList (glyf_table); -		printd ("Process GPOS\n");+		printd ("Processing GPOS\n");  		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 (44); // offset to lookup list 		-		// script list ?+		// script list  		fd.add_ushort (1);   // number of items in script list 		fd.add_tag ("DFLT"); // default script 		fd.add_ushort (8);	 // offset to script table from script list@@ -65,33 +65,107 @@ public class GposTable : OtfTable { 		fd.add_ushort (0); // feature prameters (null) 		fd.add_ushort (1); // number of lookups 		fd.add_ushort (0); // lookup index+	+		Gee.ArrayList<FontData> pair_set_data = new Gee.ArrayList<FontData>();		+		pairs.fetch_all_pairs ();+		+		KernSplitter kern_splitter = new KernSplitter (pairs);+		+		while (true) {+			if (offset < 0) {+				break;+			}+			+			KernList pairs_subset = kern_splitter.get_subset (offset);+			+			if (pairs_subset.get_length () == 0) {+				break;+			}+		+			FontData pairs = get_pair_pos_format1 (pairs_subset);+			pair_set_data.add (pairs);+			+			offset += pairs_subset.get_length ();+		}  		 		// lookup table 		fd.add_ushort (1); // number of lookups 		fd.add_ushort (4); // offset to lookup 1 		-		fd.add_ushort (2); // lookup type -		fd.add_ushort (0); // lookup flags-		fd.add_ushort (1); // number of subtables-		fd.add_ushort (8); // array of offsets to subtables+		int16 extention_pos = (int16) (pair_set_data.size * 2); 		-		// MarkFilteringSet +		for (int16 index = 0; index < pair_set_data.size; index++) {+			extention_pos += index * 8;+		}+		+		int64 pair_set_data_length = 0;+		int64 extension_length = 8;+		+		foreach (FontData pair_set in pair_set_data) {+			pair_set_data_length += pair_set.length_with_padding ();+			extension_length += 8;+		}+		+		if (pair_set_data.size > 0) {+			FontData last_pair_set = pair_set_data.get (pair_set_data.size - 1);+			uint64 last_externsion_offset = extension_length + pair_set_data_length; -		fd.append (get_pair_pos_format1 ());+			last_externsion_offset -= 8;+			last_externsion_offset -= last_pair_set.length ();+			+			if (last_externsion_offset > uint32.MAX) {+				warning ("Too manu kerning pairs for the extension positioning table."+					+ @"last_externsion_offset: $last_externsion_offset > "+					+ @"$(uint32.MAX)");+				pair_set_data.clear ();+			}+		}+	+		fd.add_ushort (9); // lookup type +		fd.add_ushort (0); // lookup flags+		fd.add_ushort ((uint16) pair_set_data.size); // number of subtables+			+		if (pair_set_data.size > 0) {+			for (int j = 0; j < pair_set_data.size; j++) {+				uint16 lookup_size = (uint16) pair_set_data.size * 2;+				uint16 offset_to_extension = (uint16) (6 + lookup_size + j * 8);+				fd.add_ushort (offset_to_extension);  // array of offsets to subtables	+			}	+				+			// extension positioning table+			int k = pair_set_data.size - 1;+			while (extension_length > 0 && k >= 0) {+				FontData pair_set = pair_set_data.get (k);+				pair_set_data_length -= pair_set.length ();+				extension_length -= 8;+				+				uint64 externsion_offset = extension_length + pair_set_data_length;+				+				if (externsion_offset > uint32.MAX) {+					warning ("Too manu kerning pairs for extension positioning table.");+				}+				+				fd.add_ushort (1); // format+				fd.add_ushort (2); // lookup type +				fd.add_ulong ((uint32) externsion_offset); // extension offset+				k--;+			}+			+			// MarkFilteringSet ++			foreach (FontData pair_set in pair_set_data) {+				fd.append (pair_set);+			}	+		} 		 		fd.pad ();	 		this.font_data = fd; 	} -	uint16 get_max_pairs () {-		return (uint16) ((uint16.MAX - 10) / 3.0);-	}- 	// PairPosFormat1 subtable-	FontData get_pair_pos_format1 () throws GLib.Error {+	FontData get_pair_pos_format1 (KernList pairs_subset) throws GLib.Error { 		FontData fd = new FontData (); 		uint coverage_offset;-		uint16 max_pairs_per_table = get_max_pairs (); 		uint16 num_pairs; 		int i; 		uint pair_set_offset;@@ -100,26 +174,19 @@ public class GposTable : OtfTable { 		uint last_gid_left; 		uint last_gid_right; 		uint16 pair_set_count;-		-		if (pairs.get_length () == 0) {-			pairs.fetch_all_pairs ();-		}--		// FIXME: add another table instead of truncating it-		if (pairs.get_length () > max_pairs_per_table) {-			warning (@"Too many kerning pairs. $(pairs.get_length ())");-			num_pairs = max_pairs_per_table;-		} -		num_pairs = (pairs.get_length () < max_pairs_per_table) ? -			 (uint16) pairs.get_length () : max_pairs_per_table;+		num_pairs = (uint16) pairs_subset.get_length (); 		-		pair_set_count = (uint16) pairs.get_length_left (); // FIXME: boundaries+		pair_set_count = (uint16) pairs_subset.get_length_left (); // FIXME: boundaries 		-		coverage_offset = 10 + pairs_offset_length () + pairs_set_length ();+		coverage_offset = 10 + pairs_offset_length (pairs_subset) + pairs_set_length (pairs_subset); 		 		if (coverage_offset > uint16.MAX) {-			warning (@"Invalid coverage offset. Number of pairs: $(pairs.get_length ())");+			warning (@"Invalid coverage offset." ++				@"Total: $(pairs.get_length ()), " ++				@"subset: $(pairs_subset.get_length ())" ++				@"coverage_offset: $(coverage_offset) > 65535");+				 			num_pairs = 0; 			coverage_offset = 10; 		}@@ -132,11 +199,11 @@ public class GposTable : OtfTable { 		fd.add_ushort (pair_set_count); // n pairs 		 		// pair offsets orderd by coverage index-		pair_set_offset = 10 + pairs_offset_length ();+		pair_set_offset = 10 + pairs_offset_length (pairs_subset); 		 		written = 0; 		written_pairs = 0;-		pairs.all_pairs_format1 ((k) => {+		pairs_subset.all_pairs_format1 ((k) => { 			try { 				if (pair_set_offset > uint16.MAX) { 					warning ("Invalid offset.");@@ -156,8 +223,8 @@ public class GposTable : OtfTable { 			} 		}, num_pairs); 		-		if (unlikely (written != pairs_offset_length ())) {-			warning (@"Bad pairs_offset_length () calculated: $(pairs_offset_length ()), real length $written");+		if (unlikely (written != pairs_offset_length (pairs_subset))) {+			warning (@"Bad pairs_offset_length () calculated: $(pairs_offset_length (pairs_subset)), real length $written"); 		} 		 		// pair table @@ -165,7 +232,7 @@ public class GposTable : OtfTable { 		written = 0; 		last_gid_left = 0; 		last_gid_right = 0;-		pairs.all_pairs_format1 ((pn) => {+		pairs_subset.all_pairs_format1 ((pn) => { 			try { 				PairFormat1 p = pn; 				uint pairset_length = p.pairs.size;@@ -216,13 +283,13 @@ public class GposTable : OtfTable { 			} 		}, num_pairs); 		-		if (unlikely (pairs_set_length () != written)) {-			warning (@"Bad pair set length: $(pairs_set_length ()), real length: $written");+		if (unlikely (pairs_set_length (pairs_subset) != written)) {+			warning (@"Bad pair set length: $(pairs_set_length (pairs_subset)), real length: $written"); 		} 		 		if (unlikely (fd.length () != coverage_offset)) { 			warning (@"Bad coverage offset, coverage_offset: $coverage_offset, real length: $(fd.length ())");-			warning (@"pairs_offset_length: $(pairs_offset_length ()) pairs_set_length: $(pairs_set_length ())");+			warning (@"pairs_offset_length: $(pairs_offset_length (pairs_subset)) pairs_set_length: $(pairs_set_length (pairs_subset))"); 		} 		 		// coverage@@ -230,7 +297,7 @@ public class GposTable : OtfTable { 		fd.add_ushort (pair_set_count); 		 		written = 0;-		pairs.all_pairs_format1 ((p) => {+		pairs_subset.all_pairs_format1 ((p) => { 			try { 				fd.add_ushort (p.left); // gid 				written += 2;@@ -240,24 +307,24 @@ public class GposTable : OtfTable { 		}, num_pairs); 		 		if (unlikely (written != 2 * pair_set_count)) {-			warning ("written != 2 * pair_set_count");+			warning (@"written != 2 * pair_set_count: $written != 2 * $(pair_set_count)"); 		} 		 		return fd; 	} 	-	public uint pairs_set_length () {+	public static uint pairs_set_length (KernList kerning_list) { 		uint len = 0; 		-		pairs.all_pairs_format1 ((p) => {+		kerning_list.all_pairs_format1 ((p) => { 			len += 2 + 4 * p.pairs.size; 		}); 		 		return len; 	} 	-	public uint pairs_offset_length () {-		return 2 * pairs.pairs.size;+	public static uint pairs_offset_length (KernList kerning_list) {+		return 2 * kerning_list.pairs.size; 	} } diff --git a/libbirdfont/OpenFontFormat/KernList.vala b/libbirdfont/OpenFontFormat/KernList.valaindex 4752a9e..94aae80 100644--- a/libbirdfont/OpenFontFormat/KernList.vala+++ b/libbirdfont/OpenFontFormat/KernList.vala@@ -20,15 +20,15 @@ public class KernList : GLib.Object { 	public delegate void KernIterator (Kern k); 	public delegate void PairFormat1Iterator (PairFormat1 k); -	GlyfTable glyf_table;-	uint num_pairs;+	public GlyfTable glyf_table;+	public uint num_pairs; 	 	public KernList (GlyfTable glyf_table) { 		this.glyf_table = glyf_table; 		num_pairs = 0; 		pairs = new Gee.ArrayList<PairFormat1> ();  	}-	+		 	/** @return number of pairs. */ 	public uint fetch_all_pairs () { 		PairFormat1 current_pairs = new PairFormat1 ();@@ -50,7 +50,7 @@ public class KernList : GLib.Object { 			if (unlikely (kerning_pair.character.get_name () == "")) { 				warning ("No name for glyph"); 			}-+			 			current_pairs = new PairFormat1 (); 			gid_left = (uint16) glyf_table.get_gid (kerning_pair.character.get_name ()); 			current_pairs.left = gid_left;@@ -124,6 +124,18 @@ public class KernList : GLib.Object { 			i++; 		} 	}+	+	public void all_single_kern (PairFormat1Iterator iter) {+		foreach (PairFormat1 p in pairs) {+			foreach (Kern k in p.pairs) {+				PairFormat1 single = new PairFormat1 ();+				single.left = p.left;+				single.pairs.add (k);+				+				iter (single);+			}+		}+	} }  }diff --git a/libbirdfont/OpenFontFormat/KernSplitter.vala b/libbirdfont/OpenFontFormat/KernSplitter.valanew file mode 100644index 0000000..03fd50a--- /dev/null+++ b/libbirdfont/OpenFontFormat/KernSplitter.vala@@ -0,0 +1,76 @@+/*+	Copyright (C) 2017 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 KernSplitter : GLib.Object {+	public Gee.ArrayList<PairFormat1> pairs;+	private KernList source_list;+	+	public KernSplitter (KernList kerning_list) {+		source_list = kerning_list;+		pairs = new Gee.ArrayList<PairFormat1> (); +		+		kerning_list.all_single_kern((pair) => {+			pairs.add (pair);+		});+	}+	+	/** Prevent integer overflow in coverage table of the PairPos1 subtable. */+	public bool is_full (KernList kerning_pairs) {+		uint length = 10;+		length += GposTable.pairs_offset_length (kerning_pairs);+		length += GposTable.pairs_set_length (kerning_pairs);+		+		return length > (uint16.MAX - 10);+	}+	+	public KernList get_subset (uint offset) {+		int count = 0;+		KernList result = new KernList (source_list.glyf_table);+		+		PairFormat1 current = new PairFormat1 ();+		current.left = 0xFFFF;+		+		for (uint i = offset; i < pairs.size; i++) {+			PairFormat1 next = pairs.get ((int) i);+			+			if (is_full (result)) {+				break;+			}+			+			if (next.left != current.left) {+				current = new PairFormat1 ();+				current.left = next.left;+				result.pairs.add (current);+			}+			+			if (unlikely (next.pairs.size != 1)) {+				warning ("Splitting kerning pairs failed. "+					+ @"next.pairs.size: != $(next.pairs.size)");+			}+			+			current.pairs.add (next.pairs.get (0));+			count++;+		}++		foreach (PairFormat1 kerning in result.pairs) {+ 			result.num_pairs += kerning.pairs.size;+ 		}+		+		return result;+	}+}++}diff --git a/libbirdfont/OpenFontFormat/KerningPair.vala b/libbirdfont/OpenFontFormat/KerningPair.valaindex 2f9dc80..6673a0a 100644--- a/libbirdfont/OpenFontFormat/KerningPair.vala+++ b/libbirdfont/OpenFontFormat/KerningPair.vala@@ -21,8 +21,7 @@ namespace BirdFont { public class KerningPair : GLib.Object { 	public Glyph character; 	public Gee.ArrayList<Kerning> kerning;--	Gee.ArrayList<Glyph> right;+	public Gee.ArrayList<Glyph> right; 	 	public KerningPair (Glyph left) { 		character = left;

Contact

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