diff --git a/Lib/fontTools/ttLib/tables/TupleVariation.py b/Lib/fontTools/ttLib/tables/TupleVariation.py index aaeb4ca21..f77cf1780 100644 --- a/Lib/fontTools/ttLib/tables/TupleVariation.py +++ b/Lib/fontTools/ttLib/tables/TupleVariation.py @@ -30,6 +30,7 @@ log = logging.getLogger(__name__) class TupleVariation(object): + def __init__(self, axes, coordinates): self.axes = axes.copy() self.coordinates = coordinates[:] @@ -443,8 +444,10 @@ class TupleVariation(object): size += axisCount * 4 return size - def checkDeltaType(self): - # check if deltas are (x, y) as in gvar, or single values as in cvar + def getDeltaType(self): + """ Check if deltas are (x, y) as in gvar, or single values as in cvar. + Returns a string ("gvar" or "cvar"), or None if empty. + """ firstDelta = next((c for c in self.coordinates if c is not None), None) if firstDelta is None: return # empty or has no impact @@ -458,7 +461,7 @@ class TupleVariation(object): def scaleDeltas(self, scalar): if scalar == 1.0: return # no change - deltaType = self.checkDeltaType() + deltaType = self.getDeltaType() if deltaType == "gvar": if scalar == 0: self.coordinates = [(0, 0)] * len(self.coordinates) @@ -477,7 +480,7 @@ class TupleVariation(object): ] def roundDeltas(self): - deltaType = self.checkDeltaType() + deltaType = self.getDeltaType() if deltaType == "gvar": self.coordinates = [ (otRound(d[0]), otRound(d[1])) if d is not None else None @@ -491,7 +494,7 @@ class TupleVariation(object): def calcInferredDeltas(self, origCoords, endPts): from fontTools.varLib.iup import iup_delta - if self.checkDeltaType() == "cvar": + if self.getDeltaType() == "cvar": raise TypeError( "Only 'gvar' TupleVariation can have inferred deltas" ) @@ -535,26 +538,29 @@ class TupleVariation(object): return NotImplemented deltas1 = self.coordinates length = len(deltas1) - deltaType = self.checkDeltaType() + deltaType = self.getDeltaType() deltas2 = other.coordinates if len(deltas2) != length: raise ValueError( "cannot sum TupleVariation deltas with different lengths" ) - for i, d2 in zip(range(length), deltas2): - d1 = deltas1[i] - if d1 is not None and d2 is not None: - if deltaType == "gvar": + if deltaType == "gvar": + for i, d2 in zip(range(length), deltas2): + d1 = deltas1[i] + try: deltas1[i] = (d1[0] + d2[0], d1[1] + d2[1]) - else: - deltas1[i] = d1 + d2 - else: - if deltaType == "gvar": + except TypeError: raise ValueError( "cannot sum gvar deltas with inferred points" ) - if d1 is None and d2 is not None: + else: + for i, d2 in zip(range(length), deltas2): + d1 = deltas1[i] + if d1 is not None and d2 is not None: + deltas1[i] = d1 + d2 + elif d1 is None and d2 is not None: deltas1[i] = d2 + # elif d2 is None do nothing return self diff --git a/Lib/fontTools/varLib/instancer.py b/Lib/fontTools/varLib/instancer.py index ac12285b5..344b37767 100644 --- a/Lib/fontTools/varLib/instancer.py +++ b/Lib/fontTools/varLib/instancer.py @@ -40,6 +40,7 @@ def instantiateTupleVariationStore(variations, location, origCoords=None, endPts # no influence, drop the TupleVariation continue + # compute inferred deltas only for gvar ('origCoords' is None for cvar) if origCoords is not None: var.calcInferredDeltas(origCoords, endPts) diff --git a/Tests/ttLib/tables/TupleVariation_test.py b/Tests/ttLib/tables/TupleVariation_test.py index 6910cbf0a..5a29f18f8 100644 --- a/Tests/ttLib/tables/TupleVariation_test.py +++ b/Tests/ttLib/tables/TupleVariation_test.py @@ -69,6 +69,13 @@ SKIA_GVAR_I_DATA = deHexStr( class TupleVariationTest(unittest.TestCase): + def __init__(self, methodName): + unittest.TestCase.__init__(self, methodName) + # Python 3 renamed assertRaisesRegexp to assertRaisesRegex, + # and fires deprecation warnings if a program uses the old name. + if not hasattr(self, "assertRaisesRegex"): + self.assertRaisesRegex = self.assertRaisesRegexp + def test_equal(self): var1 = TupleVariation({"wght":(0.0, 1.0, 1.0)}, [(0,0), (9,8), (7,6)]) var2 = TupleVariation({"wght":(0.0, 1.0, 1.0)}, [(0,0), (9,8), (7,6)]) @@ -681,24 +688,24 @@ class TupleVariationTest(unittest.TestCase): content = writer.file.getvalue().decode("utf-8") return [line.strip() for line in content.splitlines()][1:] - def test_checkDeltaType(self): + def test_getDeltaType(self): empty = TupleVariation({}, []) - self.assertIsNone(empty.checkDeltaType()) + self.assertIsNone(empty.getDeltaType()) empty = TupleVariation({}, [None]) - self.assertIsNone(empty.checkDeltaType()) + self.assertIsNone(empty.getDeltaType()) gvarTuple = TupleVariation({}, [None, (0, 0)]) - self.assertEqual(gvarTuple.checkDeltaType(), "gvar") + self.assertEqual(gvarTuple.getDeltaType(), "gvar") cvarTuple = TupleVariation({}, [None, 0]) - self.assertEqual(cvarTuple.checkDeltaType(), "cvar") + self.assertEqual(cvarTuple.getDeltaType(), "cvar") cvarTuple.coordinates[1] *= 1.0 - self.assertEqual(cvarTuple.checkDeltaType(), "cvar") + self.assertEqual(cvarTuple.getDeltaType(), "cvar") with self.assertRaises(TypeError): - TupleVariation({}, [None, "a"]).checkDeltaType() + TupleVariation({}, [None, "a"]).getDeltaType() def test_scaleDeltas_cvar(self): var = TupleVariation({}, [100, None]) @@ -706,8 +713,9 @@ class TupleVariationTest(unittest.TestCase): var.scaleDeltas(1.0) self.assertEqual(var.coordinates, [100, None]) - var.scaleDeltas(0.5) - self.assertEqual(var.coordinates, [50.0, None]) + var.scaleDeltas(0.333) + self.assertAlmostEqual(var.coordinates[0], 33.3) + self.assertIsNone(var.coordinates[1]) var.scaleDeltas(0.0) self.assertEqual(var.coordinates, [0, 0]) @@ -718,8 +726,10 @@ class TupleVariationTest(unittest.TestCase): var.scaleDeltas(1.0) self.assertEqual(var.coordinates, [(100, 200), None]) - var.scaleDeltas(0.5) - self.assertEqual(var.coordinates, [(50.0, 100.0), None]) + var.scaleDeltas(0.333) + self.assertAlmostEqual(var.coordinates[0][0], 33.3) + self.assertAlmostEqual(var.coordinates[0][1], 66.6) + self.assertIsNone(var.coordinates[1]) var.scaleDeltas(0.0) self.assertEqual(var.coordinates, [(0, 0), (0, 0)]) @@ -814,6 +824,20 @@ class TupleVariationTest(unittest.TestCase): ] ) + def test_sum_deltas_gvar_invalid_length(self): + var1 = TupleVariation({}, [(1, 2)]) + var2 = TupleVariation({}, [(1, 2), (3, 4)]) + + with self.assertRaisesRegex(ValueError, "deltas with different lengths"): + var1 += var2 + + def test_sum_deltas_gvar_with_inferred_points(self): + var1 = TupleVariation({}, [(1, 2), None]) + var2 = TupleVariation({}, [(2, 3), None]) + + with self.assertRaisesRegex(ValueError, "deltas with inferred points"): + var1 += var2 + def test_sum_deltas_cvar(self): axes = {"wght": (0.0, 1.0, 1.0)} var1 = TupleVariation(axes, [0, 1, None, None])