remove unused Variable{Float,Int} namedtuples from otTables/otConverters

This commit is contained in:
Cosimo Lupo 2021-07-22 11:51:25 +01:00
parent 0eb27e9878
commit e8e2aa530b
4 changed files with 37 additions and 206 deletions

View File

@ -26,20 +26,10 @@ from fontTools.ttLib.tables import C_O_L_R_
from fontTools.ttLib.tables import C_P_A_L_ from fontTools.ttLib.tables import C_P_A_L_
from fontTools.ttLib.tables import _n_a_m_e from fontTools.ttLib.tables import _n_a_m_e
from fontTools.ttLib.tables import otTables as ot from fontTools.ttLib.tables import otTables as ot
from fontTools.ttLib.tables.otTables import ( from fontTools.ttLib.tables.otTables import ExtendMode, CompositeMode
ExtendMode,
CompositeMode,
VariableValue,
VariableFloat,
VariableInt,
)
from .errors import ColorLibError from .errors import ColorLibError
from .geometry import round_start_circle_stable_containment from .geometry import round_start_circle_stable_containment
from .table_builder import ( from .table_builder import BuildCallback, TableBuilder
convertTupleClass,
BuildCallback,
TableBuilder,
)
# TODO move type aliases to colorLib.types? # TODO move type aliases to colorLib.types?
@ -52,52 +42,45 @@ _ColorGlyphsV0Dict = Dict[str, Sequence[Tuple[str, int]]]
MAX_PAINT_COLR_LAYER_COUNT = 255 MAX_PAINT_COLR_LAYER_COUNT = 255
_DEFAULT_ALPHA = VariableFloat(1.0) _DEFAULT_ALPHA = 1.0
_MAX_REUSE_LEN = 32 _MAX_REUSE_LEN = 32
def _beforeBuildPaintVarRadialGradient(paint, source, srcMapFn=lambda v: v): def _beforeBuildPaintRadialGradient(paint, source):
# normalize input types (which may or may not specify a varIdx) x0 = source["x0"]
x0 = convertTupleClass(VariableFloat, source["x0"]) y0 = source["y0"]
y0 = convertTupleClass(VariableFloat, source["y0"]) r0 = source["r0"]
r0 = convertTupleClass(VariableFloat, source["r0"]) x1 = source["x1"]
x1 = convertTupleClass(VariableFloat, source["x1"]) y1 = source["y1"]
y1 = convertTupleClass(VariableFloat, source["y1"]) r1 = source["r1"]
r1 = convertTupleClass(VariableFloat, source["r1"])
# TODO apparently no builder_test confirms this works (?) # TODO apparently no builder_test confirms this works (?)
# avoid abrupt change after rounding when c0 is near c1's perimeter # avoid abrupt change after rounding when c0 is near c1's perimeter
c = round_start_circle_stable_containment( c = round_start_circle_stable_containment((x0, y0), r0, (x1, y1), r1)
(x0.value, y0.value), r0.value, (x1.value, y1.value), r1.value x0, y0 = c.centre
) r0 = c.radius
x0, y0 = x0._replace(value=c.centre[0]), y0._replace(value=c.centre[1])
r0 = r0._replace(value=c.radius)
# update source to ensure paint is built with corrected values # update source to ensure paint is built with corrected values
source["x0"] = srcMapFn(x0) source["x0"] = x0
source["y0"] = srcMapFn(y0) source["y0"] = y0
source["r0"] = srcMapFn(r0) source["r0"] = r0
source["x1"] = srcMapFn(x1) source["x1"] = x1
source["y1"] = srcMapFn(y1) source["y1"] = y1
source["r1"] = srcMapFn(r1) source["r1"] = r1
return paint, source return paint, source
def _beforeBuildPaintRadialGradient(paint, source):
return _beforeBuildPaintVarRadialGradient(paint, source, lambda v: v.value)
def _defaultColorStop(): def _defaultColorStop():
colorStop = ot.ColorStop() colorStop = ot.ColorStop()
colorStop.Alpha = _DEFAULT_ALPHA.value colorStop.Alpha = _DEFAULT_ALPHA
return colorStop return colorStop
def _defaultVarColorStop(): def _defaultVarColorStop():
colorStop = ot.VarColorStop() colorStop = ot.VarColorStop()
colorStop.Alpha = _DEFAULT_ALPHA.value colorStop.Alpha = _DEFAULT_ALPHA
return colorStop return colorStop
@ -115,7 +98,7 @@ def _defaultVarColorLine():
def _defaultPaintSolid(): def _defaultPaintSolid():
paint = ot.Paint() paint = ot.Paint()
paint.Alpha = _DEFAULT_ALPHA.value paint.Alpha = _DEFAULT_ALPHA
return paint return paint
@ -130,14 +113,21 @@ def _buildPaintCallbacks():
BuildCallback.BEFORE_BUILD, BuildCallback.BEFORE_BUILD,
ot.Paint, ot.Paint,
ot.PaintFormat.PaintVarRadialGradient, ot.PaintFormat.PaintVarRadialGradient,
): _beforeBuildPaintVarRadialGradient, ): _beforeBuildPaintRadialGradient,
(BuildCallback.CREATE_DEFAULT, ot.ColorStop): _defaultColorStop, (BuildCallback.CREATE_DEFAULT, ot.ColorStop): _defaultColorStop,
(BuildCallback.CREATE_DEFAULT, ot.VarColorStop): _defaultVarColorStop, (BuildCallback.CREATE_DEFAULT, ot.VarColorStop): _defaultVarColorStop,
(BuildCallback.CREATE_DEFAULT, ot.ColorLine): _defaultColorLine, (BuildCallback.CREATE_DEFAULT, ot.ColorLine): _defaultColorLine,
(BuildCallback.CREATE_DEFAULT, ot.VarColorLine): _defaultVarColorLine, (BuildCallback.CREATE_DEFAULT, ot.VarColorLine): _defaultVarColorLine,
(BuildCallback.CREATE_DEFAULT, ot.VarColorLine): _defaultVarColorLine, (
(BuildCallback.CREATE_DEFAULT, ot.Paint, ot.PaintFormat.PaintSolid): _defaultPaintSolid, BuildCallback.CREATE_DEFAULT,
(BuildCallback.CREATE_DEFAULT, ot.Paint, ot.PaintFormat.PaintVarSolid): _defaultPaintSolid, ot.Paint,
ot.PaintFormat.PaintSolid,
): _defaultPaintSolid,
(
BuildCallback.CREATE_DEFAULT,
ot.Paint,
ot.PaintFormat.PaintVarSolid,
): _defaultPaintSolid,
} }

View File

@ -17,8 +17,6 @@ from fontTools.ttLib.tables.otConverters import (
Short, Short,
UInt8, UInt8,
UShort, UShort,
VarInt16,
VarUInt16,
IntValue, IntValue,
FloatValue, FloatValue,
) )
@ -50,14 +48,6 @@ def _assignable(convertersByName):
return {k: v for k, v in convertersByName.items() if not isinstance(v, ComputedInt)} return {k: v for k, v in convertersByName.items() if not isinstance(v, ComputedInt)}
def convertTupleClass(tupleClass, value):
if isinstance(value, tupleClass):
return value
if isinstance(value, tuple):
return tupleClass(*value)
return tupleClass(value)
def _isNonStrSequence(value): def _isNonStrSequence(value):
return isinstance(value, collections.abc.Sequence) and not isinstance(value, str) return isinstance(value, collections.abc.Sequence) and not isinstance(value, str)
@ -97,13 +87,9 @@ class TableBuilder:
self._callbackTable = callbackTable self._callbackTable = callbackTable
def _convert(self, dest, field, converter, value): def _convert(self, dest, field, converter, value):
tupleClass = getattr(converter, "tupleClass", None)
enumClass = getattr(converter, "enumClass", None) enumClass = getattr(converter, "enumClass", None)
if tupleClass: if enumClass:
value = convertTupleClass(tupleClass, value)
elif enumClass:
if isinstance(value, enumClass): if isinstance(value, enumClass):
pass pass
elif isinstance(value, str): elif isinstance(value, str):
@ -213,11 +199,8 @@ class TableUnbuilder:
continue continue
value = getattr(table, converter.name) value = getattr(table, converter.name)
tupleClass = getattr(converter, "tupleClass", None)
enumClass = getattr(converter, "enumClass", None) enumClass = getattr(converter, "enumClass", None)
if tupleClass: if enumClass:
source[converter.name] = tuple(value)
elif enumClass:
source[converter.name] = value.name.lower() source[converter.name] = value.name.lower()
elif isinstance(converter, Struct): elif isinstance(converter, Struct):
if converter.repeat: if converter.repeat:

View File

@ -14,8 +14,8 @@ from .otBase import (CountReference, FormatSwitchingBaseTable,
OTTableReader, OTTableWriter, ValueRecordFactory) OTTableReader, OTTableWriter, ValueRecordFactory)
from .otTables import (lookupTypes, AATStateTable, AATState, AATAction, from .otTables import (lookupTypes, AATStateTable, AATState, AATAction,
ContextualMorphAction, LigatureMorphAction, ContextualMorphAction, LigatureMorphAction,
InsertionMorphAction, MorxSubtable, VariableFloat, InsertionMorphAction, MorxSubtable,
VariableInt, ExtendMode as _ExtendMode, ExtendMode as _ExtendMode,
CompositeMode as _CompositeMode) CompositeMode as _CompositeMode)
from itertools import zip_longest from itertools import zip_longest
from functools import partial from functools import partial
@ -1700,104 +1700,6 @@ class LookupFlag(UShort):
xmlWriter.comment(" ".join(flags)) xmlWriter.comment(" ".join(flags))
xmlWriter.newline() xmlWriter.newline()
def _issubclass_namedtuple(x):
return (
issubclass(x, tuple)
and getattr(x, "_fields", None) is not None
)
class _NamedTupleConverter(BaseConverter):
# subclasses must override this
tupleClass = NotImplemented
# List[SimpleValue]
converterClasses = NotImplemented
def __init__(self, name, repeat, aux, tableClass=None):
# we expect all converters to be subclasses of SimpleValue
assert all(issubclass(klass, SimpleValue) for klass in self.converterClasses)
assert _issubclass_namedtuple(self.tupleClass), repr(self.tupleClass)
assert len(self.tupleClass._fields) == len(self.converterClasses)
assert tableClass is None # tableClass is unused by SimplValues
BaseConverter.__init__(self, name, repeat, aux)
self.converters = [
klass(name=name, repeat=None, aux=None)
for name, klass in zip(self.tupleClass._fields, self.converterClasses)
]
self.convertersByName = {conv.name: conv for conv in self.converters}
# returned by getRecordSize method
self.staticSize = sum(c.staticSize for c in self.converters)
def read(self, reader, font, tableDict):
kwargs = {
conv.name: conv.read(reader, font, tableDict)
for conv in self.converters
}
return self.tupleClass(**kwargs)
def write(self, writer, font, tableDict, value, repeatIndex=None):
for conv in self.converters:
v = getattr(value, conv.name)
# repeatIndex is unused for SimpleValues
conv.write(writer, font, tableDict, v, repeatIndex=None)
def xmlWrite(self, xmlWriter, font, value, name, attrs):
assert value is not None
defaults = value.__new__.__defaults__ or ()
assert len(self.converters) >= len(defaults)
values = {}
required = object()
for conv, default in zip_longest(
reversed(self.converters),
reversed(defaults),
fillvalue=required,
):
v = getattr(value, conv.name)
if default is required or v != default:
values[conv.name] = conv.toString(v)
if attrs is None:
attrs = []
attrs.extend(
(conv.name, values[conv.name])
for conv in self.converters
if conv.name in values
)
xmlWriter.simpletag(name, attrs)
xmlWriter.newline()
def xmlRead(self, attrs, content, font):
converters = self.convertersByName
kwargs = {
k: converters[k].fromString(v)
for k, v in attrs.items()
}
return self.tupleClass(**kwargs)
class VarFixed(_NamedTupleConverter):
tupleClass = VariableFloat
converterClasses = [Fixed, ULong]
class VarF2Dot14(_NamedTupleConverter):
tupleClass = VariableFloat
converterClasses = [F2Dot14, ULong]
class VarInt16(_NamedTupleConverter):
tupleClass = VariableInt
converterClasses = [Short, ULong]
class VarUInt16(_NamedTupleConverter):
tupleClass = VariableInt
converterClasses = [UShort, ULong]
class VarAngle(_NamedTupleConverter):
tupleClass = VariableFloat
converterClasses = [F2Dot14, ULong]
class _UInt8Enum(UInt8): class _UInt8Enum(UInt8):
enumClass = NotImplemented enumClass = NotImplemented
@ -1867,11 +1769,4 @@ converterMapping = {
"OffsetTo": lambda C: partial(Table, tableClass=C), "OffsetTo": lambda C: partial(Table, tableClass=C),
"LOffsetTo": lambda C: partial(LTable, tableClass=C), "LOffsetTo": lambda C: partial(LTable, tableClass=C),
"LOffset24To": lambda C: partial(Table24, tableClass=C), "LOffset24To": lambda C: partial(Table24, tableClass=C),
# Variable types
"VarFixed": VarFixed,
"VarF2Dot14": VarF2Dot14,
"VarInt16": VarInt16,
"VarUInt16": VarUInt16,
"VarAngle": VarAngle,
} }

View File

@ -1297,43 +1297,6 @@ class BaseGlyphList(BaseTable):
return self.__dict__.copy() return self.__dict__.copy()
class VariableValue(namedtuple("VariableValue", ["value", "varIdx"])):
__slots__ = ()
_value_mapper = None
def __new__(cls, value, varIdx=0xFFFFFFFF):
return super().__new__(
cls,
cls._value_mapper(value) if cls._value_mapper else value,
varIdx
)
@classmethod
def _make(cls, iterable):
if cls._value_mapper:
it = iter(iterable)
try:
value = next(it)
except StopIteration:
pass
else:
value = cls._value_mapper(value)
iterable = itertools.chain((value,), it)
return super()._make(iterable)
class VariableFloat(VariableValue):
__slots__ = ()
_value_mapper = float
class VariableInt(VariableValue):
__slots__ = ()
_value_mapper = otRound
class ExtendMode(IntEnum): class ExtendMode(IntEnum):
PAD = 0 PAD = 0
REPEAT = 1 REPEAT = 1