Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[designspaceLib] splitVariableFonts loses filename attribute in <variable-fonts> #3308

Open
ryanbugden opened this issue Oct 21, 2023 · 6 comments

Comments

@ryanbugden
Copy link

I may be doing something wrong here. But I can't seem to get the filename attribute from a <variable-fonts> tag in a designspace file.

def getVariableFonts(self) -> List[VariableFontDescriptor]:

Here's a test ds file I'm using:

<?xml version='1.0' encoding='UTF-8'?>
<designspace format="5.0">
    <axes>
        <axis tag="wght" name="weight" minimum="400" maximum="700" default="400" />
    </axes>
    <variable-fonts>
        <variable-font name="Test Font Variable" filename="Test_Font-Variable">
            <axis-subsets>
                <axis-subset name="weight" />
            </axis-subsets>
        </variable-font>
    </variable-fonts>
    <sources>
        <source filename="thick.ufo" familyname="E" stylename="Thick">
        <location>
            <dimension name="weight" xvalue="700" />
        </location>
        </source>
        <source filename="thin.ufo" familyname="E" stylename="Thin">
        <location>
            <dimension name="weight" xvalue="400" />
        </location>
        </source>
    </sources>
    <instances>
        <instance familyname="E" stylename="Thick" filename="instances/FileName-E-Thick.ufo">
            <location>
                <dimension name="weight" xvalue="700" />
            </location>
        </instance>
        <instance familyname="E" stylename="Thin" filename="instances/FileName-E-Thin.ufo">
            <location>
                <dimension name="weight" xvalue="400" />
            </location>
        </instance>
        <instance familyname="E" stylename="Style_2" filename="instances/FileName-E-Style_2.ufo">
            <location>
                <dimension name="weight" xvalue="700" yvalue="400" />
            </location>
        </instance>
    </instances>
</designspace>

The code I'm using to try and get the filename:

from ufoProcessor.ufoOperator import UFOOperator

operator = UFOOperator('path/test.designspace')

for name, interpolableOperator in operator.getInterpolableUFOOperators(useVariableFonts=True):
    vf = interpolableOperator.getVariableFonts()
    print(vf)
    print(vf[0].filename)

This is the output:

[VariableFontDescriptor(
    filename=None,
    axisSubsets=[RangeAxisSubsetDescriptor(
        name='weight',
        userMinimum=-inf,
        userDefault=None,
        userMaximum=inf,
    )],
    lib={},
)]
None

It's able to get the correct axis subset name, but not the filename.

TIA!

@justvanrossum
Copy link
Collaborator

Can you provide an example that does not use ufoProcessor?

@ryanbugden
Copy link
Author

Oops yes. Looks like it has something to do with how I used the useVariableFonts flag. Will close this issue, thanks @justvanrossum

from fontTools.designspaceLib import DesignSpaceDocument
from ufoProcessor.ufoOperator import UFOOperator

# Straight from fontTools
doc = DesignSpaceDocument()
doc.read('/Users/Ryan/Desktop/test.designspace')
vf = doc.getVariableFonts()
print(vf[0].filename)

# UFOOperator, useVariableFonts=True
operator = UFOOperator('/Users/Ryan/Desktop/test.designspace')
for name, interpolableOperator in operator.getInterpolableUFOOperators(useVariableFonts=True):
    vf = interpolableOperator.getVariableFonts()
    print(vf[0].filename)
    
# UFOOperator, useVariableFonts=False
for name, interpolableOperator in operator.getInterpolableUFOOperators(useVariableFonts=False):
    vf = interpolableOperator.getVariableFonts()
    print(vf[0].filename)

Output:

Test_Font-Variable
None
Test_Font-Variable

@ryanbugden
Copy link
Author

ryanbugden commented Oct 21, 2023

@justvanrossum
I'm coming into this fresh, so forgive me if I'm missing something, but is there a reason, the variable-font’s filename is dropped from the DesignSpaceDocument in splitVariableFonts?

from fontTools.designspaceLib import DesignSpaceDocument
from fontTools.designspaceLib.split import splitInterpolable, splitVariableFonts

# Getting the <variable-fonts> filename from the flat document works.
doc = DesignSpaceDocument()
doc.read('/Users/Ryan/Desktop/test.designspace')
vf = doc.getVariableFonts()
print(vf[0].filename)

# Still works with splitInterpolable
split_interp = splitInterpolable(doc)
for name, interp in split_interp:
    vf = interp.getVariableFonts()
    print(vf[0].filename)

# Loses filename with splitVariableFonts
split_var = splitVariableFonts(doc)
for name, var in split_var:
    vf = var.getVariableFonts()
    print(vf[0].filename)

Output:

Test_Font-Variable
Test_Font-Variable
None

I think it's happening around here:

vfDoc = _extractSubSpace(

@ryanbugden ryanbugden reopened this Oct 21, 2023
@ryanbugden ryanbugden changed the title [designspaceLib] getVariableFonts is not getting the right filename [designspaceLib] splitVariableFonts loses filename attribute in <variable-fonts> Oct 21, 2023
@justvanrossum
Copy link
Collaborator

I'm not sure what's going on here, and I hope @belluzj can shed some light on this.

@belluzj
Copy link
Contributor

belluzj commented Oct 23, 2023

Hello, here is an explanation of what is going on, although it's not an excuse and the code could be be improved: splitVariableFonts(doc) will turn each <variable-font> in the input doc into a standalone Designspace doc that represents that VF. In particular, the stand-alone doc does not include a <variable-font> anymore (see keepVFs=False on line 149), that's because (so I thought at the time):

  1. the data of <variable-font> element has been fully used to subset the designspace, and so the <variable-font> element is not needed anymore. That assumption turns out to be false, as for example you're spotting the filename field, which gets lost indeed.
  2. not having a <variable-font> element means the standalone designspace is V4 and can be passed to older tools that wouldn't understand the <variable-font> thing; and so splitVariableFonts() is used to implement convert5to4()

Possible workaround for now: zip your <variable-font> elements with the results of splitVariableFonts() to have access to your information:

split_var = splitVariableFonts(doc)
for vf, (name, varDoc) in zip(doc.getVariableFonts(), split_var):
    print(vf[0].filename)

Possible improvement: make splitVariableFonts() keep the single <variable-font> in the standalone designspace by default (so no information is lost); make convert5to4() delete that <variable-font> before returning the version 4 document.

Does that help?

@ryanbugden
Copy link
Author

Hi @belluzj, thanks for looking into this. I understand the initial thinking, and the improvement proposal makes sense to me! Thanks for the workaround as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants