diff --git a/Lib/glyphsLib/builder/builders.py b/Lib/glyphsLib/builder/builders.py
index 74ec553af..60c50c54d 100644
--- a/Lib/glyphsLib/builder/builders.py
+++ b/Lib/glyphsLib/builder/builders.py
@@ -508,6 +508,10 @@ def _copy_bracket_layers_to_ufo_glyphs(self, bracket_layer_map):
)
# swap components if base glyph contains matching bracket layers.
for comp in ufo_glyph.components:
+ if comp.baseGlyph == glyph_name:
+ # Do not create self referencing glyph components. See:
+ # tests\builder\designspace_roundtrip_test.py::test_roundtrip_self_ref
+ continue
bracket_comp_name = _bracket_glyph_name(
comp.baseGlyph, reverse, location
)
diff --git a/tests/builder/designspace_roundtrip_test.py b/tests/builder/designspace_roundtrip_test.py
index 0c9685b57..86b4b8c81 100644
--- a/tests/builder/designspace_roundtrip_test.py
+++ b/tests/builder/designspace_roundtrip_test.py
@@ -76,3 +76,52 @@ def test_default_master_roundtrips(ufo_module):
assert reg.copyGroups is True
assert reg.copyInfo is True
assert reg.copyLib is True
+
+
+def test_roundtrip_self_ref(datadir, ufo_module):
+ """This test is to solve the problem of roundtrips sometimes resulting in
+ broken ufos when working with bracket layers.
+
+ Starting with UFO: It's okay to have a bracket glyph that references its
+ base glyph as a component. However, on the glyphs.app side it's not okay
+ because the base and bracket glyphs are merged into a single glyph with
+ the bracket glyph now being a layer. Glyphsapp (2.6.1) does not like the
+ self referencing component, but that's the best we can do to preserve the
+ information.
+
+ The goal here is to make sure that the valid ufo we start with, is still
+ valid in ufo after roundtriping. We are not concerned with making
+ glyphs.app work properly at the intemediary stage.
+ """
+ path = datadir / "BracketSelfReference/BracketSelfReference.designspace"
+ designspace = designspaceLib.DesignSpaceDocument.fromfile(path)
+
+ for source in designspace.sources:
+ font = ufo_module.Font(source.path)
+ assert "zero" in font
+ assert "zero.BRACKET.500" in font
+ assert "space" in font
+
+ # Check zero.BRACKET.500 component correct
+ assert font["zero.BRACKET.500"].components[0].baseGlyph == "zero"
+
+ gs_font = to_glyphs(designspace)
+
+ # Check that the "zero" glyph contains our bracket layers
+ glyph_obj = gs_font.glyphs["zero"]
+ layer_names = [layer.name for layer in glyph_obj.layers]
+ assert "Regular [500]" in layer_names
+ assert "Bold [500]" in layer_names
+
+ # Check that our bracket layers contain the base glyph as a component
+ bracket_layers = [layer for layer in glyph_obj.layers if "[500]" in layer.name]
+ for layer in bracket_layers:
+ component_names = [component.name for component in layer.components]
+ assert component_names == ["zero"]
+
+ designspace2 = to_designspace(gs_font, ufo_module=ufo_module)
+ ufos = [source.font for source in designspace2.sources]
+
+ # Check zero.BRACKET.500 does not reference itself after roundtrip
+ for ufo in ufos:
+ assert ufo["zero.BRACKET.500"].components[0].baseGlyph == "zero"
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/fontinfo.plist b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/fontinfo.plist
new file mode 100644
index 000000000..d8777d445
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/fontinfo.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ ascender
+ 800
+ capHeight
+ 700
+ descender
+ -200
+ familyName
+ BracketSelfReference
+ italicAngle
+ 0
+ openTypeHeadCreated
+ 2019/07/25 10:20:06
+ openTypeOS2Type
+
+ 3
+
+ postscriptUnderlinePosition
+ -100
+ postscriptUnderlineThickness
+ 50
+ styleName
+ Bold
+ unitsPerEm
+ 1000
+ versionMajor
+ 1
+ versionMinor
+ 0
+ xHeight
+ 500
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/contents.plist b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/contents.plist
new file mode 100644
index 000000000..d0681736d
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/contents.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ space
+ space.glif
+ zero
+ zero.glif
+ zero.BRACKET.500
+ zero.B_R_A_C_K_E_T_.500.glif
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/layerinfo.plist b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/layerinfo.plist
new file mode 100644
index 000000000..88994ea41
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/layerinfo.plist
@@ -0,0 +1,15 @@
+
+
+
+
+ lib
+
+ com.schriftgestaltung.layerId
+ 48798C20-C9A0-4BB9-9A3E-BDB30805D9C9
+ com.schriftgestaltung.layerOrderInGlyph.space
+ 1
+ com.schriftgestaltung.layerOrderInGlyph.zero
+ 0
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/space.glif b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/space.glif
new file mode 100644
index 000000000..56fe0bf3d
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/space.glif
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2019/07/25 10:21:14
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/zero.B_R_A_C_K_E_T_.500.glif b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/zero.B_R_A_C_K_E_T_.500.glif
new file mode 100644
index 000000000..ed8933060
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/zero.B_R_A_C_K_E_T_.500.glif
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs._originalLayerName
+ Bold [500]
+ com.schriftgestaltung.Glyphs.lastChange
+ 2021/03/31 15:27:05
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/zero.glif b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/zero.glif
new file mode 100644
index 000000000..ed2efb1d6
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/glyphs/zero.glif
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2021/03/31 15:27:05
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/layercontents.plist b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/layercontents.plist
new file mode 100644
index 000000000..b9c1a4f27
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/layercontents.plist
@@ -0,0 +1,10 @@
+
+
+
+
+
+ public.default
+ glyphs
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/lib.plist b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/lib.plist
new file mode 100644
index 000000000..6c2dcff1e
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/lib.plist
@@ -0,0 +1,67 @@
+
+
+
+
+ com.schriftgestaltung.appVersion
+ 1352
+ com.schriftgestaltung.customParameter.GSFont.Axes
+
+
+ Name
+ Weight
+ Tag
+ wght
+
+
+ Name
+ Width
+ Tag
+ wdth
+
+
+ com.schriftgestaltung.customParameter.GSFont.DisplayStrings
+
+
+ 0
+
+
+
+ com.schriftgestaltung.customParameter.GSFont.disablesAutomaticAlignment
+
+ com.schriftgestaltung.customParameter.GSFont.useNiceNames
+ 1
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue1
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue2
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue3
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.iconName
+
+ com.schriftgestaltung.customParameter.GSFontMaster.weightValue
+ 700
+ com.schriftgestaltung.customParameter.GSFontMaster.widthValue
+ 100
+ com.schriftgestaltung.fontMasterID
+ 48798C20-C9A0-4BB9-9A3E-BDB30805D9C9
+ com.schriftgestaltung.fontMasterOrder
+ 1
+ com.schriftgestaltung.keyboardIncrement
+ 1
+ com.schriftgestaltung.weight
+ Bold
+ com.schriftgestaltung.weightValue
+ 700
+ com.schriftgestaltung.width
+ Regular
+ com.schriftgestaltung.widthValue
+ 100
+ public.glyphOrder
+
+ zero
+ space
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/metainfo.plist b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/metainfo.plist
new file mode 100644
index 000000000..7b8b34ac6
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Bold.ufo/metainfo.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ creator
+ com.github.fonttools.ufoLib
+ formatVersion
+ 3
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/fontinfo.plist b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/fontinfo.plist
new file mode 100644
index 000000000..9bf5a01d5
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/fontinfo.plist
@@ -0,0 +1,36 @@
+
+
+
+
+ ascender
+ 800
+ capHeight
+ 700
+ descender
+ -200
+ familyName
+ BracketSelfReference
+ italicAngle
+ 0
+ openTypeHeadCreated
+ 2019/07/25 10:20:06
+ openTypeOS2Type
+
+ 3
+
+ postscriptUnderlinePosition
+ -100
+ postscriptUnderlineThickness
+ 50
+ styleName
+ Regular
+ unitsPerEm
+ 1000
+ versionMajor
+ 1
+ versionMinor
+ 0
+ xHeight
+ 500
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/contents.plist b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/contents.plist
new file mode 100644
index 000000000..d0681736d
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/contents.plist
@@ -0,0 +1,12 @@
+
+
+
+
+ space
+ space.glif
+ zero
+ zero.glif
+ zero.BRACKET.500
+ zero.B_R_A_C_K_E_T_.500.glif
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/layerinfo.plist b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/layerinfo.plist
new file mode 100644
index 000000000..695afa81d
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/layerinfo.plist
@@ -0,0 +1,15 @@
+
+
+
+
+ lib
+
+ com.schriftgestaltung.layerId
+ AC80BBED-896D-4DAA-A852-C79F9201ACE8
+ com.schriftgestaltung.layerOrderInGlyph.space
+ 0
+ com.schriftgestaltung.layerOrderInGlyph.zero
+ 1
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/space.glif b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/space.glif
new file mode 100644
index 000000000..56fe0bf3d
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/space.glif
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2019/07/25 10:21:14
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/zero.B_R_A_C_K_E_T_.500.glif b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/zero.B_R_A_C_K_E_T_.500.glif
new file mode 100644
index 000000000..32284cc54
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/zero.B_R_A_C_K_E_T_.500.glif
@@ -0,0 +1,15 @@
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs._originalLayerName
+ Regular [500]
+ com.schriftgestaltung.Glyphs.lastChange
+ 2021/03/31 15:27:05
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/zero.glif b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/zero.glif
new file mode 100644
index 000000000..240669d67
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/glyphs/zero.glif
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2021/03/31 15:27:05
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/layercontents.plist b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/layercontents.plist
new file mode 100644
index 000000000..b9c1a4f27
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/layercontents.plist
@@ -0,0 +1,10 @@
+
+
+
+
+
+ public.default
+ glyphs
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/lib.plist b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/lib.plist
new file mode 100644
index 000000000..a11506a4a
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/lib.plist
@@ -0,0 +1,67 @@
+
+
+
+
+ com.schriftgestaltung.appVersion
+ 1352
+ com.schriftgestaltung.customParameter.GSFont.Axes
+
+
+ Name
+ Weight
+ Tag
+ wght
+
+
+ Name
+ Width
+ Tag
+ wdth
+
+
+ com.schriftgestaltung.customParameter.GSFont.DisplayStrings
+
+
+ 0
+
+
+
+ com.schriftgestaltung.customParameter.GSFont.disablesAutomaticAlignment
+
+ com.schriftgestaltung.customParameter.GSFont.useNiceNames
+ 1
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue1
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue2
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.customValue3
+ 0
+ com.schriftgestaltung.customParameter.GSFontMaster.iconName
+
+ com.schriftgestaltung.customParameter.GSFontMaster.weightValue
+ 400
+ com.schriftgestaltung.customParameter.GSFontMaster.widthValue
+ 100
+ com.schriftgestaltung.fontMasterID
+ AC80BBED-896D-4DAA-A852-C79F9201ACE8
+ com.schriftgestaltung.fontMasterOrder
+ 0
+ com.schriftgestaltung.keyboardIncrement
+ 1
+ com.schriftgestaltung.weight
+ Regular
+ com.schriftgestaltung.weightValue
+ 400
+ com.schriftgestaltung.width
+ Regular
+ com.schriftgestaltung.widthValue
+ 100
+ public.glyphOrder
+
+ zero
+ space
+
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/metainfo.plist b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/metainfo.plist
new file mode 100644
index 000000000..7b8b34ac6
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference-Regular.ufo/metainfo.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ creator
+ com.github.fonttools.ufoLib
+ formatVersion
+ 3
+
+
diff --git a/tests/data/BracketSelfReference/BracketSelfReference.designspace b/tests/data/BracketSelfReference/BracketSelfReference.designspace
new file mode 100644
index 000000000..40839dab0
--- /dev/null
+++ b/tests/data/BracketSelfReference/BracketSelfReference.designspace
@@ -0,0 +1,132 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.export
+
+ com.schriftgestaltung.intanceInterpolations
+
+ AC80BBED-896D-4DAA-A852-C79F9201ACE8
+ 1
+
+ com.schriftgestaltung.manualInterpolation
+
+ com.schriftgestaltung.weight
+ Regular
+ com.schriftgestaltung.width
+ Medium (normal)
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.export
+
+ com.schriftgestaltung.intanceInterpolations
+
+ 48798C20-C9A0-4BB9-9A3E-BDB30805D9C9
+ 0.66667
+ AC80BBED-896D-4DAA-A852-C79F9201ACE8
+ 0.33333
+
+ com.schriftgestaltung.manualInterpolation
+
+ com.schriftgestaltung.weight
+ SemiBold
+ com.schriftgestaltung.width
+ Medium (normal)
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.export
+
+ com.schriftgestaltung.intanceInterpolations
+
+ 48798C20-C9A0-4BB9-9A3E-BDB30805D9C9
+ 1
+
+ com.schriftgestaltung.manualInterpolation
+
+ com.schriftgestaltung.weight
+ Bold
+ com.schriftgestaltung.width
+ Medium (normal)
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.export
+
+ com.schriftgestaltung.intanceInterpolations
+
+ 48798C20-C9A0-4BB9-9A3E-BDB30805D9C9
+ 0.33333
+ AC80BBED-896D-4DAA-A852-C79F9201ACE8
+ 0.66667
+
+ com.schriftgestaltung.manualInterpolation
+
+ com.schriftgestaltung.weight
+ Medium
+ com.schriftgestaltung.width
+ Medium (normal)
+
+
+
+
+