diff --git a/Lib/ufo2ft/__init__.py b/Lib/ufo2ft/__init__.py
index a317d6b20..d7e382c6b 100644
--- a/Lib/ufo2ft/__init__.py
+++ b/Lib/ufo2ft/__init__.py
@@ -172,6 +172,7 @@ def compileTTF(
rememberCurveType=True,
removeOverlaps=False,
overlapsBackend=None,
+ flattenComponents=False,
inplace=False,
layerName=None,
skipExportGlyphs=None,
@@ -182,6 +183,9 @@ def compileTTF(
*removeOverlaps* performs a union operation on all the glyphs' contours.
+ *flattenComponents* un-nests glyphs so that they have at most one level of
+ components.
+
*convertCubics* and *cubicConversionError* specify how the conversion from cubic
to quadratic curves should be handled.
@@ -205,6 +209,7 @@ def compileTTF(
inplace=inplace,
removeOverlaps=removeOverlaps,
overlapsBackend=overlapsBackend,
+ flattenComponents=flattenComponents,
convertCubics=convertCubics,
conversionError=cubicConversionError,
reverseDirection=reverseDirection,
@@ -247,6 +252,7 @@ def compileInterpolatableTTFs(
useProductionNames=None,
cubicConversionError=None,
reverseDirection=True,
+ flattenComponents=False,
inplace=False,
layerNames=None,
skipExportGlyphs=None,
@@ -290,6 +296,7 @@ def compileInterpolatableTTFs(
ufos,
inplace=inplace,
conversionError=cubicConversionError,
+ flattenComponents=flattenComponents,
reverseDirection=reverseDirection,
layerNames=layerNames,
skipExportGlyphs=skipExportGlyphs,
@@ -353,6 +360,7 @@ def compileInterpolatableTTFsFromDS(
useProductionNames=None,
cubicConversionError=None,
reverseDirection=True,
+ flattenComponents=False,
inplace=False,
debugFeatureFile=None,
notdefGlyph=None,
@@ -407,6 +415,7 @@ def compileInterpolatableTTFsFromDS(
useProductionNames=useProductionNames,
cubicConversionError=cubicConversionError,
reverseDirection=reverseDirection,
+ flattenComponents=flattenComponents,
inplace=inplace,
layerNames=layerNames,
skipExportGlyphs=skipExportGlyphs,
@@ -568,6 +577,7 @@ def compileVariableTTF(
reverseDirection=True,
excludeVariationTables=(),
optimizeGvar=True,
+ flattenComponents=False,
inplace=False,
debugFeatureFile=None,
notdefGlyph=None,
@@ -597,6 +607,7 @@ def compileVariableTTF(
useProductionNames=False, # will rename glyphs after varfont is built
cubicConversionError=cubicConversionError,
reverseDirection=reverseDirection,
+ flattenComponents=flattenComponents,
inplace=inplace,
debugFeatureFile=debugFeatureFile,
notdefGlyph=notdefGlyph,
diff --git a/Lib/ufo2ft/preProcessor.py b/Lib/ufo2ft/preProcessor.py
index 81f48781d..37089c1ec 100644
--- a/Lib/ufo2ft/preProcessor.py
+++ b/Lib/ufo2ft/preProcessor.py
@@ -110,7 +110,9 @@ class TTFPreProcessor(OTFPreProcessor):
"""Preprocessor for building TrueType-flavored OpenType fonts.
By default, it decomposes all the glyphs with mixed component/contour
- outlines.
+ outlines. If the ``flattenComponents`` setting is True, glyphs with
+ nested components are flattened so that they have at most one level of
+ components.
If ``removeOverlaps`` is True, it performs a union boolean operation on
all the glyphs' contours.
@@ -144,6 +146,7 @@ def initDefaultFilters(
self,
removeOverlaps=False,
overlapsBackend=None,
+ flattenComponents=False,
convertCubics=True,
conversionError=None,
reverseDirection=True,
@@ -157,6 +160,10 @@ def initDefaultFilters(
# that have both components and at least one contour
filters.append(DecomposeComponentsFilter(include=lambda g: len(g)))
+ if flattenComponents:
+ from ufo2ft.filters.flattenComponents import FlattenComponentsFilter
+ filters.append(FlattenComponentsFilter())
+
if removeOverlaps:
from ufo2ft.filters.removeOverlaps import RemoveOverlapsFilter
@@ -196,14 +203,16 @@ class TTFInterpolatablePreProcessor(object):
be interpolation compatible, depending on the particular filter used or
whether they are applied to only some vs all of the UFOs.
- The ``conversionError``, ``reverseDirection`` and ``rememberCurveType``
- arguments work in the same way as in the ``TTFPreProcessor``.
+ The ``conversionError``, ``reverseDirection``, ``flattenComponents`` and
+ ``rememberCurveType`` arguments work in the same way as in the
+ ``TTFPreProcessor``.
"""
def __init__(
self,
ufos,
inplace=False,
+ flattenComponents=False,
conversionError=None,
reverseDirection=True,
rememberCurveType=True,
@@ -214,6 +223,7 @@ def __init__(
self.ufos = ufos
self.inplace = inplace
+ self.flattenComponents = flattenComponents
if layerNames is None:
layerNames = [None] * len(ufos)
@@ -260,6 +270,11 @@ def process(self):
for ufo, glyphSet in zip(self.ufos, self.glyphSets):
decompose(ufo, glyphSet)
+ if self.flattenComponents:
+ from ufo2ft.filters.flattenComponents import FlattenComponentsFilter
+ for ufo, glyphSet in zip(self.ufos, self.glyphSets):
+ FlattenComponentsFilter()(ufo, glyphSet)
+
# finally apply all custom post-filters
for funcs, ufo, glyphSet in zip(self.postFilters, self.ufos, self.glyphSets):
for func in funcs:
diff --git a/tests/data/NestedComponents-Bold.ufo/fontinfo.plist b/tests/data/NestedComponents-Bold.ufo/fontinfo.plist
new file mode 100644
index 000000000..a4f1c263f
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/fontinfo.plist
@@ -0,0 +1,189 @@
+
+
+
+
+ ascender
+ 750
+ capHeight
+ 750
+ descender
+ -250
+ italicAngle
+ -12.5
+ macintoshFONDFamilyID
+ 15000
+ macintoshFONDName
+ SomeFont Regular (FOND Name)
+ note
+ A note.
+ openTypeHeadCreated
+ 2000/01/01 00:00:00
+ openTypeHeadFlags
+
+ 0
+ 1
+
+ openTypeHeadLowestRecPPEM
+ 10
+ openTypeHheaCaretOffset
+ 0
+ openTypeHheaCaretSlopeRise
+ 1
+ openTypeHheaCaretSlopeRun
+ 0
+ openTypeNameCompatibleFullName
+ Some Font Regular (Compatible Full Name)
+ openTypeNameDescription
+ Some Font by Some Designer for Some Foundry.
+ openTypeNameDesigner
+ Some Designer
+ openTypeNameDesignerURL
+ http://somedesigner.com
+ openTypeNameLicense
+ License info for Some Foundry.
+ openTypeNameLicenseURL
+ http://somefoundry.com/license
+ openTypeNameManufacturer
+ Some Foundry
+ openTypeNameManufacturerURL
+ http://somefoundry.com
+ openTypeNamePreferredFamilyName
+ Some Font (Preferred Family Name)
+ openTypeNameSampleText
+ Sample Text for Some Font.
+ openTypeNameUniqueID
+ OpenType name Table Unique ID
+ openTypeNameVersion
+ OpenType name Table Version
+ openTypeNameWWSFamilyName
+ Some Font (WWS Family Name)
+ openTypeNameWWSSubfamilyName
+ Regular (WWS Subfamily Name)
+ openTypeOS2CodePageRanges
+
+ 0
+
+ openTypeOS2FamilyClass
+
+ 1
+ 1
+
+ openTypeOS2Panose
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+
+ openTypeOS2Selection
+
+ 3
+
+ openTypeOS2SubscriptXOffset
+ 0
+ openTypeOS2SubscriptXSize
+ 200
+ openTypeOS2SubscriptYOffset
+ -100
+ openTypeOS2SubscriptYSize
+ 400
+ openTypeOS2SuperscriptXOffset
+ 0
+ openTypeOS2SuperscriptXSize
+ 200
+ openTypeOS2SuperscriptYOffset
+ 200
+ openTypeOS2SuperscriptYSize
+ 400
+ openTypeOS2Type
+
+ openTypeOS2UnicodeRanges
+
+ 0
+ 1
+
+ openTypeOS2VendorID
+ SOME
+ openTypeVheaCaretOffset
+ 0
+ openTypeVheaCaretSlopeRise
+ 0
+ openTypeVheaCaretSlopeRun
+ 1
+ openTypeVheaVertTypoAscender
+ 750
+ openTypeVheaVertTypoDescender
+ -250
+ openTypeVheaVertTypoLineGap
+ 200
+ postscriptBlueFuzz
+ 1
+ postscriptBlueScale
+ 0.04
+ postscriptBlueShift
+ 7
+ postscriptBlueValues
+
+ 500.0
+ 510.0
+
+ postscriptDefaultCharacter
+ .notdef
+ postscriptDefaultWidthX
+ 400
+ postscriptFamilyBlues
+
+ 500.0
+ 510.0
+
+ postscriptFamilyOtherBlues
+
+ -260.0
+ -250.0
+
+ postscriptForceBold
+
+ postscriptIsFixedPitch
+
+ postscriptNominalWidthX
+ 400.0
+ postscriptOtherBlues
+
+ postscriptSlantAngle
+ -12.5
+ postscriptStemSnapH
+
+ 0.0
+ 0.0
+
+ postscriptStemSnapV
+
+ 0.0
+ 0.0
+
+ postscriptUniqueID
+ 4000000
+ postscriptWindowsCharacterSet
+ 1
+ styleName
+ Regular
+ trademark
+ Trademark Some Foundry
+ unitsPerEm
+ 1000
+ versionMajor
+ 1
+ versionMinor
+ 0
+ xHeight
+ 500
+ year
+ 2008
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/_notdef.glif b/tests/data/NestedComponents-Bold.ufo/glyphs/_notdef.glif
new file mode 100644
index 000000000..ba2587f06
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/_notdef.glif
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/a.glif b/tests/data/NestedComponents-Bold.ufo/glyphs/a.glif
new file mode 100644
index 000000000..68335b673
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/a.glif
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/b.glif b/tests/data/NestedComponents-Bold.ufo/glyphs/b.glif
new file mode 100644
index 000000000..050a9afab
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/b.glif
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/c.glif b/tests/data/NestedComponents-Bold.ufo/glyphs/c.glif
new file mode 100644
index 000000000..7aa3a9a77
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/c.glif
@@ -0,0 +1,23 @@
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.ComponentInfo
+
+
+ alignment
+ -1
+ index
+ 0
+ name
+ a
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/contents.plist b/tests/data/NestedComponents-Bold.ufo/glyphs/contents.plist
new file mode 100644
index 000000000..f47769123
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/contents.plist
@@ -0,0 +1,20 @@
+
+
+
+
+ .notdef
+ _notdef.glif
+ a
+ a.glif
+ b
+ b.glif
+ c
+ c.glif
+ d
+ d.glif
+ e
+ e.glif
+ space
+ space.glif
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/d.glif b/tests/data/NestedComponents-Bold.ufo/glyphs/d.glif
new file mode 100644
index 000000000..7a79ecb9f
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/d.glif
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.ComponentInfo
+
+
+ alignment
+ -1
+ index
+ 0
+ name
+ b
+
+
+ alignment
+ -1
+ index
+ 1
+ name
+ a
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/e.glif b/tests/data/NestedComponents-Bold.ufo/glyphs/e.glif
new file mode 100644
index 000000000..cd8cc9cb6
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/e.glif
@@ -0,0 +1,32 @@
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.ComponentInfo
+
+
+ alignment
+ -1
+ index
+ 0
+ name
+ c
+
+
+ alignment
+ -1
+ index
+ 1
+ name
+ d
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/glyphs/space.glif b/tests/data/NestedComponents-Bold.ufo/glyphs/space.glif
new file mode 100644
index 000000000..95c4372cf
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/glyphs/space.glif
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/layercontents.plist b/tests/data/NestedComponents-Bold.ufo/layercontents.plist
new file mode 100644
index 000000000..cf95d3573
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/layercontents.plist
@@ -0,0 +1,10 @@
+
+
+
+
+
+ public.default
+ glyphs
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/lib.plist b/tests/data/NestedComponents-Bold.ufo/lib.plist
new file mode 100644
index 000000000..ae49b07cb
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/lib.plist
@@ -0,0 +1,143 @@
+
+
+
+
+ com.schriftgestaltung.disablesAutomaticAlignment
+
+ com.schriftgestaltung.font.customParameters
+
+
+ name
+ openTypeGaspRangeRecords
+ value
+
+
+ rangeGaspBehavior
+
+ 1
+ 3
+
+ rangeMaxPPEM
+ 7
+
+
+ rangeGaspBehavior
+
+ 0
+ 1
+ 2
+ 3
+
+ rangeMaxPPEM
+ 65535
+
+
+
+
+ name
+ openTypeNameRecords
+ value
+
+
+ encodingID
+ 0
+ languageID
+ 0
+ nameID
+ 3
+ platformID
+ 1
+ string
+ Unique Font Identifier
+
+
+ encodingID
+ 1
+ languageID
+ 1033
+ nameID
+ 8
+ platformID
+ 3
+ string
+ Some Foundry (Manufacturer Name)
+
+
+
+
+ com.schriftgestaltung.font.userData
+
+ GSDimensionPlugin.Dimensions
+
+ master01
+
+
+
+ com.schriftgestaltung.fontMasterID
+ 0A7BF222-74C5-44F5-877F-4AAEDEB31DD5
+ com.schriftgestaltung.glyphOrder
+
+ .notdef
+ glyph1
+ glyph2
+ space
+ a
+ b
+ c
+ d
+ e
+ f
+ g
+ h
+ i
+ j
+ k
+ l
+
+ com.schriftgestaltung.master.name
+ Bold
+ com.schriftgestaltung.useNiceNames
+
+ com.schriftgestaltung.weightValue
+ 800
+ public.glyphOrder
+
+ .notdef
+ space
+ a
+ b
+ c
+ d
+ e
+
+ public.postscriptNames
+
+ a
+ uni0061
+ b
+ uni0062
+ c
+ uni0063
+ d
+ uni0064
+ e
+ uni0065
+ f
+ uni0066
+ g
+ uni0067
+ h
+ uni0068
+ i
+ uni0069
+ j
+ uni006A
+ k
+ uni006B
+ l
+ uni006C
+ space
+ uni0020
+
+
+
diff --git a/tests/data/NestedComponents-Bold.ufo/metainfo.plist b/tests/data/NestedComponents-Bold.ufo/metainfo.plist
new file mode 100644
index 000000000..74e4b3b4f
--- /dev/null
+++ b/tests/data/NestedComponents-Bold.ufo/metainfo.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ creator
+ com.schriftgestaltung.GlyphsUFOExport
+ formatVersion
+ 3
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/fontinfo.plist b/tests/data/NestedComponents-Regular.ufo/fontinfo.plist
new file mode 100644
index 000000000..ff553b8a8
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/fontinfo.plist
@@ -0,0 +1,276 @@
+
+
+
+
+ ascender
+ 750
+ capHeight
+ 750
+ descender
+ -250
+ guidelines
+
+
+ angle
+ 0
+ x
+ 250
+ y
+ 0
+
+
+ angle
+ 0
+ x
+ -20
+ y
+ 0
+
+
+ angle
+ 0
+ x
+ 30
+ y
+ 0
+
+
+ y
+ 500
+
+
+ y
+ -200
+
+
+ y
+ 700
+
+
+ angle
+ 135
+ x
+ 0
+ y
+ 0
+
+
+ angle
+ 45
+ x
+ 0
+ y
+ 700
+
+
+ angle
+ 135
+ x
+ 20
+ y
+ 0
+
+
+ italicAngle
+ -12.5
+ macintoshFONDFamilyID
+ 15000
+ macintoshFONDName
+ SomeFont Regular (FOND Name)
+ note
+ A note.
+ openTypeHeadCreated
+ 2000/01/01 00:00:00
+ openTypeHeadFlags
+
+ 0
+ 1
+
+ openTypeHeadLowestRecPPEM
+ 10
+ openTypeHheaAscender
+ 750
+ openTypeHheaCaretOffset
+ 0
+ openTypeHheaCaretSlopeRise
+ 1
+ openTypeHheaCaretSlopeRun
+ 0
+ openTypeHheaDescender
+ -250
+ openTypeHheaLineGap
+ 200
+ openTypeNameCompatibleFullName
+ Some Font Regular (Compatible Full Name)
+ openTypeNameDescription
+ Some Font by Some Designer for Some Foundry.
+ openTypeNameDesigner
+ Some Designer
+ openTypeNameDesignerURL
+ http://somedesigner.com
+ openTypeNameLicense
+ License info for Some Foundry.
+ openTypeNameLicenseURL
+ http://somefoundry.com/license
+ openTypeNameManufacturer
+ Some Foundry
+ openTypeNameManufacturerURL
+ http://somefoundry.com
+ openTypeNamePreferredFamilyName
+ Some Font (Preferred Family Name)
+ openTypeNameSampleText
+ Sample Text for Some Font.
+ openTypeNameUniqueID
+ OpenType name Table Unique ID
+ openTypeNameVersion
+ OpenType name Table Version
+ openTypeNameWWSFamilyName
+ Some Font (WWS Family Name)
+ openTypeNameWWSSubfamilyName
+ Regular (WWS Subfamily Name)
+ openTypeOS2CodePageRanges
+
+ 0
+
+ openTypeOS2FamilyClass
+
+ 1
+ 1
+
+ openTypeOS2Panose
+
+ 0
+ 1
+ 2
+ 3
+ 4
+ 5
+ 6
+ 7
+ 8
+ 9
+
+ openTypeOS2Selection
+
+ 3
+
+ openTypeOS2StrikeoutPosition
+ 300
+ openTypeOS2StrikeoutSize
+ 20
+ openTypeOS2SubscriptXOffset
+ 0
+ openTypeOS2SubscriptXSize
+ 200
+ openTypeOS2SubscriptYOffset
+ -100
+ openTypeOS2SubscriptYSize
+ 400
+ openTypeOS2SuperscriptXOffset
+ 0
+ openTypeOS2SuperscriptXSize
+ 200
+ openTypeOS2SuperscriptYOffset
+ 200
+ openTypeOS2SuperscriptYSize
+ 400
+ openTypeOS2Type
+
+ openTypeOS2TypoAscender
+ 750
+ openTypeOS2TypoDescender
+ -250
+ openTypeOS2TypoLineGap
+ 200
+ openTypeOS2UnicodeRanges
+
+ 0
+ 1
+
+ openTypeOS2VendorID
+ SOME
+ openTypeOS2WinAscent
+ 750
+ openTypeOS2WinDescent
+ 250
+ openTypeVheaCaretOffset
+ 0
+ openTypeVheaCaretSlopeRise
+ 0
+ openTypeVheaCaretSlopeRun
+ 1
+ openTypeVheaVertTypoAscender
+ 750
+ openTypeVheaVertTypoDescender
+ -250
+ openTypeVheaVertTypoLineGap
+ 200
+ postscriptBlueFuzz
+ 1
+ postscriptBlueScale
+ 0.04
+ postscriptBlueShift
+ 7
+ postscriptBlueValues
+
+ 500.0
+ 510.0
+
+ postscriptDefaultCharacter
+ .notdef
+ postscriptDefaultWidthX
+ 400
+ postscriptFamilyBlues
+
+ 500.0
+ 510.0
+
+ postscriptFamilyOtherBlues
+
+ -260.0
+ -250.0
+
+ postscriptForceBold
+
+ postscriptIsFixedPitch
+
+ postscriptNominalWidthX
+ 400.0
+ postscriptOtherBlues
+
+ postscriptSlantAngle
+ -12.5
+ postscriptStemSnapH
+
+ 100.0
+ 120.0
+
+ postscriptStemSnapV
+
+ 80.0
+ 90.0
+
+ postscriptUnderlinePosition
+ -200
+ postscriptUnderlineThickness
+ 20
+ postscriptUniqueID
+ 4000000
+ postscriptWindowsCharacterSet
+ 1
+ styleName
+ Regular
+ trademark
+ Trademark Some Foundry
+ unitsPerEm
+ 1000
+ versionMajor
+ 1
+ versionMinor
+ 0
+ xHeight
+ 500
+ year
+ 2008
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/_notdef.glif b/tests/data/NestedComponents-Regular.ufo/glyphs/_notdef.glif
new file mode 100644
index 000000000..571e17ff8
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/_notdef.glif
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/a.glif b/tests/data/NestedComponents-Regular.ufo/glyphs/a.glif
new file mode 100644
index 000000000..56491bef3
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/a.glif
@@ -0,0 +1,19 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2020-12-07 11:48:13 +0000
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/b.glif b/tests/data/NestedComponents-Regular.ufo/glyphs/b.glif
new file mode 100644
index 000000000..cfa3215f2
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/b.glif
@@ -0,0 +1,27 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2020-12-07 11:48:16 +0000
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/c.glif b/tests/data/NestedComponents-Regular.ufo/glyphs/c.glif
new file mode 100644
index 000000000..eba4d273c
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/c.glif
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.ComponentInfo
+
+
+ alignment
+ -1
+ index
+ 0
+ name
+ a
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2020-12-07 11:48:18 +0000
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/contents.plist b/tests/data/NestedComponents-Regular.ufo/glyphs/contents.plist
new file mode 100644
index 000000000..f47769123
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/contents.plist
@@ -0,0 +1,20 @@
+
+
+
+
+ .notdef
+ _notdef.glif
+ a
+ a.glif
+ b
+ b.glif
+ c
+ c.glif
+ d
+ d.glif
+ e
+ e.glif
+ space
+ space.glif
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/d.glif b/tests/data/NestedComponents-Regular.ufo/glyphs/d.glif
new file mode 100644
index 000000000..306720ae2
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/d.glif
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.ComponentInfo
+
+
+ alignment
+ -1
+ index
+ 0
+ name
+ b
+
+
+ alignment
+ -1
+ index
+ 1
+ name
+ a
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2020-12-07 11:48:21 +0000
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/e.glif b/tests/data/NestedComponents-Regular.ufo/glyphs/e.glif
new file mode 100644
index 000000000..ca489303e
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/e.glif
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+ com.schriftgestaltung.Glyphs.ComponentInfo
+
+
+ alignment
+ -1
+ index
+ 0
+ name
+ c
+
+
+ alignment
+ -1
+ index
+ 1
+ name
+ d
+
+
+ com.schriftgestaltung.Glyphs.lastChange
+ 2020-12-07 11:48:37 +0000
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/glyphs/space.glif b/tests/data/NestedComponents-Regular.ufo/glyphs/space.glif
new file mode 100644
index 000000000..bbc0a0506
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/glyphs/space.glif
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/layercontents.plist b/tests/data/NestedComponents-Regular.ufo/layercontents.plist
new file mode 100644
index 000000000..cf95d3573
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/layercontents.plist
@@ -0,0 +1,10 @@
+
+
+
+
+
+ public.default
+ glyphs
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/lib.plist b/tests/data/NestedComponents-Regular.ufo/lib.plist
new file mode 100644
index 000000000..65a43715f
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/lib.plist
@@ -0,0 +1,157 @@
+
+
+
+
+ com.schriftgestaltung.disablesAutomaticAlignment
+
+ com.schriftgestaltung.font.customParameters
+
+
+ name
+ openTypeGaspRangeRecords
+ value
+
+
+ rangeGaspBehavior
+
+ 1
+ 3
+
+ rangeMaxPPEM
+ 7
+
+
+ rangeGaspBehavior
+
+ 0
+ 1
+ 2
+ 3
+
+ rangeMaxPPEM
+ 65535
+
+
+
+
+ name
+ openTypeNameRecords
+ value
+
+
+ encodingID
+ 0
+ languageID
+ 0
+ nameID
+ 3
+ platformID
+ 1
+ string
+ Unique Font Identifier
+
+
+ encodingID
+ 1
+ languageID
+ 1033
+ nameID
+ 8
+ platformID
+ 3
+ string
+ Some Foundry (Manufacturer Name)
+
+
+
+
+ com.schriftgestaltung.font.userData
+
+ GSDimensionPlugin.Dimensions
+
+ master01
+
+
+
+ com.schriftgestaltung.fontMaster.customParameters
+
+
+ name
+ Alignment Zones
+ value
+
+
+ pos
+ -260.0
+ size
+ 10.0
+
+
+
+
+ com.schriftgestaltung.fontMasterID
+ master01
+ com.schriftgestaltung.glyphOrder
+
+ .notdef
+ glyph1
+ glyph2
+ space
+ a
+ b
+ c
+ d
+ e
+ f
+ g
+ h
+ i
+ j
+ k
+ l
+
+ com.schriftgestaltung.useNiceNames
+
+ com.schriftgestaltung.weightValue
+ 400
+ public.glyphOrder
+
+ .notdef
+ space
+ a
+ b
+ c
+ d
+ e
+
+ public.postscriptNames
+
+ a
+ uni0061
+ b
+ uni0062
+ c
+ uni0063
+ d
+ uni0064
+ e
+ uni0065
+ f
+ uni0066
+ g
+ uni0067
+ h
+ uni0068
+ i
+ uni0069
+ j
+ uni006A
+ k
+ uni006B
+ l
+ uni006C
+ space
+ uni0020
+
+
+
diff --git a/tests/data/NestedComponents-Regular.ufo/metainfo.plist b/tests/data/NestedComponents-Regular.ufo/metainfo.plist
new file mode 100644
index 000000000..74e4b3b4f
--- /dev/null
+++ b/tests/data/NestedComponents-Regular.ufo/metainfo.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ creator
+ com.schriftgestaltung.GlyphsUFOExport
+ formatVersion
+ 3
+
+
diff --git a/tests/integration_test.py b/tests/integration_test.py
index 993e219c9..e80ae9e5e 100644
--- a/tests/integration_test.py
+++ b/tests/integration_test.py
@@ -119,6 +119,23 @@ def test_removeOverlaps_pathops(self, testufo):
ttf = compileTTF(testufo, removeOverlaps=True, overlapsBackend="pathops")
expectTTX(ttf, "TestFont-NoOverlaps-TTF-pathops.ttx")
+ def test_nestedComponents(self, FontClass):
+ ufo = FontClass(getpath("NestedComponents-Regular.ufo"))
+ ttf = compileTTF(ufo)
+ assert ttf["maxp"].maxComponentDepth != 1
+ ttf = compileTTF(ufo, flattenComponents=True)
+ assert ttf["maxp"].maxComponentDepth == 1
+
+ def test_nestedComponents_interpolatable(self, FontClass):
+ ufos = [ FontClass(getpath("NestedComponents-Regular.ufo")),
+ FontClass(getpath("NestedComponents-Bold.ufo")) ]
+ ttfs = compileInterpolatableTTFs(ufos)
+ for ttf in ttfs:
+ assert ttf["maxp"].maxComponentDepth != 1
+ ttfs = compileInterpolatableTTFs(ufos, flattenComponents=True)
+ for ttf in ttfs:
+ assert ttf["maxp"].maxComponentDepth == 1
+
def test_interpolatableTTFs_lazy(self, FontClass):
# two same UFOs **must** be interpolatable
ufos = [FontClass(getpath("TestFont.ufo")) for _ in range(2)]