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

propagate_anchors: fix handling of contextual anchors #1037

Merged
merged 2 commits into from
Oct 8, 2024
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
7 changes: 6 additions & 1 deletion Lib/glyphsLib/builder/transformations/propagate_anchors.py
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,7 @@ def origin_adjusted_anchors(anchors: list[GSAnchor]) -> Iterable[GSAnchor]:
GSAnchor(
name=a.name,
position=Point(a.position.x - origin.x, a.position.y - origin.y),
userData=dict(a.userData),
)
for a in anchors
if a.name != "*origin"
Expand Down Expand Up @@ -398,7 +399,11 @@ def get_component_layer_anchors(
if layer_anchors is not None:
# return a copy as they may be modified in place
layer_anchors = [
GSAnchor(name=a.name, position=Point(a.position.x, a.position.y))
GSAnchor(
name=a.name,
position=Point(a.position.x, a.position.y),
userData=dict(a.userData),
)
for a in layer_anchors
]
return layer_anchors
Expand Down
6 changes: 4 additions & 2 deletions Lib/glyphsLib/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2787,13 +2787,15 @@ def _serialize_to_plist(self, writer):
_parent = None
_defaultsForName = {"position": Point(0, 0)}

def __init__(self, name=None, position=None):
def __init__(self, name=None, position=None, userData=None):
self.name = "" if name is None else name
self._userData = None
if position is None:
self.position = copy.deepcopy(self._defaultsForName["position"])
else:
self.position = position
self._userData = None
if userData is not None:
self.userData = userData

def __repr__(self):
return '<{} "{}" x={:.1f} y={:.1f}>'.format(
Expand Down
64 changes: 62 additions & 2 deletions tests/builder/transformations/propagate_anchors_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -112,8 +112,13 @@ def add_component_anchor(self, name: str) -> Self:
component.anchor = name
return self

def add_anchor(self, name: str, pos: tuple[float, float]) -> Self:
anchor = GSAnchor(name, Point(*pos))
def add_anchor(
self,
name: str,
pos: tuple[float, float],
userData: dict | None = None,
) -> Self:
anchor = GSAnchor(name, Point(*pos), userData=userData)
self.current_layer.anchors.append(anchor)
return self

Expand Down Expand Up @@ -193,6 +198,7 @@ def assert_anchors(actual, expected):
for a, e in zip(actual, expected):
assert a.name == e[0]
assert a.position == Point(*e[1])
assert dict(a.userData) == (e[2] if len(e) > 2 else {})


def test_no_components_anchors_are_unchanged():
Expand Down Expand Up @@ -611,6 +617,60 @@ def test_origin_anchor():
)


def test_contextual_anchors():
glyphs = (
GlyphSetBuilder()
.add_glyph(
"behDotless-ar.init",
lambda glyph: (
glyph.add_anchor("bottom", (50, 0))
.add_anchor(
"*bottom",
(95, 0),
userData={"GPOS_Context": "* behDotless-ar.medi"},
)
.add_anchor("top", (35, 229))
),
)
.add_glyph(
"behDotless-ar.medi",
lambda glyph: (
glyph.add_component("behDotless-ar.init", (0, 0)).add_anchor(
"*bottom",
(95, 0),
userData={"GPOS_Context": "* behDotless-ar.fina"},
)
),
)
.add_glyph(
"behDotless-ar.fina",
lambda glyph: glyph.add_component("behDotless-ar.init", (0, 0)),
)
.build()
)
propagate_all_anchors_impl(glyphs)

new_glyph = glyphs["behDotless-ar.medi"]
assert_anchors(
new_glyph.layers[0].anchors,
[
("bottom", (50, 0)),
("*bottom", (95, 0), {"GPOS_Context": "* behDotless-ar.fina"}),
("top", (35, 229)),
],
)

new_glyph = glyphs["behDotless-ar.fina"]
assert_anchors(
new_glyph.layers[0].anchors,
[
("bottom", (50, 0)),
("*bottom", (95, 0), {"GPOS_Context": "* behDotless-ar.medi"}),
("top", (35, 229)),
],
)


def test_invert_names_on_rotation():
# derived from the observed behaviour of glyphs 3.2.2 (3259)
glyphs = (
Expand Down
Loading