diff --git a/src/fontra/workflow/actions/features.py b/src/fontra/workflow/actions/features.py index 382cbb487..1c9e3522b 100644 --- a/src/fontra/workflow/actions/features.py +++ b/src/fontra/workflow/actions/features.py @@ -185,22 +185,18 @@ async def processFeatures(self, features: OpenTypeFeatures) -> OpenTypeFeatures: return OpenTypeFeatures(text=featureText) -vkrnTopPrefix = "kern.top." -vkrnBottomPrefix = "kern.bottom." +class BaseGenerateKerningFeature(BaseFilter): + _kernFeatureTag = "kern" + _kern1Prefix = "public.kern1." + _kern2Prefix = "public.kern2." + _dropKernAttrName = "dropKern" - -def _kernKeySortFunc(item): - key, _ = item - return key.startswith(vkrnTopPrefix) or key.startswith(vkrnBottomPrefix) - - -@registerFilterAction("generate-vkrn-feature") -@dataclass(kw_only=True) -class GenerateVkrnFeature(BaseFilter): - dropVkrn: bool = True + def _kernKeySortFunc(self, item): + key, _ = item + return key.startswith(self._kern1Prefix) or key.startswith(self._kern2Prefix) async def processFeatures(self, features: OpenTypeFeatures) -> OpenTypeFeatures: - verticalKerning = (await self.inputKerning).get("vkrn") + verticalKerning = (await self.inputKerning).get(self._kernFeatureTag) if verticalKerning is None: return features @@ -226,16 +222,16 @@ async def processFeatures(self, features: OpenTypeFeatures) -> OpenTypeFeatures: for groupName, group in sorted(verticalKerning.groups.items()): w.addGroup(groupName, group) - fea = w.addFeature("vkrn") + fea = w.addFeature(self._kernFeatureTag) for left, rightDict in sorted( - verticalKerning.values.items(), key=_kernKeySortFunc + verticalKerning.values.items(), key=self._kernKeySortFunc ): - if left.startswith(vkrnTopPrefix): + if left.startswith(self._kern1Prefix): left = "@" + left - for right, values in sorted(rightDict.items(), key=_kernKeySortFunc): - if right.startswith(vkrnBottomPrefix): + for right, values in sorted(rightDict.items(), key=self._kernKeySortFunc): + if right.startswith(self._kern2Prefix): right = "@" + right values = [0 if v is None else round(v) for v in values] @@ -264,10 +260,27 @@ async def getKerning( kerning = await self.inputKerning return ( kerning - if not self.dropVkrn + if not getattr(self, self._dropKernAttrName) else { kernType: kernTable for kernType, kernTable in kerning.items() - if kernType != "vkrn" + if kernType != self._kernFeatureTag } ) + + +@registerFilterAction("generate-kern-feature") +@dataclass(kw_only=True) +class GenerateKernFeature(BaseGenerateKerningFeature): + dropKern: bool = True + + +@registerFilterAction("generate-vkrn-feature") +@dataclass(kw_only=True) +class GenerateVkrnFeature(BaseGenerateKerningFeature): + dropVkrn: bool = True + + _kernFeatureTag = "vkrn" + _kern1Prefix = "kern.top." + _kern2Prefix = "kern.bottom." + _dropKernAttrName = "dropVkrn" diff --git a/test-py/data/workflow/output-generate-kern-feature.fontra/features.txt b/test-py/data/workflow/output-generate-kern-feature.fontra/features.txt new file mode 100644 index 000000000..e7641485f --- /dev/null +++ b/test-py/data/workflow/output-generate-kern-feature.fontra/features.txt @@ -0,0 +1,4 @@ + +feature kern { + pos A B (wdth=0,wght=100:-10 wdth=0,wght=900:-20 wdth=1000,wght=100:-15 wdth=1000,wght=900:-25); +} kern; diff --git a/test-py/data/workflow/output-generate-kern-feature.fontra/font-data.json b/test-py/data/workflow/output-generate-kern-feature.fontra/font-data.json new file mode 100644 index 000000000..375a767b9 --- /dev/null +++ b/test-py/data/workflow/output-generate-kern-feature.fontra/font-data.json @@ -0,0 +1,179 @@ +{ +"axes": { +"axes": [ +{ +"name": "width", +"label": "width", +"tag": "wdth", +"minValue": 0, +"defaultValue": 0, +"maxValue": 1000 +}, +{ +"name": "weight", +"label": "weight", +"tag": "wght", +"minValue": 100, +"defaultValue": 100, +"maxValue": 900, +"mapping": [ +[ +100, +150 +], +[ +900, +850 +] +] +} +] +}, +"sources": { +"3aa9223b": { +"name": "Support", +"location": { +"weight": 595, +"width": 0 +}, +"lineMetricsHorizontalLayout": { +"ascender": { +"value": 800, +"zone": 16 +}, +"capHeight": { +"value": 750, +"zone": 16 +}, +"xHeight": { +"value": 500, +"zone": 16 +}, +"baseline": { +"value": 0, +"zone": -16 +}, +"descender": { +"value": -250, +"zone": -16 +} +} +}, +"5bea6334": { +"name": "LightCondensed", +"location": { +"weight": 150, +"width": 0 +}, +"lineMetricsHorizontalLayout": { +"ascender": { +"value": 800, +"zone": 16 +}, +"capHeight": { +"value": 750, +"zone": 16 +}, +"xHeight": { +"value": 500, +"zone": 16 +}, +"baseline": { +"value": 0, +"zone": -16 +}, +"descender": { +"value": -250, +"zone": -16 +} +} +}, +"5d4e7f1d": { +"name": "BoldWide", +"location": { +"weight": 850, +"width": 1000 +}, +"lineMetricsHorizontalLayout": { +"ascender": { +"value": 800, +"zone": 16 +}, +"capHeight": { +"value": 750, +"zone": 16 +}, +"xHeight": { +"value": 500, +"zone": 16 +}, +"baseline": { +"value": 0, +"zone": -16 +}, +"descender": { +"value": -250, +"zone": -16 +} +} +}, +"d7abd222": { +"name": "LightWide", +"location": { +"weight": 150, +"width": 1000 +}, +"lineMetricsHorizontalLayout": { +"ascender": { +"value": 800, +"zone": 16 +}, +"capHeight": { +"value": 750, +"zone": 16 +}, +"xHeight": { +"value": 500, +"zone": 16 +}, +"baseline": { +"value": 0, +"zone": -16 +}, +"descender": { +"value": -250, +"zone": -16 +} +} +}, +"f22d1bbd": { +"name": "BoldCondensed", +"location": { +"weight": 850, +"width": 0 +}, +"lineMetricsHorizontalLayout": { +"ascender": { +"value": 800, +"zone": 16 +}, +"capHeight": { +"value": 750, +"zone": 16 +}, +"xHeight": { +"value": 500, +"zone": 16 +}, +"baseline": { +"value": 0, +"zone": -16 +}, +"descender": { +"value": -250, +"zone": -16 +} +} +} +} +} diff --git a/test-py/data/workflow/output-generate-kern-feature.fontra/glyph-info.csv b/test-py/data/workflow/output-generate-kern-feature.fontra/glyph-info.csv new file mode 100644 index 000000000..3422d937a --- /dev/null +++ b/test-py/data/workflow/output-generate-kern-feature.fontra/glyph-info.csv @@ -0,0 +1,3 @@ +glyph name;code points +A;U+0041,U+0061 +B;U+0042,U+0062 diff --git a/test-py/data/workflow/output-generate-kern-feature.fontra/glyphs/A^1.json b/test-py/data/workflow/output-generate-kern-feature.fontra/glyphs/A^1.json new file mode 100644 index 000000000..e1bcdb271 --- /dev/null +++ b/test-py/data/workflow/output-generate-kern-feature.fontra/glyphs/A^1.json @@ -0,0 +1,416 @@ +{ +"name": "A", +"sources": [ +{ +"name": "LightCondensed", +"layerName": "MutatorSansLightCondensed/foreground", +"location": { +"weight": 150, +"width": 0 +} +}, +{ +"name": "BoldCondensed", +"layerName": "MutatorSansBoldCondensed/foreground", +"location": { +"weight": 850, +"width": 0 +} +}, +{ +"name": "LightWide", +"layerName": "MutatorSansLightWide/foreground", +"location": { +"weight": 150, +"width": 1000 +} +}, +{ +"name": "BoldWide", +"layerName": "MutatorSansBoldWide/foreground", +"location": { +"weight": 850, +"width": 1000 +} +} +], +"layers": { +"MutatorSansBoldCondensed/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": -10, +"y": 0 +}, +{ +"x": 250, +"y": 0 +}, +{ +"x": 334, +"y": 800 +}, +{ +"x": 104, +"y": 800 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 110, +"y": 120 +}, +{ +"x": 580, +"y": 120 +}, +{ +"x": 580, +"y": 330 +}, +{ +"x": 110, +"y": 330 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 390, +"y": 0 +}, +{ +"x": 730, +"y": 0 +}, +{ +"x": 614, +"y": 800 +}, +{ +"x": 294, +"y": 800 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 204, +"y": 540 +}, +{ +"x": 474, +"y": 540 +}, +{ +"x": 474, +"y": 800 +}, +{ +"x": 204, +"y": 800 +} +], +"isClosed": true +} +] +}, +"xAdvance": 740 +} +}, +"MutatorSansBoldWide/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 20, +"y": 0 +}, +{ +"x": 350, +"y": 0 +}, +{ +"x": 640, +"y": 800 +}, +{ +"x": 360, +"y": 800 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 210, +"y": 120 +}, +{ +"x": 940, +"y": 120 +}, +{ +"x": 940, +"y": 340 +}, +{ +"x": 210, +"y": 340 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 800, +"y": 0 +}, +{ +"x": 1270, +"y": 0 +}, +{ +"x": 930, +"y": 800 +}, +{ +"x": 480, +"y": 800 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 410, +"y": 540 +}, +{ +"x": 830, +"y": 540 +}, +{ +"x": 830, +"y": 800 +}, +{ +"x": 410, +"y": 800 +} +], +"isClosed": true +} +] +}, +"xAdvance": 1290 +} +}, +"MutatorSansLightCondensed/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 20, +"y": 0 +}, +{ +"x": 60, +"y": 0 +}, +{ +"x": 200, +"y": 700 +}, +{ +"x": 165, +"y": 700 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 75, +"y": 164 +}, +{ +"x": 325, +"y": 164 +}, +{ +"x": 325, +"y": 200 +}, +{ +"x": 75, +"y": 200 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 332, +"y": 0 +}, +{ +"x": 376, +"y": 0 +}, +{ +"x": 231, +"y": 700 +}, +{ +"x": 192, +"y": 700 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 175, +"y": 661 +}, +{ +"x": 222, +"y": 661 +}, +{ +"x": 222, +"y": 700 +}, +{ +"x": 175, +"y": 700 +} +], +"isClosed": true +} +] +}, +"xAdvance": 396 +} +}, +"MutatorSansLightCondensed/support": { +"glyph": { +"xAdvance": 930 +} +}, +"MutatorSansLightWide/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 50, +"y": 0 +}, +{ +"x": 97, +"y": 0 +}, +{ +"x": 612, +"y": 700 +}, +{ +"x": 570, +"y": 700 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 245, +"y": 224 +}, +{ +"x": 945, +"y": 224 +}, +{ +"x": 945, +"y": 254 +}, +{ +"x": 245, +"y": 254 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 1087, +"y": 0 +}, +{ +"x": 1140, +"y": 0 +}, +{ +"x": 620, +"y": 700 +}, +{ +"x": 572, +"y": 700 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 570, +"y": 664 +}, +{ +"x": 620, +"y": 664 +}, +{ +"x": 620, +"y": 700 +}, +{ +"x": 570, +"y": 700 +} +], +"isClosed": true +} +] +}, +"xAdvance": 1190 +} +} +} +} diff --git a/test-py/data/workflow/output-generate-kern-feature.fontra/glyphs/B^1.json b/test-py/data/workflow/output-generate-kern-feature.fontra/glyphs/B^1.json new file mode 100644 index 000000000..7ca132e51 --- /dev/null +++ b/test-py/data/workflow/output-generate-kern-feature.fontra/glyphs/B^1.json @@ -0,0 +1,1032 @@ +{ +"name": "B", +"sources": [ +{ +"name": "LightCondensed", +"layerName": "MutatorSansLightCondensed/foreground", +"location": { +"weight": 150, +"width": 0 +} +}, +{ +"name": "BoldCondensed", +"layerName": "MutatorSansBoldCondensed/foreground", +"location": { +"weight": 850, +"width": 0 +} +}, +{ +"name": "LightWide", +"layerName": "MutatorSansLightWide/foreground", +"location": { +"weight": 150, +"width": 1000 +} +}, +{ +"name": "BoldWide", +"layerName": "MutatorSansBoldWide/foreground", +"location": { +"weight": 850, +"width": 1000 +} +}, +{ +"name": "support.crossbar", +"layerName": "MutatorSansLightCondensed/support.crossbar", +"location": { +"weight": 595, +"width": 0 +} +} +], +"layers": { +"MutatorSansBoldCondensed/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 30, +"y": 0 +}, +{ +"x": 340, +"y": 0 +}, +{ +"x": 340, +"y": 800 +}, +{ +"x": 30, +"y": 800 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 280, +"y": 347 +}, +{ +"x": 345, +"y": 347, +"smooth": true +}, +{ +"x": 374, +"y": 347, +"type": "cubic" +}, +{ +"x": 397, +"y": 340, +"type": "cubic" +}, +{ +"x": 397, +"y": 292, +"smooth": true +}, +{ +"x": 397, +"y": 249, +"type": "cubic" +}, +{ +"x": 374, +"y": 238, +"type": "cubic" +}, +{ +"x": 345, +"y": 238, +"smooth": true +}, +{ +"x": 280, +"y": 238 +}, +{ +"x": 280, +"y": 0 +}, +{ +"x": 396, +"y": 0, +"smooth": true +}, +{ +"x": 651, +"y": 0, +"type": "cubic" +}, +{ +"x": 700, +"y": 94, +"type": "cubic" +}, +{ +"x": 700, +"y": 230, +"smooth": true +}, +{ +"x": 700, +"y": 356, +"type": "cubic" +}, +{ +"x": 645, +"y": 417, +"type": "cubic" +}, +{ +"x": 551, +"y": 434 +}, +{ +"x": 541, +"y": 377 +}, +{ +"x": 618, +"y": 392, +"type": "cubic" +}, +{ +"x": 690, +"y": 444, +"type": "cubic" +}, +{ +"x": 690, +"y": 563, +"smooth": true +}, +{ +"x": 690, +"y": 711, +"type": "cubic" +}, +{ +"x": 621, +"y": 800, +"type": "cubic" +}, +{ +"x": 385, +"y": 800, +"smooth": true +}, +{ +"x": 280, +"y": 800 +}, +{ +"x": 280, +"y": 574 +}, +{ +"x": 345, +"y": 574, +"smooth": true +}, +{ +"x": 374, +"y": 574, +"type": "cubic" +}, +{ +"x": 397, +"y": 564, +"type": "cubic" +}, +{ +"x": 397, +"y": 523, +"smooth": true +}, +{ +"x": 397, +"y": 475, +"type": "cubic" +}, +{ +"x": 374, +"y": 470, +"type": "cubic" +}, +{ +"x": 345, +"y": 470, +"smooth": true +}, +{ +"x": 280, +"y": 470 +} +], +"isClosed": true +} +] +}, +"xAdvance": 710 +} +}, +"MutatorSansBoldWide/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 60, +"y": 0 +}, +{ +"x": 480, +"y": 0 +}, +{ +"x": 480, +"y": 801 +}, +{ +"x": 60, +"y": 801 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 450, +"y": 337 +}, +{ +"x": 732, +"y": 337, +"smooth": true +}, +{ +"x": 774, +"y": 337, +"type": "cubic" +}, +{ +"x": 807, +"y": 330, +"type": "cubic" +}, +{ +"x": 807, +"y": 286, +"smooth": true +}, +{ +"x": 807, +"y": 248, +"type": "cubic" +}, +{ +"x": 774, +"y": 238, +"type": "cubic" +}, +{ +"x": 732, +"y": 238, +"smooth": true +}, +{ +"x": 450, +"y": 238 +}, +{ +"x": 450, +"y": 0 +}, +{ +"x": 906, +"y": 0, +"smooth": true +}, +{ +"x": 1161, +"y": 0, +"type": "cubic" +}, +{ +"x": 1230, +"y": 94, +"type": "cubic" +}, +{ +"x": 1230, +"y": 230, +"smooth": true +}, +{ +"x": 1230, +"y": 356, +"type": "cubic" +}, +{ +"x": 1155, +"y": 417, +"type": "cubic" +}, +{ +"x": 1061, +"y": 434 +}, +{ +"x": 1031, +"y": 377 +}, +{ +"x": 1108, +"y": 392, +"type": "cubic" +}, +{ +"x": 1200, +"y": 444, +"type": "cubic" +}, +{ +"x": 1200, +"y": 563, +"smooth": true +}, +{ +"x": 1200, +"y": 711, +"type": "cubic" +}, +{ +"x": 1111, +"y": 800, +"type": "cubic" +}, +{ +"x": 846, +"y": 800, +"smooth": true +}, +{ +"x": 450, +"y": 800 +}, +{ +"x": 450, +"y": 574 +}, +{ +"x": 693, +"y": 574, +"smooth": true +}, +{ +"x": 744, +"y": 574, +"type": "cubic" +}, +{ +"x": 777, +"y": 565, +"type": "cubic" +}, +{ +"x": 777, +"y": 528, +"smooth": true +}, +{ +"x": 777, +"y": 476, +"type": "cubic" +}, +{ +"x": 744, +"y": 480, +"type": "cubic" +}, +{ +"x": 693, +"y": 480, +"smooth": true +}, +{ +"x": 450, +"y": 480 +} +], +"isClosed": true +} +] +}, +"xAdvance": 1270 +} +}, +"MutatorSansLightCondensed/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 60, +"y": 0 +}, +{ +"x": 100, +"y": 0 +}, +{ +"x": 100, +"y": 700 +}, +{ +"x": 60, +"y": 700 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 80, +"y": 333 +}, +{ +"x": 210, +"y": 333, +"smooth": true +}, +{ +"x": 315, +"y": 333, +"type": "cubic" +}, +{ +"x": 364, +"y": 269, +"type": "cubic" +}, +{ +"x": 364, +"y": 183, +"smooth": true +}, +{ +"x": 364, +"y": 93, +"type": "cubic" +}, +{ +"x": 312, +"y": 36, +"type": "cubic" +}, +{ +"x": 200, +"y": 36, +"smooth": true +}, +{ +"x": 80, +"y": 36 +}, +{ +"x": 80, +"y": 0 +}, +{ +"x": 190, +"y": 0, +"smooth": true +}, +{ +"x": 343, +"y": 0, +"type": "cubic" +}, +{ +"x": 403, +"y": 79, +"type": "cubic" +}, +{ +"x": 403, +"y": 183, +"smooth": true +}, +{ +"x": 403, +"y": 273, +"type": "cubic" +}, +{ +"x": 353, +"y": 351, +"type": "cubic" +}, +{ +"x": 233, +"y": 361 +}, +{ +"x": 253, +"y": 350 +}, +{ +"x": 342, +"y": 366, +"type": "cubic" +}, +{ +"x": 383, +"y": 439, +"type": "cubic" +}, +{ +"x": 383, +"y": 517, +"smooth": true +}, +{ +"x": 383, +"y": 618, +"type": "cubic" +}, +{ +"x": 341, +"y": 700, +"type": "cubic" +}, +{ +"x": 180, +"y": 700, +"smooth": true +}, +{ +"x": 80, +"y": 700 +}, +{ +"x": 80, +"y": 664 +}, +{ +"x": 190, +"y": 664, +"smooth": true +}, +{ +"x": 310, +"y": 664, +"type": "cubic" +}, +{ +"x": 344, +"y": 603, +"type": "cubic" +}, +{ +"x": 344, +"y": 517, +"smooth": true +}, +{ +"x": 344, +"y": 431, +"type": "cubic" +}, +{ +"x": 295, +"y": 368, +"type": "cubic" +}, +{ +"x": 190, +"y": 368, +"smooth": true +}, +{ +"x": 80, +"y": 368 +} +], +"isClosed": true +} +] +}, +"xAdvance": 443 +} +}, +"MutatorSansLightCondensed/support.crossbar": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 39, +"y": 0 +}, +{ +"x": 272, +"y": 0 +}, +{ +"x": 272, +"y": 772 +}, +{ +"x": 39, +"y": 772 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 223, +"y": 321 +}, +{ +"x": 317, +"y": 321, +"smooth": true +}, +{ +"x": 367, +"y": 321, +"type": "cubic" +}, +{ +"x": 398, +"y": 302, +"type": "cubic" +}, +{ +"x": 398, +"y": 250, +"smooth": true +}, +{ +"x": 398, +"y": 201, +"type": "cubic" +}, +{ +"x": 366, +"y": 181, +"type": "cubic" +}, +{ +"x": 314, +"y": 181, +"smooth": true +}, +{ +"x": 223, +"y": 181 +}, +{ +"x": 223, +"y": 0 +}, +{ +"x": 347, +"y": 0, +"smooth": true +}, +{ +"x": 573, +"y": 0, +"type": "cubic" +}, +{ +"x": 626, +"y": 90, +"type": "cubic" +}, +{ +"x": 626, +"y": 217, +"smooth": true +}, +{ +"x": 626, +"y": 332, +"type": "cubic" +}, +{ +"x": 572, +"y": 398, +"type": "cubic" +}, +{ +"x": 471, +"y": 413 +}, +{ +"x": 469, +"y": 369 +}, +{ +"x": 550, +"y": 385, +"type": "cubic" +}, +{ +"x": 613, +"y": 443, +"type": "cubic" +}, +{ +"x": 613, +"y": 550, +"smooth": true +}, +{ +"x": 613, +"y": 685, +"type": "cubic" +}, +{ +"x": 551, +"y": 772, +"type": "cubic" +}, +{ +"x": 337, +"y": 772, +"smooth": true +}, +{ +"x": 223, +"y": 772 +}, +{ +"x": 223, +"y": 600 +}, +{ +"x": 311, +"y": 600, +"smooth": true +}, +{ +"x": 366, +"y": 600, +"type": "cubic" +}, +{ +"x": 392, +"y": 581, +"type": "cubic" +}, +{ +"x": 392, +"y": 534, +"smooth": true +}, +{ +"x": 392, +"y": 483, +"type": "cubic" +}, +{ +"x": 362, +"y": 467, +"type": "cubic" +}, +{ +"x": 311, +"y": 467, +"smooth": true +}, +{ +"x": 223, +"y": 467 +} +], +"isClosed": true +} +] +}, +"xAdvance": 645 +} +}, +"MutatorSansLightWide/foreground": { +"glyph": { +"path": { +"contours": [ +{ +"points": [ +{ +"x": 120, +"y": 0 +}, +{ +"x": 160, +"y": 0 +}, +{ +"x": 160, +"y": 700 +}, +{ +"x": 120, +"y": 700 +} +], +"isClosed": true +}, +{ +"points": [ +{ +"x": 140, +"y": 333 +}, +{ +"x": 880, +"y": 333, +"smooth": true +}, +{ +"x": 999, +"y": 333, +"type": "cubic" +}, +{ +"x": 1054, +"y": 269, +"type": "cubic" +}, +{ +"x": 1054, +"y": 183, +"smooth": true +}, +{ +"x": 1054, +"y": 97, +"type": "cubic" +}, +{ +"x": 999, +"y": 36, +"type": "cubic" +}, +{ +"x": 880, +"y": 36, +"smooth": true +}, +{ +"x": 140, +"y": 36 +}, +{ +"x": 140, +"y": 0 +}, +{ +"x": 870, +"y": 0, +"smooth": true +}, +{ +"x": 1030, +"y": 0, +"type": "cubic" +}, +{ +"x": 1093, +"y": 83, +"type": "cubic" +}, +{ +"x": 1093, +"y": 183, +"smooth": true +}, +{ +"x": 1093, +"y": 273, +"type": "cubic" +}, +{ +"x": 1043, +"y": 347, +"type": "cubic" +}, +{ +"x": 920, +"y": 363 +}, +{ +"x": 900, +"y": 345 +}, +{ +"x": 994, +"y": 371, +"type": "cubic" +}, +{ +"x": 1033, +"y": 439, +"type": "cubic" +}, +{ +"x": 1033, +"y": 517, +"smooth": true +}, +{ +"x": 1033, +"y": 618, +"type": "cubic" +}, +{ +"x": 970, +"y": 700, +"type": "cubic" +}, +{ +"x": 810, +"y": 700, +"smooth": true +}, +{ +"x": 140, +"y": 700 +}, +{ +"x": 140, +"y": 664 +}, +{ +"x": 820, +"y": 664, +"smooth": true +}, +{ +"x": 939, +"y": 664, +"type": "cubic" +}, +{ +"x": 994, +"y": 603, +"type": "cubic" +}, +{ +"x": 994, +"y": 517, +"smooth": true +}, +{ +"x": 994, +"y": 431, +"type": "cubic" +}, +{ +"x": 939, +"y": 368, +"type": "cubic" +}, +{ +"x": 820, +"y": 368, +"smooth": true +}, +{ +"x": 140, +"y": 368 +} +], +"isClosed": true +} +] +}, +"xAdvance": 1173 +} +} +} +} diff --git a/test-py/test_workflow.py b/test-py/test_workflow.py index 4cc0a63bb..8dd4acdaa 100644 --- a/test-py/test_workflow.py +++ b/test-py/test_workflow.py @@ -1244,6 +1244,22 @@ def test_command(tmpdir, configYAMLSources, substitutions): False, [], ), + ( + "generate-kern-feature", + """ + steps: + - input: fontra-read + source: "test-py/data/workflow/input1-A.fontra" + - filter: subset-axes + dropAxisNames: ["italic"] + - filter: generate-kern-feature + dropKern: true + - output: fontra-write + destination: "output-generate-kern-feature.fontra" + """, + False, + [], + ), ( "instantiate-location-base", """