dl1wjd2's picture
Upload folder using huggingface_hub (part 5)
88c064c verified
Raw History Blame Contribute Delete
5.54 kB
"""Helpers for instancing CFF2 charstrings."""
from fontTools.cffLib.specializer import blendArgValues, numBlendArgValues
from fontTools.misc.roundTools import otRound
from fontTools.varLib.models import supportScalar
# Generalized operators with relative x, y coordinates (flex's 13th is fd).
_PATH_OPERATORS = {"rmoveto", "rlineto", "rrcurveto", "flex"}
_STEM_OPERATORS = {"hstem", "hstemhm", "vstem", "vstemhm"}
def _isStemCommand(commands, i):
op, args = commands[i]
if op in _STEM_OPERATORS:
return True
# Implicit vstems before hintmask/cntrmask.
return (
op == ""
and i + 1 < len(commands)
and commands[i + 1][0] in {"hintmask", "cntrmask"}
and not any(isinstance(arg, bytes) for arg in args)
)
def getRegionScalarRanges(varStore, fvarAxes, pinnedLocation):
"""Return each region's scalar range after pinning the given axes.
These ranges let flex1 generalization determine whether its direction is
fixed throughout the remaining design space.
"""
regionScalarRanges = []
for region in varStore.VarRegionList.Region:
support = region.get_support(fvarAxes)
pinnedSupport = {
axis: triple for axis, triple in support.items() if axis in pinnedLocation
}
scalar = supportScalar(pinnedLocation, pinnedSupport)
# Invalid tents are left unknown: supportScalar ignores what instancing zeroes.
if any(
lower > peak or peak > upper or lower < 0 < upper
for lower, peak, upper in pinnedSupport.values()
):
regionScalarRanges.append((0, 1))
elif len(pinnedSupport) == len(support):
regionScalarRanges.append((scalar, scalar))
else:
regionScalarRanges.append((0, scalar))
return regionScalarRanges
def convertPrivateDictDeltas(values, numRegions, *, toAbsolute):
"""Convert a Private DICT delta array's region deltas.
Defaults are already absolute; region deltas are relative to the preceding
value. Make those absolute before instancing, and relative again afterwards.
"""
previous = [0] * numRegions
result = []
for value in values:
if isinstance(value, list):
default, *deltas = value
else:
default, deltas = value, [0] * numRegions
assert len(deltas) == numRegions
if toAbsolute:
deltas = [p + d for p, d in zip(previous, deltas)]
result.append([default] + deltas)
else:
result.append([default] + [d - p for d, p in zip(deltas, previous)])
previous = deltas
return result
def convertToAbsoluteCoordinates(commands, vsIndex, getNumRegions):
"""Convert generalized CFF2 outline and stem coordinates in place.
Return ``None`` on success, or the reason the commands cannot safely be
converted. All flex operators must already have been generalized to
``flex``; an ambiguous variable ``flex1`` cannot be made absolute.
"""
seenBlend = False
for op, args in commands:
if op == "vsindex":
if seenBlend:
return "vsindex after a blend"
elif op == "flex1":
return "flex1 changes direction across the design space"
assert op not in {"hflex", "hflex1"}
seenBlend = seenBlend or any(isinstance(arg, list) for arg in args)
numValues = getNumRegions(vsIndex) + 1
outline = [[0] * numValues, [0] * numValues]
for i, (op, args) in enumerate(commands):
if op == "vsindex":
# Before any blend, so no deltas to carry over.
vsIndex = args[0]
numValues = getNumRegions(vsIndex) + 1
outline = [axis[:1] + [0] * (numValues - 1) for axis in outline]
continue
if op in _PATH_OPERATORS:
positions = outline
numCoordinates = 12 if op == "flex" else len(args)
elif _isStemCommand(commands, i):
positions = [[0] * numValues]
numCoordinates = len(args)
else:
continue
for j in range(numCoordinates):
k = j % len(positions)
values = blendArgValues(args[j], numValues)
position = positions[k] = [p + v for p, v in zip(positions[k], values)]
args[j] = position + [1] if any(position[1:]) else position[0]
return None
def convertToRelativeCoordinates(commands, round=otRound):
"""Round absolute CFF2 coordinates and make them relative again in place."""
def roundArg(arg):
if isinstance(arg, list):
return [round(arg[0])] + arg[1:]
return round(arg)
outline = [[0], [0]]
for i, (op, args) in enumerate(commands):
if op in _PATH_OPERATORS:
positions = outline
numCoordinates = 12 if op == "flex" else len(args)
elif _isStemCommand(commands, i):
positions = [[0]]
numCoordinates = len(args)
else:
continue
for j in range(numCoordinates):
k = j % len(positions)
arg = roundArg(args[j])
numValues = max(len(positions[k]), numBlendArgValues(arg))
values = blendArgValues(arg, numValues)
previous = positions[k] + [0] * (numValues - len(positions[k]))
diff = [v - p for v, p in zip(values, previous)]
positions[k] = values
args[j] = diff + [1] if any(diff[1:]) else diff[0]
if op == "flex":
args[12] = roundArg(args[12])