From 5d5c16207be1a5be06bdd192b13ddd1f4402e12e Mon Sep 17 00:00:00 2001 From: Simon Cozens Date: Mon, 5 Sep 2022 14:27:08 +0100 Subject: [PATCH] Speed up varscalar with caching (#2798) * Speed up varscalar with caching * Don't use cached_property * Make model pool a class attribute * Don't catch things on the values side * Remove unused import --- Lib/fontTools/feaLib/builder.py | 1 + Lib/fontTools/feaLib/variableScalar.py | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/Lib/fontTools/feaLib/builder.py b/Lib/fontTools/feaLib/builder.py index 0a9917610..3e36e5ebe 100644 --- a/Lib/fontTools/feaLib/builder.py +++ b/Lib/fontTools/feaLib/builder.py @@ -770,6 +770,7 @@ class Builder(object): gdef.remap_device_varidxes(varidx_map) if 'GPOS' in self.font: self.font['GPOS'].table.remap_device_varidxes(varidx_map) + VariableScalar.clear_cache() if any( ( gdef.GlyphClassDef, diff --git a/Lib/fontTools/feaLib/variableScalar.py b/Lib/fontTools/feaLib/variableScalar.py index a286568ee..4b63d101b 100644 --- a/Lib/fontTools/feaLib/variableScalar.py +++ b/Lib/fontTools/feaLib/variableScalar.py @@ -8,6 +8,15 @@ def Location(loc): class VariableScalar: """A scalar with different values at different points in the designspace.""" + # We will often use exactly the same locations (i.e. the font's + # masters) for a large number of variable scalars. Instead of + # creating a model for each, let's share the models. + model_pool = {} + + @classmethod + def clear_cache(cls): + cls.model_pool = {} + def __init__(self, location_value={}): self.values = {} self.axes = {} @@ -84,7 +93,12 @@ class VariableScalar: @property def model(self): locations = [dict(self._normalized_location(k)) for k in self.values.keys()] - return VariationModel(locations) + key = tuple([tuple(x.items()) for x in locations]) + if key in self.model_pool: + return self.model_pool[key] + m = VariationModel(locations) + self.model_pool[key] = m + return m def get_deltas_and_supports(self): values = list(self.values.values())