From f9c995b0bf286c617234556fc9de57f8cf48a06a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 24 Jul 2024 14:48:53 +0200 Subject: [PATCH 1/5] Add support for locationBase --- src/fontra_rcjk/base.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/fontra_rcjk/base.py b/src/fontra_rcjk/base.py index a3b186e..510317a 100644 --- a/src/fontra_rcjk/base.py +++ b/src/fontra_rcjk/base.py @@ -149,6 +149,7 @@ def buildVariableGlyphFromLayerGlyphs(layerGlyphs, fontAxes) -> VariableGlyph: sources = [ GlyphSource( name="", + locationBase=defaultGlyph.lib.get("robocjk.locationBase"), layerName="foreground", customData={FONTRA_STATUS_KEY: defaultGlyph.lib.get("robocjk.status", 0)}, ) @@ -209,6 +210,7 @@ def buildVariableGlyphFromLayerGlyphs(layerGlyphs, fontAxes) -> VariableGlyph: if components: layerGlyph.components += components + locationBase = varDict.get("locationBase") location = varDict["location"] location = { k: float(v) if isinstance(v, str) else v for k, v in location.items() @@ -216,6 +218,7 @@ def buildVariableGlyphFromLayerGlyphs(layerGlyphs, fontAxes) -> VariableGlyph: sources.append( GlyphSource( name=sourceName, + locationBase=locationBase, location=location, layerName=fontraLayerNameMapping.get(layerName, layerName), inactive=inactiveFlag, @@ -362,6 +365,8 @@ def buildLayerGlyphsFromVariableGlyph( devStatus = source.customData.get(FONTRA_STATUS_KEY, 0) if source.layerName == defaultLayerName: defaultGlyph.lib["robocjk.status"] = devStatus + if source.locationBase is not None: + defaultGlyph.lib["robocjk.locationBase"] = source.locationBase # This is the default glyph, we don't treat it like a layer in .rcjk continue @@ -372,9 +377,13 @@ def buildLayerGlyphsFromVariableGlyph( "location": source.location, "status": devStatus, } + if layerGlyph.width != defaultGlyph.width: varDict["width"] = layerGlyph.width + if source.locationBase is not None: + varDict["locationBase"] = source.locationBase + deepComponents = buildLibComponentsFromVariableComponents( layerGlyph.variableComponents ) From c8ec4afd663c61225224c8c96de4ff842575c106 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 24 Jul 2024 21:23:54 +0200 Subject: [PATCH 2/5] Add test font that uses locationBase, test round tripping --- .../characterGlyph/A_.glif | 97 ++++++++++ .../characterGlyph/B_.glif | 133 ++++++++++++++ .../A_.glif | 32 ++++ .../B_.glif | 50 +++++ .../A_.glif | 32 ++++ .../B_.glif | 50 +++++ .../A_.glif | 8 + .../B_.glif | 50 +++++ .../A_.glif | 32 ++++ .../B_.glif | 50 +++++ .../designspace.json | 173 ++++++++++++++++++ .../MutatorSansLocationBase.rcjk/fontLib.json | 1 + tests/test_font.py | 27 ++- 13 files changed, 734 insertions(+), 1 deletion(-) create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/A_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/B_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/A_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/B_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/A_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/B_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.20b935b5a9fb/A_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.cro.1347e01e146b/B_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/A_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/B_.glif create mode 100644 tests/data/MutatorSansLocationBase.rcjk/designspace.json create mode 100644 tests/data/MutatorSansLocationBase.rcjk/fontLib.json diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/A_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/A_.glif new file mode 100644 index 0000000..80a9cb4 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/A_.glif @@ -0,0 +1,97 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + robocjk.locationBase + 5bea6334 + robocjk.status + 0 + robocjk.variationGlyphs + + + fontraLayerName + MutatorSansBoldCondensed/foreground + layerName + MutatorSansBoldCondensed_foreground.db3714ad9ac4 + location + + locationBase + f22d1bbd + on + + sourceName + BoldCondensed + status + 0 + width + 740 + + + fontraLayerName + MutatorSansLightWide/foreground + layerName + MutatorSansLightWide_foreground.8bb25a79b80b + location + + locationBase + d7abd222 + on + + sourceName + LightWide + status + 0 + width + 1190 + + + fontraLayerName + MutatorSansBoldWide/foreground + layerName + MutatorSansBoldWide_foreground.53eb9954912f + location + + locationBase + 5d4e7f1d + on + + sourceName + BoldWide + status + 0 + width + 1290 + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/B_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/B_.glif new file mode 100644 index 0000000..6d4d594 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/B_.glif @@ -0,0 +1,133 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + robocjk.locationBase + 5bea6334 + robocjk.status + 0 + robocjk.variationGlyphs + + + fontraLayerName + MutatorSansBoldCondensed/foreground + layerName + MutatorSansBoldCondensed_foreground.db3714ad9ac4 + location + + locationBase + f22d1bbd + on + + sourceName + BoldCondensed + status + 0 + width + 710 + + + fontraLayerName + MutatorSansLightWide/foreground + layerName + MutatorSansLightWide_foreground.8bb25a79b80b + location + + locationBase + d7abd222 + on + + sourceName + LightWide + status + 0 + width + 1173 + + + fontraLayerName + MutatorSansBoldWide/foreground + layerName + MutatorSansBoldWide_foreground.53eb9954912f + location + + locationBase + 5d4e7f1d + on + + sourceName + BoldWide + status + 0 + width + 1270 + + + fontraLayerName + MutatorSansLightCondensed/support.crossbar + layerName + MutatorSansLightCondensed_support.cro.1347e01e146b + location + + locationBase + 3aa9223b + on + + sourceName + support.crossbar + status + 0 + width + 645 + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/A_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/A_.glif new file mode 100644 index 0000000..3d1a033 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/A_.glif @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/B_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/B_.glif new file mode 100644 index 0000000..f9ffaf4 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldCondensed_foreground.db3714ad9ac4/B_.glif @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/A_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/A_.glif new file mode 100644 index 0000000..5b0d9cb --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/A_.glif @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/B_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/B_.glif new file mode 100644 index 0000000..8bfd311 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansBoldWide_foreground.53eb9954912f/B_.glif @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.20b935b5a9fb/A_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.20b935b5a9fb/A_.glif new file mode 100644 index 0000000..d41c075 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.20b935b5a9fb/A_.glif @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.cro.1347e01e146b/B_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.cro.1347e01e146b/B_.glif new file mode 100644 index 0000000..bc37f19 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightCondensed_support.cro.1347e01e146b/B_.glif @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/A_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/A_.glif new file mode 100644 index 0000000..20644c3 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/A_.glif @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/B_.glif b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/B_.glif new file mode 100644 index 0000000..3e5d1ce --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/characterGlyph/MutatorSansLightWide_foreground.8bb25a79b80b/B_.glif @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/data/MutatorSansLocationBase.rcjk/designspace.json b/tests/data/MutatorSansLocationBase.rcjk/designspace.json new file mode 100644 index 0000000..b38247e --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/designspace.json @@ -0,0 +1,173 @@ +{ + "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/tests/data/MutatorSansLocationBase.rcjk/fontLib.json b/tests/data/MutatorSansLocationBase.rcjk/fontLib.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/tests/data/MutatorSansLocationBase.rcjk/fontLib.json @@ -0,0 +1 @@ +{} diff --git a/tests/test_font.py b/tests/test_font.py index e9e64a6..9b8bafc 100644 --- a/tests/test_font.py +++ b/tests/test_font.py @@ -5,7 +5,8 @@ from importlib.metadata import entry_points import pytest -from fontra.backends import getFileSystemBackend +from fontra.backends import getFileSystemBackend, newFileSystemBackend +from fontra.backends.copy import copyFont from fontra.core.classes import ( Anchor, Axes, @@ -468,6 +469,12 @@ def writableTestFont(tmpdir): return getBackendClassByName("rcjk").fromPath(destPath) +@pytest.fixture +def mutatorTestFont(): + sourcePath = dataDir / "MutatorSansLocationBase.rcjk" + return getBackendClassByName("rcjk").fromPath(sourcePath) + + glyphData_a_before = [ "", '', @@ -1117,3 +1124,21 @@ async def test_statusFieldDefinitions(writableTestFont): fontLib = json.loads(fontLibPath.read_text()) assert editedCustomData == fontLib + + +async def test_round_trip_locationBase(mutatorTestFont, tmpdir): + tmpdir = pathlib.Path(tmpdir) + destPath = tmpdir / "test.rcjk" + + destFont = newFileSystemBackend(destPath) + + async with contextlib.aclosing(destFont), contextlib.aclosing(mutatorTestFont): + await copyFont(mutatorTestFont, destFont) + + reopenedFont = getFileSystemBackend(destPath) + async with contextlib.aclosing(reopenedFont): + for glyphName in ["A", "B"]: + sourceGlyph = await mutatorTestFont.getGlyph(glyphName) + destGlyph = await mutatorTestFont.getGlyph(glyphName) + assert sourceGlyph == destGlyph + assert all(source.locationBase for source in sourceGlyph.sources) From d80b6c9b0a3cf5f3c86eb6856f32d25fb72b5e03 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 24 Jul 2024 21:24:29 +0200 Subject: [PATCH 3/5] Better closing logic --- tests/test_font.py | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/tests/test_font.py b/tests/test_font.py index 9b8bafc..6f4b302 100644 --- a/tests/test_font.py +++ b/tests/test_font.py @@ -1132,13 +1132,14 @@ async def test_round_trip_locationBase(mutatorTestFont, tmpdir): destFont = newFileSystemBackend(destPath) - async with contextlib.aclosing(destFont), contextlib.aclosing(mutatorTestFont): - await copyFont(mutatorTestFont, destFont) - - reopenedFont = getFileSystemBackend(destPath) - async with contextlib.aclosing(reopenedFont): - for glyphName in ["A", "B"]: - sourceGlyph = await mutatorTestFont.getGlyph(glyphName) - destGlyph = await mutatorTestFont.getGlyph(glyphName) - assert sourceGlyph == destGlyph - assert all(source.locationBase for source in sourceGlyph.sources) + async with contextlib.aclosing(mutatorTestFont): + async with contextlib.aclosing(destFont): + await copyFont(mutatorTestFont, destFont) + + reopenedFont = getFileSystemBackend(destPath) + async with contextlib.aclosing(reopenedFont): + for glyphName in ["A", "B"]: + sourceGlyph = await mutatorTestFont.getGlyph(glyphName) + destGlyph = await mutatorTestFont.getGlyph(glyphName) + assert sourceGlyph == destGlyph + assert all(source.locationBase for source in sourceGlyph.sources) From 841297aafee2484547bba1c63dad4db591060c1a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 24 Jul 2024 21:35:01 +0200 Subject: [PATCH 4/5] Fix test so it actually compares different glyphs --- tests/test_font.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_font.py b/tests/test_font.py index 6f4b302..13caa34 100644 --- a/tests/test_font.py +++ b/tests/test_font.py @@ -1140,6 +1140,6 @@ async def test_round_trip_locationBase(mutatorTestFont, tmpdir): async with contextlib.aclosing(reopenedFont): for glyphName in ["A", "B"]: sourceGlyph = await mutatorTestFont.getGlyph(glyphName) - destGlyph = await mutatorTestFont.getGlyph(glyphName) + destGlyph = await reopenedFont.getGlyph(glyphName) assert sourceGlyph == destGlyph assert all(source.locationBase for source in sourceGlyph.sources) From 3d4050b8574d86efc8c08242b489cdf87158fe06 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 24 Jul 2024 21:48:07 +0200 Subject: [PATCH 5/5] Make sure to reset locationBase if it is None --- src/fontra_rcjk/base.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fontra_rcjk/base.py b/src/fontra_rcjk/base.py index 510317a..584814b 100644 --- a/src/fontra_rcjk/base.py +++ b/src/fontra_rcjk/base.py @@ -367,6 +367,8 @@ def buildLayerGlyphsFromVariableGlyph( defaultGlyph.lib["robocjk.status"] = devStatus if source.locationBase is not None: defaultGlyph.lib["robocjk.locationBase"] = source.locationBase + else: + defaultGlyph.lib.pop("robocjk.locationBase", None) # This is the default glyph, we don't treat it like a layer in .rcjk continue