From bb433a71345d689001abb087c758e397df34b17b Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 16 Apr 2024 17:28:41 +0200 Subject: [PATCH 1/3] upconvert legacy data that uses old and twisted shadow axis rules --- src/fontra_rcjk/backend_fs.py | 4 +- src/fontra_rcjk/backend_mysql.py | 5 +- src/fontra_rcjk/base.py | 46 ++++++++++++++++++- .../characterGlyph/uni0030.glif | 15 +----- tests/test_font.py | 6 +-- 5 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/fontra_rcjk/backend_fs.py b/src/fontra_rcjk/backend_fs.py index 4221bcb..b5108b2 100644 --- a/src/fontra_rcjk/backend_fs.py +++ b/src/fontra_rcjk/backend_fs.py @@ -164,7 +164,9 @@ async def getGlyph(self, glyphName: str) -> VariableGlyph | None: layerGlyphs = self._getLayerGlyphs(glyphName) except KeyError: return None - return buildVariableGlyphFromLayerGlyphs(layerGlyphs) + return buildVariableGlyphFromLayerGlyphs( + layerGlyphs, self.designspace.axes.axes + ) def _getLayerGlyphs(self, glyphName): layerGlyphs = self._tempGlyphCache.get(glyphName) diff --git a/src/fontra_rcjk/backend_mysql.py b/src/fontra_rcjk/backend_mysql.py index dc555c4..04b1b25 100644 --- a/src/fontra_rcjk/backend_mysql.py +++ b/src/fontra_rcjk/backend_mysql.py @@ -256,8 +256,11 @@ async def getGlyph(self, glyphName: str) -> VariableGlyph | None: return None glyph = self._readGlyphFromCacheDir(glyphName) if glyph is None: + designspace = await self._getDesignspace() layerGlyphs = await self._getLayerGlyphs(glyphName) - glyph = buildVariableGlyphFromLayerGlyphs(layerGlyphs) + glyph = buildVariableGlyphFromLayerGlyphs( + layerGlyphs, designspace.axes.axes + ) self._writeGlyphToCacheDir(glyphName, glyph) return glyph diff --git a/src/fontra_rcjk/base.py b/src/fontra_rcjk/base.py index 1422372..4431435 100644 --- a/src/fontra_rcjk/base.py +++ b/src/fontra_rcjk/base.py @@ -22,6 +22,7 @@ from fontTools.misc.transform import DecomposedTransform from fontTools.ufoLib.filenames import illegalCharacters from fontTools.ufoLib.glifLib import readGlyphFromString, writeGlyphToString +from fontTools.varLib.models import piecewiseLinearMap FONTRA_STATUS_KEY = "fontra.development.status" @@ -119,7 +120,7 @@ def cleanupAxis(axisDict): return GlyphAxis(**axisDict) -def buildVariableGlyphFromLayerGlyphs(layerGlyphs) -> VariableGlyph: +def buildVariableGlyphFromLayerGlyphs(layerGlyphs, fontAxes) -> VariableGlyph: layers = { layerName: Layer(glyph=glyph.toStaticGlyph()) for layerName, glyph in layerGlyphs.items() @@ -219,13 +220,51 @@ def buildVariableGlyphFromLayerGlyphs(layerGlyphs) -> VariableGlyph: for layerName, layer in layers.items() } - return VariableGlyph( + glyph = VariableGlyph( name=defaultGlyph.name, axes=defaultGlyph.axes, sources=sources, layers=layers, ) + if not defaultGlyph.lib.get("robocjk.localAxes.behavior.2024", False): + upconvertShadowAxes(glyph, fontAxes) + + return glyph + + +def upconvertShadowAxes(glyph, fontAxes): + fontAxisNames = {axis.name for axis in fontAxes} + glyphAxisNames = {axis.name for axis in glyph.axes} + if fontAxisNames.isdisjoint(glyphAxisNames): + return + + glyphAxesByName = {axis.name: axis for axis in glyph.axes} + + for fontAxis in fontAxes: + axisName = fontAxis.name + fontAxisTuple = (fontAxis.minValue, fontAxis.defaultValue, fontAxis.maxValue) + if fontAxis.mapping: + mapping = dict(fontAxis.mapping) + fontAxisTuple = tuple(piecewiseLinearMap(v, mapping) for v in fontAxisTuple) + glyphAxis = glyphAxesByName.get(axisName) + if glyphAxis is None: + continue + + mapping = dict( + zip( + [glyphAxis.minValue, glyphAxis.defaultValue, glyphAxis.maxValue], + fontAxisTuple, + ) + ) + + for source in glyph.sources: + v = source.location.get(axisName) + if v is not None: + source.location[axisName] = piecewiseLinearMap(v, mapping) + + glyph.axes = [axis for axis in glyph.axes if axis.name not in fontAxisNames] + def buildVariableComponentsFromLibComponents(deepComponents, dcNames): components = [] @@ -359,6 +398,9 @@ def buildLayerGlyphsFromVariableGlyph( # Get rid of legacy data defaultGlyph.lib.pop("fontra.layerNames", None) + # Mark that we shouldn't try to upconvert shadow axes + defaultGlyph.lib["robocjk.localAxes.behavior.2024"] = True + return layerGlyphs diff --git a/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif b/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif index 734ab1f..8b1c9ea 100644 --- a/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif +++ b/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif @@ -11,19 +11,6 @@ public.markColor 1,0,0,1 - robocjk.axes - - - defaultValue - 0 - maxValue - 1 - minValue - 0 - name - wght - - robocjk.deepComponents @@ -96,7 +83,7 @@ location wght - 1.0 + 700.0 on diff --git a/tests/test_font.py b/tests/test_font.py index 7c09821..6cc0e24 100644 --- a/tests/test_font.py +++ b/tests/test_font.py @@ -154,9 +154,7 @@ ( "rcjk", { - "axes": [ - {"defaultValue": 0.0, "maxValue": 1.0, "minValue": 0.0, "name": "wght"} - ], + "axes": [], "name": "uni0031", "sources": [ { @@ -167,7 +165,7 @@ }, { "name": "wght", - "location": {"wght": 1.0}, + "location": {"wght": 700}, "layerName": "wght", "customData": {"fontra.development.status": 0}, }, From 2f9eb65e904cdf9b9d747ff8b1e856154478ded0 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 16 Apr 2024 17:29:15 +0200 Subject: [PATCH 2/3] Whitespace --- src/fontra_rcjk/base.py | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fontra_rcjk/base.py b/src/fontra_rcjk/base.py index 4431435..0f62dff 100644 --- a/src/fontra_rcjk/base.py +++ b/src/fontra_rcjk/base.py @@ -247,6 +247,7 @@ def upconvertShadowAxes(glyph, fontAxes): if fontAxis.mapping: mapping = dict(fontAxis.mapping) fontAxisTuple = tuple(piecewiseLinearMap(v, mapping) for v in fontAxisTuple) + glyphAxis = glyphAxesByName.get(axisName) if glyphAxis is None: continue From f1a88adfc667c8f924545c94506792cb254374c1 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 16 Apr 2024 17:41:31 +0200 Subject: [PATCH 3/3] Adjust test data to new shadow axis behavior --- tests/data/figArnaud.rcjk/characterGlyph/a.glif | 2 ++ .../figArnaud.rcjk/characterGlyph/uni0030.glif | 2 ++ tests/test_font.py | 14 ++++++++++++++ 3 files changed, 18 insertions(+) diff --git a/tests/data/figArnaud.rcjk/characterGlyph/a.glif b/tests/data/figArnaud.rcjk/characterGlyph/a.glif index 7ffd2f8..12e54e3 100644 --- a/tests/data/figArnaud.rcjk/characterGlyph/a.glif +++ b/tests/data/figArnaud.rcjk/characterGlyph/a.glif @@ -15,6 +15,8 @@ some note + robocjk.localAxes.behavior.2024 + robocjk.status 0 robocjk.variationGlyphs diff --git a/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif b/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif index 8b1c9ea..af42200 100644 --- a/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif +++ b/tests/data/figArnaud.rcjk/characterGlyph/uni0030.glif @@ -42,6 +42,8 @@ + robocjk.localAxes.behavior.2024 + robocjk.status 0 robocjk.variationGlyphs diff --git a/tests/test_font.py b/tests/test_font.py index 6cc0e24..ed29975 100644 --- a/tests/test_font.py +++ b/tests/test_font.py @@ -480,6 +480,8 @@ def writableTestFont(tmpdir): " ", " ", " ", + " robocjk.localAxes.behavior.2024", + " ", " robocjk.status", " 0", " robocjk.variationGlyphs", @@ -525,6 +527,8 @@ def writableTestFont(tmpdir): " ", " ", " ", + " robocjk.localAxes.behavior.2024", + " ", " robocjk.status", " 0", " robocjk.variationGlyphs", @@ -590,6 +594,8 @@ async def test_putGlyph(writableTestFont): " ", " ", " ", + " robocjk.localAxes.behavior.2024", + " ", " robocjk.status", " 0", " xyz.fontra.something.nothing", @@ -642,6 +648,8 @@ async def test_delete_source_layer(writableTestFont): " wght", " ", " ", + " robocjk.localAxes.behavior.2024", + " ", " robocjk.status", " 0", " robocjk.variationGlyphs", @@ -750,6 +758,8 @@ async def test_write_roundtrip(writableTestFont, glyphName): " ", " ", " ", + " robocjk.localAxes.behavior.2024", + " ", " robocjk.status", " 0", " robocjk.variationGlyphs", @@ -848,6 +858,8 @@ async def test_bad_layer_name(writableTestFont): " ", " public.markColor", " 1,0,0,1", + " robocjk.localAxes.behavior.2024", + " ", " robocjk.status", " 0", " xyz.fontra.test", @@ -975,6 +987,8 @@ async def test_readMixClassicAndVariableComponents(): " ", " ", " ", + " robocjk.localAxes.behavior.2024", + " ", " robocjk.status", " 0", " ",