COLRVariationMerger: implement reuse of VarIndexBase between tables with same varIdxes
When multiple variable tables refer to the same delta-sets they can now share the same VarIndexBase so the resulting DeltaSetIndexMap is a bit smaller. For simplicity, we only reuse VarIndexBase when variable tables fully share (ie. same, and same number of) varIdxes; potentially we could reuse subsets of varIdxes (e.g. a VarColoStop.Alpha has a +0.5 delta, and later on elsewhere a PaintVarSolid.Alpha has a similar +0.5 delta; the latter could have a VarIndexBase that reuses an existing DeltaSetIndexMap entry for the former), but for now this I think is good enough.
This commit is contained in:
parent
99a754a48e
commit
c397764720
@ -723,7 +723,6 @@ def _add_COLR(font, model, master_fonts, axisTags, colr_layer_reuse=True):
|
|||||||
mapping = store.optimize()
|
mapping = store.optimize()
|
||||||
colr.VarStore = store
|
colr.VarStore = store
|
||||||
varIdxes = [mapping[v] for v in merger.varIdxes]
|
varIdxes = [mapping[v] for v in merger.varIdxes]
|
||||||
# TODO: Optimize reusable runs of delta-set indices from multiple paints
|
|
||||||
colr.VarIndexMap = builder.buildDeltaSetIndexMap(varIdxes)
|
colr.VarIndexMap = builder.buildDeltaSetIndexMap(varIdxes)
|
||||||
|
|
||||||
# rebuild LayerList to optimize PaintColrLayers layer reuse
|
# rebuild LayerList to optimize PaintColrLayers layer reuse
|
||||||
|
@ -4,6 +4,7 @@ Merge OpenType Layout tables (GDEF / GPOS / GSUB).
|
|||||||
import os
|
import os
|
||||||
import copy
|
import copy
|
||||||
import enum
|
import enum
|
||||||
|
import itertools
|
||||||
from operator import ior
|
from operator import ior
|
||||||
import logging
|
import logging
|
||||||
from fontTools.misc import classifyTools
|
from fontTools.misc import classifyTools
|
||||||
@ -1122,7 +1123,11 @@ class COLRVariationMerger(VariationMerger):
|
|||||||
|
|
||||||
def __init__(self, model, axisTags, font):
|
def __init__(self, model, axisTags, font):
|
||||||
VariationMerger.__init__(self, model, axisTags, font)
|
VariationMerger.__init__(self, model, axisTags, font)
|
||||||
self.varIdxes = []
|
# maps {tuple(varIdxes): VarIndexBase} to facilitate reuse of VarIndexBase
|
||||||
|
# between variable tables with same varIdxes.
|
||||||
|
self.varIndexCache = {}
|
||||||
|
# total number of varIdxes (i.e. sum(len(vs) for vs in self.varIndexCache))
|
||||||
|
self.varIndexCount = 0
|
||||||
# set of id()s of the subtables that contain variations after merging
|
# set of id()s of the subtables that contain variations after merging
|
||||||
# and need to be upgraded to the associated VarType.
|
# and need to be upgraded to the associated VarType.
|
||||||
self.varTableIds = set()
|
self.varTableIds = set()
|
||||||
@ -1130,6 +1135,18 @@ class COLRVariationMerger(VariationMerger):
|
|||||||
def mergeTables(self, font, master_ttfs, tableTags=("COLR",)):
|
def mergeTables(self, font, master_ttfs, tableTags=("COLR",)):
|
||||||
VariationMerger.mergeTables(self, font, master_ttfs, tableTags)
|
VariationMerger.mergeTables(self, font, master_ttfs, tableTags)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def varIdxes(self):
|
||||||
|
"""Return flat list of all the varIdxes generated while merging.
|
||||||
|
|
||||||
|
To be called after mergeTables() for building a DeltaSetIndexMap.
|
||||||
|
"""
|
||||||
|
# dict remembers insertion order (as of py37+), and we extend the cache
|
||||||
|
# of VarIndexBases incrementally as new, unique tuples of varIdxes are found
|
||||||
|
# while merging, thus we don't need to sort but we just unpack the keys and
|
||||||
|
# chain the tuples
|
||||||
|
return [v for v in itertools.chain(*self.varIndexCache.keys())]
|
||||||
|
|
||||||
def checkFormatEnum(self, out, lst, validate=lambda _: True):
|
def checkFormatEnum(self, out, lst, validate=lambda _: True):
|
||||||
fmt = out.Format
|
fmt = out.Format
|
||||||
formatEnum = out.formatEnum
|
formatEnum = out.formatEnum
|
||||||
@ -1209,10 +1226,14 @@ class COLRVariationMerger(VariationMerger):
|
|||||||
baseValue, varIdx = self.storeMastersForAttr(out, lst, attr)
|
baseValue, varIdx = self.storeMastersForAttr(out, lst, attr)
|
||||||
setattr(out, attr, baseValue)
|
setattr(out, attr, baseValue)
|
||||||
varIdxes.append(varIdx)
|
varIdxes.append(varIdx)
|
||||||
|
varIdxes = tuple(varIdxes)
|
||||||
|
|
||||||
if any(v != ot.NO_VARIATION_INDEX for v in varIdxes):
|
if any(v != ot.NO_VARIATION_INDEX for v in varIdxes):
|
||||||
varIndexBase = len(self.varIdxes)
|
# try to reuse an existing VarIndexBase for the same varIdxes, or else
|
||||||
self.varIdxes.extend(varIdxes)
|
# create a new one at the end of self.varIndexCache (py37+ dicts are ordered)
|
||||||
|
varIndexBase = self.varIndexCache.setdefault(varIdxes, self.varIndexCount)
|
||||||
|
if varIndexBase == self.varIndexCount:
|
||||||
|
self.varIndexCount += len(varIdxes)
|
||||||
|
|
||||||
return varIndexBase
|
return varIndexBase
|
||||||
|
|
||||||
|
@ -422,6 +422,65 @@ class COLRVariationMergerTest:
|
|||||||
[NO_VARIATION_INDEX, NO_VARIATION_INDEX, 0, NO_VARIATION_INDEX],
|
[NO_VARIATION_INDEX, NO_VARIATION_INDEX, 0, NO_VARIATION_INDEX],
|
||||||
id="sweep_grad-startAngle",
|
id="sweep_grad-startAngle",
|
||||||
),
|
),
|
||||||
|
pytest.param(
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"Format": int(ot.PaintFormat.PaintSweepGradient),
|
||||||
|
"ColorLine": {
|
||||||
|
"Extend": int(ot.ExtendMode.PAD),
|
||||||
|
"ColorStop": [
|
||||||
|
{"StopOffset": 0.0, "PaletteIndex": 0, "Alpha": 1.0},
|
||||||
|
{"StopOffset": 1.0, "PaletteIndex": 1, "Alpha": 1.0},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"centerX": 0,
|
||||||
|
"centerY": 0,
|
||||||
|
"startAngle": 0.0,
|
||||||
|
"endAngle": 180.0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"Format": int(ot.PaintFormat.PaintSweepGradient),
|
||||||
|
"ColorLine": {
|
||||||
|
"Extend": int(ot.ExtendMode.PAD),
|
||||||
|
"ColorStop": [
|
||||||
|
{"StopOffset": 0.0, "PaletteIndex": 0, "Alpha": 0.5},
|
||||||
|
{"StopOffset": 1.0, "PaletteIndex": 1, "Alpha": 0.5},
|
||||||
|
],
|
||||||
|
},
|
||||||
|
"centerX": 0,
|
||||||
|
"centerY": 0,
|
||||||
|
"startAngle": 0.0,
|
||||||
|
"endAngle": 180.0,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
[
|
||||||
|
'<Paint Format="9"><!-- PaintVarSweepGradient -->',
|
||||||
|
" <ColorLine>",
|
||||||
|
' <Extend value="pad"/>',
|
||||||
|
" <!-- StopCount=2 -->",
|
||||||
|
' <ColorStop index="0">',
|
||||||
|
' <StopOffset value="0.0"/>',
|
||||||
|
' <PaletteIndex value="0"/>',
|
||||||
|
' <Alpha value="1.0"/>',
|
||||||
|
' <VarIndexBase value="0"/>',
|
||||||
|
" </ColorStop>",
|
||||||
|
' <ColorStop index="1">',
|
||||||
|
' <StopOffset value="1.0"/>',
|
||||||
|
' <PaletteIndex value="1"/>',
|
||||||
|
' <Alpha value="1.0"/>',
|
||||||
|
' <VarIndexBase value="0"/>',
|
||||||
|
" </ColorStop>",
|
||||||
|
" </ColorLine>",
|
||||||
|
' <centerX value="0"/>',
|
||||||
|
' <centerY value="0"/>',
|
||||||
|
' <startAngle value="0.0"/>',
|
||||||
|
' <endAngle value="180.0"/>',
|
||||||
|
' <VarIndexBase/>',
|
||||||
|
"</Paint>",
|
||||||
|
],
|
||||||
|
[NO_VARIATION_INDEX, 0],
|
||||||
|
id="sweep_grad-stops-alpha-reuse-varidxbase",
|
||||||
|
),
|
||||||
pytest.param(
|
pytest.param(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user