OpenType - Fractions
Posted: Thu Sep 14, 2017 1:50 pm
The beauty of writing OpenType layout feature code is the fact you can come up with your own implementation of a specific problem.
More and more fonts come with feature code for fractions, some only contain ligatures to standard fractions like 1/2. But there are also several complex solutions which contain a generic solution so they cover a wider range of fractions.
This implementation shows how to add support for fractions supporting just a little more than the basics.
From a mathematical point of view, there is a specific order of precedence in which operations must be done.
The feature code that makes this happen is available here:
Feel free to use this in your own fonts, and if you see room for improvements, let us know!
More and more fonts come with feature code for fractions, some only contain ligatures to standard fractions like 1/2. But there are also several complex solutions which contain a generic solution so they cover a wider range of fractions.
This implementation shows how to add support for fractions supporting just a little more than the basics.
From a mathematical point of view, there is a specific order of precedence in which operations must be done.
- Anything in parentheses must be done first
- Next are divisions and multiplications
- And finally additions and subtractions
The feature code that makes this happen is available here:
Code: Select all
script latn {
feature Fractions;
}
class @hyphen [hyphen uni2010 uni2011];
class @Denominators [onequarter onehalf threequarters fraction onethird twothirds onefifth twofifths-fourfifths onesixth fivesixths oneeighth threeeighths fiveeighths seveneighths zero.dnom-nine.dnom plus.subs minus.subs equal.subs parenleft.subs parenright.subs a.subs-z.subs];
class @Numerators [zero.sups-nine.sups plus.sups minus.sups equal.sups parenleft.sups parenright.sups a.sups-z.sups];
class @basiclatinbasic [asterisk period zero-nine A-Z a-z];
class @basiclatin [asterisk plus hyphen period zero-nine A-Z a-z];
class @SingleClass1 [a-z];
class @SingleClass2 [a.subs-z.subs];
class @FIGS1 [zero-nine];
class @SingleClass3 [zero.dnom-nine.dnom];
class @SingleClass4 [a.sups-z.sups];
class @SingleClass5 [zero.sups-nine.sups];
feature Fractions frac {
lookup FractionContextNumeratorsParentheses;
lookup FractionContextBasic;
lookup FractionContextDenominatorsParentheses;
}
lookup FractionContextNumeratorsParentheses {
context parenleft (@basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context parenleft (@basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin @basiclatin parenright slash);
sub 0 NumbersToNumerators;
context (@Numerators) @basiclatin;
sub 0 NumbersToNumerators;
context (@Numerators) parenright;
sub 0 NumbersToNumerators;
ignore context (fraction @Denominators) parenright;
context (@Numerators) slash;
sub 0 SlashToFraction;
}
lookup FractionContextBasic {
context @basiclatinbasic (slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context @basiclatinbasic (@basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic @basiclatinbasic slash);
sub 0 NumbersToNumerators;
context (@Numerators) slash;
sub 0 SlashToFraction;
context (fraction) @basiclatinbasic;
sub 0 NumbersToDenominators;
context (@Denominators) @basiclatinbasic;
sub 0 NumbersToDenominators;
}
lookup FractionContextDenominatorsParentheses {
ignore context (parenright.subs) parenright;
context (fraction) parenleft;
sub 0 NumbersToDenominators;
context (parenleft.subs) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) @basiclatin;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
context (parenleft.subs @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators @Denominators) parenright;
sub 0 NumbersToDenominators;
}
lookup SlashToFraction {
sub slash -> fraction;
}
lookup NumbersToDenominators {
sub parenleft -> parenleft.subs;
sub parenright -> parenright.subs;
sub plus -> plus.subs;
sub @hyphen -> minus.subs;
sub @FIGS1 -> @SingleClass3;
sub equal -> equal.subs;
sub @SingleClass1 -> @SingleClass2;
sub minus -> minus.subs;
}
lookup NumbersToNumerators {
sub parenleft -> parenleft.sups;
sub parenright -> parenright.sups;
sub plus -> plus.sups;
sub @hyphen -> minus.sups;
sub @FIGS1 -> @SingleClass5;
sub equal -> equal.sups;
sub @SingleClass1 -> @SingleClass4;
sub minus -> minus.sups;
}