diff --git a/Lib/fontTools/ttLib/tables/otData.py b/Lib/fontTools/ttLib/tables/otData.py index 9c9efc595..6e34945bf 100644 --- a/Lib/fontTools/ttLib/tables/otData.py +++ b/Lib/fontTools/ttLib/tables/otData.py @@ -3323,6 +3323,29 @@ otData = [ ], ), # MultiVariationStore + ( + "SparseVarRegionAxis", + [ + ("uint16", "AxisIndex", None, None, ""), + ("F2Dot14", "StartCoord", None, None, ""), + ("F2Dot14", "PeakCoord", None, None, ""), + ("F2Dot14", "EndCoord", None, None, ""), + ], + ), + ( + "SparseVarRegion", + [ + ("uint16", "SparseRegionCount", None, None, ""), + ("struct", "SparseVarRegionAxis", "SparseRegionCount", 0, ""), + ], + ), + ( + "SparseVarRegionList", + [ + ("uint16", "RegionCount", None, None, ""), + ("LOffsetTo(SparseVarRegion)", "Region", "RegionCount", 0, ""), + ], + ), ( "MultiVarData", [ @@ -3336,7 +3359,7 @@ otData = [ "MultiVarStore", [ ("uint16", "Format", None, None, "Set to 1."), - ("LOffset", "VarRegionList", None, None, ""), + ("LOffset", "SparseVarRegionList", None, None, ""), ("uint16", "MultiVarDataCount", None, None, ""), ("LOffset", "MultiVarData", "MultiVarDataCount", 0, ""), ], diff --git a/Lib/fontTools/varLib/builder.py b/Lib/fontTools/varLib/builder.py index f05802770..456c34c4d 100644 --- a/Lib/fontTools/varLib/builder.py +++ b/Lib/fontTools/varLib/builder.py @@ -10,6 +10,13 @@ def buildVarRegionAxis(axisSupport): return self +def buildSparseVarRegionAxis(axisIndex, axisSupport): + self = ot.SparseVarRegionAxis() + self.AxisIndex = axisIndex + self.StartCoord, self.PeakCoord, self.EndCoord = [float(v) for v in axisSupport] + return self + + def buildVarRegion(support, axisTags): assert all(tag in axisTags for tag in support.keys()), ( "Unknown axis tag found.", @@ -23,6 +30,24 @@ def buildVarRegion(support, axisTags): return self +def buildSparseVarRegion(support, axisTags): + assert all(tag in axisTags for tag in support.keys()), ( + "Unknown axis tag found.", + support, + axisTags, + ) + self = ot.SparseVarRegion() + self.SparseVarRegionAxis = [] + for i, tag in enumerate(axisTags): + if tag not in support: + continue + self.SparseVarRegionAxis.append( + buildSparseVarRegionAxis(i, support.get(tag, (0, 0, 0))) + ) + self.SparseRegionCount = len(self.SparseVarRegionAxis) + return self + + def buildVarRegionList(supports, axisTags): self = ot.VarRegionList() self.RegionAxisCount = len(axisTags) @@ -33,6 +58,16 @@ def buildVarRegionList(supports, axisTags): return self +def buildSparseVarRegionList(supports, axisTags): + self = ot.SparseVarRegionList() + self.RegionAxisCount = len(axisTags) + self.Region = [] + for support in supports: + self.Region.append(buildSparseVarRegion(support, axisTags)) + self.RegionCount = len(self.Region) + return self + + def _reorderItem(lst, mapping): return [lst[i] for i in mapping] @@ -147,7 +182,7 @@ def buildMultiVarData(varRegionIndices, items): def buildMultiVarStore(varRegionList, multiVarDataList): self = ot.MultiVarStore() self.Format = 1 - self.VarRegionList = varRegionList + self.SparseVarRegionList = varRegionList self.MultiVarData = list(multiVarDataList) self.MultiVarDataCount = len(self.MultiVarData) return self diff --git a/Lib/fontTools/varLib/instancer/__init__.py b/Lib/fontTools/varLib/instancer/__init__.py index 69977d257..b3e27bd2c 100644 --- a/Lib/fontTools/varLib/instancer/__init__.py +++ b/Lib/fontTools/varLib/instancer/__init__.py @@ -469,7 +469,9 @@ class OverlapMode(IntEnum): def instantiateVARC(varfont, axisLimits): log.info("Instantiating VARC tables") - # TODO(behdad) My confidence in this function is rather low + # TODO(behdad) My confidence in this function is rather low; + # It needs more testing. Specially with partial-instancing, + # I don't think it currently works. varc = varfont["VARC"].table if varc.VarCompositeGlyphs: @@ -495,29 +497,28 @@ def instantiateVARC(varfont, axisLimits): fvar = varfont["fvar"] location = axisLimits.pinnedLocation() - for region in store.VarRegionList.Region: - assert len(region.VarRegionAxis) == len(fvar.axes) + for region in store.SparseVarRegionList.Region: newRegionAxis = [] - for regionTriple, fvarAxis in zip(region.VarRegionAxis, fvar.axes): - tag = fvarAxis.axisTag + for regionRecord in region.SparseVarRegionAxis: + tag = fvar.axes[regionRecord.AxisIndex].axisTag if tag in location: continue if tag in axisLimits: limits = axisLimits[tag] triple = ( - regionTriple.StartCoord, - regionTriple.PeakCoord, - regionTriple.EndCoord, + regionRecord.StartCoord, + regionRecord.PeakCoord, + regionRecord.EndCoord, ) triple = tuple( limits.renormalizeValue(v, extrapolate=False) for v in triple ) ( - regionTriple.StartCoord, - regionTriple.PeakCoord, - regionTriple.EndCoord, + regionRecord.StartCoord, + regionRecord.PeakCoord, + regionRecord.EndCoord, ) = triple - newRegionAxis.append(regionTriple) + newRegionAxis.append(regionRecord) region.VarRegionAxis = newRegionAxis region.VarRegionAxisCount = len(newRegionAxis) diff --git a/Lib/fontTools/varLib/multiVarStore.py b/Lib/fontTools/varLib/multiVarStore.py index 3d7ba71ae..6c755118b 100644 --- a/Lib/fontTools/varLib/multiVarStore.py +++ b/Lib/fontTools/varLib/multiVarStore.py @@ -6,7 +6,8 @@ from fontTools.varLib.models import supportScalar import fontTools.varLib.varStore # For monkey-patching from fontTools.varLib.builder import ( buildVarRegionList, - buildVarRegion, + buildSparseVarRegionList, + buildSparseVarRegion, buildMultiVarStore, buildMultiVarData, ) @@ -28,7 +29,7 @@ class OnlineMultiVarStoreBuilder(object): def __init__(self, axisTags): self._axisTags = axisTags self._regionMap = {} - self._regionList = buildVarRegionList([], axisTags) + self._regionList = buildSparseVarRegionList([], axisTags) self._store = buildMultiVarStore(self._regionList, []) self._data = None self._model = None @@ -64,7 +65,7 @@ class OnlineMultiVarStoreBuilder(object): key = _getLocationKey(region) idx = regionMap.get(key) if idx is None: - varRegion = buildVarRegion(region, self._axisTags) + varRegion = buildSparseVarRegion(region, self._axisTags) idx = regionMap[key] = len(regionList.Region) regionList.Region.append(varRegion) regionIndices.append(idx) @@ -133,6 +134,16 @@ def MultiVarData_addItem(self, deltas, *, round=round): ot.MultiVarData.addItem = MultiVarData_addItem +def SparseVarRegion_get_support(self, fvar_axes): + return { + fvar_axes[reg.AxisIndex].axisTag: (reg.StartCoord, reg.PeakCoord, reg.EndCoord) + for reg in self.SparseVarRegionAxis + } + + +ot.SparseVarRegion.get_support = SparseVarRegion_get_support + + def MultiVarStore___bool__(self): return bool(self.MultiVarData) @@ -145,7 +156,9 @@ class MultiVarStoreInstancer(object): self.fvar_axes = fvar_axes assert multivarstore is None or multivarstore.Format == 1 self._varData = multivarstore.MultiVarData if multivarstore else [] - self._regions = multivarstore.VarRegionList.Region if multivarstore else [] + self._regions = ( + multivarstore.SparseVarRegionList.Region if multivarstore else [] + ) self.setLocation(location) def setLocation(self, location): @@ -195,8 +208,10 @@ def MultiVarStore_subset_varidxes(self, varIdxes): return ot.VarStore.subset_varidxes(self, varIdxes, VarData="MultiVarData") -def MultiVarStore_prune_regions(self, *, VarData="VarData"): - return ot.VarStore.prune_regions(self, VarData="MultiVarData") +def MultiVarStore_prune_regions(self): + return ot.VarStore.prune_regions( + self, VarData="MultiVarData", VarRegionList="SparseVarRegionList" + ) ot.MultiVarStore.prune_regions = MultiVarStore_prune_regions @@ -207,7 +222,7 @@ def MultiVarStore_get_supports(self, major, fvarAxes): supports = [] varData = self.MultiVarData[major] for regionIdx in varData.VarRegionIndex: - region = self.VarRegionList.Region[regionIdx] + region = self.SparseVarRegionList.Region[regionIdx] support = region.get_support(fvarAxes) supports.append(support) return supports diff --git a/Lib/fontTools/varLib/varStore.py b/Lib/fontTools/varLib/varStore.py index ecfc02fc7..f54fad2db 100644 --- a/Lib/fontTools/varLib/varStore.py +++ b/Lib/fontTools/varLib/varStore.py @@ -305,7 +305,7 @@ def VarStore_subset_varidxes( setattr(self, VarData, newVarData) setattr(self, VarData + "Count", len(newVarData)) - self.prune_regions(VarData=VarData) + self.prune_regions() return varDataMap @@ -313,7 +313,7 @@ def VarStore_subset_varidxes( ot.VarStore.subset_varidxes = VarStore_subset_varidxes -def VarStore_prune_regions(self, *, VarData="VarData"): +def VarStore_prune_regions(self, *, VarData="VarData", VarRegionList="VarRegionList"): """Remove unused VarRegions.""" # # Subset VarRegionList @@ -324,7 +324,7 @@ def VarStore_prune_regions(self, *, VarData="VarData"): for data in getattr(self, VarData): usedRegions.update(data.VarRegionIndex) # Subset. - regionList = self.VarRegionList + regionList = getattr(self, VarRegionList) regions = regionList.Region newRegions = [] regionMap = {} diff --git a/Tests/ttLib/data/varc-6868.ttf b/Tests/ttLib/data/varc-6868.ttf index 66cf83e30..71d94e042 100644 Binary files a/Tests/ttLib/data/varc-6868.ttf and b/Tests/ttLib/data/varc-6868.ttf differ diff --git a/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx b/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx index dd9cc2f4b..da7980037 100644 --- a/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx +++ b/Tests/ttLib/data/varc-ac00-ac01-500upem.ttx @@ -245,271 +245,42 @@ - - + - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - - - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + + - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + diff --git a/Tests/ttLib/data/varc-ac00-ac01.ttf b/Tests/ttLib/data/varc-ac00-ac01.ttf index a8cbf6f74..cfe10a044 100644 Binary files a/Tests/ttLib/data/varc-ac00-ac01.ttf and b/Tests/ttLib/data/varc-ac00-ac01.ttf differ