Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No width linking of brace layers #985

Merged
merged 3 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 14 additions & 16 deletions Lib/glyphsLib/builder/glyph.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,22 +250,20 @@ def effective_width(layer, glyph):
# The width may be taken from another master via the customParameters
# 'Link Metrics With Master' or 'Link Metrics With First Master'.
font = glyph.parent
master = font.masters[layer.associatedMasterId or layer.layerId]
metrics_source = master.metricsSource
if metrics_source is None:
width = layer.width
else:
metric_layer = 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
return width
master = font.masters[layer.layerId]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line is the important change of the patch, it says to only consider the master of this layer (if any) for the metrics source, and never the "associated master". For intermediate layers it means that there's no metrics source, whereas previously they used the metrics source of their parent layer, which was wrong.

if master:
metrics_source = master.metricsSource
if metrics_source:
metric_layer = 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}"
)
return width
return layer.width


def to_ufo_glyph_color(self, ufo_glyph, layer, glyph, do_color_layers=True):
Expand Down
241 changes: 241 additions & 0 deletions tests/data/IntermediateLayerWidth.glyphs
Original file line number Diff line number Diff line change
@@ -0,0 +1,241 @@
{
.appVersion = "3259";
.formatVersion = 3;
DisplayStrings = (
a
);
axes = (
{
name = Weight;
tag = wght;
},
{
name = ROUND;
tag = ROND;
}
);
date = "2024-04-22 16:44:09 +0000";
familyName = "New Font";
fontMaster = (
{
axesValues = (
400,
0
);
id = "m-400-0";
metricValues = (
{
over = 16;
pos = 800;
},
{
over = -16;
},
{
over = -16;
pos = -200;
},
{
over = 16;
pos = 700;
},
{
over = 16;
pos = 500;
},
{
}
);
name = Regular;
},
{
axesValues = (
700,
0
);
iconName = SemiBold;
id = "m-700-0";
metricValues = (
{
over = 16;
pos = 800;
},
{
over = -16;
},
{
over = -16;
pos = -200;
},
{
over = 16;
pos = 700;
},
{
over = 16;
pos = 500;
},
{
}
);
name = Bold;
},
{
axesValues = (
400,
1
);
customParameters = (
{
name = "Link Metrics With Master";
value = "m-400-0";
}
);
id = "m-400-1";
metricValues = (
{
over = 16;
pos = 800;
},
{
over = -16;
},
{
over = -16;
pos = -200;
},
{
over = 16;
pos = 700;
},
{
over = 16;
pos = 500;
},
{
}
);
name = "Regular ROUND";
},
{
axesValues = (
700,
1
);
customParameters = (
{
name = "Link Metrics With Master";
value = "m-700-0";
}
);
iconName = SemiBold;
id = "m-700-1";
metricValues = (
{
over = 16;
pos = 800;
},
{
over = -16;
},
{
over = -16;
pos = -200;
},
{
over = 16;
pos = 700;
},
{
over = 16;
pos = 500;
},
{
}
);
name = "Bold ROUND";
}
);
glyphs = (
{
glyphname = a;
lastChange = "2024-04-23 07:38:25 +0000";
layers = (
{
layerId = "m-400-1";
width = 100;
},
{
layerId = "m-400-0";
width = 100;
},
{
layerId = "m-700-1";
width = 300;
},
{
associatedMasterId = "m-400-0";
attr = {
coordinates = (
500,
0
);
};
layerId = "m-500-0";
name = "Intermediate 500 0";
width = 200;
},
{
layerId = "m-700-0";
width = 300;
},
{
associatedMasterId = "m-400-1";
attr = {
coordinates = (
500,
1
);
};
layerId = "m-500-1";
name = "Intermediate 500 1";
width = 200;
}
);
unicode = 97;
},
{
glyphname = space;
layers = (
{
layerId = "m-400-1";
width = 200;
}
);
unicode = 32;
}
);
metrics = (
{
type = ascender;
},
{
type = baseline;
},
{
type = descender;
},
{
type = "cap height";
},
{
type = "x-height";
},
{
type = "italic angle";
}
);
unitsPerEm = 1000;
versionMajor = 1;
versionMinor = 0;
}
45 changes: 44 additions & 1 deletion tests/special_layer_width_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@

import os

from glyphsLib import load_to_ufos
from glyphsLib import load_to_ufos, GSFont, to_designspace


def glyphs_file_path():
Expand All @@ -42,3 +42,46 @@ def test_substitution_layer_width():
assert masters[1]["B"].width == 600
assert masters[0]["B.BRACKET.varAlt01"].width == 510
assert masters[1]["B.BRACKET.varAlt01"].width == 610


def test_intermediate_layer_width_with_metrics_source_on_parent():
"""This checks that "intermediate layers", a.k.a. "brace layers", do not
incorrectly inherit an irrelevant width from their parent layer.

Scenario in the test file:

- Glyph /a
- Regular (400, 0): advance width = 100
- Intermediate layer {500, 0}: advance width = 200
- Bold (700, 0): advance width = 300
- Regular ROUND (400, 1); advance width = 100
* This master layer has a "metricsSource" pointing to Regular (400, 0)
to ensure the widths are consistent.
- Intermediate layer {500, 1}: advance width = 200
* This intermediate layer is under consideration for the test.
- Bold ROUND (700, 1): advance width = 300

Previously, the advance width of the intermediate layer `{500, 1}` would be
forcibly taken from the `metricsSource` of the master layer `Regular ROUND
(400, 1)` to which the intermediate layer `{500, 1}` was attached, and so it
would get 100 instead of 200.

With this patch, the advance width of the layer `{500, 1}` will not be
changed, because the the layer `{500, 1}` does not define itself a
`metricsSource`.

See https://github.com/googlefonts/glyphsLib/pull/985
"""
test_path = os.path.join(
os.path.dirname(__file__), "data", "IntermediateLayerWidth.glyphs"
)
font = GSFont(test_path)
doc = to_designspace(font)
for intermediate_round in doc.sources:
if intermediate_round.getFullDesignLocation(doc) == {"Weight": 500, "ROUND": 1}:
break
else:
assert False, "Can't find intermediate layer in the desigspace"
assert (
intermediate_round.font.layers[intermediate_round.layerName]["a"].width == 200
)
Loading