Merge pull request #2609 from fonttools/ds5-add-some-polish

[designspaceLib] Add some polish to the v5 paths
This commit is contained in:
Nikolaus Waxweiler 2022-05-04 16:13:03 +01:00 committed by GitHub
commit 42e4d66184
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 100 additions and 56 deletions

View File

@ -5,6 +5,8 @@ from typing import Dict, List, Optional, Union
from fontTools.designspaceLib import ( from fontTools.designspaceLib import (
DesignSpaceDocument, DesignSpaceDocument,
DesignSpaceDocumentError,
DiscreteAxisDescriptor,
RangeAxisSubsetDescriptor, RangeAxisSubsetDescriptor,
SimpleLocationDict, SimpleLocationDict,
VariableFontDescriptor, VariableFontDescriptor,
@ -89,6 +91,10 @@ def userRegionToDesignRegion(doc: DesignSpaceDocument, userRegion: Region) -> Re
designRegion = {} designRegion = {}
for name, value in userRegion.items(): for name, value in userRegion.items():
axis = doc.getAxis(name) axis = doc.getAxis(name)
if axis is None:
raise DesignSpaceDocumentError(
f"Cannot find axis named '{name}' for region."
)
if isinstance(value, (float, int)): if isinstance(value, (float, int)):
designRegion[name] = axis.map_forward(value) designRegion[name] = axis.map_forward(value)
else: else:
@ -107,7 +113,16 @@ def getVFUserRegion(doc: DesignSpaceDocument, vf: VariableFontDescriptor) -> Reg
# - it's a single location = use it to know which rules should apply in the VF # - it's a single location = use it to know which rules should apply in the VF
for axisSubset in vf.axisSubsets: for axisSubset in vf.axisSubsets:
axis = doc.getAxis(axisSubset.name) axis = doc.getAxis(axisSubset.name)
if axis is None:
raise DesignSpaceDocumentError(
f"Cannot find axis named '{axisSubset.name}' for variable font '{vf.name}'."
)
if isinstance(axisSubset, RangeAxisSubsetDescriptor): if isinstance(axisSubset, RangeAxisSubsetDescriptor):
if isinstance(axis, DiscreteAxisDescriptor):
raise DesignSpaceDocumentError(
f"Cannot select a range over '{axis.name}' for variable font '{vf.name}' "
"because it's a discrete axis, use only 'userValue' instead."
)
vfUserRegion[axis.name] = Range( vfUserRegion[axis.name] = Range(
max(axisSubset.userMinimum, axis.minimum), max(axisSubset.userMinimum, axis.minimum),
min(axisSubset.userMaximum, axis.maximum), min(axisSubset.userMaximum, axis.maximum),
@ -118,5 +133,8 @@ def getVFUserRegion(doc: DesignSpaceDocument, vf: VariableFontDescriptor) -> Reg
# Any axis not mentioned explicitly has a single location = default value # Any axis not mentioned explicitly has a single location = default value
for axis in doc.axes: for axis in doc.axes:
if axis.name not in vfUserRegion: if axis.name not in vfUserRegion:
assert isinstance(
axis.default, (int, float)
), f"Axis '{axis.name}' has no valid default value."
vfUserRegion[axis.name] = axis.default vfUserRegion[axis.name] = axis.default
return vfUserRegion return vfUserRegion

View File

@ -1,7 +1,7 @@
<?xml version='1.0' encoding='UTF-8'?> <?xml version='1.0' encoding='UTF-8'?>
<designspace format="5.0"> <designspace format="5.0">
<axes elidedfallbackname="Regular"> <axes elidedfallbackname="Regular">
<axis tag="wght" name="weight" minimum="200" maximum="1000" default="200"> <axis tag="wght" name="Weight" minimum="200" maximum="1000" default="200">
<labelname xml:lang="en">Wéíght</labelname> <labelname xml:lang="en">Wéíght</labelname>
<labelname xml:lang="fa-IR">قطر</labelname> <labelname xml:lang="fa-IR">قطر</labelname>
<map input="200" output="0"/> <map input="200" output="0"/>
@ -24,7 +24,7 @@
</labels> </labels>
</axis> </axis>
<axis tag="wdth" name="width" minimum="50" maximum="150" default="100" hidden="1"> <axis tag="wdth" name="Width" minimum="50" maximum="150" default="100" hidden="1">
<labelname xml:lang="fr">Chasse</labelname> <labelname xml:lang="fr">Chasse</labelname>
<map input="50" output="10"/> <map input="50" output="10"/>
<map input="100" output="20"/> <map input="100" output="20"/>
@ -59,15 +59,15 @@
<label name="Some Style"> <label name="Some Style">
<labelname xml:lang="fr">Un Style</labelname> <labelname xml:lang="fr">Un Style</labelname>
<location> <location>
<dimension name="weight" uservalue="300"/> <dimension name="Weight" uservalue="300"/>
<dimension name="width" uservalue="50"/> <dimension name="Width" uservalue="50"/>
<dimension name="Italic" uservalue="0"/> <dimension name="Italic" uservalue="0"/>
</location> </location>
</label> </label>
<label name="Other"> <label name="Other">
<location> <location>
<dimension name="weight" uservalue="700"/> <dimension name="Weight" uservalue="700"/>
<dimension name="width" uservalue="100"/> <dimension name="Width" uservalue="100"/>
<dimension name="Italic" uservalue="1"/> <dimension name="Italic" uservalue="1"/>
</location> </location>
</label> </label>
@ -84,7 +84,7 @@
</rules> </rules>
<sources> <sources>
<source filename="masters/masterTest1.ufo" name="master.ufo1" familyname="MasterFamilyName" stylename="MasterStyleNameOne"> <source filename="masterTest1.ufo" name="master.ufo1" familyname="MasterFamilyName" stylename="MasterStyleNameOne">
<familyname xml:lang="fr">Montserrat</familyname> <familyname xml:lang="fr">Montserrat</familyname>
<familyname xml:lang="ja">モンセラート</familyname> <familyname xml:lang="ja">モンセラート</familyname>
<lib copy="1"/> <lib copy="1"/>
@ -93,21 +93,31 @@
<glyph name="A" mute="1"/> <glyph name="A" mute="1"/>
<glyph name="Z" mute="1"/> <glyph name="Z" mute="1"/>
<location> <location>
<dimension name="weight" xvalue="0"/> <dimension name="Weight" xvalue="0"/>
<dimension name="width" xvalue="20"/> <dimension name="Width" xvalue="20"/>
<dimension name="Italic" xvalue="0"/>
</location> </location>
</source> </source>
<source filename="masters/masterTest2.ufo" name="master.ufo2" familyname="MasterFamilyName" stylename="MasterStyleNameTwo"> <source filename="masterTest2.ufo" name="master.ufo2" familyname="MasterFamilyName" stylename="MasterStyleNameTwo">
<kerning mute="1"/> <kerning mute="1"/>
<location> <location>
<dimension name="weight" xvalue="1000"/> <dimension name="Weight" xvalue="1000"/>
<dimension name="width" xvalue="20"/> <dimension name="Width" xvalue="20"/>
<dimension name="Italic" xvalue="0"/>
</location> </location>
</source> </source>
<source filename="masters/masterTest2.ufo" name="master.ufo2" familyname="MasterFamilyName" stylename="Supports" layer="supports"> <source filename="masterTest2.ufo" name="master.ufo2" familyname="MasterFamilyName" stylename="Supports" layer="supports">
<location> <location>
<dimension name="weight" xvalue="1000"/> <dimension name="Weight" xvalue="1000"/>
<dimension name="width" xvalue="20"/> <dimension name="Width" xvalue="20"/>
<dimension name="Italic" xvalue="0"/>
</location>
</source>
<source filename="masterTest2.ufo" name="master.ufo3" familyname="MasterFamilyName" stylename="FauxItalic">
<location>
<dimension name="Weight" xvalue="0"/>
<dimension name="Width" xvalue="100"/>
<dimension name="Italic" xvalue="1"/>
</location> </location>
</source> </source>
</sources> </sources>
@ -193,8 +203,8 @@
<stylemapfamilyname xml:lang="de">Montserrat Halbfett</stylemapfamilyname> <stylemapfamilyname xml:lang="de">Montserrat Halbfett</stylemapfamilyname>
<stylemapfamilyname xml:lang="ja">モンセラート SemiBold</stylemapfamilyname> <stylemapfamilyname xml:lang="ja">モンセラート SemiBold</stylemapfamilyname>
<location> <location>
<dimension name="weight" xvalue="500"/> <dimension name="Weight" xvalue="500"/>
<dimension name="width" xvalue="20"/> <dimension name="Width" xvalue="20"/>
</location> </location>
<!-- The following elements are deprecated in v5.0. They can still be <!-- The following elements are deprecated in v5.0. They can still be
@ -220,28 +230,28 @@
</instance> </instance>
<instance name="instance.ufo2" familyname="InstanceFamilyName" stylename="InstanceStyleName" filename="instances/instanceTest2.ufo" postscriptfontname="InstancePostscriptName" stylemapfamilyname="InstanceStyleMapFamilyName" stylemapstylename="InstanceStyleMapStyleName"> <instance name="instance.ufo2" familyname="InstanceFamilyName" stylename="InstanceStyleName" filename="instances/instanceTest2.ufo" postscriptfontname="InstancePostscriptName" stylemapfamilyname="InstanceStyleMapFamilyName" stylemapstylename="InstanceStyleMapStyleName">
<location> <location>
<dimension name="weight" xvalue="500"/> <dimension name="Weight" xvalue="500"/>
<dimension name="width" xvalue="400" yvalue="300"/> <dimension name="Width" xvalue="400" yvalue="300"/>
</location> </location>
<!-- ROUNDTRIP_TEST_REMOVE_ME_BEGIN --> <!-- ROUNDTRIP_TEST_REMOVE_ME_BEGIN -->
<glyphs> <glyphs>
<glyph unicode="0x65 0xc9 0x12d" name="arrow"> <glyph unicode="0x65 0xc9 0x12d" name="arrow">
<location> <location>
<dimension name="weight" xvalue="120"/> <dimension name="Weight" xvalue="120"/>
<dimension name="width" xvalue="100"/> <dimension name="Width" xvalue="100"/>
</location> </location>
<note>A note about this glyph</note> <note>A note about this glyph</note>
<masters> <masters>
<master glyphname="BB" source="master.ufo1"> <master glyphname="BB" source="master.ufo1">
<location> <location>
<dimension name="weight" xvalue="20"/> <dimension name="Weight" xvalue="20"/>
<dimension name="width" xvalue="20"/> <dimension name="Width" xvalue="20"/>
</location> </location>
</master> </master>
<master glyphname="CC" source="master.ufo2"> <master glyphname="CC" source="master.ufo2">
<location> <location>
<dimension name="weight" xvalue="900"/> <dimension name="Weight" xvalue="900"/>
<dimension name="width" xvalue="900"/> <dimension name="Width" xvalue="900"/>
</location> </location>
</master> </master>
</masters> </masters>
@ -262,24 +272,24 @@
- with user coordinates (uservalue="") - with user coordinates (uservalue="")
- with a mix of both coordinate systems - with a mix of both coordinate systems
--> -->
<instance location="asdf"/> <instance location="Some Style"/>
<instance> <instance>
<location> <location>
<dimension name="weight" xvalue="600"/> <dimension name="Weight" xvalue="600"/>
<dimension name="width" xvalue="401" yvalue="420"/> <dimension name="Width" xvalue="401" yvalue="420"/>
</location> </location>
</instance> </instance>
<instance> <instance>
<location> <location>
<dimension name="weight" xvalue="10"/> <dimension name="Weight" xvalue="10"/>
<dimension name="width" uservalue="100"/> <dimension name="Width" uservalue="100"/>
<dimension name="Italic" xvalue="0"/> <dimension name="Italic" xvalue="0"/>
</location> </location>
</instance> </instance>
<instance> <instance>
<location> <location>
<dimension name="weight" uservalue="300"/> <dimension name="Weight" uservalue="300"/>
<dimension name="width" uservalue="130"/> <dimension name="Width" uservalue="130"/>
<dimension name="Italic" uservalue="1"/> <dimension name="Italic" uservalue="1"/>
</location> </location>
</instance> </instance>

View File

@ -34,7 +34,7 @@ def test_read_v5_document_simple(datadir):
[ [
AxisDescriptor( AxisDescriptor(
tag="wght", tag="wght",
name="weight", name="Weight",
minimum=200, minimum=200,
maximum=1000, maximum=1000,
default=200, default=200,
@ -82,7 +82,7 @@ def test_read_v5_document_simple(datadir):
), ),
AxisDescriptor( AxisDescriptor(
tag="wdth", tag="wdth",
name="width", name="Width",
minimum=50, minimum=50,
maximum=150, maximum=150,
default=100, default=100,
@ -123,10 +123,10 @@ def test_read_v5_document_simple(datadir):
LocationLabelDescriptor( LocationLabelDescriptor(
name="Some Style", name="Some Style",
labelNames={"fr": "Un Style"}, labelNames={"fr": "Un Style"},
userLocation={"weight": 300, "width": 50, "Italic": 0}, userLocation={"Weight": 300, "Width": 50, "Italic": 0},
), ),
LocationLabelDescriptor( LocationLabelDescriptor(
name="Other", userLocation={"weight": 700, "width": 100, "Italic": 1} name="Other", userLocation={"Weight": 700, "Width": 100, "Italic": 1}
), ),
], ],
) )
@ -139,7 +139,7 @@ def test_read_v5_document_simple(datadir):
path=posix(str((datadir / "masters/masterTest1.ufo").resolve())), path=posix(str((datadir / "masters/masterTest1.ufo").resolve())),
name="master.ufo1", name="master.ufo1",
layerName=None, layerName=None,
location={"weight": 0.0, "width": 20.0}, location={"Italic": 0.0, "Weight": 0.0, "Width": 20.0},
copyLib=True, copyLib=True,
copyInfo=True, copyInfo=True,
copyGroups=False, copyGroups=False,
@ -156,7 +156,7 @@ def test_read_v5_document_simple(datadir):
path=posix(str((datadir / "masters/masterTest2.ufo").resolve())), path=posix(str((datadir / "masters/masterTest2.ufo").resolve())),
name="master.ufo2", name="master.ufo2",
layerName=None, layerName=None,
location={"weight": 1000.0, "width": 20.0}, location={"Italic": 0.0, "Weight": 1000.0, "Width": 20.0},
copyLib=False, copyLib=False,
copyInfo=False, copyInfo=False,
copyGroups=False, copyGroups=False,
@ -173,7 +173,7 @@ def test_read_v5_document_simple(datadir):
path=posix(str((datadir / "masters/masterTest2.ufo").resolve())), path=posix(str((datadir / "masters/masterTest2.ufo").resolve())),
name="master.ufo2", name="master.ufo2",
layerName="supports", layerName="supports",
location={"weight": 1000.0, "width": 20.0}, location={"Italic": 0.0, "Weight": 1000.0, "Width": 20.0},
copyLib=False, copyLib=False,
copyInfo=False, copyInfo=False,
copyGroups=False, copyGroups=False,
@ -185,6 +185,22 @@ def test_read_v5_document_simple(datadir):
styleName="Supports", styleName="Supports",
localisedFamilyName={}, localisedFamilyName={},
), ),
SourceDescriptor(
filename="masters/masterTest2.ufo",
path=posix(str((datadir / "masters/masterTest2.ufo").resolve())),
name="master.ufo3",
layerName=None,
location={"Italic": 1.0, "Weight": 0.0, "Width": 100.0},
copyLib=False,
copyGroups=False,
copyFeatures=False,
muteKerning=False,
muteInfo=False,
mutedGlyphNames=[],
familyName="MasterFamilyName",
styleName="FauxItalic",
localisedFamilyName={},
),
], ],
) )
@ -245,7 +261,7 @@ def test_read_v5_document_simple(datadir):
filename="instances/instanceTest1.ufo", filename="instances/instanceTest1.ufo",
path=posix(str((datadir / "instances/instanceTest1.ufo").resolve())), path=posix(str((datadir / "instances/instanceTest1.ufo").resolve())),
name="instance.ufo1", name="instance.ufo1",
designLocation={"weight": 500.0, "width": 20.0}, designLocation={"Weight": 500.0, "Width": 20.0},
familyName="InstanceFamilyName", familyName="InstanceFamilyName",
styleName="InstanceStyleName", styleName="InstanceStyleName",
postScriptFontName="InstancePostscriptName", postScriptFontName="InstancePostscriptName",
@ -268,7 +284,7 @@ def test_read_v5_document_simple(datadir):
filename="instances/instanceTest2.ufo", filename="instances/instanceTest2.ufo",
path=posix(str((datadir / "instances/instanceTest2.ufo").resolve())), path=posix(str((datadir / "instances/instanceTest2.ufo").resolve())),
name="instance.ufo2", name="instance.ufo2",
designLocation={"weight": 500.0, "width": (400.0, 300.0)}, designLocation={"Weight": 500.0, "Width": (400.0, 300.0)},
familyName="InstanceFamilyName", familyName="InstanceFamilyName",
styleName="InstanceStyleName", styleName="InstanceStyleName",
postScriptFontName="InstancePostscriptName", postScriptFontName="InstancePostscriptName",
@ -278,16 +294,16 @@ def test_read_v5_document_simple(datadir):
"arrow": { "arrow": {
"unicodes": [101, 201, 301], "unicodes": [101, 201, 301],
"note": "A note about this glyph", "note": "A note about this glyph",
"instanceLocation": {"weight": 120.0, "width": 100.0}, "instanceLocation": {"Weight": 120.0, "Width": 100.0},
"masters": [ "masters": [
{ {
"font": "master.ufo1", "font": "master.ufo1",
"location": {"weight": 20.0, "width": 20.0}, "location": {"Weight": 20.0, "Width": 20.0},
"glyphName": "BB", "glyphName": "BB",
}, },
{ {
"font": "master.ufo2", "font": "master.ufo2",
"location": {"weight": 900.0, "width": 900.0}, "location": {"Weight": 900.0, "Width": 900.0},
"glyphName": "CC", "glyphName": "CC",
}, },
], ],
@ -296,17 +312,17 @@ def test_read_v5_document_simple(datadir):
}, },
), ),
InstanceDescriptor( InstanceDescriptor(
locationLabel="asdf", locationLabel="Some Style",
), ),
InstanceDescriptor( InstanceDescriptor(
designLocation={"weight": 600.0, "width": (401.0, 420.0)}, designLocation={"Weight": 600.0, "Width": (401.0, 420.0)},
), ),
InstanceDescriptor( InstanceDescriptor(
designLocation={"weight": 10.0, "Italic": 0.0}, designLocation={"Weight": 10.0, "Italic": 0.0},
userLocation={"width": 100.0}, userLocation={"Width": 100.0},
), ),
InstanceDescriptor( InstanceDescriptor(
userLocation={"weight": 300.0, "width": 130.0, "Italic": 1.0}, userLocation={"Weight": 300.0, "Width": 130.0, "Italic": 1.0},
), ),
], ],
) )

View File

@ -19,7 +19,7 @@ def test_instance_getStatNames(datadir):
def test_not_all_ordering_specified_and_translations(datadir): def test_not_all_ordering_specified_and_translations(datadir):
doc = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace") doc = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace")
assert getStatNames(doc, {"weight": 200, "width": 125, "Italic": 1}) == StatNames( assert getStatNames(doc, {"Weight": 200, "Width": 125, "Italic": 1}) == StatNames(
familyNames={ familyNames={
"en": "MasterFamilyName", "en": "MasterFamilyName",
"fr": "Montserrat", "fr": "Montserrat",

View File

@ -15,7 +15,7 @@ def test_getStatAxes(datadir):
doc = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace") doc = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace")
assert getStatAxes( assert getStatAxes(
doc, {"Italic": 0, "width": Range(50, 150), "weight": Range(200, 900)} doc, {"Italic": 0, "Width": Range(50, 150), "Weight": Range(200, 900)}
) == [ ) == [
{ {
"values": [ "values": [
@ -82,7 +82,7 @@ def test_getStatAxes(datadir):
"rangeMinValue": 150.0, "rangeMinValue": 150.0,
}, },
], ],
"name": {"en": "width", "fr": "Chasse"}, "name": {"en": "Width", "fr": "Chasse"},
"ordering": 1, "ordering": 1,
"tag": "wdth", "tag": "wdth",
}, },
@ -96,7 +96,7 @@ def test_getStatAxes(datadir):
}, },
] ]
assert getStatAxes(doc, {"Italic": 1, "width": 100, "weight": Range(400, 700)}) == [ assert getStatAxes(doc, {"Italic": 1, "Width": 100, "Weight": Range(400, 700)}) == [
{ {
"values": [ "values": [
{ {
@ -129,7 +129,7 @@ def test_getStatAxes(datadir):
"values": [ "values": [
{"flags": 3, "name": {"en": "Normal"}, "value": 100.0}, {"flags": 3, "name": {"en": "Normal"}, "value": 100.0},
], ],
"name": {"en": "width", "fr": "Chasse"}, "name": {"en": "Width", "fr": "Chasse"},
"ordering": 1, "ordering": 1,
"tag": "wdth", "tag": "wdth",
}, },
@ -148,7 +148,7 @@ def test_getStatLocations(datadir):
doc = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace") doc = DesignSpaceDocument.fromfile(datadir / "test_v5.designspace")
assert getStatLocations( assert getStatLocations(
doc, {"Italic": 0, "width": Range(50, 150), "weight": Range(200, 900)} doc, {"Italic": 0, "Width": Range(50, 150), "Weight": Range(200, 900)}
) == [ ) == [
{ {
"flags": 0, "flags": 0,
@ -157,7 +157,7 @@ def test_getStatLocations(datadir):
}, },
] ]
assert getStatLocations( assert getStatLocations(
doc, {"Italic": 1, "width": Range(50, 150), "weight": Range(200, 900)} doc, {"Italic": 1, "Width": Range(50, 150), "Weight": Range(200, 900)}
) == [ ) == [
{ {
"flags": 0, "flags": 0,