[VARC] Use sparse-regions in MultiVarStore

Might revert as the savings are small.
https://github.com/harfbuzz/boring-expansion-spec/issues/103#issuecomment-1861531669
This commit is contained in:
Behdad Esfahbod 2023-12-18 13:15:38 -07:00
parent a958c68d79
commit c91984ef77
8 changed files with 115 additions and 270 deletions

View File

@ -3323,6 +3323,29 @@ otData = [
], ],
), ),
# MultiVariationStore # 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", "MultiVarData",
[ [
@ -3336,7 +3359,7 @@ otData = [
"MultiVarStore", "MultiVarStore",
[ [
("uint16", "Format", None, None, "Set to 1."), ("uint16", "Format", None, None, "Set to 1."),
("LOffset", "VarRegionList", None, None, ""), ("LOffset", "SparseVarRegionList", None, None, ""),
("uint16", "MultiVarDataCount", None, None, ""), ("uint16", "MultiVarDataCount", None, None, ""),
("LOffset", "MultiVarData", "MultiVarDataCount", 0, ""), ("LOffset", "MultiVarData", "MultiVarDataCount", 0, ""),
], ],

View File

@ -10,6 +10,13 @@ def buildVarRegionAxis(axisSupport):
return self 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): def buildVarRegion(support, axisTags):
assert all(tag in axisTags for tag in support.keys()), ( assert all(tag in axisTags for tag in support.keys()), (
"Unknown axis tag found.", "Unknown axis tag found.",
@ -23,6 +30,24 @@ def buildVarRegion(support, axisTags):
return self 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): def buildVarRegionList(supports, axisTags):
self = ot.VarRegionList() self = ot.VarRegionList()
self.RegionAxisCount = len(axisTags) self.RegionAxisCount = len(axisTags)
@ -33,6 +58,16 @@ def buildVarRegionList(supports, axisTags):
return self 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): def _reorderItem(lst, mapping):
return [lst[i] for i in mapping] return [lst[i] for i in mapping]
@ -147,7 +182,7 @@ def buildMultiVarData(varRegionIndices, items):
def buildMultiVarStore(varRegionList, multiVarDataList): def buildMultiVarStore(varRegionList, multiVarDataList):
self = ot.MultiVarStore() self = ot.MultiVarStore()
self.Format = 1 self.Format = 1
self.VarRegionList = varRegionList self.SparseVarRegionList = varRegionList
self.MultiVarData = list(multiVarDataList) self.MultiVarData = list(multiVarDataList)
self.MultiVarDataCount = len(self.MultiVarData) self.MultiVarDataCount = len(self.MultiVarData)
return self return self

View File

@ -469,7 +469,9 @@ class OverlapMode(IntEnum):
def instantiateVARC(varfont, axisLimits): def instantiateVARC(varfont, axisLimits):
log.info("Instantiating VARC tables") 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 varc = varfont["VARC"].table
if varc.VarCompositeGlyphs: if varc.VarCompositeGlyphs:
@ -495,29 +497,28 @@ def instantiateVARC(varfont, axisLimits):
fvar = varfont["fvar"] fvar = varfont["fvar"]
location = axisLimits.pinnedLocation() location = axisLimits.pinnedLocation()
for region in store.VarRegionList.Region: for region in store.SparseVarRegionList.Region:
assert len(region.VarRegionAxis) == len(fvar.axes)
newRegionAxis = [] newRegionAxis = []
for regionTriple, fvarAxis in zip(region.VarRegionAxis, fvar.axes): for regionRecord in region.SparseVarRegionAxis:
tag = fvarAxis.axisTag tag = fvar.axes[regionRecord.AxisIndex].axisTag
if tag in location: if tag in location:
continue continue
if tag in axisLimits: if tag in axisLimits:
limits = axisLimits[tag] limits = axisLimits[tag]
triple = ( triple = (
regionTriple.StartCoord, regionRecord.StartCoord,
regionTriple.PeakCoord, regionRecord.PeakCoord,
regionTriple.EndCoord, regionRecord.EndCoord,
) )
triple = tuple( triple = tuple(
limits.renormalizeValue(v, extrapolate=False) for v in triple limits.renormalizeValue(v, extrapolate=False) for v in triple
) )
( (
regionTriple.StartCoord, regionRecord.StartCoord,
regionTriple.PeakCoord, regionRecord.PeakCoord,
regionTriple.EndCoord, regionRecord.EndCoord,
) = triple ) = triple
newRegionAxis.append(regionTriple) newRegionAxis.append(regionRecord)
region.VarRegionAxis = newRegionAxis region.VarRegionAxis = newRegionAxis
region.VarRegionAxisCount = len(newRegionAxis) region.VarRegionAxisCount = len(newRegionAxis)

View File

@ -6,7 +6,8 @@ from fontTools.varLib.models import supportScalar
import fontTools.varLib.varStore # For monkey-patching import fontTools.varLib.varStore # For monkey-patching
from fontTools.varLib.builder import ( from fontTools.varLib.builder import (
buildVarRegionList, buildVarRegionList,
buildVarRegion, buildSparseVarRegionList,
buildSparseVarRegion,
buildMultiVarStore, buildMultiVarStore,
buildMultiVarData, buildMultiVarData,
) )
@ -28,7 +29,7 @@ class OnlineMultiVarStoreBuilder(object):
def __init__(self, axisTags): def __init__(self, axisTags):
self._axisTags = axisTags self._axisTags = axisTags
self._regionMap = {} self._regionMap = {}
self._regionList = buildVarRegionList([], axisTags) self._regionList = buildSparseVarRegionList([], axisTags)
self._store = buildMultiVarStore(self._regionList, []) self._store = buildMultiVarStore(self._regionList, [])
self._data = None self._data = None
self._model = None self._model = None
@ -64,7 +65,7 @@ class OnlineMultiVarStoreBuilder(object):
key = _getLocationKey(region) key = _getLocationKey(region)
idx = regionMap.get(key) idx = regionMap.get(key)
if idx is None: if idx is None:
varRegion = buildVarRegion(region, self._axisTags) varRegion = buildSparseVarRegion(region, self._axisTags)
idx = regionMap[key] = len(regionList.Region) idx = regionMap[key] = len(regionList.Region)
regionList.Region.append(varRegion) regionList.Region.append(varRegion)
regionIndices.append(idx) regionIndices.append(idx)
@ -133,6 +134,16 @@ def MultiVarData_addItem(self, deltas, *, round=round):
ot.MultiVarData.addItem = MultiVarData_addItem 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): def MultiVarStore___bool__(self):
return bool(self.MultiVarData) return bool(self.MultiVarData)
@ -145,7 +156,9 @@ class MultiVarStoreInstancer(object):
self.fvar_axes = fvar_axes self.fvar_axes = fvar_axes
assert multivarstore is None or multivarstore.Format == 1 assert multivarstore is None or multivarstore.Format == 1
self._varData = multivarstore.MultiVarData if multivarstore else [] 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) self.setLocation(location)
def setLocation(self, location): def setLocation(self, location):
@ -195,8 +208,10 @@ def MultiVarStore_subset_varidxes(self, varIdxes):
return ot.VarStore.subset_varidxes(self, varIdxes, VarData="MultiVarData") return ot.VarStore.subset_varidxes(self, varIdxes, VarData="MultiVarData")
def MultiVarStore_prune_regions(self, *, VarData="VarData"): def MultiVarStore_prune_regions(self):
return ot.VarStore.prune_regions(self, VarData="MultiVarData") return ot.VarStore.prune_regions(
self, VarData="MultiVarData", VarRegionList="SparseVarRegionList"
)
ot.MultiVarStore.prune_regions = MultiVarStore_prune_regions ot.MultiVarStore.prune_regions = MultiVarStore_prune_regions
@ -207,7 +222,7 @@ def MultiVarStore_get_supports(self, major, fvarAxes):
supports = [] supports = []
varData = self.MultiVarData[major] varData = self.MultiVarData[major]
for regionIdx in varData.VarRegionIndex: for regionIdx in varData.VarRegionIndex:
region = self.VarRegionList.Region[regionIdx] region = self.SparseVarRegionList.Region[regionIdx]
support = region.get_support(fvarAxes) support = region.get_support(fvarAxes)
supports.append(support) supports.append(support)
return supports return supports

View File

@ -305,7 +305,7 @@ def VarStore_subset_varidxes(
setattr(self, VarData, newVarData) setattr(self, VarData, newVarData)
setattr(self, VarData + "Count", len(newVarData)) setattr(self, VarData + "Count", len(newVarData))
self.prune_regions(VarData=VarData) self.prune_regions()
return varDataMap return varDataMap
@ -313,7 +313,7 @@ def VarStore_subset_varidxes(
ot.VarStore.subset_varidxes = 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.""" """Remove unused VarRegions."""
# #
# Subset VarRegionList # Subset VarRegionList
@ -324,7 +324,7 @@ def VarStore_prune_regions(self, *, VarData="VarData"):
for data in getattr(self, VarData): for data in getattr(self, VarData):
usedRegions.update(data.VarRegionIndex) usedRegions.update(data.VarRegionIndex)
# Subset. # Subset.
regionList = self.VarRegionList regionList = getattr(self, VarRegionList)
regions = regionList.Region regions = regionList.Region
newRegions = [] newRegions = []
regionMap = {} regionMap = {}

Binary file not shown.

View File

@ -245,271 +245,42 @@
</Coverage> </Coverage>
<MultiVarStore Format="1"> <MultiVarStore Format="1">
<Format value="1"/> <Format value="1"/>
<VarRegionList> <SparseVarRegionList>
<!-- RegionAxisCount=17 -->
<!-- RegionCount=3 --> <!-- RegionCount=3 -->
<Region index="0"> <Region index="0">
<VarRegionAxis index="0"> <!-- SparseRegionCount=1 -->
<SparseVarRegionAxis index="0">
<AxisIndex value="0"/>
<StartCoord value="0.0"/> <StartCoord value="0.0"/>
<PeakCoord value="1.0"/> <PeakCoord value="1.0"/>
<EndCoord value="1.0"/> <EndCoord value="1.0"/>
</VarRegionAxis> </SparseVarRegionAxis>
<VarRegionAxis index="1">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="2">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="3">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="4">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="5">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="6">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="7">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="8">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="9">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="10">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="11">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="12">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="13">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="14">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="15">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="16">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
</Region> </Region>
<Region index="1"> <Region index="1">
<VarRegionAxis index="0"> <!-- SparseRegionCount=1 -->
<StartCoord value="0.0"/> <SparseVarRegionAxis index="0">
<PeakCoord value="0.0"/> <AxisIndex value="1"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
<StartCoord value="0.0"/> <StartCoord value="0.0"/>
<PeakCoord value="1.0"/> <PeakCoord value="1.0"/>
<EndCoord value="1.0"/> <EndCoord value="1.0"/>
</VarRegionAxis> </SparseVarRegionAxis>
<VarRegionAxis index="2">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="3">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="4">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="5">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="6">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="7">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="8">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="9">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="10">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="11">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="12">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="13">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="14">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="15">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="16">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
</Region> </Region>
<Region index="2"> <Region index="2">
<VarRegionAxis index="0"> <!-- SparseRegionCount=2 -->
<SparseVarRegionAxis index="0">
<AxisIndex value="0"/>
<StartCoord value="0.0"/> <StartCoord value="0.0"/>
<PeakCoord value="1.0"/> <PeakCoord value="1.0"/>
<EndCoord value="1.0"/> <EndCoord value="1.0"/>
</VarRegionAxis> </SparseVarRegionAxis>
<VarRegionAxis index="1"> <SparseVarRegionAxis index="1">
<AxisIndex value="1"/>
<StartCoord value="0.0"/> <StartCoord value="0.0"/>
<PeakCoord value="1.0"/> <PeakCoord value="1.0"/>
<EndCoord value="1.0"/> <EndCoord value="1.0"/>
</VarRegionAxis> </SparseVarRegionAxis>
<VarRegionAxis index="2">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="3">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="4">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="5">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="6">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="7">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="8">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="9">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="10">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="11">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="12">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="13">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="14">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="15">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="16">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
</Region> </Region>
</VarRegionList> </SparseVarRegionList>
<!-- MultiVarDataCount=1 --> <!-- MultiVarDataCount=1 -->
<MultiVarData index="0" Format="1"> <MultiVarData index="0" Format="1">
<Format value="1"/> <Format value="1"/>

Binary file not shown.