Open clauseggers opened 1 year ago
OK, that looks like a problem with instance mapping in Babelfont. For now, try running it on the font binary instead of the source; I'll see what's going on with babelfont.
(Another data point is that Emma's fork works fine.)
Please try git babelfont:
pip3 install -U git+https://github.com/simoncozens/babelfont/
I just tried Emma’s version, and I got further, but still exception
fez2fea Playfair.glyphs nut_fractions.fez > nut_fractions.fea
<features>:42:16: Ambiguous glyph name that looks like a range: 'brevecomb-cy'
<features>:43:20: Ambiguous glyph name that looks like a range: 'brevecomb-cy.case'
<features>:46:24: Ambiguous glyph name that looks like a range: 'i-cy'
<features>:46:29: Ambiguous glyph name that looks like a range: 'je-cy'
# # Couldn't find glyph 'bar1.afrc' in font (bar1.afrc at (1, 9))
Traceback (most recent call last):
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/__init__.py", line 417, in parseString
rv = self.expand_statements(rv)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/__init__.py", line 436, in expand_statements
returned = callback()
^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/__init__.py", line 490, in <lambda>
verb_ret = (verb, [transformer._THUNK, lambda: transformer.action(ret)])
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/Feature.py", line 65, in action
statements = self.parser.expand_statements(statements)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/__init__.py", line 436, in expand_statements
returned = callback()
^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/__init__.py", line 499, in <lambda>
verb_ret = (verb, [transformer._THUNK, lambda : transformer.transform(tree) ])
^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/lark/visitors.py", line 161, in transform
return self._transform_tree(tree)
^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/lark/visitors.py", line 157, in _transform_tree
return self._call_userfunc(tree, children)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/lark/visitors.py", line 128, in _call_userfunc
raise VisitError(tree.data, tree, e)
lark.exceptions.VisitError: Error trying to process rule "action":
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/claus/.local/bin/fez2fea", line 42, in <module>
p.parseFile(args.fee)
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/__init__.py", line 406, in parseFile
return self.parseString(data)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/__init__.py", line 419, in parseString
raise e.orig_exc
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/lark/visitors.py", line 124, in _call_userfunc
return f(children)
^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/fez/Fractions.py", line 108, in action
assert len(fraction) == 1
^^^^^^^^^^^^^^^^^^
AssertionError
OK, so you can only have one fraction slash glyph. What's your nut_fractions.fez
?
So that is the next question. I want these nuts in the afrc
feature and I have made special zero.dnom.afrc
(&c) and zero.numr.afrc
for this purpose. The horizontal solidus is called bar1.afrc
.
I have yet to understand the syntax of the fez
files, so I just tried running it on this:
LoadPlugin Fractions;
Feature dnom { Substitute /dnom$/~dnom -> /.dnom$/; };
Feature numr { Substitute /numr$/~numr -> /.numr$/; };
Feature afrc {
Fractions /numr$/ bar1.afrc /dnom$/ 152;
};
PS: I can’t get the Vim syntax files to work. They are made for fee
for some reason?
PS: I installed these things in a virtualenv. Probably didn’t alias all the binaries to the dir for this purpose that is included in my PATH. Is that the issue?
I just tried to put all the executables in my PATH but that didn’t make a difference.
Here's what I get with a fraction
glyph which is a 400-unit long slug and a nut_fractions.fez
like this:
LoadPlugin Fractions;
Feature frac {
Fractions /numr$/ fraction /dnom$/ 0;
};
Same issue as before.
fez2fea Playfair-2_1-Roman.glyphs Settings/nut_fractions.fez > nut_fractions.fez.fea
Traceback (most recent call last):
File "/Users/claus/.local/bin/fez2fea", line 32, in <module>
font = load(args.font) # XXX master
^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/babelfont/__init__.py", line 17, in load
return Convert(filename).load()
^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/babelfont/convertors/__init__.py", line 70, in load
return c.load(self, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/babelfont/convertors/__init__.py", line 26, in load
return self._load()
^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/babelfont/convertors/glyphs.py", line 89, in _load
self.font.instances.append(self._load_instance(ginstance))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/claus/.local/virtualenv/fez/venv/lib/python3.11/site-packages/babelfont/convertors/glyphs.py", line 342, in _load_instance
raise ValueError("Need to Synthesize location")
ValueError: Need to Synthesize location
So that one's a babelfont issue. You'll need to install babelfont from git in your virtual env. Or just temporarily delete the "variable" instance in your glyphs file. Your fez code looks fine.
I did install babel
from git as you linked earlier
pip3 install -U git+https://github.com/simoncozens/babelfont/
in a virtualenv, and then linked the binary to my path. This doesn‘t work giving me the last error I posted.
If I delete the VF-instance then it does work (it produces output – haven’t checked it yet)
Can you explain to me how this works: I generated the feature, and now have to plonk it back into Glyphs under a manual afrc
feature. I then ignore the
table GDEF {
GlyphClassDef [A Aacute … [];
} GDEF;
table, and paste the lookup routines 1 and 2 into the afrc
feature, and delete the
feature afrc {
lookup Routine_1;
} afrc;
feature afrc {
lookup Routine_2;
} afrc;
However that gives me lookup Routine_1
containing substitutions
lookup Routine_1 {
lookupflag 0;
;
sub [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] bar1.afrc' by bar1.afrc bar1.afrc bar1.afrc bar1.afrc;
sub bar1.afrc' [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] by bar1.afrc bar1.afrc bar1.afrc bar1.afrc;
sub [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] bar1.afrc' by bar1.afrc bar1.afrc bar1.afrc;
sub bar1.afrc' [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] by bar1.afrc bar1.afrc bar1.afrc;
sub [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] [zero.numr.afrc one.numr.afrc two.numr.afrc three.numr.afrc four.numr.afrc five.numr.afrc six.numr.afrc seven.numr.afrc eight.numr.afrc nine.numr.afrc] bar1.afrc' by bar1.afrc bar1.afrc;
sub bar1.afrc' [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] [zero.dnom.afrc one.dnom.afrc two.dnom.afrc three.dnom.afrc four.dnom.afrc five.dnom.afrc six.dnom.afrc seven.dnom.afrc eight.dnom.afrc nine.dnom.afrc] by bar1.afrc bar1.afrc;
} Routine_1;
and lookup Routine_2
giving me all the position adjustments.
Now where are the initial substitutions from the regular numbers? My *.(d)nom.afrc
glyphs are to be used in the nut fractions, but where are the substitutions from a string like '23/45' into the `afrca glyphs?
However that gives me lookup Routine_1 containing substitutions and lookup Routine_2 giving me all the position adjustments.
This is all good so far.
where are the substitutions from a string like '23/45' into the `afrca glyphs?
This plugin deals with the common case where you will use the frac
feature and have already defined the dnom
and numr
features. In such cases, a shaping engine like Harfbuzz will automatically call dnom
/numr
as part of fraction processing.
It sounds like you additionally want something to make the denominator/numerator substitutions for you as part of the afrc
feature. This is slightly out of scope for the plugin as-written, so you'll have to implement it yourself. Here's how I would do it in FEZ. You can still copy the output into Glyphs.
DefineClass @digits = [one two three four five six seven eight nine];
Feature afrc {
# Maybe you want to change fraction slash to bar1.afrc here. That needs a separate lookup
Routine SlashToBar { Substitute fraction -> bar1.afrc; };
# Denominator substitutions are easy; any digit coming after either a bar1.afrc or another denominator
Routine Denominator {
Substitute [bar1.afrc /dnom$/] (@digits) -> @digits.dnom.arfc;
};
# Numerator substitutions are harder because we don't know how many places there will be before the slash.
Routine Numerator {
Substitute (@digits) @digits @digits @digits bar1.afrc -> @digits.numr.arfc;
Substitute (@digits) @digits @digits bar1.afrc -> @digits.numr.arfc;
Substitute (@digits) @digits bar1.afrc -> @digits.numr.arfc;
Substitute (@digits) bar1.afrc -> @digits.numr.arfc;
};
Routine Fraction {
Fractions /numr$/ bar1.afrc /dnom$/ 152;
};
};
Numerator substitutions are harder because we don't know how many places there will be before the slash.
Does FEZ support reverse chaining contextual single substitutions? That would make numerators as easy as denominators.
Thank you Simon. I want to put the afac
in its own self-contained feature using its own special glyphs. So I edited your script slightly to use my naming.
LoadPlugin Fractions;
DefineClass @afrcFigures = [one two three four five six seven eight nine];
DefineClass @afrcFraction = [slash fraction];
Feature afrc {
# Change slash to bar.afrc here. That needs a separate lookup
Routine SlashToBar { Substitute @afrcFraction -> bar.afrc; };
# Denominator substitutions are easy; any digit coming after either a bar.afrc or another denominator
Routine Denominator {
Substitute [bar.afrc /dnom$/] (@afrcFigures) -> @afrcFigures.dnom.afrc;
};
# Numerator substitutions are harder because we don't know how many places there will be before the slash.
Routine Numerator {
Substitute (@afrcFigures) @afrcFigures @afrcFigures @afrcFigures bar.afrc -> @afrcFigures.numr.afrc;
Substitute (@afrcFigures) @afrcFigures @afrcFigures bar.afrc -> @afrcFigures.numr.afrc;
Substitute (@afrcFigures) @afrcFigures bar.afrc -> @afrcFigures.numr.afrc;
Substitute (@afrcFigures) bar.afrc -> @afrcFigures.numr.afrc;
};
Routine Fraction {
Fractions /numr$/ bar.afrc /dnom$/ 152;
};
};
Problem is that I can not get – what seems to be – parts of GSUB and all of GPOS to work.
Does FEZ support reverse chaining contextual single substitutions?
Yes, with ReverseSubstitute
, but then you're restricting yourself to actually spec compliant shaping engines, which is very few of them. :-)
/dnom$/
and /numr$/
should be /dnom.afrc$/
and /numr.afrc$/
respectively.
I see, thank you very much Simon. It now works. There are however the issue of Variable Fonts looming large. So here is the question, do you think the GPOS values could be tokenised in Glyphs?
Personally, that's not how I'd do it, as the values are computed based on widths of glyphs etc. FEZ has the ability to create "variable scalars", so I would need to update the plugin to be a bit more variable-aware. I haven't needed this in my projects since the fraction figures have had quite similar widths across masters, but it seems like something worth doing for the future.
However, this would not allow you to do Glyphs exports, since the "variable scalar" syntax in FEA (which FEZ generates) is only supported in fontTools and Font Creator; Glyphs handles it through tokens, as you say, because Glyphs went with its own non-standard variable FEA syntax. I suppose one could come up with something which reads a variable FEA file, turns all the variable scalars into tokens, and tells you what the values of those tokens should be in the different masters, but I'm afraid I don't really have much use for that sort of thing (I use fontmake for all my exports), so I wouldn't be very interested in writing it myself.
Alright, thanks for writing it out Simon. I’ll have a think about it.
I want to try to manually replace all the numeric GPOS values in the generated FEA with Glyphs tokens. The obstacle here is how the values are calculated, which I can’t decipher.
I can suss out some of the calculations are done in the "Center the glyphs" section but that is where I get stuck. The very first line in the generated fea
gpos
sections looks like this:
pos one.numr.afrc' <314 0 -243 0> one.numr.afrc' <557 0 -243 0> one.numr.afrc' <800 0 -243 0> one.numr.afrc' <1043 0 -243 0> bar.afrc bar.afrc bar.afrc bar.afrc;
The -243 I have figured out as the negative advance width of the one.numr.afrc
, but the first value in the <314 0 -243 0>
I can’t figure out. I have the overlap set to zero to make this easier, 314 is can’t get to looking at my glyph metrics. Can you tell me how this value is derived?
Trying to run
fez2fea
gives me this: