In reply to Kerning the Impossible:
sim: the typeface for the samples (except for the 18x8 one) is the xterm 'Default' font, with some modifications (the ligatures, for instance, I drew from scratch).
sgh: The basic procedure is the kerning; the ligatures are done afterwards as contextual glyph substitutions conditional upon spacing. For instance, one of the rules in the 'ligatures' file is "f-i** fi", meaning "an 'i' preceded by an 'f' kerned close, followed by anything, is replaced by the glyph from 'li_fi.pbm'". Some of the ligatures are three-character, and the ligatures file consists of a series of rules whose order in the file determines precedence. For instance, higher up the file is the rule "f-f-i ffi", which uses a different glyph for the middle 'f' of 'ffi' to that which would be used for the 'f' of 'fi' otherwise. When making the ligatures, I have been careful to ensure that any two compatible ligatures have a combined three-character ligature (not always the same as the ligatures that make it up), such as fth. There is one exception, Fth, because the 't' of Ft is smaller than normal; in Fth only the th is ligated. I should add that technically many of the so-called 'ligatures' are really only glyph substitutions, because the characters that comprise them are not joined together.
The algorithm to calculate the spacing makes use of the fact that the only thing that 'matters' to a character spacing-wise is the position of the character before it. So, it works along from left to right, at each point holding a table of the best score for each of the three positions of the last character (-1, 0, and +1 px). Then, for each of the three possible positions of the next character, it works out the new score (so that's 9 combinations, and for each it just adds one kerning-pair-score to one score from the table), and finds which score is best for each next-character-position, and those new best scores go in the table. All of this takes constant time per character, so traversing the whole string should take O(n) time.
When it gets to the end, it just has to pick whichever of the three scores is best, and work backwards along the string reconstructing the deviation of each character. The current implementation does this by attaching the deviation values for the whole string to each of the three table entries, which means those values have to be copied for the table updates - which means the current implementation is actually O(n^2) - but it should be possible to store a kind of 'trellis' that can be traced backwards in O(n) time. I just haven't got around to putting in the effort since it's already fast enough for 80 columns.
The action-at-a-distance effect is difficult to get rid of - or rather, forcing changes to be local would tend to give very poor kerning. For instance, when you start typing your hhhh... it doesn't know whether you're going to follow that with iiii... or mmmm..., so it has no idea whether to give you plenty of space (by pushing all the h left) or plenty of anti-space (by pushing them right). So, you find you've typically only got about half as much 'flexibility' to work with. Certainly, it could be done, but I find that one rapidly gets used to bits of the display 'wobbling' as you type - it's not as distracting as you'd think. (Playing NetHack with it, on the other hand... now /that's/ impossible)