Clone in a terminal:
GsubTable.vala
/*
	Copyright (C) 2012 2013 2014 2015 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.
*/
using Math;

namespace BirdFont {

public class GsubTable : OtfTable {
	
	GlyfTable glyf_table;
	
	public GsubTable (GlyfTable glyf_table) {
		this.glyf_table = glyf_table;
		id = "GSUB";
	}
	
	public override void parse (FontData dis) throws GLib.Error {
	}

	public void process () throws GLib.Error {
		FontData fd;
		
		fd = new FontData ();
		CligFeature clig_feature = new CligFeature (glyf_table);

		Lookups lookups = new Lookups ();
		FeatureList features = new FeatureList ();

		bool has_clig = clig_feature.contextual.has_ligatures ()
			|| clig_feature.has_regular_ligatures ();
			
		if (has_clig) {
			Lookups clig_lookups = clig_feature.get_lookups ();
			Feature clig_feature_lookup = new Feature ("clig", lookups);
			
			if (clig_feature.contextual.has_ligatures ()) {
				clig_feature_lookup.add_feature_lookup ("chain context");
			}
				
			if (clig_feature.has_regular_ligatures ()) {
				clig_feature_lookup.add_feature_lookup ("ligatures");
			}
			
			features.add (clig_feature_lookup);
			lookups.append (clig_lookups);
		}
		
		add_alternate_table (features, lookups, "swsh");
		add_alternate_table (features, lookups, "salt");
		add_alternate_table (features, lookups, "c2sc");
		add_alternate_table (features, lookups, "smcp");
	
		FontData feature_tags = features.generate_feature_tags ();

		uint feature_list_offset = 28 + 2 * features.features.size;
		uint lookup_list_offset = feature_list_offset + feature_tags.length_with_padding ();
		
		fd.add_ulong (0x00010000); // table version
		fd.add_ushort (10); // offset to script list
		fd.add_ushort ((uint16) feature_list_offset); // offset to feature list
		fd.add_ushort ((uint16) lookup_list_offset); // offset to lookup 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
		
		// script table
		fd.add_ushort (4); // offset to default language system
		fd.add_ushort (0); // number of languages
		
		// LangSys table 
		fd.add_ushort (0); // reserved
		fd.add_ushort (0xFFFF); // required features (0xFFFF is none)
		fd.add_ushort ((uint16) features.features.size); // number of features

		// FIXME: double check this
		for (int i = 0; i < features.features.size; i++) {
			fd.add_ushort ((uint16) i); // feature index
		}

		// feature lookups with references to the lookup list
		fd.append (feature_tags);

		if (lookup_list_offset != fd.length_with_padding ()) {
			warning (@"Bad offset to lookup list: $(lookup_list_offset) != $(fd.length_with_padding ())");
		}

		// lookup list and the table data
		FontData lookup_list = lookups.generate_lookup_list ();
		fd.append (lookup_list);
		
		fd.pad ();
		
		this.font_data = fd;
	}

	/** Add alterate substitutions to lookups and features. */
	public void add_alternate_table (FeatureList features, Lookups lookups, string tag) 
	throws GLib.Error {
		AlternateFeature alt = new AlternateFeature (glyf_table, tag);
		if (alt.has_alternates ()) {			
			Lookups alt_lookup = alt.get_lookups ();
			Feature alt_feature_lookup = new Feature (tag, lookups);
			alt_feature_lookup.add_feature_lookup (tag);
			features.add (alt_feature_lookup);	
			lookups.append (alt_lookup);
		}
	}

}

}

Contact

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