Pomax / lib-font

This library adds a new Font() object to the JavaScript toolbox, similar to new Image() for images
MIT License
734 stars 72 forks source link

GSUB things #89

Closed Pomax closed 4 years ago

Pomax commented 4 years ago

This is turning into quite a bit of work, the GSUB tables are fairly ludicrous =P

consider this a work in progress, but even with something like ArrowType's "Recursive" we already see that ffi lligatures are far more of a challenge than expected. For instance, let's admire this output

>node test.js
font supports 'f': true (glyphid: 300)
font supports 'l': true (glyphid: 330)
font supports 'i': true (glyphid: 312)
[DFLT:dflt:afrc] add 293 to [533-535,553-558]
[DFLT:dflt:case] add 43 to [560-560,563-564,566-571,585-588,598-598,600-602,606-606,612-613,617-629,631-635,694-698]
[DFLT:dflt:dnom] add 11 to [520-529,1255-1255]
[DFLT:dflt:liga] has ligature sequence: {300,300,946} -> 734 (= 'f' + 'f' + '??' -> '??')
[DFLT:dflt:liga] has ligature sequence: {300,300,964} -> 735 (= 'f' + 'f' + '??' -> '??')
[DFLT:dflt:liga] has ligature sequence: {300,946} -> 732 (= 'f' + '??' -> '??')
[DFLT:dflt:liga] has ligature sequence: {300,964} -> 733 (= 'f' + '??' -> '??')
[DFLT:dflt:numr] add 11 to [520-529,1255-1255]
[DFLT:dflt:ordn] add 2 to [240,346]
[DFLT:dflt:pnum] add 735 to [521]
[DFLT:dflt:sinf] add 11 to [520-529,1255-1255]
[DFLT:dflt:ss01] add 929 to [240-264]
[DFLT:dflt:ss02] add 8 to [301-307,1062-1062]
[DFLT:dflt:ss03] add 2 to [300,1061]
[DFLT:dflt:ss05] add 16 to [330-335,463-464,1077-1082,1092-1093]
[DFLT:dflt:ss06] add 16 to [380-387,1083-1090]
[DFLT:dflt:ss07] add 26 to [962-963,1022-1043,1048-1048,1051-1051]
[DFLT:dflt:ss08] add 13 to [98-103,213-217,228-228,1039-1039]
[DFLT:dflt:ss09] add 6 to [526,529,539,542,549,552]
[DFLT:dflt:ss10] add 10 to [520,536,543,829,836,857,860,1255,1257,1258]
[DFLT:dflt:ss11] add 2 to [521,1256]
[DFLT:dflt:ss12] add 2 to [606,790]
[DFLT:dflt:ss20] add 10 to [520,536,543,829,836,857,860,1255,1257,1258]
[DFLT:dflt:sups] add 11 to [520-529,1255-1255]
[DFLT:dflt:titl] add 954 to [147]
[DFLT:dflt:zero] add 10 to [520,536,543,829,836,857,860,1255,1257,1258]
[latn:dflt:afrc] add 293 to [533-535,553-558]
[latn:dflt:case] add 43 to [560-560,563-564,566-571,585-588,598-598,600-602,606-606,612-613,617-629,631-635,694-698]
[latn:dflt:dnom] add 11 to [520-529,1255-1255]
[latn:dflt:liga] has ligature sequence: {300,300,946} -> 734 (= 'f' + 'f' + '??' -> '??')
[latn:dflt:liga] has ligature sequence: {300,300,964} -> 735 (= 'f' + 'f' + '??' -> '??')
[latn:dflt:liga] has ligature sequence: {300,946} -> 732 (= 'f' + '??' -> '??')
[latn:dflt:liga] has ligature sequence: {300,964} -> 733 (= 'f' + '??' -> '??')
[latn:dflt:numr] add 11 to [520-529,1255-1255]
[latn:dflt:ordn] add 2 to [240,346]
[latn:dflt:pnum] add 735 to [521]
[latn:dflt:sinf] add 11 to [520-529,1255-1255]
[latn:dflt:ss01] add 929 to [240-264]
[latn:dflt:ss02] add 8 to [301-307,1062-1062]
[latn:dflt:ss03] add 2 to [300,1061]
[latn:dflt:ss05] add 16 to [330-335,463-464,1077-1082,1092-1093]
[latn:dflt:ss06] add 16 to [380-387,1083-1090]
[latn:dflt:ss07] add 26 to [962-963,1022-1043,1048-1048,1051-1051]
[latn:dflt:ss08] add 13 to [98-103,213-217,228-228,1039-1039]
[latn:dflt:ss09] add 6 to [526,529,539,542,549,552]
[latn:dflt:ss10] add 10 to [520,536,543,829,836,857,860,1255,1257,1258]
[latn:dflt:ss11] add 2 to [521,1256]
[latn:dflt:ss12] add 2 to [606,790]
[latn:dflt:ss20] add 10 to [520,536,543,829,836,857,860,1255,1257,1258]
[latn:dflt:sups] add 11 to [520-529,1255-1255]
[latn:dflt:titl] add 954 to [147]
[latn:dflt:zero] add 10 to [520,536,543,829,836,857,860,1255,1257,1258]

Note those ligatures showing ??... that's because there's seemingly nothing to look up. These are ligatures composed of normal letters f (glyphid 300) but definitely-not-the-normal letters i (id=312) and l (id=330), instead they use glyph 946 ("i.italic") and glyph 964 ("l.italic"), and I'm pretty sure the substitution from plain to italic is somewhere in those lookuptype1 rules, but that's a lot of reverse lookup...

Note that this PR is substantial, and yet still only covers part of the work.

Pomax commented 4 years ago

Note that perhaps it's time to start ignoring Recursive, because OpenSans gives this now:

>node test\gsub\test.elaborate.js

font supports 'f': true (glyphid: 73)
font supports 'i': true (glyphid: 76)
[latn:dflt:lnum] add 10 to [899-908]
[latn:dflt:onum] add 10 to [19-28]
[latn:dflt:onum] add 10 to [19-19,21-28,898-898]
[latn:dflt:pnum] add 1 to [20]
[latn:dflt:liga] has ligature sequence: {73,73,79} -> 606 (= 'f' + 'f' + 'l' -> 'ffl')
[latn:dflt:liga] has ligature sequence: {73,73,76} -> 605 (= 'f' + 'f' + 'i' -> 'ffi')
[latn:dflt:liga] has ligature sequence: {73,73} -> 909 (= 'f' + 'f' -> 'ff')
[latn:dflt:liga] has ligature sequence: {73,79} -> 565 (= 'f' + 'l' -> 'fl')
[latn:dflt:liga] has ligature sequence: {73,76} -> 564 (= 'f' + 'i' -> 'fi')
[latn:dflt:salt] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:dflt:salt] add 20 to [918-937]
[latn:dflt:ss01] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:dflt:ss01] add 20 to [918-937]
[latn:dflt:ss02] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:dflt:ss03] add 20 to [918-937]
[latn:dflt:tnum] add 10 to [899-908]
[latn:dflt:tnum] add 1 to [898]
[latn:MOL :lnum] add 10 to [899-908]
[latn:MOL :locl] add 4 to [292-293,329-330]
[latn:MOL :onum] add 10 to [19-28]
[latn:MOL :onum] add 10 to [19-19,21-28,898-898]
[latn:MOL :pnum] add 1 to [20]
[latn:MOL :liga] has ligature sequence: {73,73,79} -> 606 (= 'f' + 'f' + 'l' -> 'ffl')
[latn:MOL :liga] has ligature sequence: {73,73,76} -> 605 (= 'f' + 'f' + 'i' -> 'ffi')
[latn:MOL :liga] has ligature sequence: {73,73} -> 909 (= 'f' + 'f' -> 'ff')
[latn:MOL :liga] has ligature sequence: {73,79} -> 565 (= 'f' + 'l' -> 'fl')
[latn:MOL :liga] has ligature sequence: {73,76} -> 564 (= 'f' + 'i' -> 'fi')
[latn:MOL :salt] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:MOL :salt] add 20 to [918-937]
[latn:MOL :ss01] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:MOL :ss01] add 20 to [918-937]
[latn:MOL :ss02] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:MOL :ss03] add 20 to [918-937]
[latn:MOL :tnum] add 10 to [899-908]
[latn:MOL :tnum] add 1 to [898]
[latn:ROM :lnum] add 10 to [899-908]
[latn:ROM :locl] add 4 to [292-293,329-330]
[latn:ROM :onum] add 10 to [19-28]
[latn:ROM :onum] add 10 to [19-19,21-28,898-898]
[latn:ROM :pnum] add 1 to [20]
[latn:ROM :liga] has ligature sequence: {73,73,79} -> 606 (= 'f' + 'f' + 'l' -> 'ffl')
[latn:ROM :liga] has ligature sequence: {73,73,76} -> 605 (= 'f' + 'f' + 'i' -> 'ffi')
[latn:ROM :liga] has ligature sequence: {73,73} -> 909 (= 'f' + 'f' -> 'ff')
[latn:ROM :liga] has ligature sequence: {73,79} -> 565 (= 'f' + 'l' -> 'fl')
[latn:ROM :liga] has ligature sequence: {73,76} -> 564 (= 'f' + 'i' -> 'fi')
[latn:ROM :salt] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:ROM :salt] add 20 to [918-937]
[latn:ROM :ss01] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:ROM :ss01] add 20 to [918-937]
[latn:ROM :ss02] add 5 to [74-74,223-223,225-225,227-227,229-229]
[latn:ROM :ss03] add 20 to [918-937]
[latn:ROM :tnum] add 10 to [899-908]
[latn:ROM :tnum] add 1 to [898]
RoelN commented 4 years ago

These last few commits seem to nail it, for lookup types 1 and 4! Thanks for the hard work, @Pomax. Some local testing shows results making sense!

The reason why Recursive seems to be off, is that it doesn't contain ligatures for regular characters, only for regular characters plus replaced glyphs (for example f,f,i.italic). For current Wakamai Fondue, it would suffice to not count this as a ligature as it reports only on character level.

That said, I would love to think of a way to show this without using the glyphs concept. It looks like the ffi ligature is only used when the CRSV axis is fully on (1). In that mode, the f remains the same glyph, but the i changes shape. So indeed to this ligature to kick in, the sequence is f,f,i.italic. How do you explain that? "The follow ligatures are only shown when CRSV is activated"? (Or for that matter, ss04 or any other feature that changes a character's default glyph to an alternative one)

@arrowtype Any thoughts on this?

Pomax commented 4 years ago

You'd need to actually run through full GSUB in reverse but yeah as information that sounds about right "ligature: ffi notes: CRSV=1" maybe?

arrowtype commented 4 years ago

Sorry, the Recursive ligatures are maybe a bit of a tricky edge case.

The ligatures are activate in two conditions:

Basically, these are ligatures that happen in Italic but not Roman styles.

image

RoelN commented 4 years ago

Thanks for confirming, @arrowtype!