lerpFontVariations function

List<FontVariation>? lerpFontVariations(
  1. List<FontVariation>? a,
  2. List<FontVariation>? b,
  3. double t
)

Interpolate between two lists of FontVariation objects.

Variations are paired by axis, and interpolated using FontVariation.lerp.

Entries that are only present in one list are animated using a step-function at t=0.5 that enables or disables the variation. This can be jarring and largely defeats the point of animating font variations. For best results, specify the same axes in both lists, and for best performance, specify them in the same order.

Performance details

This algorithm is O(N), but the constant factor varies based on the input, and that is probably more important (because typically N is going to be tiny, like 1 or 2; at the time of writing, there are only about five defined axes that fonts typically use!).

It is fastest when the lists contain the same axes (FontVariation.axis) in the same order. The result is again in the same order, and no attempt is made to detect or remove duplicates in this process. This is, by far, the recommended way to use this algorithm.

When the order of items in the two input lists vary, the constant factor increases substantially, as it involves creating two maps and a set, inserting every variation in both lists into the maps and the set, and then iterating over them to recreate the list.

In this case, the resulting order is arbitrary. Duplicates are dropped; in each list, the last FontVariation for any particular axis is the one used to compute the value for that axis. Values that only appear on one side are interpolated using FontVariation.lerp against a null value, and resulting null values are omitted from the resulting list.

When the lists begin with matching pairs of axes, the fast algorithm is used up to the point where the lists diverge, and the more expensive algorithm is used on the remaining entries.

See also:

Implementation

List<FontVariation>? lerpFontVariations(List<FontVariation>? a, List<FontVariation>? b, double t) {
  if (t == 0.0) {
    return a;
  }
  if (t == 1.0) {
    return b;
  }
  if (a == null || a.isEmpty || b == null || b.isEmpty) {
    // If one side is empty, that means anything on the other
    // side will use the null-to-something lerp, which is to
    // say, a step function at t=0.5.
    return t < 0.5 ? a : b;
  }
  assert(a.isNotEmpty && b.isNotEmpty);
  final List<FontVariation> result = <FontVariation>[];
  // First, try the efficient O(N) solution in the event that
  // the lists are compatible.
  int index = 0;
  final int minLength = a.length < b.length ? a.length : b.length;
  for (; index < minLength; index += 1) {
    if (a[index].axis != b[index].axis) {
      // The lists aren't compatible.
      break;
    }
    result.add(FontVariation.lerp(a[index], b[index], t)!);
  }
  final int maxLength = a.length > b.length ? a.length : b.length;
  if (index < maxLength) {
    // If we get here, we have found some case where we cannot
    // use the efficient approach.
    final Set<String> axes = HashSet<String>();
    final Map<String, FontVariation> aVariations = HashMap<String, FontVariation>();
    for (int indexA = index; indexA < a.length; indexA += 1) {
      aVariations[a[indexA].axis] = a[indexA];
      axes.add(a[indexA].axis);
    }
    final Map<String, FontVariation> bVariations = HashMap<String, FontVariation>();
    for (int indexB = index; indexB < b.length; indexB += 1) {
      bVariations[b[indexB].axis] = b[indexB];
      axes.add(b[indexB].axis);
    }
    for (final String axis in axes) {
      final FontVariation? variation = FontVariation.lerp(aVariations[axis], bVariations[axis], t);
      if (variation != null) {
        result.add(variation);
      }
    }
  }
  return result;
}