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

UFO default layer with custom name #664

Merged
merged 8 commits into from
Feb 26, 2021
Merged
Show file tree
Hide file tree
Changes from all 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
8 changes: 4 additions & 4 deletions Lib/glyphsLib/builder/builders.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,12 +259,12 @@ def masters(self):

for master_id, source in self._sources.items():
ufo = source.font
master = self.font.masters[master_id]
if self.propagate_anchors:
self.to_ufo_propagate_font_anchors(ufo)
for layer in ufo.layers:
self.to_ufo_layer_lib(layer)
for layer in list(ufo.layers):
self.to_ufo_layer_lib(master, ufo, layer)

master = self.font.masters[master_id]
# to_ufo_custom_params may apply "Replace Features" or "Replace Prefix"
# parameters so it requires UFOs have their features set first; at the
# same time, to generate a GDEF table we first need to have defined the
Expand Down Expand Up @@ -736,7 +736,7 @@ def font(self):
del layer[glyph_name]

for layer in _sorted_backgrounds_last(source.font.layers):
self.to_glyphs_layer_lib(layer)
self.to_glyphs_layer_lib(layer, master)
for glyph in layer:
self.to_glyphs_glyph(glyph, layer, master)

Expand Down
2 changes: 2 additions & 0 deletions Lib/glyphsLib/builder/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,3 +100,5 @@
{"class": "KernFeatureWriter", "options": {"mode": "append"}},
{"class": "MarkFeatureWriter", "options": {"mode": "skip"}},
]

DEFAULT_LAYER_NAME = PUBLIC_PREFIX + "default"
2 changes: 1 addition & 1 deletion Lib/glyphsLib/builder/layers.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def _layer_order_in_glyph(self, layer):


def to_glyphs_layer(self, ufo_layer, glyph, master):
if ufo_layer.name == "public.default": # TODO: (jany) constant
if ufo_layer is self._sources[master.id].font.layers.defaultLayer:
layer = _get_or_make_foreground(self, glyph, master)
elif ufo_layer.name == "public.background":
master_layer = _get_or_make_foreground(self, glyph, master)
Expand Down
35 changes: 30 additions & 5 deletions Lib/glyphsLib/builder/user_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,13 @@
PUBLIC_PREFIX,
UFO2FT_FEATURE_WRITERS_KEY,
DEFAULT_FEATURE_WRITERS,
DEFAULT_LAYER_NAME,
)

UFO_DATA_KEY = GLYPHLIB_PREFIX + "ufoData"
FONT_USER_DATA_KEY = GLYPHLIB_PREFIX + "fontUserData"
LAYER_LIB_KEY = GLYPHLIB_PREFIX + "layerLib"
LAYER_NAME_KEY = GLYPHLIB_PREFIX + "layerName"
GLYPH_USER_DATA_KEY = GLYPHLIB_PREFIX + "glyphUserData"
NODE_USER_DATA_KEY = GLYPHLIB_PREFIX + "nodeUserData"

Expand Down Expand Up @@ -77,10 +79,24 @@ def to_ufo_glyph_user_data(self, ufo, glyph):
ufo.lib[key] = dict(glyph.userData)


def to_ufo_layer_lib(self, ufo_layer):
def to_ufo_layer_lib(self, master, ufo, ufo_layer):
key = LAYER_LIB_KEY + "." + ufo_layer.name
# glyphsLib v5.3.2 and previous versions stored the layer lib in
# the GSFont useData under a key named after the layer.
# When different original UFOs each had a layer with the same layer name,
# only the layer lib of the last one was stored and was exported to UFOs
if key in self.font.userData.keys():
ufo_layer.lib = self.font.userData[key]
ufo_layer.lib.update(self.font.userData[key])
if key in master.userData.keys():
ufo_layer.lib.update(master.userData[key])
if LAYER_NAME_KEY in ufo_layer.lib:
layer_name = ufo_layer.lib.pop(LAYER_NAME_KEY)
# ufoLib2
if hasattr(ufo, "renameLayer") and callable(ufo.renameLayer):
ufo.renameLayer(ufo_layer.name, layer_name)
# defcon
else:
ufo_layer.name = layer_name


def to_ufo_layer_user_data(self, ufo_glyph, layer):
Expand Down Expand Up @@ -146,15 +162,24 @@ def to_glyphs_glyph_user_data(self, ufo, glyph):
glyph.userData = ufo.lib[key]


def to_glyphs_layer_lib(self, ufo_layer):
def to_glyphs_layer_lib(self, ufo_layer, master):
user_data = {}
for key, value in ufo_layer.lib.items():
if _user_data_has_no_special_meaning(key):
user_data[key] = value

# the default layer may have a custom name
layer_name = ufo_layer.name
if (
ufo_layer is self._sources[master.id].font.layers.defaultLayer
and layer_name != DEFAULT_LAYER_NAME
):
user_data[LAYER_NAME_KEY] = ufo_layer.name
layer_name = DEFAULT_LAYER_NAME

if user_data:
key = LAYER_LIB_KEY + "." + ufo_layer.name
self.font.userData[key] = user_data
key = LAYER_LIB_KEY + "." + layer_name
master.userData[key] = user_data


def to_glyphs_layer_user_data(self, ufo_glyph, layer):
Expand Down
75 changes: 60 additions & 15 deletions tests/builder/lib_and_user_data_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -198,29 +198,74 @@ def test_ufo_data_into_font_master_user_data(tmpdir, ufo_module):
assert ufo.data[filename] == data


def test_layer_lib_into_font_user_data(ufo_module):
ufo = ufo_module.Font()
ufo.layers["public.default"].lib["layerLibKey1"] = "layerLibValue1"
layer = ufo.newLayer("sketches")
layer.lib["layerLibKey2"] = "layerLibValue2"
def test_layer_lib_into_master_user_data(ufo_module):
ufo1 = ufo_module.Font()
ufo1.layers["public.default"].lib["layerLibKey1"] = "ufo1 layerLibValue1"
layer = ufo1.newLayer("sketches")
layer.lib["layerLibKey2"] = "ufo1 layerLibValue2"
# layers won't roundtrip if they contain no glyph, except for the default
layer.newGlyph("bob")
ufo2 = ufo_module.Font()
ufo2.layers["public.default"].lib["layerLibKey1"] = "ufo2 layerLibValue1"
layer = ufo2.newLayer("sketches")
layer.lib["layerLibKey2"] = "ufo2 layerLibValue2"
layer.newGlyph("bob")

font = to_glyphs([ufo])
font = to_glyphs([ufo1, ufo2])

assert font.userData[GLYPHLIB_PREFIX + "layerLib.public.default"] == {
"layerLibKey1": "layerLibValue1"
default_layer_key = GLYPHLIB_PREFIX + "layerLib.public.default"
sketches_layer_key = GLYPHLIB_PREFIX + "layerLib.sketches"
assert default_layer_key not in font.userData
assert sketches_layer_key not in font.userData
assert font.masters[0].userData[default_layer_key] == {
"layerLibKey1": "ufo1 layerLibValue1"
}
assert font.userData[GLYPHLIB_PREFIX + "layerLib.sketches"] == {
"layerLibKey2": "layerLibValue2"
assert font.masters[0].userData[sketches_layer_key] == {
"layerLibKey2": "ufo1 layerLibValue2"
}
assert font.masters[1].userData[default_layer_key] == {
"layerLibKey1": "ufo2 layerLibValue1"
}
assert font.masters[1].userData[sketches_layer_key] == {
"layerLibKey2": "ufo2 layerLibValue2"
}

(ufo,) = to_ufos(font)
(ufo1, ufo2) = to_ufos(font)

assert ufo1.layers["public.default"].lib["layerLibKey1"] == "ufo1 layerLibValue1"
assert "layerLibKey1" not in ufo1.layers["sketches"].lib
assert ufo1.layers["sketches"].lib["layerLibKey2"] == "ufo1 layerLibValue2"
assert "layerLibKey2" not in ufo1.layers["public.default"].lib
assert ufo2.layers["public.default"].lib["layerLibKey1"] == "ufo2 layerLibValue1"
assert "layerLibKey1" not in ufo2.layers["sketches"].lib
assert ufo2.layers["sketches"].lib["layerLibKey2"] == "ufo2 layerLibValue2"
assert "layerLibKey2" not in ufo2.layers["public.default"].lib


def test_layer_lib_in_font_user_data(ufo_module):
font = classes.GSFont()
font.masters.append(classes.GSFontMaster())
font.masters.append(classes.GSFontMaster())
glyph = classes.GSGlyph(name="a")
font.glyphs.append(glyph)
layer = classes.GSLayer()
layer.layerId = font.masters[0].id
layer.width = 0
glyph.layers.append(layer)
layer = classes.GSLayer()
layer.layerId = font.masters[1].id
layer.width = 0
glyph.layers.append(layer)

assert ufo.layers["public.default"].lib["layerLibKey1"] == "layerLibValue1"
assert "layerLibKey1" not in ufo.layers["sketches"].lib
assert ufo.layers["sketches"].lib["layerLibKey2"] == "layerLibValue2"
assert "layerLibKey2" not in ufo.layers["public.default"].lib
font.userData[GLYPHLIB_PREFIX + "layerLib.public.default"] = {
"layerLibKey": "layerLibValue"
}

ufo1, ufo2 = to_ufos(font)
assert "layerLibKey" in ufo1.layers["public.default"].lib
assert ufo1.layers["public.default"].lib["layerLibKey"] == "layerLibValue"
assert "layerLibKey" in ufo2.layers["public.default"].lib
assert ufo2.layers["public.default"].lib["layerLibKey"] == "layerLibValue"


def test_glyph_user_data_into_ufo_lib():
Expand Down
17 changes: 17 additions & 0 deletions tests/builder/to_glyphs_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -585,6 +585,23 @@ def test_custom_stylemap_style_name(ufo_module):
assert ufo.info.styleMapStyleName == "bold"


def test_custom_default_layer_name(ufo_module):
ufo1 = ufo_module.Font()
ufo2 = ufo_module.Font()
if hasattr(ufo1, "renameLayer") and callable(ufo1.renameLayer):
ufo1.renameLayer("public.default", "custom default")
ufo2.renameLayer("public.default", "other default")
else:
ufo1.layers.defaultLayer.name = "custom default"
ufo2.layers.defaultLayer.name = "other default"

font = to_glyphs([ufo1, ufo2])
(ufo1, ufo2) = to_ufos(font)

assert ufo1.layers.defaultLayer.name == "custom default"
assert ufo2.layers.defaultLayer.name == "other default"


def test_weird_kerning_roundtrip(ufo_module):
groups = {
"public.kern1.i": [
Expand Down