[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
(
"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, ""),
],

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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 = {}

Binary file not shown.

View File

@ -245,271 +245,42 @@
</Coverage>
<MultiVarStore Format="1">
<Format value="1"/>
<VarRegionList>
<!-- RegionAxisCount=17 -->
<SparseVarRegionList>
<!-- RegionCount=3 -->
<Region index="0">
<VarRegionAxis index="0">
<!-- SparseRegionCount=1 -->
<SparseVarRegionAxis index="0">
<AxisIndex value="0"/>
<StartCoord value="0.0"/>
<PeakCoord value="1.0"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
<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>
</SparseVarRegionAxis>
</Region>
<Region index="1">
<VarRegionAxis index="0">
<StartCoord value="0.0"/>
<PeakCoord value="0.0"/>
<EndCoord value="0.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
<!-- SparseRegionCount=1 -->
<SparseVarRegionAxis index="0">
<AxisIndex value="1"/>
<StartCoord value="0.0"/>
<PeakCoord value="1.0"/>
<EndCoord value="1.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>
</SparseVarRegionAxis>
</Region>
<Region index="2">
<VarRegionAxis index="0">
<!-- SparseRegionCount=2 -->
<SparseVarRegionAxis index="0">
<AxisIndex value="0"/>
<StartCoord value="0.0"/>
<PeakCoord value="1.0"/>
<EndCoord value="1.0"/>
</VarRegionAxis>
<VarRegionAxis index="1">
</SparseVarRegionAxis>
<SparseVarRegionAxis index="1">
<AxisIndex value="1"/>
<StartCoord value="0.0"/>
<PeakCoord value="1.0"/>
<EndCoord value="1.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>
</SparseVarRegionAxis>
</Region>
</VarRegionList>
</SparseVarRegionList>
<!-- MultiVarDataCount=1 -->
<MultiVarData index="0" Format="1">
<Format value="1"/>

Binary file not shown.