Clone in a terminal:
Commit 6022f25
Johan Mattsson - 2022-04-09T17:20:56+00:00
6022f25bef8bf409bb52391903e3ec21db1ffe41johan.mattsson.m@gmail.com

Add support for FK kerning table

Changed files (6)

Diff

diff --git a/libbirdfont/OpenFontFormat/DirectoryTable.vala b/libbirdfont/OpenFontFormat/DirectoryTable.valaindex 6fe14ec..37109be 100644--- a/libbirdfont/OpenFontFormat/DirectoryTable.vala+++ b/libbirdfont/OpenFontFormat/DirectoryTable.vala@@ -19,6 +19,7 @@ public class DirectoryTable : OtfTable { 	 	public CmapTable cmap_table; 	public CvtTable  cvt_table;+	public FkTable fk_table;	 	public GaspTable gasp_table; 	public GdefTable gdef_table; 	public GlyfTable glyf_table;@@ -57,6 +58,7 @@ public class DirectoryTable : OtfTable { 		name_table = new NameTable (); 		os_2_table = new Os2Table (glyf_table, hmtx_table, hhea_table);  		post_table = new PostTable (glyf_table);+		fk_table = new FkTable (glyf_table, kern_table); 		 		id = "Directory table"; 		@@ -96,6 +98,8 @@ public class DirectoryTable : OtfTable { 		if (tables.size == 0) { 			tables.add (offset_table); 			tables.add (this);++			tables.add (fk_table); 			 			tables.add (gpos_table); 			tables.add (gsub_table);@@ -154,8 +158,13 @@ public class DirectoryTable : OtfTable { 			length = dis.read_ulong (); 			 			printd (@"$(tag.str) \toffset: $offset \tlength: $length \tchecksum: $checksum.\n");-			-			if (tag.str == "cvt") {++			if (tag.str == "FK  ") {+				fk_table.id = tag.str;+				fk_table.checksum = checksum;+				fk_table.offset = offset;+				fk_table.length = length;+			} else if (tag.str == "cvt") { 				cvt_table.id = tag.str; 				cvt_table.checksum = checksum; 				cvt_table.offset = offset;@@ -262,8 +271,20 @@ public class DirectoryTable : OtfTable { 		if (kern_table.has_data ()) { 			cvt_table.parse (dis); 		}+		+		if (fk_table.has_data ()) {+			fk_table.parse (dis);+		} 	}-	++	public void parse_fk_table (FontData dis) throws Error {+		if (fk_table.has_data ()) {+			fk_table.parse (dis);+		} else {+			warning ("Fk table is empty.");+		}+	}+		 	public void parse_kern_table (FontData dis) throws Error { 		if (kern_table.has_data ()) { 			kern_table.parse (dis);@@ -352,7 +373,12 @@ public class DirectoryTable : OtfTable { 				warning ("kern_table has invalid checksum"); 				valid = false; 			}-			++			if (fk_table.has_data () && !fk_table.validate (dis)) {+				warning ("fk_table has invalid checksum");+				valid = false;+			}+						 			if (!gpos_table.validate (dis)) { 				warning (@"gpos_table has invalid checksum"); 				diff --git a/libbirdfont/OpenFontFormat/FkKern.vala b/libbirdfont/OpenFontFormat/FkKern.valanew file mode 100644index 0000000..25217b8--- /dev/null+++ b/libbirdfont/OpenFontFormat/FkKern.vala@@ -0,0 +1,45 @@+/*+	Copyright (C) 2022 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 FkKern : GLib.Object {+	public int left;+	public int right;+	public double kerning;+	+	public FkKern (int l, int r, double k) {+		if (l < 0) {+			warning ("Negative gid (left)");+		}++		if (r < 0) {+			warning ("Negative gid (right)");+		}+		+		left = l;+		right = r;+		kerning = k;+	}+	+	public FkKern copy () {+		return new FkKern (left, right, kerning);+	}+	+	public string to_string () {+		return @"left: $left, right: $right, kerning: $kerning";+	}+}++}diff --git a/libbirdfont/OpenFontFormat/FkTable.vala b/libbirdfont/OpenFontFormat/FkTable.valanew file mode 100644index 0000000..449ec19--- /dev/null+++ b/libbirdfont/OpenFontFormat/FkTable.vala@@ -0,0 +1,150 @@+/*+	Copyright (C) 2022 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 FkTable : OtfTable {+	GlyfTable glyf_table;+	KernTable kern_table;++	public FkTable (GlyfTable glyf_table, KernTable kern_table) {+		this.glyf_table = glyf_table;+		this.kern_table = kern_table;+		id = "FK  ";+	}++	public static int32 to_fixed (double d) {+		int32 val = (int32) Math.floor (d);+		int32 mant = (int32) Math.floor (0x10000 * (d - val));+		val = (val << 16) | mant;+		return val;+	}++	public static double from_fixed (int32 val) {+		return val / 65536.0;+	}+	+	public override void parse (FontData dis) throws GLib.Error {+		uint16 version_upper;+		uint16 version_lower;++		uint32 n_pairs;+			+		dis.seek (offset);+		+		version_upper = dis.read_ushort ();+		version_lower = dis.read_ushort ();++		if (!(version_upper == 1 && version_lower == 0)) {+			warning (@"Expecting version 1.0. Found version: $version_upper.$version_lower");+			return;+		}+		+		n_pairs = dis.read_ulong ();+		+		printd (@"Pairs in fk table $n_pairs\n");++		uint32 gid1 = -1;+		uint32 gid2 = -1;+		int32 k = -1;+		double kerning = -1;+				+		for (uint32 i = 0; i < n_pairs; i++) {+			gid1 = dis.read_ulong ();+			gid2 = dis.read_ulong ();+			k = dis.read_int32 ();+			kerning = from_fixed (k);+			kern_table.fk_kerning.add (new FkKern ((int) gid1, (int) gid2, kerning));+		}+		+		if (dis.get_read_pos () != dis.length_with_padding ()) {+			warning (@"Data left in fk table. Read pos $(dis.get_read_pos ()), length: $(dis.length_with_padding ())");+		}+	}+	+	public void process () throws GLib.Error {+		FontData fd = new FontData ();+		KerningClasses classes = BirdFont.get_current_font ().get_kerning_classes ();+		+		fd.add_ushort (1); // version upper+		fd.add_ushort (0); // version lower++		write_kerning_pairs(fd);++		fd.pad ();+		this.font_data = fd;+	}++	public void write_kerning_pairs (FontData fd) throws GLib.Error { +		KerningClasses classes = BirdFont.get_current_font ().get_kerning_classes ();+		Gee.ArrayList<FkKern> pairs = new Gee.ArrayList<FkKern> ();+		+		classes.each_pair ((g1, g2, kerning) => {+			int gid1 = glyf_table.get_gid (g1);+			int gid2 = glyf_table.get_gid (g2);+			+			if (gid1 == -1) {+				warning (@"Glyph id not found for $g1");+				return;+			}++			if (gid2 == -1) {+				warning (@"Glyph not found for $g2");+				return;+			}+						+			pairs.add (new FkKern ((int) gid1, (int) gid2, kerning));+		});++		pairs.sort ((a, b) => {+			FkKern first = (FkKern) a;+			FkKern next = (FkKern) b;+			+			if (first.left == next.left) {+				return first.right - next.right;+			}+			+			return first.left - next.left;+		});++		uint32 num_pairs = (uint32) pairs.size;+		fd.add_ulong (num_pairs);+						+		foreach (FkKern k in pairs) {+			write_pair (fd, k.left, k.right, k.kerning);+		}+	}+	+	public void write_pair (FontData fd, int gid1, int gid2, double kerning) throws GLib.Error {+		if (gid1 < 0) {+			warning (@"Negative gid1.");+			throw new FileError.FAILED (@"gid1 is $gid1");+		}++		if (gid2 < 0) {+			warning (@"Negative gid2.");+			throw new FileError.FAILED (@"gid2 is $gid2");+		}+	+		int32 fixed_kerning = to_fixed (kerning * HeadTable.UNITS);+	+		fd.add_ulong ((uint) gid1); // left gid+		fd.add_ulong ((uint) gid2); // right gid+		fd.add_long (fixed_kerning); // kerning+	}+}+++}+diff --git a/libbirdfont/OpenFontFormat/FontData.vala b/libbirdfont/OpenFontFormat/FontData.valaindex 4a42023..3b11a72 100644--- a/libbirdfont/OpenFontFormat/FontData.vala+++ b/libbirdfont/OpenFontFormat/FontData.vala@@ -195,6 +195,15 @@ public class FontData : Object { 		return f; 	} +	public int32 read_int32 () {+		int32 f;+		f = read () << 8 * 3;+		f += read () << 8 * 2;+		f += read () << 8 * 1;+		f += read () << 8 * 0;+		return f;+	}+	 	public uint64 read_uint64 () { 		uint64 f; 		f = (uint64) read () << 8 * 7;@@ -278,7 +287,18 @@ public class FontData : Object { 	public void add_ulong (uint32 d) throws Error { 		add_u32 (d); 	}++	public void add_long (int32 d) throws Error {+		add_32 (d);+	}++	public void add_32 (int32 i) throws GLib.Error {+		uint32 s = (uint16) (i >> 16); 		+		add_u16 ((uint16) s);+		add_u16 ((uint16) (i - (s << 16)));+	}+				 	public void add_byte (uint8 b) throws Error { 		add (b); 	}diff --git a/libbirdfont/OpenFontFormat/KernTable.vala b/libbirdfont/OpenFontFormat/KernTable.valaindex 05b0d82..54b86fa 100644--- a/libbirdfont/OpenFontFormat/KernTable.vala+++ b/libbirdfont/OpenFontFormat/KernTable.vala@@ -27,7 +27,9 @@ public class KernTable : OtfTable { 	KernList pairs; 	 	// Only used for loading pairs-	public Gee.ArrayList<Kern> kerning = new Gee.ArrayList<Kern> (); // TODO: replace with the KernList+	public Gee.ArrayList<Kern> kerning = new Gee.ArrayList<Kern> ();+	public Gee.ArrayList<FkKern> fk_kerning = new Gee.ArrayList<FkKern> (); // Also only used for loading pairs+		 	public uint kerning_pairs = 0; 	 	public KernTable (GlyfTable gt) {diff --git a/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala b/libbirdfont/OpenFontFormat/OpenFontFormatReader.valaindex a6824bf..7e1ec30 100644--- a/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala+++ b/libbirdfont/OpenFontFormat/OpenFontFormatReader.vala@@ -109,7 +109,11 @@ public class OpenFontFormatReader : Object { 	public void parse_head_table () throws Error { 		directory_table.parse_head_table (font_data); 	}-			++	public void parse_fk_table () throws Error {+		directory_table.parse_fk_table (font_data);+	}+	 	public void set_limits () { 		Font f = OpenFontFormatWriter.font; 		@@ -144,6 +148,7 @@ public class OpenFontFormatReader : Object { 			reader.parse_kern_table (); 			reader.parse_cmap_table (); 			reader.parse_head_table ();+			reader.parse_fk_table (); 			 			kern_table = reader.directory_table.kern_table; 			cmap_table = reader.directory_table.cmap_table;@@ -152,33 +157,48 @@ public class OpenFontFormatReader : Object { 			npairs = kern_table.kerning.size; 			 			units_per_em = HeadTable.units_per_em;-			+ 			foreach (Kern k in kern_table.kerning) { 				left = cmap_table.get_char (k.left); 				right = cmap_table.get_char (k.right); 				kerning = 100 * (k.kerning / units_per_em); 				-				if (left <= 0x1F || right <= 0x1F) {-					warning ("Ignoring kerning of control character.");-				} else {-					if (@"$kerning" != "0") {-						bf_kerning.append ("<kerning left=\"");-						bf_kerning.append (BirdFontFile.serialize_unichar (left));-						bf_kerning.append ("\" ");-						bf_kerning.append ("right=\"");-						bf_kerning.append (BirdFontFile.serialize_unichar (right));-						bf_kerning.append ("\" ");-						bf_kerning.append ("hadjustment=\"");-						bf_kerning.append (@"$kerning".replace (",", "."));-						bf_kerning.append ("\" />\n");-					}-				}+				add_kerning (bf_kerning, left, right, kerning); 			}++			foreach (FkKern k in kern_table.fk_kerning) {+				left = cmap_table.get_char (k.left);+				right = cmap_table.get_char (k.right);+				kerning = 100 * (k.kerning / units_per_em);+				+				add_kerning (bf_kerning, left, right, kerning);+			}+			+			printd (@"FK kerning pairs: $(kern_table.fk_kerning.size)\n"); 		} catch (GLib.Error e) { 			warning (@"Failed to parse font. $(e.message)"); 		} 		 		return bf_kerning.str;				 	}++	static void add_kerning (StringBuilder bf_kerning, unichar left, unichar right, double kerning) {+		if (left <= 0x1F || right <= 0x1F) {+			warning ("Ignoring kerning of control character.");+		} else {+			if (@"$kerning" != "0") {+				bf_kerning.append ("<kerning left=\"");+				bf_kerning.append (BirdFontFile.encode ((!) left.to_string ()));+				bf_kerning.append ("\" ");+				bf_kerning.append ("right=\"");+				bf_kerning.append (BirdFontFile.encode ((!) right.to_string ()));+				bf_kerning.append ("\" ");+				bf_kerning.append ("hadjustment=\"");+				bf_kerning.append (@"$kerning".replace (",", "."));+				bf_kerning.append ("\" />\n");+			}+		}+	} }-}++}\ No newline at end of file

Contact

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