aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/python
diff options
context:
space:
mode:
authorrobot-piglet <robot-piglet@yandex-team.com>2024-04-01 04:03:58 +0300
committerrobot-piglet <robot-piglet@yandex-team.com>2024-04-01 04:15:53 +0300
commit6e7835911e36724b4c14f4888d6f0222994eadf0 (patch)
tree7f6210d918014bc308e98934e896d34aadb9bac0 /contrib/python
parent8e91894b5642604c33982805651a0f59bcdaf137 (diff)
downloadydb-6e7835911e36724b4c14f4888d6f0222994eadf0.tar.gz
Intermediate changes
Diffstat (limited to 'contrib/python')
-rw-r--r--contrib/python/fonttools/.dist-info/METADATA9
-rw-r--r--contrib/python/fonttools/fontTools/__init__.py2
-rw-r--r--contrib/python/fonttools/fontTools/cu2qu/ufo.py12
-rw-r--r--contrib/python/fonttools/fontTools/pens/basePen.py50
-rw-r--r--contrib/python/fonttools/fontTools/pens/filterPen.py86
-rw-r--r--contrib/python/fonttools/fontTools/pens/pointPen.py79
-rw-r--r--contrib/python/fonttools/fontTools/pens/recordingPen.py158
-rw-r--r--contrib/python/fonttools/fontTools/varLib/instancer/__init__.py6
-rw-r--r--contrib/python/fonttools/ya.make2
9 files changed, 360 insertions, 44 deletions
diff --git a/contrib/python/fonttools/.dist-info/METADATA b/contrib/python/fonttools/.dist-info/METADATA
index a711f82b4e..b374ebc499 100644
--- a/contrib/python/fonttools/.dist-info/METADATA
+++ b/contrib/python/fonttools/.dist-info/METADATA
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: fonttools
-Version: 4.49.0
+Version: 4.50.0
Summary: Tools to manipulate font files
Home-page: http://github.com/fonttools/fonttools
Author: Just van Rossum
@@ -375,6 +375,13 @@ Have fun!
Changelog
~~~~~~~~~
+4.50.0 (released 2024-03-15)
+----------------------------
+
+- [pens] Added decomposing filter pens that draw components as regular contours (#3460).
+- [instancer] Drop explicit no-op axes from TupleVariations (#3457).
+- [cu2qu/ufo] Return set of modified glyph names from fonts_to_quadratic (#3456).
+
4.49.0 (released 2024-02-15)
----------------------------
diff --git a/contrib/python/fonttools/fontTools/__init__.py b/contrib/python/fonttools/fontTools/__init__.py
index e6a745bd52..ead49e26c8 100644
--- a/contrib/python/fonttools/fontTools/__init__.py
+++ b/contrib/python/fonttools/fontTools/__init__.py
@@ -3,6 +3,6 @@ from fontTools.misc.loggingTools import configLogger
log = logging.getLogger(__name__)
-version = __version__ = "4.49.0"
+version = __version__ = "4.50.0"
__all__ = ["version", "log", "configLogger"]
diff --git a/contrib/python/fonttools/fontTools/cu2qu/ufo.py b/contrib/python/fonttools/fontTools/cu2qu/ufo.py
index 10367cfecf..7a6dbc67f8 100644
--- a/contrib/python/fonttools/fontTools/cu2qu/ufo.py
+++ b/contrib/python/fonttools/fontTools/cu2qu/ufo.py
@@ -250,7 +250,7 @@ def fonts_to_quadratic(
compatibility. If this is not required, calling fonts_to_quadratic with one
font at a time may yield slightly more optimized results.
- Return True if fonts were modified, else return False.
+ Return the set of modified glyph names if any, else return an empty set.
By default, cu2qu stores the curve type in the fonts' lib, under a private
key "com.github.googlei18n.cu2qu.curve_type", and will not try to convert
@@ -296,7 +296,7 @@ def fonts_to_quadratic(
elif max_err_em:
max_errors = [f.info.unitsPerEm * max_err_em for f in fonts]
- modified = False
+ modified = set()
glyph_errors = {}
for name in set().union(*(f.keys() for f in fonts)):
glyphs = []
@@ -306,9 +306,10 @@ def fonts_to_quadratic(
glyphs.append(font[name])
cur_max_errors.append(error)
try:
- modified |= _glyphs_to_quadratic(
+ if _glyphs_to_quadratic(
glyphs, cur_max_errors, reverse_direction, stats, all_quadratic
- )
+ ):
+ modified.add(name)
except IncompatibleGlyphsError as exc:
logger.error(exc)
glyph_errors[name] = exc
@@ -329,7 +330,6 @@ def fonts_to_quadratic(
new_curve_type = "quadratic" if all_quadratic else "mixed"
if curve_type != new_curve_type:
font.lib[CURVE_TYPE_LIB_KEY] = new_curve_type
- modified = True
return modified
@@ -343,7 +343,7 @@ def glyph_to_quadratic(glyph, **kwargs):
def font_to_quadratic(font, **kwargs):
"""Convenience wrapper around fonts_to_quadratic, for just one font.
- Return True if the font was modified, else return False.
+ Return the set of modified glyph names if any, else return empty set.
"""
return fonts_to_quadratic([font], **kwargs)
diff --git a/contrib/python/fonttools/fontTools/pens/basePen.py b/contrib/python/fonttools/fontTools/pens/basePen.py
index 5d2cf5032c..ba38f70090 100644
--- a/contrib/python/fonttools/fontTools/pens/basePen.py
+++ b/contrib/python/fonttools/fontTools/pens/basePen.py
@@ -39,7 +39,7 @@ sequence of length 2 will do.
from typing import Tuple, Dict
from fontTools.misc.loggingTools import LogMixin
-from fontTools.misc.transform import DecomposedTransform
+from fontTools.misc.transform import DecomposedTransform, Identity
__all__ = [
"AbstractPen",
@@ -195,17 +195,40 @@ class DecomposingPen(LoggingPen):
By default a warning message is logged when a base glyph is missing;
set the class variable ``skipMissingComponents`` to False if you want
- to raise a :class:`MissingComponentError` exception.
+ all instances of a sub-class to raise a :class:`MissingComponentError`
+ exception by default.
"""
skipMissingComponents = True
+ # alias error for convenience
+ MissingComponentError = MissingComponentError
- def __init__(self, glyphSet):
- """Takes a single 'glyphSet' argument (dict), in which the glyphs
- that are referenced as components are looked up by their name.
+ def __init__(
+ self,
+ glyphSet,
+ *args,
+ skipMissingComponents=None,
+ reverseFlipped=False,
+ **kwargs,
+ ):
+ """Takes a 'glyphSet' argument (dict), in which the glyphs that are referenced
+ as components are looked up by their name.
+
+ If the optional 'reverseFlipped' argument is True, components whose transformation
+ matrix has a negative determinant will be decomposed with a reversed path direction
+ to compensate for the flip.
+
+ The optional 'skipMissingComponents' argument can be set to True/False to
+ override the homonymous class attribute for a given pen instance.
"""
- super(DecomposingPen, self).__init__()
+ super(DecomposingPen, self).__init__(*args, **kwargs)
self.glyphSet = glyphSet
+ self.skipMissingComponents = (
+ self.__class__.skipMissingComponents
+ if skipMissingComponents is None
+ else skipMissingComponents
+ )
+ self.reverseFlipped = reverseFlipped
def addComponent(self, glyphName, transformation):
"""Transform the points of the base glyph and draw it onto self."""
@@ -218,8 +241,19 @@ class DecomposingPen(LoggingPen):
raise MissingComponentError(glyphName)
self.log.warning("glyph '%s' is missing from glyphSet; skipped" % glyphName)
else:
- tPen = TransformPen(self, transformation)
- glyph.draw(tPen)
+ pen = self
+ if transformation != Identity:
+ pen = TransformPen(pen, transformation)
+ if self.reverseFlipped:
+ # if the transformation has a negative determinant, it will
+ # reverse the contour direction of the component
+ a, b, c, d = transformation[:4]
+ det = a * d - b * c
+ if det < 0:
+ from fontTools.pens.reverseContourPen import ReverseContourPen
+
+ pen = ReverseContourPen(pen)
+ glyph.draw(pen)
def addVarComponent(self, glyphName, transformation, location):
# GlyphSet decomposes for us
diff --git a/contrib/python/fonttools/fontTools/pens/filterPen.py b/contrib/python/fonttools/fontTools/pens/filterPen.py
index 6c8712c261..f104e67dd3 100644
--- a/contrib/python/fonttools/fontTools/pens/filterPen.py
+++ b/contrib/python/fonttools/fontTools/pens/filterPen.py
@@ -1,5 +1,7 @@
-from fontTools.pens.basePen import AbstractPen
-from fontTools.pens.pointPen import AbstractPointPen
+from __future__ import annotations
+
+from fontTools.pens.basePen import AbstractPen, DecomposingPen
+from fontTools.pens.pointPen import AbstractPointPen, DecomposingPointPen
from fontTools.pens.recordingPen import RecordingPen
@@ -150,8 +152,8 @@ class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
('endPath', (), {})
"""
- def __init__(self, outPointPen):
- self._outPen = outPointPen
+ def __init__(self, outPen):
+ self._outPen = outPen
def beginPath(self, **kwargs):
self._outPen.beginPath(**kwargs)
@@ -161,3 +163,79 @@ class FilterPointPen(_PassThruComponentsMixin, AbstractPointPen):
def addPoint(self, pt, segmentType=None, smooth=False, name=None, **kwargs):
self._outPen.addPoint(pt, segmentType, smooth, name, **kwargs)
+
+
+class _DecomposingFilterPenMixin:
+ """Mixin class that decomposes components as regular contours.
+
+ Shared by both DecomposingFilterPen and DecomposingFilterPointPen.
+
+ Takes two required parameters, another (segment or point) pen 'outPen' to draw
+ with, and a 'glyphSet' dict of drawable glyph objects to draw components from.
+
+ The 'skipMissingComponents' and 'reverseFlipped' optional arguments work the
+ same as in the DecomposingPen/DecomposingPointPen. Both are False by default.
+
+ In addition, the decomposing filter pens also take the following two options:
+
+ 'include' is an optional set of component base glyph names to consider for
+ decomposition; the default include=None means decompose all components no matter
+ the base glyph name).
+
+ 'decomposeNested' (bool) controls whether to recurse decomposition into nested
+ components of components (this only matters when 'include' was also provided);
+ if False, only decompose top-level components included in the set, but not
+ also their children.
+ """
+
+ # raises MissingComponentError if base glyph is not found in glyphSet
+ skipMissingComponents = False
+
+ def __init__(
+ self,
+ outPen,
+ glyphSet,
+ skipMissingComponents=None,
+ reverseFlipped=False,
+ include: set[str] | None = None,
+ decomposeNested: bool = True,
+ ):
+ super().__init__(
+ outPen=outPen,
+ glyphSet=glyphSet,
+ skipMissingComponents=skipMissingComponents,
+ reverseFlipped=reverseFlipped,
+ )
+ self.include = include
+ self.decomposeNested = decomposeNested
+
+ def addComponent(self, baseGlyphName, transformation, **kwargs):
+ # only decompose the component if it's included in the set
+ if self.include is None or baseGlyphName in self.include:
+ # if we're decomposing nested components, temporarily set include to None
+ include_bak = self.include
+ if self.decomposeNested and self.include:
+ self.include = None
+ try:
+ super().addComponent(baseGlyphName, transformation, **kwargs)
+ finally:
+ if self.include != include_bak:
+ self.include = include_bak
+ else:
+ _PassThruComponentsMixin.addComponent(
+ self, baseGlyphName, transformation, **kwargs
+ )
+
+
+class DecomposingFilterPen(_DecomposingFilterPenMixin, DecomposingPen, FilterPen):
+ """Filter pen that draws components as regular contours."""
+
+ pass
+
+
+class DecomposingFilterPointPen(
+ _DecomposingFilterPenMixin, DecomposingPointPen, FilterPointPen
+):
+ """Filter point pen that draws components as regular contours."""
+
+ pass
diff --git a/contrib/python/fonttools/fontTools/pens/pointPen.py b/contrib/python/fonttools/fontTools/pens/pointPen.py
index eb1ebc2048..93a9201c99 100644
--- a/contrib/python/fonttools/fontTools/pens/pointPen.py
+++ b/contrib/python/fonttools/fontTools/pens/pointPen.py
@@ -15,8 +15,9 @@ For instance, whether or not a point is smooth, and its name.
import math
from typing import Any, Optional, Tuple, Dict
-from fontTools.pens.basePen import AbstractPen, PenError
-from fontTools.misc.transform import DecomposedTransform
+from fontTools.misc.loggingTools import LogMixin
+from fontTools.pens.basePen import AbstractPen, MissingComponentError, PenError
+from fontTools.misc.transform import DecomposedTransform, Identity
__all__ = [
"AbstractPointPen",
@@ -523,3 +524,77 @@ class ReverseContourPointPen(AbstractPointPen):
if self.currentContour is not None:
raise PenError("Components must be added before or after contours")
self.pen.addComponent(glyphName, transform, identifier=identifier, **kwargs)
+
+
+class DecomposingPointPen(LogMixin, AbstractPointPen):
+ """Implements a 'addComponent' method that decomposes components
+ (i.e. draws them onto self as simple contours).
+ It can also be used as a mixin class (e.g. see DecomposingRecordingPointPen).
+
+ You must override beginPath, addPoint, endPath. You may
+ additionally override addVarComponent and addComponent.
+
+ By default a warning message is logged when a base glyph is missing;
+ set the class variable ``skipMissingComponents`` to False if you want
+ all instances of a sub-class to raise a :class:`MissingComponentError`
+ exception by default.
+ """
+
+ skipMissingComponents = True
+ # alias error for convenience
+ MissingComponentError = MissingComponentError
+
+ def __init__(
+ self,
+ glyphSet,
+ *args,
+ skipMissingComponents=None,
+ reverseFlipped=False,
+ **kwargs,
+ ):
+ """Takes a 'glyphSet' argument (dict), in which the glyphs that are referenced
+ as components are looked up by their name.
+
+ If the optional 'reverseFlipped' argument is True, components whose transformation
+ matrix has a negative determinant will be decomposed with a reversed path direction
+ to compensate for the flip.
+
+ The optional 'skipMissingComponents' argument can be set to True/False to
+ override the homonymous class attribute for a given pen instance.
+ """
+ super().__init__(*args, **kwargs)
+ self.glyphSet = glyphSet
+ self.skipMissingComponents = (
+ self.__class__.skipMissingComponents
+ if skipMissingComponents is None
+ else skipMissingComponents
+ )
+ self.reverseFlipped = reverseFlipped
+
+ def addComponent(self, baseGlyphName, transformation, identifier=None, **kwargs):
+ """Transform the points of the base glyph and draw it onto self.
+
+ The `identifier` parameter and any extra kwargs are ignored.
+ """
+ from fontTools.pens.transformPen import TransformPointPen
+
+ try:
+ glyph = self.glyphSet[baseGlyphName]
+ except KeyError:
+ if not self.skipMissingComponents:
+ raise MissingComponentError(baseGlyphName)
+ self.log.warning(
+ "glyph '%s' is missing from glyphSet; skipped" % baseGlyphName
+ )
+ else:
+ pen = self
+ if transformation != Identity:
+ pen = TransformPointPen(pen, transformation)
+ if self.reverseFlipped:
+ # if the transformation has a negative determinant, it will
+ # reverse the contour direction of the component
+ a, b, c, d = transformation[:4]
+ det = a * d - b * c
+ if a * d - b * c < 0:
+ pen = ReverseContourPointPen(pen)
+ glyph.drawPoints(pen)
diff --git a/contrib/python/fonttools/fontTools/pens/recordingPen.py b/contrib/python/fonttools/fontTools/pens/recordingPen.py
index 4f44a4d59f..ba165e1951 100644
--- a/contrib/python/fonttools/fontTools/pens/recordingPen.py
+++ b/contrib/python/fonttools/fontTools/pens/recordingPen.py
@@ -1,13 +1,14 @@
"""Pen recording operations that can be accessed or replayed."""
from fontTools.pens.basePen import AbstractPen, DecomposingPen
-from fontTools.pens.pointPen import AbstractPointPen
+from fontTools.pens.pointPen import AbstractPointPen, DecomposingPointPen
__all__ = [
"replayRecording",
"RecordingPen",
"DecomposingRecordingPen",
+ "DecomposingRecordingPointPen",
"RecordingPointPen",
"lerpRecordings",
]
@@ -85,28 +86,55 @@ class DecomposingRecordingPen(DecomposingPen, RecordingPen):
"""Same as RecordingPen, except that it doesn't keep components
as references, but draws them decomposed as regular contours.
- The constructor takes a single 'glyphSet' positional argument,
+ The constructor takes a required 'glyphSet' positional argument,
a dictionary of glyph objects (i.e. with a 'draw' method) keyed
- by thir name::
-
- >>> class SimpleGlyph(object):
- ... def draw(self, pen):
- ... pen.moveTo((0, 0))
- ... pen.curveTo((1, 1), (2, 2), (3, 3))
- ... pen.closePath()
- >>> class CompositeGlyph(object):
- ... def draw(self, pen):
- ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
- >>> glyphSet = {'a': SimpleGlyph(), 'b': CompositeGlyph()}
- >>> for name, glyph in sorted(glyphSet.items()):
- ... pen = DecomposingRecordingPen(glyphSet)
- ... glyph.draw(pen)
- ... print("{}: {}".format(name, pen.value))
- a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
- b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
+ by thir name; other arguments are forwarded to the DecomposingPen's
+ constructor::
+
+ >>> class SimpleGlyph(object):
+ ... def draw(self, pen):
+ ... pen.moveTo((0, 0))
+ ... pen.curveTo((1, 1), (2, 2), (3, 3))
+ ... pen.closePath()
+ >>> class CompositeGlyph(object):
+ ... def draw(self, pen):
+ ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
+ >>> class MissingComponent(object):
+ ... def draw(self, pen):
+ ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
+ >>> class FlippedComponent(object):
+ ... def draw(self, pen):
+ ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
+ >>> glyphSet = {
+ ... 'a': SimpleGlyph(),
+ ... 'b': CompositeGlyph(),
+ ... 'c': MissingComponent(),
+ ... 'd': FlippedComponent(),
+ ... }
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPen(glyphSet)
+ ... try:
+ ... glyph.draw(pen)
+ ... except pen.MissingComponentError:
+ ... pass
+ ... print("{}: {}".format(name, pen.value))
+ a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
+ b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
+ c: []
+ d: [('moveTo', ((0, 0),)), ('curveTo', ((-1, 1), (-2, 2), (-3, 3))), ('closePath', ())]
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPen(
+ ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
+ ... )
+ ... glyph.draw(pen)
+ ... print("{}: {}".format(name, pen.value))
+ a: [('moveTo', ((0, 0),)), ('curveTo', ((1, 1), (2, 2), (3, 3))), ('closePath', ())]
+ b: [('moveTo', ((-1, 1),)), ('curveTo', ((0, 2), (1, 3), (2, 4))), ('closePath', ())]
+ c: []
+ d: [('moveTo', ((0, 0),)), ('lineTo', ((-3, 3),)), ('curveTo', ((-2, 2), (-1, 1), (0, 0))), ('closePath', ())]
"""
- # raises KeyError if base glyph is not found in glyphSet
+ # raises MissingComponentError(KeyError) if base glyph is not found in glyphSet
skipMissingComponents = False
@@ -174,6 +202,96 @@ class RecordingPointPen(AbstractPointPen):
drawPoints = replay
+class DecomposingRecordingPointPen(DecomposingPointPen, RecordingPointPen):
+ """Same as RecordingPointPen, except that it doesn't keep components
+ as references, but draws them decomposed as regular contours.
+
+ The constructor takes a required 'glyphSet' positional argument,
+ a dictionary of pointPen-drawable glyph objects (i.e. with a 'drawPoints' method)
+ keyed by thir name; other arguments are forwarded to the DecomposingPointPen's
+ constructor::
+
+ >>> from pprint import pprint
+ >>> class SimpleGlyph(object):
+ ... def drawPoints(self, pen):
+ ... pen.beginPath()
+ ... pen.addPoint((0, 0), "line")
+ ... pen.addPoint((1, 1))
+ ... pen.addPoint((2, 2))
+ ... pen.addPoint((3, 3), "curve")
+ ... pen.endPath()
+ >>> class CompositeGlyph(object):
+ ... def drawPoints(self, pen):
+ ... pen.addComponent('a', (1, 0, 0, 1, -1, 1))
+ >>> class MissingComponent(object):
+ ... def drawPoints(self, pen):
+ ... pen.addComponent('foobar', (1, 0, 0, 1, 0, 0))
+ >>> class FlippedComponent(object):
+ ... def drawPoints(self, pen):
+ ... pen.addComponent('a', (-1, 0, 0, 1, 0, 0))
+ >>> glyphSet = {
+ ... 'a': SimpleGlyph(),
+ ... 'b': CompositeGlyph(),
+ ... 'c': MissingComponent(),
+ ... 'd': FlippedComponent(),
+ ... }
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPointPen(glyphSet)
+ ... try:
+ ... glyph.drawPoints(pen)
+ ... except pen.MissingComponentError:
+ ... pass
+ ... pprint({name: pen.value})
+ {'a': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'line', False, None), {}),
+ ('addPoint', ((1, 1), None, False, None), {}),
+ ('addPoint', ((2, 2), None, False, None), {}),
+ ('addPoint', ((3, 3), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'b': [('beginPath', (), {}),
+ ('addPoint', ((-1, 1), 'line', False, None), {}),
+ ('addPoint', ((0, 2), None, False, None), {}),
+ ('addPoint', ((1, 3), None, False, None), {}),
+ ('addPoint', ((2, 4), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'c': []}
+ {'d': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'line', False, None), {}),
+ ('addPoint', ((-1, 1), None, False, None), {}),
+ ('addPoint', ((-2, 2), None, False, None), {}),
+ ('addPoint', ((-3, 3), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ >>> for name, glyph in sorted(glyphSet.items()):
+ ... pen = DecomposingRecordingPointPen(
+ ... glyphSet, skipMissingComponents=True, reverseFlipped=True,
+ ... )
+ ... glyph.drawPoints(pen)
+ ... pprint({name: pen.value})
+ {'a': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'line', False, None), {}),
+ ('addPoint', ((1, 1), None, False, None), {}),
+ ('addPoint', ((2, 2), None, False, None), {}),
+ ('addPoint', ((3, 3), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'b': [('beginPath', (), {}),
+ ('addPoint', ((-1, 1), 'line', False, None), {}),
+ ('addPoint', ((0, 2), None, False, None), {}),
+ ('addPoint', ((1, 3), None, False, None), {}),
+ ('addPoint', ((2, 4), 'curve', False, None), {}),
+ ('endPath', (), {})]}
+ {'c': []}
+ {'d': [('beginPath', (), {}),
+ ('addPoint', ((0, 0), 'curve', False, None), {}),
+ ('addPoint', ((-3, 3), 'line', False, None), {}),
+ ('addPoint', ((-2, 2), None, False, None), {}),
+ ('addPoint', ((-1, 1), None, False, None), {}),
+ ('endPath', (), {})]}
+ """
+
+ # raises MissingComponentError(KeyError) if base glyph is not found in glyphSet
+ skipMissingComponents = False
+
+
def lerpRecordings(recording1, recording2, factor=0.5):
"""Linearly interpolate between two recordings. The recordings
must be decomposed, i.e. they must not contain any components.
diff --git a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
index 89427dc534..c5de81cad0 100644
--- a/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
+++ b/contrib/python/fonttools/fontTools/varLib/instancer/__init__.py
@@ -531,9 +531,13 @@ def changeTupleVariationsAxisLimits(variations, axisLimits):
def changeTupleVariationAxisLimit(var, axisTag, axisLimit):
assert isinstance(axisLimit, NormalizedAxisTripleAndDistances)
- # Skip when current axis is missing (i.e. doesn't participate),
+ # Skip when current axis is missing or peaks at 0 (i.e. doesn't participate)
lower, peak, upper = var.axes.get(axisTag, (-1, 0, 1))
if peak == 0:
+ # explicitly defined, no-op axes can be omitted
+ # https://github.com/fonttools/fonttools/issues/3453
+ if axisTag in var.axes:
+ del var.axes[axisTag]
return [var]
# Drop if the var 'tent' isn't well-formed
if not (lower <= peak <= upper) or (lower < 0 and upper > 0):
diff --git a/contrib/python/fonttools/ya.make b/contrib/python/fonttools/ya.make
index e5986f9d03..a6872287a9 100644
--- a/contrib/python/fonttools/ya.make
+++ b/contrib/python/fonttools/ya.make
@@ -2,7 +2,7 @@
PY3_LIBRARY()
-VERSION(4.49.0)
+VERSION(4.50.0)
LICENSE(MIT)