Repository: googlefonts/glyphsLib
Pull request #774 (2022-02-10 10:07:05)

Retain intermediate layer width correctly
For https://github.com/googlefonts/glyphsLib/issues/773

```
# The width may be taken from another master via the customParameters 
# 'Link Metrics With Master' or 'Link Metrics With First Master'.
```

It says `may`, but then the metrics are copied regardless. I added a condition.



Patch:
diff --git a/Lib/glyphsLib/builder/glyph.py b/Lib/glyphsLib/builder/glyph.py
index 70d5deba..2178d458 100644
--- a/Lib/glyphsLib/builder/glyph.py
+++ b/Lib/glyphsLib/builder/glyph.py
@@ -254,17 +254,20 @@ def to_ufo_glyph(self, ufo_glyph, layer, glyph, do_color_layers=True):  # noqa:
     # The width may be taken from another master via the customParameters
     # 'Link Metrics With Master' or 'Link Metrics With First Master'.
     master = self.font.masters[layer.associatedMasterId or layer.layerId]
-    metric_source = master.metricsSource.id
-    metric_layer = self.font.glyphs[glyph.name].layers[metric_source]
-    if metric_layer:
-        width = metric_layer.width
-        if layer.width != width:
-            logger.debug(
-                f"{layer.parent.name}: Applying width from master "
-                f"'{metric_source}': {layer.width} -> {width}"
-            )
+    metrics_source = master.metricsSource
+    if metrics_source is None:
+        width = layer.width
     else:
-        width = None
+        metric_layer = self.font.glyphs[glyph.name].layers[metrics_source.id]
+        if metric_layer:
+            width = metric_layer.width
+            if layer.width != width:
+                logger.debug(
+                    f"{layer.parent.name}: Applying width from master "
+                    f"'{metrics_source.id}': {layer.width} -> {width}"
+                )
+        else:
+            width = None
 
     if width is None:
         pass
diff --git a/Lib/glyphsLib/builder/kerning.py b/Lib/glyphsLib/builder/kerning.py
index 0a00559e..85f9fd32 100644
--- a/Lib/glyphsLib/builder/kerning.py
+++ b/Lib/glyphsLib/builder/kerning.py
@@ -22,11 +22,12 @@ UFO_KERN_GROUP_PATTERN = re.compile("^public\\.kern([12])\\.(.*)$")
 
 def to_ufo_kerning(self):
     for master in self.font.masters:
-        master_id = master.id
-        kerning_source = master.metricsSource.id  # Maybe be a linked master
-        if kerning_source in self.font.kerning:
-            kerning = self.font.kerning[kerning_source]
-            _to_ufo_kerning(self, self._sources[master_id].font, kerning)
+        kerning_source = master.metricsSource  # Maybe be a linked master
+        if kerning_source is None:
+            kerning_source = master
+        if kerning_source.id in self.font.kerning:
+            kerning = self.font.kerning[kerning_source.id]
+            _to_ufo_kerning(self, self._sources[master.id].font, kerning)
 
 
 def _to_ufo_kerning(self, ufo, kerning_data):
diff --git a/Lib/glyphsLib/classes.py b/Lib/glyphsLib/classes.py
index 53225942..b502cfcd 100755
--- a/Lib/glyphsLib/classes.py
+++ b/Lib/glyphsLib/classes.py
@@ -1593,19 +1593,20 @@ class GSFontMaster(GSBase):
     def metricsSource(self):
         """Returns the source master to be used for glyph and kerning metrics.
 
-        Normally this is the current master itself, but when linked metrics
-        custom parameters are being used, the master referred to in the custom
-        parameter is returned instead."""
+        If linked metrics parameters are being used, the master is returned here,
+        otherwise None."""
         if self.customParameters["Link Metrics With First Master"]:
             return self.font.masters[0]
         source_master_id = self.customParameters["Link Metrics With Master"]
 
         # No custom parameters apply, go home
         if not source_master_id:
-            return self
+            return None
 
-        if source_master_id in self.font.masters:
-            return self.font.masters[source_master_id]
+        # Try by master id
+        source_master = self.font.masterForId(source_master_id)
+        if source_master is not None:
+            return source_master
 
         # Try by name
         for source_master in self.font.masters:


Test patch:
diff --git a/tests/data/SpecialLayerWidth.glyphs b/tests/data/SpecialLayerWidth.glyphs
new file mode 100644
index 00000000..54375426
--- /dev/null
+++ b/tests/data/SpecialLayerWidth.glyphs
@@ -0,0 +1,1159 @@
+{
+.appVersion = "3108";
+.formatVersion = 3;
+DisplayStrings = (
+B
+);
+axes = (
+{
+name = Weight;
+tag = wght;
+}
+);
+date = "2022-05-03 13:23:42 +0000";
+familyName = "Neue Schrift";
+fontMaster = (
+{
+axesValues = (
+0
+);
+id = m01;
+metricValues = (
+{
+over = 16;
+pos = 800;
+},
+{
+over = 16;
+pos = 700;
+},
+{
+over = 16;
+pos = 500;
+},
+{
+over = -16;
+},
+{
+over = -16;
+pos = -200;
+},
+{
+over = -16;
+}
+);
+name = Regular;
+},
+{
+axesValues = (
+100
+);
+iconName = Bold_Extended;
+id = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+metricValues = (
+{
+pos = 800;
+},
+{
+pos = 700;
+},
+{
+pos = 500;
+},
+{
+},
+{
+pos = -200;
+},
+{
+}
+);
+name = Black;
+}
+);
+glyphs = (
+{
+glyphname = A;
+lastChange = "2022-05-03 13:42:31 +0000";
+layers = (
+{
+layerId = m01;
+width = 500;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+},
+{
+associatedMasterId = m01;
+attr = {
+coordinates = (
+50
+);
+};
+layerId = "119B893D-EF68-41BB-A78D-269D1F665DD8";
+name = "{50} 3. Mai 22, 15:26";
+width = 560;
+}
+);
+unicode = 65;
+},
+{
+glyphname = B;
+lastChange = "2022-05-03 14:10:16 +0000";
+layers = (
+{
+layerId = m01;
+width = 500;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+},
+{
+associatedMasterId = m01;
+attr = {
+axisRules = (
+{
+min = 40;
+}
+);
+};
+layerId = "408A9B6B-8C40-4ABA-8CF6-C7B89585B790";
+name = "3. Mai 22, 16:01";
+width = 510;
+},
+{
+associatedMasterId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+attr = {
+axisRules = (
+{
+min = 40;
+}
+);
+};
+layerId = "E49B735E-1271-4E7F-A1CC-D09B0C05C9D6";
+name = "3. Mai 22, 16:01";
+width = 610;
+}
+);
+unicode = 66;
+},
+{
+glyphname = C;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 67;
+},
+{
+glyphname = D;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 68;
+},
+{
+glyphname = E;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 69;
+},
+{
+glyphname = F;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 70;
+},
+{
+glyphname = G;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 71;
+},
+{
+glyphname = H;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 72;
+},
+{
+glyphname = I;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 73;
+},
+{
+glyphname = J;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 74;
+},
+{
+glyphname = K;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 75;
+},
+{
+glyphname = L;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 76;
+},
+{
+glyphname = M;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 77;
+},
+{
+glyphname = N;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 78;
+},
+{
+glyphname = O;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 79;
+},
+{
+glyphname = P;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 80;
+},
+{
+glyphname = Q;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 81;
+},
+{
+glyphname = R;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 82;
+},
+{
+glyphname = S;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 83;
+},
+{
+glyphname = T;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 84;
+},
+{
+glyphname = U;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 85;
+},
+{
+glyphname = V;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 86;
+},
+{
+glyphname = W;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 87;
+},
+{
+glyphname = X;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 88;
+},
+{
+glyphname = Y;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 89;
+},
+{
+glyphname = Z;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 90;
+},
+{
+glyphname = a;
+lastChange = "2022-05-03 13:23:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 97;
+},
+{
+glyphname = b;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 98;
+},
+{
+glyphname = c;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 99;
+},
+{
+glyphname = d;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 100;
+},
+{
+glyphname = e;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 101;
+},
+{
+glyphname = f;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 102;
+},
+{
+glyphname = g;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 103;
+},
+{
+glyphname = h;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 104;
+},
+{
+glyphname = i;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 105;
+},
+{
+glyphname = j;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 106;
+},
+{
+glyphname = k;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 107;
+},
+{
+glyphname = l;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 108;
+},
+{
+glyphname = m;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 109;
+},
+{
+glyphname = n;
+lastChange = "2022-05-03 13:24:32 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 110;
+},
+{
+glyphname = o;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 111;
+},
+{
+glyphname = p;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 112;
+},
+{
+glyphname = q;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 113;
+},
+{
+glyphname = r;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 114;
+},
+{
+glyphname = s;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 115;
+},
+{
+glyphname = t;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 116;
+},
+{
+glyphname = u;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 117;
+},
+{
+glyphname = v;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 118;
+},
+{
+glyphname = w;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 119;
+},
+{
+glyphname = x;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 120;
+},
+{
+glyphname = y;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 121;
+},
+{
+glyphname = z;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 122;
+},
+{
+glyphname = zero;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 48;
+},
+{
+glyphname = one;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 49;
+},
+{
+glyphname = two;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 50;
+},
+{
+glyphname = three;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 51;
+},
+{
+glyphname = four;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 52;
+},
+{
+glyphname = five;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 53;
+},
+{
+glyphname = six;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 54;
+},
+{
+glyphname = seven;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 55;
+},
+{
+glyphname = eight;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 56;
+},
+{
+glyphname = nine;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 57;
+},
+{
+glyphname = space;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 200;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 32;
+},
+{
+glyphname = period;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 46;
+},
+{
+glyphname = comma;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 44;
+},
+{
+glyphname = hyphen;
+lastChange = "2022-05-03 14:05:56 +0000";
+layers = (
+{
+layerId = m01;
+width = 600;
+},
+{
+layerId = "FE53727E-19FD-4F70-B038-07FC4A05C22B";
+width = 600;
+}
+);
+unicode = 45;
+}
+);
+instances = (
+{
+axesValues = (
+0
+);
+instanceInterpolations = {
+m01 = 1;
+};
+name = Regular;
+},
+{
+axesValues = (
+50
+);
+instanceInterpolations = {
+"FE53727E-19FD-4F70-B038-07FC4A05C22B" = 0.5;
+m01 = 0.5;
+};
+isBold = 1;
+name = Bold;
+weightClass = 700;
+},
+{
+axesValues = (
+100
+);
+instanceInterpolations = {
+"FE53727E-19FD-4F70-B038-07FC4A05C22B" = 1;
+};
+name = Black;
+weightClass = 900;
+}
+);
+metrics = (
+{
+type = ascender;
+},
+{
+type = "cap height";
+},
+{
+type = "x-height";
+},
+{
+type = baseline;
+},
+{
+type = descender;
+},
+{
+type = "italic angle";
+}
+);
+unitsPerEm = 1000;
+versionMajor = 1;
+versionMinor = 0;
+}
diff --git a/tests/specal_layer_width_test.py b/tests/specal_layer_width_test.py
new file mode 100644
index 00000000..2c12bcc2
--- /dev/null
+++ b/tests/specal_layer_width_test.py
@@ -0,0 +1,44 @@
+#
+# Copyright 2016 Google Inc. All Rights Reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+import os
+
+from glyphsLib import load_to_ufos
+
+
+def glyphs_file_path():
+    return os.path.join(os.path.dirname(__file__), "data", "SpecialLayerWidth.glyphs")
+
+
+def getLayer(font, layerName):
+    for layer in font.layers:
+        if layerName in layer.name:
+            return layer
+
+
+def test_intermediate_layer_width():
+    ufos = load_to_ufos(glyphs_file_path())
+    assert ufos[0]["A"].width == 500
+    assert getLayer(ufos[0], "{50}")["A"].width == 560  # not interpolated half-way
+    assert ufos[1]["A"].width == 600
+
+
+def test_substitution_layer_width():
+    masters, instances = load_to_ufos(glyphs_file_path(), include_instances=True)
+    assert masters[0]["B"].width == 500
+    assert masters[1]["B"].width == 600
+    assert masters[0]["B.BRACKET.40"].width == 510
+    assert masters[1]["B.BRACKET.40"].width == 610