add math device tables to Python API#5348
Conversation
|
The C code looks fine to me. I'm concerned a bit about duplication of attributes. Could it be better to allow setting device tables like the following? This looks more concise to me,but could break assumption about attribute value type in existing scripts. |
|
Thanks for your suggestion, I think using a dict is much better than using tuples. I don't like setting the constant and the device table together since this would basically break every piece of code that sets the math constants and you would have to implement this type check everywhere if you're not sure about FontForge's version. I also don't like having to re-set the constant whenever changing the adjustment values. There is definitely the case where you want to add an adjustment to an existing constant and you would have to (most likely get it first and then) set the constant again together with the device table. In my opinion, a separate property is the lesser of two evils. Inspired by your dict suggestion, I'm thinking of an API like this: font.math.MathLeadingDeviceTable = {9: -1, 10: 2}
font.math.MathLeadingDeviceTable[12] = -2
devtab = font.math.MathLeadingDeviceTable # {9: -1, 10: 2, 12: -2}
adj = font.math.MathLeadingDeviceTable[9] # -1What do you think? I don't know if this is possible with Python's C API, but I will check. |
|
Yep, maybe squashing things together is not such a good idea after all, and I also like the dictionary API much more. Let's ask for @skef's input before you update it. I think the dict value assignment already works for layers: |
Just to say it -- the setting side isn't actually the problem with the unified design. It would be easy enough to differentiate by the input type, setting the constant when the argument is (or can be converted to) an int, setting the device table when it's a dict, and setting both when its a tuple. The problem comes when you want to read the data, and right now reading one of these properties yields an int, and having it yield something else is what would break compatibility. As for adding the new names and having those be dicts, it seems like a reasonable solution. You'll want to sanity check the keys and values and reject those that don't make sense with a sensible exception. |
|
Thanks for your feedback. I've looked into how to implement this and I'm still not sure if it is possible. font.math.MathLeadingDeviceTable = {9: -1, 10: 2}
devtab = font.math.MathLeadingDeviceTable # {9: -1, 10: 2}
I thought about implementing a new I'm pretty new to C and the Python/C API, so maybe I'm missing something obvious. Any ideas are appreciated. |
|
I'll think about the C-API engineering questions and try to give some guidance in the next few days. |
I think your idea about You'll need some trick to make this type aware of the specific |
|
You will also need to define both getter and setter in the relevant PyGetSetDef record. The setter would need to accommodate both plain dict: and the new object you define: |
|
I haven't had time to think about this in any depth. It poses a problem we've run into in other places that I haven't determined the best way to solve. Each of these device tables is, in design, just a dictionary. So you want to be able to get and set them as dictionaries. However, internally the data isn't always going to take the form of a Python structure, so then there's the question of what to do on the C/Python line. And it seems like the solution to that is to do something like FontForge does with Layers, where a layer is a separate object implemented in C with the needed data (although it's annoying to do this with a dictionary). But then layers have an additional problem, which is that there are really two "kinds" of layer, the layer that you access to the API to get and set the content of a glyph, and then this C-API object. This is confusing -- you get the layer and make changes to it and think those changes will have an effect on the glyph but they don't; you have to assign the layer back to get the changes. You could have the same problem here depending on the implementation. If it's a separate object and you , for example, assign like |
|
The indexable object was quite tricky after all, but I think I nailed it now. |
|
Copying here from mf2vec-dev#1, as it probably got lost in the side PR. @skef, could you please check and comment on the proposed API?
|
I don't have an inherently negative view of this, but there are some other parts of the Python API (which I'm afraid currently escape me) that cause problems when a fontforge.font object is deleted. It sounds like this has the potential to cause similar problems. Right now we basically say: "Be careful not to use this after the font object goes away", which obviously isn't great but is maybe acceptable. It's not awesome to introduce new things with this problem, but it's not a deal breaker either. To do the hero's version of this, I suppose one would have a list of reverse references to each such outstanding object in the font, and the object could have a boolean to turn it off so that the font can deactivate its orphan objects. |
|
After further deliberation I chose to abandon the @mf2vec-dev's concern about counterintuitive assignment (mf2vec-dev#1 (review)) is definitely valid, but the similar counterintuitive behavior is already present in FontForge, for example in |
Support font.math.*DeviceTable as indexable object
|
The
Should I push a trivial change to trigger a re-run or is there a better way? |
Please ignore this failure. The mac runner is dead, and #5423 is dedicated to it. |
|
I think we are good to go here. @skef , could you please review? |
|
This is "a lot", but it's on my list to review. |
skef
left a comment
There was a problem hiding this comment.
It's a shame to add another of these interfaces that will crash when the underlying FF object (in this case the font) goes away, but I don't see the sense in requiring a fix for that in just this instance.
I didn't review everything this code makes use of, but just going through the changes themselves I don't see any problems.
|
@mf2vec-dev, could you please merge from the latest master, to verify CI checks? |
This PR adds access to the device tables of the
mathconstants via the Python API. New getter, setter and utility functions for device tables are defined. The new functions are covered by a new Python test and the new properties of themathobject are added to the documentation.I'm pretty new to programming in C. Please check my changes carefully.
Type of change