diff --git a/Lib/glyphsLib/builder/__init__.py b/Lib/glyphsLib/builder/__init__.py index f2c099af5..1dcfe0278 100644 --- a/Lib/glyphsLib/builder/__init__.py +++ b/Lib/glyphsLib/builder/__init__.py @@ -18,7 +18,7 @@ from glyphsLib import classes from .builders import UFOBuilder, GlyphsBuilder -from .transformations import TRANSFORMATIONS +from .transformations import TRANSFORMATIONS, TRANSFORMATION_CUSTOM_PARAMS logger = logging.getLogger(__name__) @@ -64,11 +64,13 @@ def to_ufos( """ if preserve_original: font = copy.deepcopy(font) + font = preflight_glyphs( + font, glyph_data=glyph_data, do_propagate_all_anchors=propagate_anchors + ) builder = UFOBuilder( - preflight_glyphs(font), + font, ufo_module=ufo_module, family_name=family_name, - propagate_anchors=propagate_anchors, minimize_glyphs_diffs=minimize_glyphs_diffs, generate_GDEF=generate_GDEF, store_editor_state=store_editor_state, @@ -129,13 +131,14 @@ def to_designspace( """ if preserve_original: font = copy.deepcopy(font) - + font = preflight_glyphs( + font, glyph_data=glyph_data, do_propagate_all_anchors=propagate_anchors + ) builder = UFOBuilder( - preflight_glyphs(font), + font, ufo_module=ufo_module, family_name=family_name, instance_dir=instance_dir, - propagate_anchors=propagate_anchors, use_designspace=True, minimize_glyphs_diffs=minimize_glyphs_diffs, generate_GDEF=generate_GDEF, @@ -148,12 +151,49 @@ def to_designspace( return builder.designspace -def preflight_glyphs(font): +def preflight_glyphs(font, *, glyph_data=None, **flags): """Run a set of transformations over a GSFont object to make - it easier to convert to UFO; resolve all the "smart stuff".""" + it easier to convert to UFO; resolve all the "smart stuff". + + Currently, the transformations are: + - `propagate_all_anchors`: copy anchors from components to their parent + + More transformations may be added in the future. + + Some transformations may have custom parameters that can be set in the + font. For example, the `propagate_all_anchors` transformation can be + disabled by setting the custom parameter "Propagate Anchors" to False + (see `TRANSFORMATION_CUSTOM_PARAMS`). + + Args: + font: a GSFont object + glyph_data: an optional GlyphData object associating various properties to + glyph names (e.g. category) that overrides the default one + **flags: a set of boolean flags to enable/disable specific transformations, + named `do_`, e.g. `do_propagate_all_anchors=False` + will disable the propagation of anchors. + + Returns: + the modified GSFont object + """ for transform in TRANSFORMATIONS: - transform(font) + do_transform = flags.pop("do_" + transform.__name__, None) + if do_transform is True: + pass + elif do_transform is False: + continue + elif do_transform is None: + if transform in TRANSFORMATION_CUSTOM_PARAMS: + param = TRANSFORMATION_CUSTOM_PARAMS[transform] + if not font.customParameters.get(param.name, param.default): + continue + else: + raise ValueError(f"Invalid value for do_{transform.__name__}") + logger.info(f"Running '{transform.__name__}' transformation") + transform(font, glyph_data=glyph_data) + if flags: + logger.warning(f"preflight_glyphs has unused `flags` arguments: {flags}") return font diff --git a/Lib/glyphsLib/builder/anchor_propagation.py b/Lib/glyphsLib/builder/anchor_propagation.py index e3bf62a6a..7f56fb29e 100644 --- a/Lib/glyphsLib/builder/anchor_propagation.py +++ b/Lib/glyphsLib/builder/anchor_propagation.py @@ -1,3 +1,11 @@ +"""This module is DEPRECATED and will be removed in a future release. + +For anchor propagation on GSFont objects, you can use the +`glyphsLib.builder.transformations.propagate_anchors` module. +For anchor propagation on UFO font objects, you can try the +`ufo2ft.filters.propagateAnchors` filter. +""" + from fontTools.misc.transform import Transform import fontTools.pens.boundsPen diff --git a/Lib/glyphsLib/builder/builders.py b/Lib/glyphsLib/builder/builders.py index 3dc579d48..70c1d4014 100644 --- a/Lib/glyphsLib/builder/builders.py +++ b/Lib/glyphsLib/builder/builders.py @@ -28,7 +28,7 @@ FONT_CUSTOM_PARAM_PREFIX, ) from .axes import WEIGHT_AXIS_DEF, WIDTH_AXIS_DEF, find_base_style, class_to_value -from glyphsLib.util import LoggerMixin +from glyphsLib.util import LoggerMixin, _DeprecatedArgument class UFOBuilder(LoggerMixin): @@ -41,7 +41,7 @@ def __init__( designspace_module=designspaceLib, family_name=None, instance_dir=None, - propagate_anchors=None, + propagate_anchors=_DeprecatedArgument, # DEPRECATED use_designspace=False, minimize_glyphs_diffs=False, generate_GDEF=True, @@ -66,9 +66,8 @@ def __init__( only instances with this name will be returned. instance_dir -- if provided, instance UFOs will be located in this directory, according to their Designspace filenames. - propagate_anchors -- set to True or False to explicitly control anchor - propagation, the default is to check for - "Propagate Anchors" custom parameter. + propagate_anchors -- DEPRECATED. Use preflight_glyphs to propagate anchors on + the GSFont before building UFOs. use_designspace -- set to True to make optimal use of the designspace: data that is common to all ufos will go there. minimize_glyphs_diffs -- set to True to store extra info in UFOs @@ -106,9 +105,18 @@ def __init__( self.expand_includes = expand_includes self.minimal = minimal - if propagate_anchors is None: - propagate_anchors = font.customParameters["Propagate Anchors"] - propagate_anchors = bool(propagate_anchors is None or propagate_anchors) + if propagate_anchors is not _DeprecatedArgument: + from warnings import warn + + warn( + "The 'propagate_anchors' argument is deprecated and will be removed " + "in a future version. " + "Use glyphsLib.builder.preflight_glyphs to propagate anchors on the " + "GSFont before building UFOs.", + DeprecationWarning, + ) + else: + propagate_anchors = False self.propagate_anchors = propagate_anchors # The set of (SourceDescriptor + UFO)s that will be built, @@ -215,7 +223,7 @@ def masters(self): for master_id, source in self._sources.items(): ufo = source.font master = self.font.masters[master_id] - if self.propagate_anchors: + if self.propagate_anchors: # deprecated, will be removed one day self.to_ufo_propagate_font_anchors(ufo) # .anchor_propagation if not self.minimal: for layer in list(ufo.layers): diff --git a/Lib/glyphsLib/builder/transformations/__init__.py b/Lib/glyphsLib/builder/transformations/__init__.py index 158397ac0..0b04d1706 100644 --- a/Lib/glyphsLib/builder/transformations/__init__.py +++ b/Lib/glyphsLib/builder/transformations/__init__.py @@ -1 +1,20 @@ -TRANSFORMATIONS = [] +from types import MappingProxyType +from typing import NamedTuple + +from .propagate_anchors import propagate_all_anchors + +TRANSFORMATIONS = [ + propagate_all_anchors, +] + + +class _CustomParameter(NamedTuple): + name: str + default: bool + + +TRANSFORMATION_CUSTOM_PARAMS = MappingProxyType( + { + propagate_all_anchors: _CustomParameter("Propagate Anchors", True), + } +) diff --git a/Lib/glyphsLib/builder/transformations/propagate_anchors.py b/Lib/glyphsLib/builder/transformations/propagate_anchors.py new file mode 100644 index 000000000..ffc198771 --- /dev/null +++ b/Lib/glyphsLib/builder/transformations/propagate_anchors.py @@ -0,0 +1,438 @@ +"""Propagating anchors from components to their composites + +Glyphs.app has a nice feature where anchors defined in the components +of composite glyphs are copied into the composites themselves. This feature +however is not very extensively documented. +The code here is based off the Rust implementation in fontc: + + https://github.com/googlefonts/fontc/blob/85795bf/glyphs-reader/src/propagate_anchors.rs + +The latter is in turn based off the original Objective-C implementation, which was +shared with us privately. +""" + +from __future__ import annotations + +import logging +from collections import deque +from itertools import chain +from math import atan2, degrees +from typing import TYPE_CHECKING + +from fontTools.misc.transform import Transform + +from glyphsLib import glyphdata +from glyphsLib.classes import GSAnchor +from glyphsLib.types import Point + + +logger = logging.getLogger(__name__) + + +if TYPE_CHECKING: + from typing import Iterable + from glyphsLib.classes import GSComponent, GSFont, GSGlyph, GSLayer + + +def propagate_all_anchors( + font: GSFont, *, glyph_data: glyphdata.GlyphData | None = None +) -> None: + """Copy anchors from component glyphs into their including composites. + + If a custom `glyph_data` is provided, it will be used to override the + category and subCategory of glyphs. + """ + glyphs = {glyph.name: glyph for glyph in font.glyphs} + propagate_all_anchors_impl(glyphs, glyph_data=glyph_data) + + +# the actual implementation, easier to test and compare with the original Rust code +def propagate_all_anchors_impl( + glyphs: dict[str, GSGlyph], *, glyph_data: glyphdata.GlyphData | None = None +) -> None: + # the reference implementation does this recursively, but we opt to + # implement it by pre-sorting the work to ensure we always process components + # first. + todo = depth_sorted_composite_glyphs(glyphs) + num_base_glyphs: dict[(str, str), int] = {} + # NOTE: there's an important detail here, which is that we need to call the + # 'anchors_traversing_components' function on each glyph, and save the returned + # anchors, but we only *set* those anchors on glyphs that have components. + # to make this work, we write the anchors to a separate data structure, and + # then only update the actual glyphs after we've done all the work. + all_anchors: dict[str, list[list[GSAnchor]]] = {} + for name in todo: + glyph = glyphs[name] + for layer in glyph.layers: + anchors = anchors_traversing_components( + glyph, + layer, + glyphs, + all_anchors, + num_base_glyphs, + glyph_data, + ) + maybe_log_new_anchors(anchors, glyph, layer) + all_anchors.setdefault(name, []).append(anchors) + + # finally update our glyphs with the new anchors, where appropriate + for name, layers in all_anchors.items(): + glyph = glyphs[name] + if _has_components(glyph): + assert len(layers) == len(glyph.layers) + for i, layer_anchors in enumerate(layers): + glyph.layers[i].anchors = layer_anchors + + +def maybe_log_new_anchors( + anchors: list[GSAnchor], glyph: GSGlyph, layer: GSLayer +) -> None: + if not _has_components(glyph) or not logger.isEnabledFor(logging.DEBUG): + return + prev_names = [a.name for a in layer.anchors] + new_names = [a.name for a in anchors] + if prev_names != new_names: + logger.debug( + "propagated anchors for ('%s': %s -> %s)", + glyph.name, + prev_names, + new_names, + ) + + +def _has_components(glyph: GSGlyph) -> bool: + return any(layer.components for layer in glyph.layers if layer._is_master_layer) + + +def _get_category( + glyph: GSGlyph, + glyph_data: glyphdata.GlyphData | None = None, +) -> str: + return ( + glyph.category + or glyphdata.get_glyph( + glyph.name, data=glyph_data, unicodes=glyph.unicodes + ).category + ) + + +def _get_subCategory( + glyph: GSGlyph, + glyph_data: glyphdata.GlyphData | None = None, +) -> str: + return ( + glyph.subCategory + or glyphdata.get_glyph( + glyph.name, data=glyph_data, unicodes=glyph.unicodes + ).subCategory + ) + + +def anchors_traversing_components( + glyph: GSGlyph, + layer: GSLayer, + glyphs: dict[str, GSGlyph], + done_anchors: dict[str, list[list[GSAnchor]]], + base_glyph_counts: dict[(str, str), int], + glyph_data: glyphdata.GlyphData | None = None, +) -> list[GSAnchor]: + """Return the anchors for this glyph, including anchors from components + + This function is a reimplmentation of a similarly named function in glyphs.app. + + The logic for copying anchors from components into their containing composites + is tricky. Anchors need to be adjusted in various ways: + + - a special "*origin" anchor may exist, which modifies the position of other anchors + - if a component is flipped on the x or y axes, we rename "top" to "bottom" + and/or "left" to "right" + - we need to apply the transform from the component + - we may need to rename an anchor when the component is part of a ligature glyph + """ + if not layer.anchors and not layer.components: + return [] + + # if this is a mark and it has anchors, just return them + # (as in, don't even look at the components) + if layer.anchors and _get_category(glyph, glyph_data) == "Mark": + return list(origin_adjusted_anchors(layer.anchors)) + + is_ligature = _get_subCategory(glyph, glyph_data) == "Ligature" + has_underscore = any(a.name.startswith("_") for a in layer.anchors) + + number_of_base_glyphs = 0 + all_anchors = {} + + for component_idx, component in enumerate(layer.components): + # because we process dependencies first we know that all components + # referenced have already been propagated + anchors = get_component_layer_anchors(component, layer, glyphs, done_anchors) + if anchors is None: + logger.debug( + "could not get layer '%s' for component '%s' of glyph '%s'", + layer.layerId, + component.name, + glyph.name, + ) + continue + + # if this component has an explicitly set attachment anchor, use it + if component_idx > 0 and component.anchor: + maybe_rename_component_anchor(component.anchor, anchors) + + component_number_of_base_glyphs = base_glyph_counts.get( + (component.name, layer.layerId), 0 + ) + + comb_has_underscore = any( + len(a.name) >= 2 and a.name.startswith("_") for a in anchors + ) + comb_has_exit = any(a.name.endswith("exit") for a in anchors) + if not (comb_has_underscore or comb_has_exit): + # delete exit anchors we may have taken from earlier components + # (since a glyph should only have one exit anchor, and logically its + # at the end) + all_anchors = { + n: a for n, a in all_anchors.items() if not n.endswith("exit") + } + + component_transform = Transform(*component.transform) + xscale, yscale = get_xy_rotation(component_transform) + for anchor in anchors: + new_has_underscore = anchor.name.startswith("_") + if (component_idx > 0 or has_underscore) and new_has_underscore: + continue + # skip entry anchors on non-first glyphs + if component_idx > 0 and anchor.name.endswith("entry"): + continue + + new_anchor_name = rename_anchor_for_scale(anchor.name, xscale, yscale) + if ( + is_ligature + and component_number_of_base_glyphs > 0 + and not new_has_underscore + and not ( + new_anchor_name.endswith("exit") + or new_anchor_name.endswith("entry") + ) + ): + # dealing with marks like top_1 on a ligature + new_anchor_name = make_liga_anchor_name( + new_anchor_name, number_of_base_glyphs + ) + + apply_transform_to_anchor(anchor, component_transform) + anchor.name = new_anchor_name + all_anchors[anchor.name] = anchor + has_underscore |= new_has_underscore + + number_of_base_glyphs += base_glyph_counts.get( + (component.name, layer.layerId), 0 + ) + + # now we've handled all the anchors from components, so copy over anchors + # that were explicitly defined on this layer: + all_anchors.update((a.name, a) for a in origin_adjusted_anchors(layer.anchors)) + has_underscore_anchor = False + has_mark_anchor = False + component_count_from_anchors = 0 + + # now we count how many components we have, based on our anchors + for name in all_anchors.keys(): + has_underscore_anchor |= name.startswith("_") + has_mark_anchor |= name[0].isalpha() and name[0].isascii() if name else False + if ( + not is_ligature + and number_of_base_glyphs == 0 + and not name.startswith("_") + and not (name.endswith("exit") or name.endswith("entry")) + and "_" in name + ): + suffix = name[name.index("_") + 1 :] + # carets count space between components, so the last caret + # is n_components - 1 + maybe_add_one = 1 if name.startswith("caret") else 0 + anchor_index = 0 + try: + anchor_index = int(suffix) + maybe_add_one + except ValueError: + pass + component_count_from_anchors = max( + component_count_from_anchors, anchor_index + ) + if not has_underscore_anchor and number_of_base_glyphs == 0 and has_mark_anchor: + number_of_base_glyphs += 1 + number_of_base_glyphs = max(number_of_base_glyphs, component_count_from_anchors) + + if any(a.name == "_bottom" for a in layer.anchors): + all_anchors.pop("top", None) + all_anchors.pop("_top", None) + if any(a.name == "_top" for a in layer.anchors): + all_anchors.pop("bottom", None) + all_anchors.pop("_bottom", None) + + base_glyph_counts[(glyph.name, layer.layerId)] = number_of_base_glyphs + + return list(all_anchors.values()) + + +def origin_adjusted_anchors(anchors: list[GSAnchor]) -> Iterable[GSAnchor]: + """Iterate over anchors taking into account the special "*origin" anchor + + If that anchor is present it will be used to adjust the positions of other + anchors, and will not be included in the output. + """ + origin = next((a.position for a in anchors if a.name == "*origin"), Point(0, 0)) + return ( + GSAnchor( + name=a.name, + position=Point(a.position.x - origin.x, a.position.y - origin.y), + ) + for a in anchors + if a.name != "*origin" + ) + + +def get_xy_rotation(xform: Transform) -> tuple[float, float]: + """Returns (x, y) where a negative value indicates axis is flipped""" + # this is based on examining the behaviour of glyphs via the macro panel + # and careful testing. + a, b = xform[:2] + # first take the rotation + angle = atan2(b, a) + # then remove the rotation, and take the scale + rotated = xform.rotate(-angle) + xscale, yscale = (rotated[0], rotated[3]) + # then invert the scale if the rotation was >= 180° + if abs(degrees(angle) - 180) < 0.001: + xscale = -xscale + yscale = -yscale + + return xscale, yscale + + +def apply_transform_to_anchor(anchor: GSAnchor, transform: Transform) -> None: + """Apply the transform but also do some rounding. + + So we don't have anchors with points like (512, 302.000000006). + """ + x, y = anchor.position + pos = transform.transformPoint((x, y)) + anchor.position = Point(round(pos[0], 6), round(pos[1], 6)) + + +def maybe_rename_component_anchor(comp_name: str, anchors: list[GSAnchor]) -> None: + # e.g, go from 'top' to 'top_1' + if "_" not in comp_name: + return + sub_name = comp_name[: comp_name.index("_")] + mark_name = f"_{sub_name}" + if any(a.name == sub_name for a in anchors) and any( + a.name == mark_name for a in anchors + ): + comp_anchor = next(a for a in anchors if a.name == sub_name) + comp_anchor.name = comp_name + + +def make_liga_anchor_name(name: str, base_number: int) -> str: + if "_" in name: + # if this anchor already has a number (like 'top_2') we want to consider that + name, suffix = name.split("_", 1) + try: + num = int(suffix) + except ValueError: + num = 1 + return f"{name}_{base_number + num}" + # otherwise we're turning 'top' into 'top_N' + return f"{name}_{base_number + 1}" + + +def rename_anchor_for_scale(name: str, xscale: float, yscale: float) -> str: + """If a component is rotated, flip bottom/top, left/right, entry/exit""" + + def swap_pair(s: str, one: str, two: str) -> str: + if one in s: + return s.replace(one, two) + elif two in s: + return s.replace(two, one) + return s + + if xscale < 0.0: + name = swap_pair(name, "left", "right") + name = swap_pair(name, "exit", "entry") + if yscale < 0.0: + name = swap_pair(name, "bottom", "top") + + return name + + +def get_component_layer_anchors( + component: GSComponent, + layer: GSLayer, + glyphs: dict[str, GSGlyph], + anchors: dict[str, list[list[GSAnchor]]], +) -> list[GSAnchor] | None: + glyph = glyphs.get(component.name) + if glyph is None: + return None + # in Glyphs.app, the `componentLayer` property would synthesize a layer + # if it is missing. glyphsLib does not have that yet, so for now we + # only support the corresponding 'master' layer of a component's base glyph. + layer_anchors = None + for layer_idx, comp_layer in enumerate(glyph.layers): + if comp_layer.layerId == layer.layerId and component.name in anchors: + try: + layer_anchors = anchors[component.name][layer_idx] + break + except IndexError: + if component.name == layer.parent.name: + # cyclic reference? ignore + break + else: + raise + 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)) + for a in layer_anchors + ] + return layer_anchors + + +def depth_sorted_composite_glyphs(glyphs: dict[str, GSGlyph]) -> list[str]: + queue = deque() + # map of the maximum component depth of a glyph. + # - a glyph with no components has depth 0, + # - a glyph with a component has depth 1, + # - a glyph with a component that itself has a component has depth 2, etc + depths = {} + component_buf = [] + for name, glyph in glyphs.items(): + if _has_components(glyph): + queue.append(glyph) + else: + depths[name] = 0 + + while queue: + next_glyph = queue.popleft() + # put all components from this glyph to our reuseable buffer + component_buf.clear() + component_buf.extend( + comp.name + for comp in chain.from_iterable(l.components for l in next_glyph.layers) + if comp.name in glyphs # ignore missing components + ) + if not component_buf: + # all components missing?! this is not actually a composite glyph + depths[next_glyph.name] = 0 + elif all(comp in depths for comp in component_buf): + # increment max depth but only if all components have been seen + depth = max(depths[comp] for comp in component_buf) + depths[next_glyph.name] = depth + 1 + else: + # else push to the back to try again after we've done the rest + # (including the currently missing components) + queue.append(next_glyph) + + by_depth = sorted((depth, name) for name, depth in depths.items()) + return [name for _, name in by_depth] diff --git a/Lib/glyphsLib/util.py b/Lib/glyphsLib/util.py index 96b62cae7..a7674521c 100644 --- a/Lib/glyphsLib/util.py +++ b/Lib/glyphsLib/util.py @@ -176,3 +176,7 @@ def __next__(self): def peek(self, n=0): return self.list[self.index + n] + + +# sentinel object to indicate a deprecated argument +_DeprecatedArgument = object() diff --git a/tests/builder/builder_test.py b/tests/builder/builder_test.py index e92eb72ac..aaa39286b 100644 --- a/tests/builder/builder_test.py +++ b/tests/builder/builder_test.py @@ -136,7 +136,8 @@ def test_propagate_anchors_on(ufo_module): ("dad", [("sad", 0, 0), ("dotabove", 50, 50)], []), ("dadDotbelow", [("dad", 0, 0), ("dotbelow", 50, -50)], []), ("yod", [], [("bottom", 50, -50)]), - ("yodyod", [("yod", 0, 0), ("yod", 100, 0)], []), + ("yod_yod", [("yod", 0, 0), ("yod", 100, 0)], []), # ligature + ("yodyod", [("yod", 0, 0), ("yod", 100, 0)], []), # not a ligature ) for name, component_data, anchor_data in glyphs: add_glyph(font, name) @@ -160,7 +161,20 @@ def test_propagate_anchors_on(ufo_module): assert anchor.name == "top" assert anchor.y == 200 + # 'yodyod' isn't explicitly classified as a 'ligature' hence it will NOT + # inherit two 'bottom_1' and 'bottom_2' anchors from each 'yod' component, + # but only one 'bottom' anchor from the last component. + # https://github.com/googlefonts/glyphsLib/issues/368#issuecomment-2103376997 glyph = ufo["yodyod"] + assert len(glyph.anchors) == 1 + for anchor in glyph.anchors: + assert anchor.name == "bottom" + assert anchor.y == -50 + assert anchor.x == 150 + + # 'yod_yod' is a ligature hence will inherit two 'bottom_{1,2}' anchors + # from each 'yod' component + glyph = ufo["yod_yod"] assert len(glyph.anchors) == 2 for anchor in glyph.anchors: assert anchor.y == -50 diff --git a/tests/builder/designspace_gen_test.py b/tests/builder/designspace_gen_test.py index 7f2f65f09..4101c20e4 100644 --- a/tests/builder/designspace_gen_test.py +++ b/tests/builder/designspace_gen_test.py @@ -26,6 +26,7 @@ import glyphsLib from glyphsLib import to_designspace, to_glyphs from glyphsLib.util import open_ufo +from glyphsLib.types import Point def test_designspace_generation_regular_same_family_name(tmpdir, ufo_module): @@ -481,7 +482,7 @@ def test_designspace_generation_bracket_GDEF(datadir, ufo_module): for layer in font.glyphs["x"].layers: anchor = glyphsLib.classes.GSAnchor() anchor.name = "top" - anchor.position = (0, 0) + anchor.position = Point(0, 0) layer.anchors.append(anchor) designspace = to_designspace(font, ufo_module=ufo_module, generate_GDEF=True) diff --git a/tests/builder/transformations/propagate_anchors_test.py b/tests/builder/transformations/propagate_anchors_test.py new file mode 100644 index 000000000..a4c90fabf --- /dev/null +++ b/tests/builder/transformations/propagate_anchors_test.py @@ -0,0 +1,559 @@ +from __future__ import annotations + +import math +import os.path + +from copy import deepcopy +from typing import TYPE_CHECKING + +from fontTools.misc.transform import Transform as Affine + +from glyphsLib.classes import GSAnchor, GSFont, GSGlyph, GSLayer, GSComponent +from glyphsLib.glyphdata import get_glyph +from glyphsLib.types import Point, Transform +from glyphsLib.writer import dumps + +from glyphsLib.builder.transformations.propagate_anchors import ( + get_xy_rotation, + propagate_all_anchors, + propagate_all_anchors_impl, + depth_sorted_composite_glyphs, +) + +if TYPE_CHECKING: + from typing import Callable, Self + +DATA = os.path.join(os.path.dirname(os.path.dirname(os.path.dirname(__file__))), "data") + + +# Basically all the tests below are translated from: +# https://github.com/googlefonts/fontc/blob/ecc727d/glyphs-reader/src/propagate_anchors.rs#L423-L959 +# This is to ensure that the Python implementation behaves the same way as the Rust one. + + +class GlyphSetBuilder: + glyphs: dict[str, GSGlyph] + + def __init__(self): + self.glyphs = {} + + def build(self) -> dict[str, GSGlyph]: + return self.glyphs + + def add_glyph(self, name: str, build_fn: Callable[["GlyphBuilder"], None]) -> Self: + glyph = GlyphBuilder(name) + build_fn(glyph) + self.glyphs[name] = glyph.build() + return self + + +class GlyphBuilder: + def __init__(self, name: str): + info = get_glyph(name) + self.glyph = glyph = GSGlyph() + glyph.name = name + glyph.unicode = info.unicode + glyph.category = info.category + glyph.subCategory = info.subCategory + self.add_layer() + + def build(self) -> GSGlyph: + return self.glyph + + def add_layer(self) -> Self: + layer = GSLayer() + layer.name = layer.layerId = layer.associatedMasterId = ( + f"layer-{len(self.glyph.layers)}" + ) + self.glyph.layers.append(layer) + return self + + def set_category(self, category: str) -> Self: + self.glyph.category = category + return self + + def set_subCategory(self, subCategory: str) -> Self: + self.glyph.subCategory = subCategory + return self + + def add_component(self, name: str, pos: tuple[float, float]) -> Self: + component = GSComponent(name, offset=pos) + self.glyph.layers[-1].components.append(component) + return self + + def rotate_component(self, degrees: float) -> Self: + # Set an explicit translate + rotation for the component + component = self.glyph.layers[-1].components[-1] + component.transform = Transform( + *Affine(*component.transform).rotate(math.radians(degrees)) + ) + return self + + def add_component_anchor(self, name: str) -> Self: + # add an explicit anchor to the last added component + component = self.glyph.layers[-1].components[-1] + component.anchor = name + return self + + def add_anchor(self, name: str, pos: tuple[float, float]) -> Self: + anchor = GSAnchor(name, Point(*pos)) + self.glyph.layers[-1].anchors.append(anchor) + return self + + +def make_glyph(name: str, components: list[str]) -> GSGlyph: + builder = GlyphBuilder(name) + for comp in components: + builder.add_component(comp, (0, 0)) # pos doesn't matter for this test + return builder.build() + + +def test_components_by_depth(): + glyphs = { + name: make_glyph(name, components) + for name, components in [ + ("A", []), + ("E", []), + ("acutecomb", []), + ("brevecomb", []), + ("brevecomb_acutecomb", ["acutecomb", "brevecomb"]), + ("AE", ["A", "E"]), + ("Aacute", ["A", "acutecomb"]), + ("Aacutebreve", ["A", "brevecomb_acutecomb"]), + ("AEacutebreve", ["AE", "brevecomb_acutecomb"]), + ] + } + + assert depth_sorted_composite_glyphs(glyphs) == [ + "A", + "E", + "acutecomb", + "brevecomb", + "AE", + "Aacute", + "brevecomb_acutecomb", + "AEacutebreve", + "Aacutebreve", + ] + + +def assert_equal_gsobjects(object1, object2): + # glyphsLib.classes objects don't implement __eq__, so we resort to compare + # their serialized forms... Ugly but works :( + assert dumps(object1) == dumps(object2) + + +def assert_equal_glyphsets(glyphs1, glyphs2): + assert len(glyphs1) == len(glyphs2) + assert glyphs1.keys() == glyphs2.keys() + for name in glyphs1: + assert_equal_gsobjects(glyphs1[name], glyphs2[name]) + + +def assert_anchors(actual, expected): + assert len(actual) == len(expected) + for a, e in zip(actual, expected): + assert a.name == e[0] + assert a.position == Point(*e[1]) + + +def test_no_components_anchors_are_unchanged(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + glyphs = ( + GlyphSetBuilder() + .add_glyph( + "A", + lambda glyph: ( + glyph.add_anchor("bottom", (234, 0)) + .add_anchor("ogonek", (411, 0)) + .add_anchor("top", (234, 810)) + ), + ) + .add_glyph( + "acutecomb", + lambda glyph: ( + glyph.add_anchor("_top", (0, 578)).add_anchor("top", (0, 810)) + ), + ) + .build() + ) + + glyphs2 = deepcopy(glyphs) + propagate_all_anchors_impl(glyphs2) + # nothing should change here + assert_equal_glyphsets(glyphs, glyphs2) + + +def test_basic_composite_anchor(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + glyphs = ( + GlyphSetBuilder() + .add_glyph( + "A", + lambda glyph: ( + glyph.add_anchor("bottom", (234, 0)) + .add_anchor("ogonek", (411, 0)) + .add_anchor("top", (234, 810)) + ), + ) + .add_glyph( + "acutecomb", + lambda glyph: ( + glyph.add_anchor("_top", (0, 578)).add_anchor("top", (0, 810)) + ), + ) + .add_glyph( + "Aacute", + lambda glyph: ( + glyph.add_component("A", (0, 0)).add_component("acutecomb", (234, 232)) + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + + new_glyph = glyphs["Aacute"] + assert_anchors( + new_glyph.layers[0].anchors, + [ + ("bottom", (234, 0)), + ("ogonek", (411, 0)), + ("top", (234, 1042)), + ], + ) + + +def test_propagate_ligature_anchors(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + # this is based on the IJ glyph in Oswald (ExtraLight) + glyphs = ( + GlyphSetBuilder() + .add_glyph( + "I", + lambda glyph: ( + glyph.add_anchor("bottom", (103, 0)) + .add_anchor("ogonek", (103, 0)) + .add_anchor("top", (103, 810)) + .add_anchor("topleft", (20, 810)) + ), + ) + .add_glyph( + "J", + lambda glyph: ( + glyph.add_anchor("bottom", (133, 0)).add_anchor("top", (163, 810)) + ), + ) + .add_glyph( + "IJ", + lambda glyph: ( + glyph.set_subCategory("Ligature") + .add_component("I", (0, 0)) + .add_component("J", (206, 0)) + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + ij = glyphs["IJ"] + # these were derived by running the built in glyphs.app propagate anchors + # method from the macro panel + assert_anchors( + ij.layers[0].anchors, + [ + ("bottom_1", (103, 0)), + ("ogonek_1", (103, 0)), + ("top_1", (103, 810)), + ("topleft_1", (20, 810)), + ("bottom_2", (339, 0)), + ("top_2", (369, 810)), + ], + ) + + +def test_digraphs_arent_ligatures(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + # this is based on the IJ glyph in Oswald (ExtraLight) + glyphs = ( + GlyphSetBuilder() + .add_glyph( + "I", + lambda glyph: ( + glyph.add_anchor("bottom", (103, 0)) + .add_anchor("ogonek", (103, 0)) + .add_anchor("top", (103, 810)) + .add_anchor("topleft", (20, 810)) + ), + ) + .add_glyph( + "J", + lambda glyph: ( + glyph.add_anchor("bottom", (133, 0)).add_anchor("top", (163, 810)) + ), + ) + .add_glyph( + "IJ", + lambda glyph: ( + glyph.add_component("I", (0, 0)).add_component("J", (206, 0)) + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + ij = glyphs["IJ"] + # these were derived by running the built in glyphs.app propagate anchors + # method from the macro panel + assert_anchors( + ij.layers[0].anchors, + # 'J' component comes last; the 'bottom' and 'top' anchors are from 'J' + # shifted by the 'J' component's offset (206, 0). + # 'ogonek' and 'topleft' are inherited from 'I', the first component, which + # has (0, 0) offset hence the same anchor positions as the original 'I' glyph. + [ + ("bottom", (339, 0)), + ("ogonek", (103, 0)), + ("top", (369, 810)), + ("topleft", (20, 810)), + ], + ) + + +def test_propagate_across_layers(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + glyphs = ( + GlyphSetBuilder() + .add_glyph( + "A", + lambda glyph: ( + glyph.add_anchor("bottom", (290, 10)) + .add_anchor("ogonek", (490, 3)) + .add_anchor("top", (290, 690)) + .add_layer() + .add_anchor("bottom", (300, 0)) + .add_anchor("ogonek", (540, 10)) + .add_anchor("top", (300, 700)) + ), + ) + .add_glyph( + "acutecomb", + lambda glyph: ( + glyph.add_anchor("_top", (335, 502)) + .add_anchor("top", (353, 721)) + .add_layer() + .add_anchor("_top", (366, 500)) + .add_anchor("top", (366, 765)) + ), + ) + .add_glyph( + "Aacute", + lambda glyph: ( + glyph.add_component("A", (0, 0)) + .add_component("acutecomb", (-45, 188)) + .add_layer() + .add_component("A", (0, 0)) + .add_component("acutecomb", (-66, 200)) + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + + new_glyph = glyphs["Aacute"] + assert_anchors( + new_glyph.layers[0].anchors, + [ + ("bottom", (290, 10)), + ("ogonek", (490, 3)), + ("top", (308, 909)), + ], + ) + + assert_anchors( + new_glyph.layers[1].anchors, + [ + ("bottom", (300, 0)), + ("ogonek", (540, 10)), + ("top", (300, 965)), + ], + ) + + +def test_remove_exit_anchor_on_component(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + glyphs = ( + GlyphSetBuilder() + .add_glyph("comma", lambda glyph: ()) + .add_glyph( + "ain-ar.init", + lambda glyph: ( + glyph.add_anchor("top", (294, 514)).add_anchor("exit", (0, 0)) + ), + ) + .add_glyph( + "ain-ar.init.alt", + lambda glyph: ( + glyph.add_component("ain-ar.init", (0, 0)).add_component( + "comma", (0, 0) + ) + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + + new_glyph = glyphs["ain-ar.init.alt"] + assert_anchors(new_glyph.layers[0].anchors, [("top", (294, 514))]) + + +def test_component_anchor(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + glyphs = ( + GlyphSetBuilder() + .add_glyph( + "acutecomb", + lambda glyph: ( + glyph.add_anchor("_top", (150, 580)).add_anchor("top", (170, 792)) + ), + ) + .add_glyph( + "aa", + lambda glyph: ( + glyph.add_anchor("bottom_1", (218, 8)) + .add_anchor("bottom_2", (742, 7)) + .add_anchor("ogonek_1", (398, 9)) + .add_anchor("ogonek_2", (902, 9)) + .add_anchor("top_1", (227, 548)) + .add_anchor("top_2", (746, 548)) + ), + ) + .add_glyph( + "a_a", + lambda glyph: glyph.add_component("aa", (0, 0)), + ) + .add_glyph( + "a_aacute", + lambda glyph: ( + glyph.add_component("a_a", (0, 0)) + .add_component("acutecomb", (596, -32)) + .add_component_anchor("top_2") + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + + new_glyph = glyphs["a_aacute"] + assert_anchors( + new_glyph.layers[0].anchors, + [ + ("bottom_1", (218, 8)), + ("bottom_2", (742, 7)), + ("ogonek_1", (398, 9)), + ("ogonek_2", (902, 9)), + ("top_1", (227, 548)), + ("top_2", (766, 760)), + ], + ) + + +def test_origin_anchor(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + glyphs = ( + GlyphSetBuilder() + .add_glyph( + "a", + lambda glyph: ( + glyph.add_anchor("*origin", (-20, 0)) + .add_anchor("bottom", (242, 7)) + .add_anchor("ogonek", (402, 9)) + .add_anchor("top", (246, 548)) + ), + ) + .add_glyph( + "acutecomb", + lambda glyph: ( + glyph.add_anchor("_top", (150, 580)).add_anchor("top", (170, 792)) + ), + ) + .add_glyph( + "aacute", + lambda glyph: ( + glyph.add_component("a", (0, 0)).add_component("acutecomb", (116, -32)) + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + + new_glyph = glyphs["aacute"] + assert_anchors( + new_glyph.layers[0].anchors, + [ + ("bottom", (262, 7)), + ("ogonek", (422, 9)), + ("top", (286, 760)), + ], + ) + + +def test_invert_names_on_rotation(): + # derived from the observed behaviour of glyphs 3.2.2 (3259) + glyphs = ( + GlyphSetBuilder() + .add_glyph("comma", lambda glyph: ()) + .add_glyph( + "commaaccentcomb", + lambda glyph: ( + glyph.add_anchor("_bottom", (289, 0)) + .add_anchor("mybottom", (277, -308)) + .add_component("comma", (9, -164)) + ), + ) + .add_glyph( + "commaturnedabovecomb", + lambda glyph: ( + glyph.add_component("commaaccentcomb", (589, 502)).rotate_component(180) + ), + ) + .build() + ) + propagate_all_anchors_impl(glyphs) + + new_glyph = glyphs["commaturnedabovecomb"] + assert_anchors( + new_glyph.layers[0].anchors, + [("_top", (300, 502)), ("mytop", (312, 810))], + ) + + +def test_affine_scale(): + assert get_xy_rotation(Affine().translate(589, 502).rotate(math.radians(180))) == ( + -1, + -1, + ) + assert get_xy_rotation(Affine().translate(10, 10)) == (1, 1) + assert get_xy_rotation(Affine().scale(1, -1)) == (1, -1) + assert get_xy_rotation(Affine().scale(-1, 1)) == (-1, 1) + assert get_xy_rotation( + Affine().translate(589, 502).rotate(math.radians(180)).scale(-1, 1) + ) == ( + 1, + -1, + ) + + +def test_real_files(): + # the tricky parts of these files have been factored out into separate tests, + # but we'll keep them in case there are other regressions lurking + expected = GSFont(os.path.join(DATA, "PropagateAnchorsTest-propagated.glyphs")) + font = GSFont(os.path.join(DATA, "PropagateAnchorsTest.glyphs")) + + propagate_all_anchors(font) + + assert len(font.glyphs) == len(expected.glyphs) + assert [g.name for g in font.glyphs] == [g.name for g in expected.glyphs] + for g1, g2 in zip(font.glyphs, expected.glyphs): + assert len(g1.layers) == len(g2.layers) + for l1, l2 in zip(g1.layers, g2.layers): + assert [(a.name, tuple(a.position)) for a in l1.anchors] == [ + (a.name, tuple(a.position)) for a in l2.anchors + ] diff --git a/tests/classes_test.py b/tests/classes_test.py index 546995317..22b9492f6 100755 --- a/tests/classes_test.py +++ b/tests/classes_test.py @@ -115,7 +115,7 @@ def add_anchor(font, glyphname, anchorname, x, y): layer.anchors = getattr(layer, "anchors", []) anchor = GSAnchor() anchor.name = anchorname - anchor.position = (x, y) + anchor.position = Point(x, y) layer.anchors.append(anchor) diff --git a/tests/data/PropagateAnchorsTest-propagated.glyphs b/tests/data/PropagateAnchorsTest-propagated.glyphs new file mode 100644 index 000000000..3f844b361 --- /dev/null +++ b/tests/data/PropagateAnchorsTest-propagated.glyphs @@ -0,0 +1,3508 @@ +{ +.appVersion = "3300"; +.formatVersion = 3; +axes = ( +{ +name = Weight; +tag = wght; +} +); +customParameters = ( +{ +name = "Write lastChange"; +value = 0; +}, +{ +name = "Write DisplayStrings"; +value = 0; +} +); +date = "2024-02-08 12:03:09 +0000"; +familyName = "Propagate Anchors Test"; +fontMaster = ( +{ +axesValues = ( +400 +); +id = m01; +metricValues = ( +{ +over = 16; +pos = 800; +}, +{ +over = 16; +pos = 700; +}, +{ +over = 16; +pos = 500; +}, +{ +over = -16; +}, +{ +over = -16; +pos = -200; +}, +{ +} +); +name = Regular; +}, +{ +axesValues = ( +700 +); +iconName = SemiBold; +id = "D3EE0982-E416-4D68-847E-1544F56AC980"; +metricValues = ( +{ +over = 16; +pos = 800; +}, +{ +over = 16; +pos = 700; +}, +{ +over = 16; +pos = 500; +}, +{ +over = -16; +}, +{ +over = -16; +pos = -200; +}, +{ +} +); +name = Bold; +} +); +glyphs = ( +{ +glyphname = A; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (206,16); +}, +{ +name = ogonek; +pos = (360,13); +}, +{ +name = top; +pos = (212,724); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(212,689,l), +(24,8,l), +(427,7,l) +); +} +); +width = 450; +}, +{ +anchors = ( +{ +name = bottom; +pos = (278,12); +}, +{ +name = ogonek; +pos = (464,13); +}, +{ +name = top; +pos = (281,758); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(282,689,l), +(13,12,l), +(566,6,l) +); +} +); +width = 600; +} +); +unicode = 65; +}, +{ +glyphname = Aacute; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (206,16); +}, +{ +name = ogonek; +pos = (360,13); +}, +{ +name = top; +pos = (232,936); +} +); +layerId = m01; +shapes = ( +{ +ref = A; +}, +{ +pos = (62,144); +ref = acutecomb; +} +); +width = 450; +}, +{ +anchors = ( +{ +name = bottom; +pos = (278,12); +}, +{ +name = ogonek; +pos = (464,13); +}, +{ +name = top; +pos = (284,970); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = A; +}, +{ +pos = (114,178); +ref = acutecomb; +} +); +width = 600; +} +); +unicode = 193; +}, +{ +glyphname = Aogonek; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (206,16); +}, +{ +name = ogonek; +pos = (360,13); +}, +{ +name = top; +pos = (212,724); +} +); +layerId = m01; +shapes = ( +{ +ref = A; +}, +{ +pos = (176,14); +ref = ogonekcomb; +} +); +width = 450; +}, +{ +anchors = ( +{ +name = bottom; +pos = (278,12); +}, +{ +name = ogonek; +pos = (464,13); +}, +{ +name = top; +pos = (281,758); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = A; +}, +{ +pos = (280,14); +ref = ogonekcomb; +} +); +width = 600; +} +); +unicode = 260; +}, +{ +glyphname = B; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 66; +}, +{ +glyphname = C; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 67; +}, +{ +glyphname = D; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 68; +}, +{ +glyphname = E; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 69; +}, +{ +glyphname = F; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 70; +}, +{ +glyphname = G; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 71; +}, +{ +glyphname = H; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 72; +}, +{ +glyphname = I; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 73; +}, +{ +glyphname = J; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 74; +}, +{ +glyphname = K; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 75; +}, +{ +glyphname = L; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 76; +}, +{ +glyphname = M; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 77; +}, +{ +glyphname = N; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 78; +}, +{ +glyphname = O; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 79; +}, +{ +glyphname = P; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 80; +}, +{ +glyphname = Q; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 81; +}, +{ +glyphname = R; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 82; +}, +{ +glyphname = S; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 83; +}, +{ +glyphname = T; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 84; +}, +{ +glyphname = U; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 85; +}, +{ +glyphname = V; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 86; +}, +{ +glyphname = W; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 87; +}, +{ +glyphname = X; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 88; +}, +{ +glyphname = Y; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 89; +}, +{ +glyphname = Z; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 90; +}, +{ +glyphname = a; +layers = ( +{ +anchors = ( +{ +name = "*origin"; +pos = (-20,0); +}, +{ +name = bottom; +pos = (242,7); +}, +{ +name = ogonek; +pos = (402,9); +}, +{ +name = top; +pos = (246,548); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(448,0,l), +(448,517,l), +(47,517,l), +(47,0,l) +); +} +); +width = 500; +}, +{ +anchors = ( +{ +name = "*origin"; +pos = (-10,0); +}, +{ +name = bottom; +pos = (284,5); +}, +{ +name = ogonek; +pos = (453,13); +}, +{ +name = top; +pos = (277,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(508,0,l), +(508,517,l), +(47,517,l), +(47,0,l) +); +} +); +userData = { +public.truetype.overlap = 1; +}; +width = 550; +} +); +unicode = 97; +}, +{ +glyphname = aa; +layers = ( +{ +anchors = ( +{ +name = bottom_1; +pos = (218,8); +}, +{ +name = bottom_2; +pos = (742,7); +}, +{ +name = ogonek_1; +pos = (398,9); +}, +{ +name = ogonek_2; +pos = (902,9); +}, +{ +name = top_1; +pos = (227,548); +}, +{ +name = top_2; +pos = (746,548); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(948,0,l), +(948,517,l), +(47,517,l), +(47,0,l) +); +} +); +width = 1000; +}, +{ +anchors = ( +{ +name = bottom_1; +pos = (281,0); +}, +{ +name = bottom_2; +pos = (834,5); +}, +{ +name = ogonek_1; +pos = (469,13); +}, +{ +name = ogonek_2; +pos = (1003,13); +}, +{ +name = top_1; +pos = (264,559); +}, +{ +name = top_2; +pos = (827,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(1058,0,l), +(1058,517,l), +(47,517,l), +(47,0,l) +); +} +); +width = 1100; +} +); +metricLeft = a; +metricRight = a; +unicode = 42803; +}, +{ +glyphname = aacute; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (262,7); +}, +{ +name = ogonek; +pos = (422,9); +}, +{ +name = top; +pos = (286,760); +} +); +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (116,-32); +ref = acutecomb; +} +); +width = 500; +}, +{ +anchors = ( +{ +name = bottom; +pos = (294,5); +}, +{ +name = ogonek; +pos = (463,13); +}, +{ +name = top; +pos = (290,771); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (120,-21); +ref = acutecomb; +} +); +width = 550; +} +); +unicode = 225; +}, +{ +glyphname = aogonek; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (262,7); +}, +{ +name = ogonek; +pos = (422,9); +}, +{ +name = top; +pos = (266,548); +} +); +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (238,10); +ref = ogonekcomb; +} +); +width = 500; +}, +{ +anchors = ( +{ +name = bottom; +pos = (294,5); +}, +{ +name = ogonek; +pos = (463,13); +}, +{ +name = top; +pos = (287,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (279,14); +ref = ogonekcomb; +} +); +width = 550; +} +); +unicode = 261; +}, +{ +glyphname = b; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 98; +}, +{ +glyphname = c; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 99; +}, +{ +glyphname = d; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 100; +}, +{ +glyphname = e; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 101; +}, +{ +glyphname = f; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 102; +}, +{ +glyphname = g; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 103; +}, +{ +glyphname = h; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 104; +}, +{ +glyphname = i; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 105; +}, +{ +glyphname = j; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 106; +}, +{ +glyphname = k; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 107; +}, +{ +glyphname = l; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 108; +}, +{ +glyphname = m; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 109; +}, +{ +glyphname = n; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 110; +}, +{ +glyphname = o; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 111; +}, +{ +glyphname = p; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 112; +}, +{ +glyphname = q; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 113; +}, +{ +glyphname = r; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 114; +}, +{ +glyphname = s; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 115; +}, +{ +glyphname = t; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 116; +}, +{ +glyphname = u; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 117; +}, +{ +glyphname = v; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 118; +}, +{ +glyphname = w; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 119; +}, +{ +glyphname = x; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 120; +}, +{ +glyphname = y; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 121; +}, +{ +glyphname = z; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 122; +}, +{ +glyphname = a_a; +layers = ( +{ +anchors = ( +{ +name = bottom_1; +pos = (218,8); +}, +{ +name = bottom_2; +pos = (742,7); +}, +{ +name = ogonek_1; +pos = (398,9); +}, +{ +name = ogonek_2; +pos = (902,9); +}, +{ +name = top_1; +pos = (227,548); +}, +{ +name = top_2; +pos = (746,548); +} +); +layerId = m01; +shapes = ( +{ +ref = aa; +} +); +width = 1000; +}, +{ +anchors = ( +{ +name = bottom_1; +pos = (281,0); +}, +{ +name = bottom_2; +pos = (834,5); +}, +{ +name = ogonek_1; +pos = (469,13); +}, +{ +name = ogonek_2; +pos = (1003,13); +}, +{ +name = top_1; +pos = (264,559); +}, +{ +name = top_2; +pos = (827,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = aa; +} +); +width = 1100; +} +); +metricLeft = a; +metricRight = a; +}, +{ +glyphname = a_a_a; +layers = ( +{ +anchors = ( +{ +name = bottom_1; +pos = (262,7); +}, +{ +name = ogonek_1; +pos = (422,9); +}, +{ +name = top_1; +pos = (266,548); +}, +{ +name = bottom_2; +pos = (718,8); +}, +{ +name = bottom_3; +pos = (1242,7); +}, +{ +name = ogonek_2; +pos = (898,9); +}, +{ +name = ogonek_3; +pos = (1402,9); +}, +{ +name = top_2; +pos = (727,548); +}, +{ +name = top_3; +pos = (1246,548); +} +); +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (500,0); +ref = a_a; +} +); +width = 1500; +}, +{ +anchors = ( +{ +name = bottom_1; +pos = (294,5); +}, +{ +name = ogonek_1; +pos = (463,13); +}, +{ +name = top_1; +pos = (287,559); +}, +{ +name = bottom_2; +pos = (831,0); +}, +{ +name = bottom_3; +pos = (1384,5); +}, +{ +name = ogonek_2; +pos = (1019,13); +}, +{ +name = ogonek_3; +pos = (1553,13); +}, +{ +name = top_2; +pos = (814,559); +}, +{ +name = top_3; +pos = (1377,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (550,0); +ref = a_a; +} +); +width = 1650; +} +); +metricLeft = a; +metricRight = a; +}, +{ +glyphname = a_aacute; +layers = ( +{ +anchors = ( +{ +name = bottom_1; +pos = (218,8); +}, +{ +name = bottom_2; +pos = (742,7); +}, +{ +name = ogonek_1; +pos = (398,9); +}, +{ +name = ogonek_2; +pos = (902,9); +}, +{ +name = top_1; +pos = (227,548); +}, +{ +name = top_2; +pos = (766,760); +} +); +layerId = m01; +shapes = ( +{ +ref = a_a; +}, +{ +anchor = top_2; +pos = (596,-32); +ref = acutecomb; +} +); +width = 1000; +}, +{ +anchors = ( +{ +name = bottom_1; +pos = (281,0); +}, +{ +name = bottom_2; +pos = (834,5); +}, +{ +name = ogonek_1; +pos = (469,13); +}, +{ +name = ogonek_2; +pos = (1003,13); +}, +{ +name = top_1; +pos = (264,559); +}, +{ +name = top_2; +pos = (830,771); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a_a; +}, +{ +anchor = top_2; +pos = (660,-21); +ref = acutecomb; +} +); +width = 1100; +} +); +metricLeft = aacute; +metricRight = a; +}, +{ +glyphname = aacute_aacute; +layers = ( +{ +anchors = ( +{ +name = bottom_1; +pos = (218,8); +}, +{ +name = bottom_2; +pos = (742,7); +}, +{ +name = ogonek_1; +pos = (398,9); +}, +{ +name = ogonek_2; +pos = (902,9); +}, +{ +name = top_1; +pos = (247,760); +}, +{ +name = top_2; +pos = (766,760); +} +); +layerId = m01; +shapes = ( +{ +ref = aa; +}, +{ +anchor = top_1; +pos = (77,-32); +ref = acutecomb; +}, +{ +anchor = top_2; +pos = (596,-32); +ref = acutecomb; +} +); +width = 1000; +}, +{ +anchors = ( +{ +name = bottom_1; +pos = (281,0); +}, +{ +name = bottom_2; +pos = (834,5); +}, +{ +name = ogonek_1; +pos = (469,13); +}, +{ +name = ogonek_2; +pos = (1003,13); +}, +{ +name = top_1; +pos = (267,771); +}, +{ +name = top_2; +pos = (830,771); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = aa; +}, +{ +anchor = top_1; +pos = (97,-21); +ref = acutecomb; +}, +{ +anchor = top_2; +pos = (660,-21); +ref = acutecomb; +} +); +width = 1100; +} +); +metricLeft = aacute; +metricRight = aacute; +}, +{ +glyphname = aacute_acedilla; +layers = ( +{ +anchors = ( +{ +name = bottom_1; +pos = (262,7); +}, +{ +name = ogonek_1; +pos = (422,9); +}, +{ +name = top_1; +pos = (286,760); +}, +{ +name = bottom_2; +pos = (767,-247); +}, +{ +name = ogonek_2; +pos = (922,9); +}, +{ +name = top_2; +pos = (766,548); +} +); +layerId = m01; +shapes = ( +{ +ref = aacute; +}, +{ +pos = (500,0); +ref = acedilla; +} +); +width = 1000; +}, +{ +anchors = ( +{ +name = bottom_1; +pos = (294,5); +}, +{ +name = ogonek_1; +pos = (463,13); +}, +{ +name = top_1; +pos = (290,771); +}, +{ +name = bottom_2; +pos = (849,-253); +}, +{ +name = ogonek_2; +pos = (1013,13); +}, +{ +name = top_2; +pos = (837,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = aacute; +}, +{ +pos = (550,0); +ref = acedilla; +} +); +width = 1100; +} +); +metricLeft = aacute; +metricRight = aacute; +subCategory = Ligature; +}, +{ +glyphname = "ain-ar"; +layers = ( +{ +anchors = ( +{ +name = top; +pos = (288,660); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(452,550,l), +(366,598,l), +(288,609,l), +(203,588,l), +(164,538,l), +(110,441,l), +(116,359,l), +(133,289,l), +(202,241,l), +(247,215,l), +(288,201,l), +(122,166,l), +(53,104,l), +(6,-5,l), +(11,-40,o), +(18,-102,o), +(22,-111,c), +(83,-206,l), +(103,-226,o), +(140,-259,o), +(144,-267,c), +(258,-289,l), +(300,-286,o), +(371,-280,o), +(385,-280,c), +(502,-242,l), +(559,-172,l), +(520,-98,l), +(458,-83,l), +(358,-147,l), +(276,-168,l), +(201,-147,l), +(144,-104,l), +(112,-39,l), +(115,19,l), +(144,75,l), +(161,81,o), +(179,90,o), +(194,93,cs), +(209,96,o), +(289,121,o), +(301,122,c), +(393,155,l), +(423,205,l), +(435,247,l), +(395,290,l), +(346,299,l), +(319,302,l), +(297,300,l), +(201,376,l), +(202,476,l), +(262,515,l), +(355,510,l), +(402,452,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = top; +pos = (288,660); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(452,550,l), +(366,598,l), +(288,609,l), +(153,578,l), +(114,528,l), +(90,441,l), +(96,359,l), +(113,289,l), +(177,243,l), +(225,215,l), +(266,201,l), +(82,166,l), +(13,104,l), +(-34,-5,l), +(-29,-40,o), +(-22,-102,o), +(-18,-111,c), +(43,-206,l), +(63,-226,o), +(140,-259,o), +(144,-267,c), +(258,-289,l), +(300,-286,o), +(371,-280,o), +(385,-280,c), +(502,-242,l), +(559,-172,l), +(520,-68,l), +(458,-53,l), +(358,-107,l), +(320,-123,l), +(251,-107,l), +(194,-76,l), +(162,-19,l), +(165,39,l), +(194,75,l), +(211,81,o), +(229,90,o), +(244,93,cs), +(259,96,o), +(305,106,o), +(321,117,c), +(419,141,l), +(444,195,l), +(443,254,l), +(403,297,l), +(346,319,l), +(319,322,l), +(297,320,l), +(231,376,l), +(252,456,l), +(294,470,l), +(367,485,l), +(402,452,l) +); +} +); +width = 600; +} +); +unicode = 1593; +}, +{ +glyphname = "ain-ar.fina"; +layers = ( +{ +anchors = ( +{ +name = entry; +pos = (608,-178); +}, +{ +name = top; +pos = (324,577); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(541,134,o), +(551,62,o), +(535,61,c), +(382,93,l), +(306,134,l), +(250,192,l), +(219,229,o), +(149,263,o), +(139,302,cs), +(119,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(418,206,l), +(221,20,l), +(200,-29,l), +(199,-73,l), +(241,-116,l), +(258,-150,o), +(307,-169,o), +(316,-172,c), +(378,-171,l), +(451,-162,l), +(533,-103,l), +(559,-95,l), +(608,-178,l), +(539,-264,l), +(373,-291,l), +(232,-268,l), +(146,-197,l), +(92,-70,l), +(94,23,l), +(159,94,l), +(219,148,l), +(301,212,l), +(396,278,l), +(442,378,l), +(387,426,l), +(314,437,l), +(257,412,l), +(222,377,l), +(223,327,l), +(274,277,l), +(352,206,l), +(435,178,l), +(544,170,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = entry; +pos = (619,-180); +}, +{ +name = top; +pos = (324,568); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(541,156,o), +(551,35,o), +(535,34,c), +(382,72,l), +(306,134,l), +(250,192,l), +(219,229,o), +(129,263,o), +(119,302,cs), +(99,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(418,206,l), +(251,20,l), +(230,-29,l), +(229,-73,l), +(271,-146,l), +(288,-150,o), +(310,-165,o), +(319,-168,c), +(378,-171,l), +(440,-137,l), +(492,-98,l), +(548,-110,l), +(619,-180,l), +(540,-275,l), +(373,-305,l), +(242,-298,l), +(116,-227,l), +(72,-70,l), +(74,33,l), +(154,94,l), +(208,157,l), +(301,220,l), +(395,302,l), +(400,357,l), +(387,396,l), +(314,407,l), +(281,393,l), +(256,368,l), +(239,350,l), +(290,295,l), +(356,228,l), +(435,200,l), +(544,192,l) +); +} +); +width = 600; +} +); +}, +{ +glyphname = "ain-ar.medi"; +layers = ( +{ +anchors = ( +{ +name = entry; +pos = (544,170); +}, +{ +name = exit; +}, +{ +name = top; +pos = (323,554); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(541,134,o), +(551,62,o), +(535,61,c), +(382,93,l), +(306,134,l), +(250,192,l), +(219,229,o), +(149,263,o), +(139,302,cs), +(119,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(418,206,l), +(161,39,l), +(94,23,l), +(64,134,l), +(179,150,l), +(301,212,l), +(396,278,l), +(442,378,l), +(387,426,l), +(314,437,l), +(257,412,l), +(222,377,l), +(223,327,l), +(274,277,l), +(352,206,l), +(435,178,l), +(544,170,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = entry; +pos = (544,172); +}, +{ +name = exit; +}, +{ +name = top; +pos = (323,554); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(541,136,o), +(551,35,o), +(535,34,c), +(382,72,l), +(314,126,l), +(237,179,l), +(206,216,o), +(129,263,o), +(119,302,cs), +(99,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(407,192,l), +(172,43,l), +(74,10,l), +(46,157,l), +(186,172,l), +(301,220,l), +(395,302,l), +(400,357,l), +(387,396,l), +(314,407,l), +(281,393,l), +(256,368,l), +(239,350,l), +(290,295,l), +(356,228,l), +(435,172,l), +(544,172,l) +); +} +); +width = 600; +} +); +}, +{ +glyphname = "ain-ar.init"; +layers = ( +{ +anchors = ( +{ +name = exit; +}, +{ +name = top; +pos = (294,514); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(434,342,l), +(315,372,l), +(244,367,l), +(207,337,l), +(170,271,l), +(172,256,o), +(172,240,o), +(176,228,c), +(210,171,l), +(239,140,l), +(265,136,o), +(312,117,o), +(338,116,c), +(457,116,l), +(480,66,l), +(478,23,l), +(427,1,l), +(175,3,ls), +(139,4,o), +(73,12,o), +(68,6,c), +(23,100,l), +(135,93,l), +(166,93,l), +(137,124,o), +(103,149,o), +(86,214,c), +(77,283,l), +(82,306,o), +(90,355,o), +(109,383,cs), +(130,414,o), +(186,458,o), +(193,460,c), +(304,470,l), +(399,458,l), +(464,429,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = exit; +}, +{ +name = top; +pos = (294,514); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(434,312,l), +(315,342,l), +(244,337,l), +(207,307,l), +(190,271,l), +(192,256,o), +(192,240,o), +(196,228,c), +(210,191,l), +(239,160,l), +(265,156,o), +(312,137,o), +(338,136,c), +(457,136,l), +(480,86,l), +(478,23,l), +(427,1,l), +(175,3,ls), +(139,4,o), +(73,12,o), +(68,6,c), +(23,130,l), +(135,123,l), +(166,123,l), +(137,154,o), +(94,179,o), +(77,214,c), +(57,283,l), +(62,306,o), +(70,355,o), +(89,383,cs), +(110,414,o), +(186,458,o), +(193,460,c), +(304,470,l), +(399,458,l), +(464,429,l) +); +} +); +width = 600; +} +); +}, +{ +glyphname = "ain-ar.init.alt"; +layers = ( +{ +anchors = ( +{ +name = top; +pos = (294,514); +} +); +layerId = m01; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +ref = comma; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = top; +pos = (294,514); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +ref = comma; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar"; +layers = ( +{ +anchors = ( +{ +name = top; +pos = (296,811); +} +); +layerId = m01; +shapes = ( +{ +ref = "ain-ar"; +}, +{ +pos = (130,248); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = top; +pos = (290,816); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar"; +}, +{ +pos = (148,243); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +unicode = 1594; +}, +{ +glyphname = "ghain-ar.fina"; +layers = ( +{ +anchors = ( +{ +name = entry; +pos = (608,-178); +}, +{ +name = top; +pos = (332,728); +} +); +layerId = m01; +shapes = ( +{ +ref = "ain-ar.fina"; +}, +{ +pos = (166,165); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = entry; +pos = (619,-180); +}, +{ +name = top; +pos = (326,724); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.fina"; +}, +{ +pos = (184,151); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar.medi"; +layers = ( +{ +anchors = ( +{ +name = entry; +pos = (544,170); +}, +{ +name = exit; +}, +{ +name = top; +pos = (331,705); +} +); +layerId = m01; +shapes = ( +{ +ref = "ain-ar.medi"; +}, +{ +pos = (165,142); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = entry; +pos = (544,172); +}, +{ +name = exit; +}, +{ +name = top; +pos = (325,710); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.medi"; +}, +{ +pos = (183,137); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar.medi.alt"; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (323,554); +}, +{ +name = top; +pos = (323,554); +}, +{ +name = exit; +} +); +layerId = m01; +shapes = ( +{ +pos = (165,142); +ref = "dotabove-ar"; +}, +{ +ref = "ain-ar.medi"; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = _top; +pos = (323,554); +}, +{ +name = top; +pos = (323,554); +}, +{ +name = exit; +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (183,137); +ref = "dotabove-ar"; +}, +{ +ref = "ain-ar.medi"; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar.init"; +layers = ( +{ +anchors = ( +{ +name = exit; +}, +{ +name = top; +pos = (302,665); +} +); +layerId = m01; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +pos = (136,102); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = exit; +}, +{ +name = top; +pos = (296,670); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +pos = (154,97); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +}, +{ +glyphname = zero; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 48; +}, +{ +glyphname = one; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 49; +}, +{ +glyphname = two; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 50; +}, +{ +glyphname = three; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 51; +}, +{ +glyphname = four; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 52; +}, +{ +glyphname = five; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 53; +}, +{ +glyphname = six; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 54; +}, +{ +glyphname = seven; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 55; +}, +{ +glyphname = eight; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 56; +}, +{ +glyphname = nine; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 57; +}, +{ +glyphname = space; +layers = ( +{ +layerId = m01; +width = 200; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 32; +}, +{ +glyphname = period; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 46; +}, +{ +glyphname = comma; +layers = ( +{ +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(343,116,l), +(298,-108,l), +(224,-94,l), +(263,28,l), +(213,29,l), +(238,108,l) +); +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(355,126,l), +(319,-109,l), +(204,-114,l), +(256,25,l), +(183,29,l), +(215,145,l) +); +} +); +width = 600; +} +); +unicode = 44; +}, +{ +glyphname = hyphen; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 45; +}, +{ +glyphname = "dotabove-ar"; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (158,412); +}, +{ +name = top; +pos = (166,563); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(132,462,l), +(178,450,l), +(191,507,l), +(143,520,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _top; +pos = (140,417); +}, +{ +name = top; +pos = (142,573); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(102,462,l), +(178,450,l), +(194,522,l), +(116,535,l) +); +} +); +width = 300; +} +); +}, +{ +glyphname = gravecomb; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (85,571); +} +); +layerId = m01; +shapes = ( +{ +pos = (370,0); +ref = acutecomb; +scale = (-1,1); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _top; +pos = (83,569); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (392,0); +ref = acutecomb; +scale = (-1,1); +} +); +width = 300; +} +); +unicode = 768; +}, +{ +glyphname = acutecomb; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (150,580); +}, +{ +name = top; +pos = (170,792); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(331,738,l), +(234,772,l), +(132,615,l), +(177,584,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _top; +pos = (167,580); +}, +{ +name = top; +pos = (170,792); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(331,738,l), +(194,772,l), +(132,615,l), +(207,584,l) +); +} +); +width = 300; +} +); +unicode = 769; +}, +{ +glyphname = brevecomb; +layers = ( +{ +anchors = ( +{ +name = "*origin"; +pos = (-50,0); +}, +{ +name = _top; +pos = (181,560); +}, +{ +name = top; +pos = (198,790); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(69,759,l), +(122,763,l), +(129,675,l), +(172,644,l), +(231,646,l), +(270,682,l), +(276,758,l), +(327,761,l), +(322,668,l), +(256,594,l), +(157,594,l), +(79,637,l), +(59,758,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = "*origin"; +pos = (-100,0); +}, +{ +name = _top; +pos = (191,546); +}, +{ +name = top; +pos = (206,787); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(69,768,l), +(152,769,l), +(159,683,l), +(185,656,l), +(229,656,l), +(250,682,l), +(256,778,l), +(347,781,l), +(342,668,l), +(256,574,l), +(134,574,l), +(67,637,l), +(48,768,l) +); +} +); +width = 300; +} +); +unicode = 774; +}, +{ +glyphname = commaturnedabovecomb; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (300,502); +}, +{ +name = mytop; +pos = (312,810); +} +); +layerId = m01; +shapes = ( +{ +angle = 180; +pos = (589,502); +ref = commaaccentcomb; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = _top; +pos = (274,511); +}, +{ +name = mytop; +pos = (278,838); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +angle = 180; +pos = (568,513); +ref = commaaccentcomb; +} +); +width = 600; +} +); +unicode = 786; +}, +{ +glyphname = commaabovecomb; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (308,501); +}, +{ +name = top; +pos = (325,821); +} +); +layerId = m01; +shapes = ( +{ +pos = (28,643); +ref = comma; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = _top; +pos = (306,503); +}, +{ +name = top; +pos = (324,831); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (53,663); +ref = comma; +} +); +width = 600; +} +); +unicode = 787; +}, +{ +glyphname = commaaccentcomb; +layers = ( +{ +anchors = ( +{ +name = _bottom; +pos = (289,0); +}, +{ +name = mybottom; +pos = (277,-308); +} +); +layerId = m01; +shapes = ( +{ +pos = (9,-164); +ref = comma; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = _bottom; +pos = (294,2); +}, +{ +name = mybottom; +pos = (290,-325); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (12,-182); +ref = comma; +} +); +width = 600; +} +); +unicode = 806; +}, +{ +glyphname = cedillacomb; +layers = ( +{ +anchors = ( +{ +name = _bottom; +pos = (177,0); +}, +{ +name = bottom; +pos = (182,-254); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(263,-225,l), +(298,-101,l), +(182,-64,l), +(208,10,l), +(162,3,l), +(133,-85,l), +(246,-130,l), +(228,-198,l), +(131,-225,l), +(152,-266,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _bottom; +pos = (177,0); +}, +{ +name = bottom; +pos = (182,-258); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(272,-231,l), +(305,-94,l), +(200,-63,l), +(213,20,l), +(142,10,l), +(123,-92,l), +(231,-121,l), +(213,-189,l), +(109,-215,l), +(147,-274,l) +); +} +); +width = 300; +} +); +unicode = 807; +}, +{ +glyphname = ogonekcomb; +layers = ( +{ +anchors = ( +{ +name = _ogonek; +pos = (184,-1); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(103,-88,l), +(103,-160,l), +(141,-206,l), +(247,-204,l), +(253,-144,l), +(176,-143,l), +(150,-105,l), +(198,-1,l), +(176,3,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _ogonek; +pos = (184,-1); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(88,-92,l), +(93,-160,l), +(141,-206,l), +(247,-204,l), +(253,-134,l), +(206,-133,l), +(180,-95,l), +(207,-1,l), +(160,4,l) +); +} +); +width = 300; +} +); +unicode = 808; +}, +{ +glyphname = brevecomb_acutecomb; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (231,560); +}, +{ +name = top; +pos = (255,988); +} +); +layerId = m01; +shapes = ( +{ +ref = brevecomb; +}, +{ +alignment = -1; +pos = (85,196); +ref = acutecomb; +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _top; +pos = (268,550); +}, +{ +name = top; +pos = (286,1003); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +alignment = -1; +pos = (-23,4); +ref = brevecomb; +}, +{ +pos = (116,211); +ref = acutecomb; +} +); +width = 300; +} +); +}, +{ +glyphname = Acedilla; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (211,-238); +}, +{ +name = ogonek; +pos = (360,13); +}, +{ +name = top; +pos = (212,724); +} +); +layerId = m01; +shapes = ( +{ +ref = A; +}, +{ +pos = (29,16); +ref = cedillacomb; +} +); +width = 450; +}, +{ +anchors = ( +{ +name = bottom; +pos = (283,-246); +}, +{ +name = ogonek; +pos = (464,13); +}, +{ +name = top; +pos = (281,758); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = A; +}, +{ +pos = (101,12); +ref = cedillacomb; +} +); +width = 600; +} +); +}, +{ +glyphname = acedilla; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (267,-247); +}, +{ +name = ogonek; +pos = (422,9); +}, +{ +name = top; +pos = (266,548); +} +); +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (85,7); +ref = cedillacomb; +} +); +width = 500; +}, +{ +anchors = ( +{ +name = bottom; +pos = (299,-253); +}, +{ +name = ogonek; +pos = (463,13); +}, +{ +name = top; +pos = (287,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (117,5); +ref = cedillacomb; +} +); +width = 550; +} +); +} +); +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/data/PropagateAnchorsTest.glyphs b/tests/data/PropagateAnchorsTest.glyphs new file mode 100644 index 000000000..3261f3ef6 --- /dev/null +++ b/tests/data/PropagateAnchorsTest.glyphs @@ -0,0 +1,2910 @@ +{ +.appVersion = "3300"; +.formatVersion = 3; +axes = ( +{ +name = Weight; +tag = wght; +} +); +customParameters = ( +{ +name = "Write lastChange"; +value = 0; +}, +{ +name = "Write DisplayStrings"; +value = 0; +} +); +date = "2024-02-08 12:03:09 +0000"; +familyName = "Propagate Anchors Test"; +fontMaster = ( +{ +axesValues = ( +400 +); +id = m01; +metricValues = ( +{ +over = 16; +pos = 800; +}, +{ +over = 16; +pos = 700; +}, +{ +over = 16; +pos = 500; +}, +{ +over = -16; +}, +{ +over = -16; +pos = -200; +}, +{ +} +); +name = Regular; +}, +{ +axesValues = ( +700 +); +iconName = SemiBold; +id = "D3EE0982-E416-4D68-847E-1544F56AC980"; +metricValues = ( +{ +over = 16; +pos = 800; +}, +{ +over = 16; +pos = 700; +}, +{ +over = 16; +pos = 500; +}, +{ +over = -16; +}, +{ +over = -16; +pos = -200; +}, +{ +} +); +name = Bold; +} +); +glyphs = ( +{ +glyphname = A; +layers = ( +{ +anchors = ( +{ +name = bottom; +pos = (206,16); +}, +{ +name = ogonek; +pos = (360,13); +}, +{ +name = top; +pos = (212,724); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(212,689,l), +(24,8,l), +(427,7,l) +); +} +); +width = 450; +}, +{ +anchors = ( +{ +name = bottom; +pos = (278,12); +}, +{ +name = ogonek; +pos = (464,13); +}, +{ +name = top; +pos = (281,758); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(282,689,l), +(13,12,l), +(566,6,l) +); +} +); +width = 600; +} +); +unicode = 65; +}, +{ +glyphname = Aacute; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = A; +}, +{ +pos = (62,144); +ref = acutecomb; +} +); +width = 450; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = A; +}, +{ +pos = (114,178); +ref = acutecomb; +} +); +width = 600; +} +); +unicode = 193; +}, +{ +glyphname = Aogonek; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = A; +}, +{ +pos = (176,14); +ref = ogonekcomb; +} +); +width = 450; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = A; +}, +{ +pos = (280,14); +ref = ogonekcomb; +} +); +width = 600; +} +); +unicode = 260; +}, +{ +glyphname = B; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 66; +}, +{ +glyphname = C; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 67; +}, +{ +glyphname = D; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 68; +}, +{ +glyphname = E; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 69; +}, +{ +glyphname = F; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 70; +}, +{ +glyphname = G; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 71; +}, +{ +glyphname = H; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 72; +}, +{ +glyphname = I; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 73; +}, +{ +glyphname = J; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 74; +}, +{ +glyphname = K; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 75; +}, +{ +glyphname = L; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 76; +}, +{ +glyphname = M; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 77; +}, +{ +glyphname = N; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 78; +}, +{ +glyphname = O; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 79; +}, +{ +glyphname = P; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 80; +}, +{ +glyphname = Q; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 81; +}, +{ +glyphname = R; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 82; +}, +{ +glyphname = S; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 83; +}, +{ +glyphname = T; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 84; +}, +{ +glyphname = U; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 85; +}, +{ +glyphname = V; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 86; +}, +{ +glyphname = W; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 87; +}, +{ +glyphname = X; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 88; +}, +{ +glyphname = Y; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 89; +}, +{ +glyphname = Z; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 90; +}, +{ +glyphname = a; +layers = ( +{ +anchors = ( +{ +name = "*origin"; +pos = (-20,0); +}, +{ +name = bottom; +pos = (242,7); +}, +{ +name = ogonek; +pos = (402,9); +}, +{ +name = top; +pos = (246,548); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(448,0,l), +(448,517,l), +(47,517,l), +(47,0,l) +); +} +); +width = 500; +}, +{ +anchors = ( +{ +name = "*origin"; +pos = (-10,0); +}, +{ +name = bottom; +pos = (284,5); +}, +{ +name = ogonek; +pos = (453,13); +}, +{ +name = top; +pos = (277,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(508,0,l), +(508,517,l), +(47,517,l), +(47,0,l) +); +} +); +userData = { +public.truetype.overlap = 1; +}; +width = 550; +} +); +unicode = 97; +}, +{ +glyphname = aa; +layers = ( +{ +anchors = ( +{ +name = bottom_1; +pos = (218,8); +}, +{ +name = bottom_2; +pos = (742,7); +}, +{ +name = ogonek_1; +pos = (398,9); +}, +{ +name = ogonek_2; +pos = (902,9); +}, +{ +name = top_1; +pos = (227,548); +}, +{ +name = top_2; +pos = (746,548); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(948,0,l), +(948,517,l), +(47,517,l), +(47,0,l) +); +} +); +width = 1000; +}, +{ +anchors = ( +{ +name = bottom_1; +pos = (281,0); +}, +{ +name = bottom_2; +pos = (834,5); +}, +{ +name = ogonek_1; +pos = (469,13); +}, +{ +name = ogonek_2; +pos = (1003,13); +}, +{ +name = top_1; +pos = (264,559); +}, +{ +name = top_2; +pos = (827,559); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(1058,0,l), +(1058,517,l), +(47,517,l), +(47,0,l) +); +} +); +width = 1100; +} +); +metricLeft = a; +metricRight = a; +unicode = 42803; +}, +{ +glyphname = aacute; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (116,-32); +ref = acutecomb; +} +); +width = 500; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (120,-21); +ref = acutecomb; +} +); +width = 550; +} +); +unicode = 225; +}, +{ +glyphname = aogonek; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (238,10); +ref = ogonekcomb; +} +); +width = 500; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (279,14); +ref = ogonekcomb; +} +); +width = 550; +} +); +unicode = 261; +}, +{ +glyphname = b; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 98; +}, +{ +glyphname = c; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 99; +}, +{ +glyphname = d; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 100; +}, +{ +glyphname = e; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 101; +}, +{ +glyphname = f; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 102; +}, +{ +glyphname = g; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 103; +}, +{ +glyphname = h; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 104; +}, +{ +glyphname = i; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 105; +}, +{ +glyphname = j; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 106; +}, +{ +glyphname = k; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 107; +}, +{ +glyphname = l; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 108; +}, +{ +glyphname = m; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 109; +}, +{ +glyphname = n; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 110; +}, +{ +glyphname = o; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 111; +}, +{ +glyphname = p; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 112; +}, +{ +glyphname = q; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 113; +}, +{ +glyphname = r; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 114; +}, +{ +glyphname = s; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 115; +}, +{ +glyphname = t; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 116; +}, +{ +glyphname = u; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 117; +}, +{ +glyphname = v; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 118; +}, +{ +glyphname = w; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 119; +}, +{ +glyphname = x; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 120; +}, +{ +glyphname = y; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 121; +}, +{ +glyphname = z; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 122; +}, +{ +glyphname = a_a; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = aa; +} +); +width = 1000; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = aa; +} +); +width = 1100; +} +); +metricLeft = a; +metricRight = a; +}, +{ +glyphname = a_a_a; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (500,0); +ref = a_a; +} +); +width = 1500; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (550,0); +ref = a_a; +} +); +width = 1650; +} +); +metricLeft = a; +metricRight = a; +}, +{ +glyphname = a_aacute; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = a_a; +}, +{ +anchor = top_2; +pos = (596,-32); +ref = acutecomb; +} +); +width = 1000; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a_a; +}, +{ +anchor = top_2; +pos = (660,-21); +ref = acutecomb; +} +); +width = 1100; +} +); +metricLeft = aacute; +metricRight = a; +}, +{ +glyphname = aacute_aacute; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = aa; +}, +{ +anchor = top_1; +pos = (77,-32); +ref = acutecomb; +}, +{ +anchor = top_2; +pos = (596,-32); +ref = acutecomb; +} +); +width = 1000; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = aa; +}, +{ +anchor = top_1; +pos = (97,-21); +ref = acutecomb; +}, +{ +anchor = top_2; +pos = (660,-21); +ref = acutecomb; +} +); +width = 1100; +} +); +metricLeft = aacute; +metricRight = aacute; +}, +{ +glyphname = aacute_acedilla; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = aacute; +}, +{ +pos = (500,0); +ref = acedilla; +} +); +width = 1000; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = aacute; +}, +{ +pos = (550,0); +ref = acedilla; +} +); +width = 1100; +} +); +metricLeft = aacute; +metricRight = aacute; +subCategory = Ligature; +}, +{ +glyphname = "ain-ar"; +layers = ( +{ +anchors = ( +{ +name = top; +pos = (288,660); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(452,550,l), +(366,598,l), +(288,609,l), +(203,588,l), +(164,538,l), +(110,441,l), +(116,359,l), +(133,289,l), +(202,241,l), +(247,215,l), +(288,201,l), +(122,166,l), +(53,104,l), +(6,-5,l), +(11,-40,o), +(18,-102,o), +(22,-111,c), +(83,-206,l), +(103,-226,o), +(140,-259,o), +(144,-267,c), +(258,-289,l), +(300,-286,o), +(371,-280,o), +(385,-280,c), +(502,-242,l), +(559,-172,l), +(520,-98,l), +(458,-83,l), +(358,-147,l), +(276,-168,l), +(201,-147,l), +(144,-104,l), +(112,-39,l), +(115,19,l), +(144,75,l), +(161,81,o), +(179,90,o), +(194,93,cs), +(209,96,o), +(289,121,o), +(301,122,c), +(393,155,l), +(423,205,l), +(435,247,l), +(395,290,l), +(346,299,l), +(319,302,l), +(297,300,l), +(201,376,l), +(202,476,l), +(262,515,l), +(355,510,l), +(402,452,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = top; +pos = (288,660); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(452,550,l), +(366,598,l), +(288,609,l), +(153,578,l), +(114,528,l), +(90,441,l), +(96,359,l), +(113,289,l), +(177,243,l), +(225,215,l), +(266,201,l), +(82,166,l), +(13,104,l), +(-34,-5,l), +(-29,-40,o), +(-22,-102,o), +(-18,-111,c), +(43,-206,l), +(63,-226,o), +(140,-259,o), +(144,-267,c), +(258,-289,l), +(300,-286,o), +(371,-280,o), +(385,-280,c), +(502,-242,l), +(559,-172,l), +(520,-68,l), +(458,-53,l), +(358,-107,l), +(320,-123,l), +(251,-107,l), +(194,-76,l), +(162,-19,l), +(165,39,l), +(194,75,l), +(211,81,o), +(229,90,o), +(244,93,cs), +(259,96,o), +(305,106,o), +(321,117,c), +(419,141,l), +(444,195,l), +(443,254,l), +(403,297,l), +(346,319,l), +(319,322,l), +(297,320,l), +(231,376,l), +(252,456,l), +(294,470,l), +(367,485,l), +(402,452,l) +); +} +); +width = 600; +} +); +unicode = 1593; +}, +{ +glyphname = "ain-ar.fina"; +layers = ( +{ +anchors = ( +{ +name = entry; +pos = (608,-178); +}, +{ +name = top; +pos = (324,577); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(541,134,o), +(551,62,o), +(535,61,c), +(382,93,l), +(306,134,l), +(250,192,l), +(219,229,o), +(149,263,o), +(139,302,cs), +(119,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(418,206,l), +(221,20,l), +(200,-29,l), +(199,-73,l), +(241,-116,l), +(258,-150,o), +(307,-169,o), +(316,-172,c), +(378,-171,l), +(451,-162,l), +(533,-103,l), +(559,-95,l), +(608,-178,l), +(539,-264,l), +(373,-291,l), +(232,-268,l), +(146,-197,l), +(92,-70,l), +(94,23,l), +(159,94,l), +(219,148,l), +(301,212,l), +(396,278,l), +(442,378,l), +(387,426,l), +(314,437,l), +(257,412,l), +(222,377,l), +(223,327,l), +(274,277,l), +(352,206,l), +(435,178,l), +(544,170,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = entry; +pos = (619,-180); +}, +{ +name = top; +pos = (324,568); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(541,156,o), +(551,35,o), +(535,34,c), +(382,72,l), +(306,134,l), +(250,192,l), +(219,229,o), +(129,263,o), +(119,302,cs), +(99,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(418,206,l), +(251,20,l), +(230,-29,l), +(229,-73,l), +(271,-146,l), +(288,-150,o), +(310,-165,o), +(319,-168,c), +(378,-171,l), +(440,-137,l), +(492,-98,l), +(548,-110,l), +(619,-180,l), +(540,-275,l), +(373,-305,l), +(242,-298,l), +(116,-227,l), +(72,-70,l), +(74,33,l), +(154,94,l), +(208,157,l), +(301,220,l), +(395,302,l), +(400,357,l), +(387,396,l), +(314,407,l), +(281,393,l), +(256,368,l), +(239,350,l), +(290,295,l), +(356,228,l), +(435,200,l), +(544,192,l) +); +} +); +width = 600; +} +); +}, +{ +glyphname = "ain-ar.medi"; +layers = ( +{ +anchors = ( +{ +name = entry; +pos = (544,170); +}, +{ +name = exit; +}, +{ +name = top; +pos = (323,554); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(541,134,o), +(551,62,o), +(535,61,c), +(382,93,l), +(306,134,l), +(250,192,l), +(219,229,o), +(149,263,o), +(139,302,cs), +(119,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(418,206,l), +(161,39,l), +(94,23,l), +(64,134,l), +(179,150,l), +(301,212,l), +(396,278,l), +(442,378,l), +(387,426,l), +(314,437,l), +(257,412,l), +(222,377,l), +(223,327,l), +(274,277,l), +(352,206,l), +(435,178,l), +(544,170,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = entry; +pos = (544,172); +}, +{ +name = exit; +}, +{ +name = top; +pos = (323,554); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(541,136,o), +(551,35,o), +(535,34,c), +(382,72,l), +(314,126,l), +(237,179,l), +(206,216,o), +(129,263,o), +(119,302,cs), +(99,380,l), +(139,442,l), +(199,478,ls), +(209,484,o), +(230,494,o), +(274,496,cs), +(318,498,o), +(346,500,o), +(360,501,cs), +(374,502,o), +(389,505,o), +(405,502,cs), +(421,499,o), +(461,466,o), +(473,457,cs), +(485,448,o), +(503,435,o), +(507,424,c), +(500,327,l), +(462,247,l), +(407,192,l), +(172,43,l), +(74,10,l), +(46,157,l), +(186,172,l), +(301,220,l), +(395,302,l), +(400,357,l), +(387,396,l), +(314,407,l), +(281,393,l), +(256,368,l), +(239,350,l), +(290,295,l), +(356,228,l), +(435,172,l), +(544,172,l) +); +} +); +width = 600; +} +); +}, +{ +glyphname = "ain-ar.init"; +layers = ( +{ +anchors = ( +{ +name = exit; +}, +{ +name = top; +pos = (294,514); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(434,342,l), +(315,372,l), +(244,367,l), +(207,337,l), +(170,271,l), +(172,256,o), +(172,240,o), +(176,228,c), +(210,171,l), +(239,140,l), +(265,136,o), +(312,117,o), +(338,116,c), +(457,116,l), +(480,66,l), +(478,23,l), +(427,1,l), +(175,3,ls), +(139,4,o), +(73,12,o), +(68,6,c), +(23,100,l), +(135,93,l), +(166,93,l), +(137,124,o), +(103,149,o), +(86,214,c), +(77,283,l), +(82,306,o), +(90,355,o), +(109,383,cs), +(130,414,o), +(186,458,o), +(193,460,c), +(304,470,l), +(399,458,l), +(464,429,l) +); +} +); +width = 600; +}, +{ +anchors = ( +{ +name = exit; +}, +{ +name = top; +pos = (294,514); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(434,312,l), +(315,342,l), +(244,337,l), +(207,307,l), +(190,271,l), +(192,256,o), +(192,240,o), +(196,228,c), +(210,191,l), +(239,160,l), +(265,156,o), +(312,137,o), +(338,136,c), +(457,136,l), +(480,86,l), +(478,23,l), +(427,1,l), +(175,3,ls), +(139,4,o), +(73,12,o), +(68,6,c), +(23,130,l), +(135,123,l), +(166,123,l), +(137,154,o), +(94,179,o), +(77,214,c), +(57,283,l), +(62,306,o), +(70,355,o), +(89,383,cs), +(110,414,o), +(186,458,o), +(193,460,c), +(304,470,l), +(399,458,l), +(464,429,l) +); +} +); +width = 600; +} +); +}, +{ +glyphname = "ain-ar.init.alt"; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +ref = comma; +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +ref = comma; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar"; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = "ain-ar"; +}, +{ +pos = (130,248); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar"; +}, +{ +pos = (148,243); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +unicode = 1594; +}, +{ +glyphname = "ghain-ar.fina"; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = "ain-ar.fina"; +}, +{ +pos = (166,165); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.fina"; +}, +{ +pos = (184,151); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar.medi"; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = "ain-ar.medi"; +}, +{ +pos = (165,142); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.medi"; +}, +{ +pos = (183,137); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar.medi.alt"; +layers = ( +{ +layerId = m01; +shapes = ( +{ +pos = (165,142); +ref = "dotabove-ar"; +}, +{ +ref = "ain-ar.medi"; +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (183,137); +ref = "dotabove-ar"; +}, +{ +ref = "ain-ar.medi"; +} +); +width = 600; +} +); +}, +{ +glyphname = "ghain-ar.init"; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +pos = (136,102); +ref = "dotabove-ar"; +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = "ain-ar.init"; +}, +{ +pos = (154,97); +ref = "dotabove-ar"; +} +); +width = 600; +} +); +}, +{ +glyphname = zero; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 48; +}, +{ +glyphname = one; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 49; +}, +{ +glyphname = two; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 50; +}, +{ +glyphname = three; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 51; +}, +{ +glyphname = four; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 52; +}, +{ +glyphname = five; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 53; +}, +{ +glyphname = six; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 54; +}, +{ +glyphname = seven; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 55; +}, +{ +glyphname = eight; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 56; +}, +{ +glyphname = nine; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 57; +}, +{ +glyphname = space; +layers = ( +{ +layerId = m01; +width = 200; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 32; +}, +{ +glyphname = period; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 46; +}, +{ +glyphname = comma; +layers = ( +{ +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(343,116,l), +(298,-108,l), +(224,-94,l), +(263,28,l), +(213,29,l), +(238,108,l) +); +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(355,126,l), +(319,-109,l), +(204,-114,l), +(256,25,l), +(183,29,l), +(215,145,l) +); +} +); +width = 600; +} +); +unicode = 44; +}, +{ +glyphname = hyphen; +layers = ( +{ +layerId = m01; +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +width = 600; +} +); +unicode = 45; +}, +{ +glyphname = "dotabove-ar"; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (158,412); +}, +{ +name = top; +pos = (166,563); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(132,462,l), +(178,450,l), +(191,507,l), +(143,520,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _top; +pos = (140,417); +}, +{ +name = top; +pos = (142,573); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(102,462,l), +(178,450,l), +(194,522,l), +(116,535,l) +); +} +); +width = 300; +} +); +}, +{ +glyphname = gravecomb; +layers = ( +{ +anchors = ( +{ +name = "*origin"; +pos = (47,0); +}, +{ +name = _top; +pos = (132,571); +} +); +layerId = m01; +shapes = ( +{ +pos = (370,0); +ref = acutecomb; +scale = (-1,1); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = "*origin"; +pos = (60,0); +}, +{ +name = _top; +pos = (143,569); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (392,0); +ref = acutecomb; +scale = (-1,1); +} +); +width = 300; +} +); +unicode = 768; +}, +{ +glyphname = acutecomb; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (150,580); +}, +{ +name = top; +pos = (170,792); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(331,738,l), +(234,772,l), +(132,615,l), +(177,584,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _top; +pos = (167,580); +}, +{ +name = top; +pos = (170,792); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(331,738,l), +(194,772,l), +(132,615,l), +(207,584,l) +); +} +); +width = 300; +} +); +unicode = 769; +}, +{ +glyphname = brevecomb; +layers = ( +{ +anchors = ( +{ +name = "*origin"; +pos = (-50,0); +}, +{ +name = _top; +pos = (181,560); +}, +{ +name = top; +pos = (198,790); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(69,759,l), +(122,763,l), +(129,675,l), +(172,644,l), +(231,646,l), +(270,682,l), +(276,758,l), +(327,761,l), +(322,668,l), +(256,594,l), +(157,594,l), +(79,637,l), +(59,758,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = "*origin"; +pos = (-100,0); +}, +{ +name = _top; +pos = (191,546); +}, +{ +name = top; +pos = (206,787); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(69,768,l), +(152,769,l), +(159,683,l), +(185,656,l), +(229,656,l), +(250,682,l), +(256,778,l), +(347,781,l), +(342,668,l), +(256,574,l), +(134,574,l), +(67,637,l), +(48,768,l) +); +} +); +width = 300; +} +); +unicode = 774; +}, +{ +glyphname = commaturnedabovecomb; +layers = ( +{ +layerId = m01; +shapes = ( +{ +angle = 180; +pos = (589,502); +ref = commaaccentcomb; +} +); +width = 600; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +angle = 180; +pos = (568,513); +ref = commaaccentcomb; +} +); +width = 600; +} +); +unicode = 786; +}, +{ +glyphname = commaabovecomb; +layers = ( +{ +anchors = ( +{ +name = _top; +pos = (308,501); +}, +{ +name = top; +pos = (325,821); +} +); +layerId = m01; +shapes = ( +{ +pos = (28,643); +ref = comma; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = _top; +pos = (306,503); +}, +{ +name = top; +pos = (324,831); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (53,663); +ref = comma; +} +); +width = 600; +} +); +unicode = 787; +}, +{ +glyphname = commaaccentcomb; +layers = ( +{ +anchors = ( +{ +name = _bottom; +pos = (289,0); +}, +{ +name = mybottom; +pos = (277,-308); +} +); +layerId = m01; +shapes = ( +{ +pos = (9,-164); +ref = comma; +} +); +width = 600; +}, +{ +anchors = ( +{ +name = _bottom; +pos = (294,2); +}, +{ +name = mybottom; +pos = (290,-325); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +pos = (12,-182); +ref = comma; +} +); +width = 600; +} +); +unicode = 806; +}, +{ +glyphname = cedillacomb; +layers = ( +{ +anchors = ( +{ +name = _bottom; +pos = (177,0); +}, +{ +name = bottom; +pos = (182,-254); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(263,-225,l), +(298,-101,l), +(182,-64,l), +(208,10,l), +(162,3,l), +(133,-85,l), +(246,-130,l), +(228,-198,l), +(131,-225,l), +(152,-266,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _bottom; +pos = (177,0); +}, +{ +name = bottom; +pos = (182,-258); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(272,-231,l), +(305,-94,l), +(200,-63,l), +(213,20,l), +(142,10,l), +(123,-92,l), +(231,-121,l), +(213,-189,l), +(109,-215,l), +(147,-274,l) +); +} +); +width = 300; +} +); +unicode = 807; +}, +{ +glyphname = ogonekcomb; +layers = ( +{ +anchors = ( +{ +name = _ogonek; +pos = (184,-1); +} +); +layerId = m01; +shapes = ( +{ +closed = 1; +nodes = ( +(103,-88,l), +(103,-160,l), +(141,-206,l), +(247,-204,l), +(253,-144,l), +(176,-143,l), +(150,-105,l), +(198,-1,l), +(176,3,l) +); +} +); +width = 300; +}, +{ +anchors = ( +{ +name = _ogonek; +pos = (184,-1); +} +); +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +closed = 1; +nodes = ( +(88,-92,l), +(93,-160,l), +(141,-206,l), +(247,-204,l), +(253,-134,l), +(206,-133,l), +(180,-95,l), +(207,-1,l), +(160,4,l) +); +} +); +width = 300; +} +); +unicode = 808; +}, +{ +glyphname = brevecomb_acutecomb; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = brevecomb; +}, +{ +alignment = -1; +pos = (85,196); +ref = acutecomb; +} +); +width = 300; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +alignment = -1; +pos = (-23,4); +ref = brevecomb; +}, +{ +pos = (116,211); +ref = acutecomb; +} +); +width = 300; +} +); +}, +{ +glyphname = Acedilla; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = A; +}, +{ +pos = (29,16); +ref = cedillacomb; +} +); +width = 450; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = A; +}, +{ +pos = (101,12); +ref = cedillacomb; +} +); +width = 600; +} +); +}, +{ +glyphname = acedilla; +layers = ( +{ +layerId = m01; +shapes = ( +{ +ref = a; +}, +{ +pos = (85,7); +ref = cedillacomb; +} +); +width = 500; +}, +{ +layerId = "D3EE0982-E416-4D68-847E-1544F56AC980"; +shapes = ( +{ +ref = a; +}, +{ +pos = (117,5); +ref = cedillacomb; +} +); +width = 550; +} +); +} +); +metrics = ( +{ +type = ascender; +}, +{ +type = "cap height"; +}, +{ +type = "x-height"; +}, +{ +type = baseline; +}, +{ +type = descender; +}, +{ +type = "italic angle"; +} +); +unitsPerEm = 1000; +versionMajor = 1; +versionMinor = 0; +}