diff --git a/Lib/fontTools/ttLib/tables/TupleVariation.py b/Lib/fontTools/ttLib/tables/TupleVariation.py index 1b8e394fd..aaeb4ca21 100644 --- a/Lib/fontTools/ttLib/tables/TupleVariation.py +++ b/Lib/fontTools/ttLib/tables/TupleVariation.py @@ -530,41 +530,32 @@ class TupleVariation(object): if optimizedLength < unoptimizedLength: self.coordinates = varOpt.coordinates - def sumDeltas(self, variations, origCoords=None, endPts=None): - # to sum the gvar deltas we need to first interpolate any inferred deltas - if origCoords is not None: - self.calcInferredDeltas(origCoords, endPts) + def __iadd__(self, other): + if not isinstance(other, TupleVariation): + return NotImplemented deltas1 = self.coordinates - axes = self.axes length = len(deltas1) - deltaRange = range(length) deltaType = self.checkDeltaType() - for other in variations: - if other.axes != axes: - raise ValueError( - "cannot merge TupleVariations with different axes" - ) - if origCoords is not None: - other.calcInferredDeltas(origCoords, endPts) - deltas2 = other.coordinates - if len(deltas2) != length: - raise ValueError( - "cannot merge TupleVariations with different lengths" - ) - for i, d2 in zip(deltaRange, deltas2): - d1 = deltas1[i] - if d1 is not None and d2 is not None: - if deltaType == "gvar": - deltas1[i] = (d1[0] + d2[0], d1[1] + d2[1]) - else: - deltas1[i] = d1 + d2 + 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": + deltas1[i] = (d1[0] + d2[0], d1[1] + d2[1]) else: - if deltaType == "gvar": - raise ValueError( - "cannot merge gvar deltas with inferred points" - ) - if d1 is None and d2 is not None: - deltas1[i] = d2 + deltas1[i] = d1 + d2 + else: + if deltaType == "gvar": + raise ValueError( + "cannot sum gvar deltas with inferred points" + ) + if d1 is None and d2 is not None: + deltas1[i] = d2 + return self def decompileSharedTuples(axisTags, sharedTupleCount, data, offset): diff --git a/Lib/fontTools/varLib/instancer.py b/Lib/fontTools/varLib/instancer.py index c34e78dcf..ac12285b5 100644 --- a/Lib/fontTools/varLib/instancer.py +++ b/Lib/fontTools/varLib/instancer.py @@ -28,7 +28,7 @@ log = logging.getLogger("fontTools.varlib.instancer") def instantiateTupleVariationStore(variations, location, origCoords=None, endPts=None): - varGroups = collections.OrderedDict() + newVariations = collections.OrderedDict() for var in variations: # Compute the scalar support of the axes to be pinned at the desired location, # excluding any axes that we are not pinning. @@ -40,44 +40,28 @@ def instantiateTupleVariationStore(variations, location, origCoords=None, endPts # no influence, drop the TupleVariation continue + if origCoords is not None: + var.calcInferredDeltas(origCoords, endPts) + var.scaleDeltas(scalar) - # group TupleVariations by overlapping "tents" (can be empty if all the axes - # were instanced) + # merge TupleVariations with overlapping "tents" axes = tuple(var.axes.items()) - if axes in varGroups: - varGroups[axes].append(var) + if axes in newVariations: + newVariations[axes] += var else: - varGroups[axes] = [var] + newVariations[axes] = var - # TupleVariations in which all axes have been pinned are dropped from gvar/cvar, - # their deltas summed up, rounded and subsequently added to the default instance - emptyAxes = () - if emptyAxes in varGroups: - defaultVars = varGroups.pop(emptyAxes) - var = defaultVars.pop(0) - var.sumDeltas(defaultVars, origCoords, endPts) + for var in newVariations.values(): var.roundDeltas() - defaultDeltas = var.coordinates - else: - defaultDeltas = [] - # merge remaining TupleVariations having the same axes - newVariations = [] - for varGroup in varGroups.values(): - var = varGroup.pop(0) - if varGroup: - var.sumDeltas(varGroup, origCoords, endPts) - elif origCoords is not None and defaultDeltas: - # if the default instance coordinates will be modified, all the inferred - # deltas that still remains need to be calculated using the original - # coordinates (can later be re-optimized using the modified ones) - var.calcInferredDeltas(origCoords, endPts) - var.roundDeltas() - newVariations.append(var) - variations[:] = newVariations + # drop TupleVariation if all axes have been pinned (var.axes.items() is empty); + # its deltas will be added to the default instance's coordinates + defaultVar = newVariations.pop(tuple(), None) - return defaultDeltas + variations[:] = list(newVariations.values()) + + return defaultVar.coordinates if defaultVar is not None else [] def instantiateGvarGlyph(varfont, glyphname, location, optimize=True): diff --git a/Tests/ttLib/tables/TupleVariation_test.py b/Tests/ttLib/tables/TupleVariation_test.py index 5fa8f2b05..6910cbf0a 100644 --- a/Tests/ttLib/tables/TupleVariation_test.py +++ b/Tests/ttLib/tables/TupleVariation_test.py @@ -788,29 +788,23 @@ class TupleVariationTest(unittest.TestCase): var.optimize([(0, 0)]*129, list(range(129-4)), isComposite=True) self.assertEqual(var.coordinates, [(0, 0)] + [None]*128) - def test_sumDeltas_gvar(self): - coordinates = [ - (0, 0), (0, 100), (100, 100), (100, 0), - (0, 0), (100, 0), (0, 0), (0, 0), - ] - endPts = [3] - axes = {"wght": (0.0, 1.0, 1.0)} + def test_sum_deltas_gvar(self): var1 = TupleVariation( - axes, + {}, [ - (-20, 0), None, None, (20, 0), - None, None, None, None, + (-20, 0), (-20, 0), (20, 0), (20, 0), + (0, 0), (0, 0), (0, 0), (0, 0), ] ) var2 = TupleVariation( - axes, + {}, [ - (-10, 0), None, None, (10, 0), - None, (20, 0), None, None, + (-10, 0), (-10, 0), (10, 0), (10, 0), + (0, 0), (20, 0), (0, 0), (0, 0), ] ) - var1.sumDeltas([var2], coordinates, endPts) + var1 += var2 self.assertEqual( var1.coordinates, @@ -820,13 +814,14 @@ class TupleVariationTest(unittest.TestCase): ] ) - def test_sumDeltas_cvar(self): + def test_sum_deltas_cvar(self): axes = {"wght": (0.0, 1.0, 1.0)} var1 = TupleVariation(axes, [0, 1, None, None]) var2 = TupleVariation(axes, [None, 2, None, 3]) var3 = TupleVariation(axes, [None, None, None, 4]) - var1.sumDeltas([var2, var3]) + var1 += var2 + var1 += var3 self.assertEqual(var1.coordinates, [0, 3, None, 7])