diff options
Diffstat (limited to 'Lib/fontTools/colorLib/table_builder.py')
-rw-r--r-- | Lib/fontTools/colorLib/table_builder.py | 61 |
1 files changed, 35 insertions, 26 deletions
diff --git a/Lib/fontTools/colorLib/table_builder.py b/Lib/fontTools/colorLib/table_builder.py index 763115b9..6fba6b0f 100644 --- a/Lib/fontTools/colorLib/table_builder.py +++ b/Lib/fontTools/colorLib/table_builder.py @@ -17,9 +17,10 @@ from fontTools.ttLib.tables.otConverters import ( Short, UInt8, UShort, + VarInt16, + VarUInt16, IntValue, FloatValue, - OptionalValue, ) from fontTools.misc.roundTools import otRound @@ -38,7 +39,7 @@ class BuildCallback(enum.Enum): """ AFTER_BUILD = enum.auto() - """Keyed on (CREATE_DEFAULT, class[, Format if available]). + """Keyed on (CREATE_DEFAULT, class). Receives no arguments. Should return a new instance of class. """ @@ -49,29 +50,37 @@ def _assignable(convertersByName): 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): return isinstance(value, collections.abc.Sequence) and not isinstance(value, str) -def _split_format(cls, source): +def _set_format(dest, source): if _isNonStrSequence(source): - assert len(source) > 0, f"{cls} needs at least format from {source}" - fmt, remainder = source[0], source[1:] + assert len(source) > 0, f"{type(dest)} needs at least format from {source}" + dest.Format = source[0] + source = source[1:] elif isinstance(source, collections.abc.Mapping): - assert "Format" in source, f"{cls} needs at least Format from {source}" - remainder = source.copy() - fmt = remainder.pop("Format") + assert "Format" in source, f"{type(dest)} needs at least Format from {source}" + dest.Format = source["Format"] else: - raise ValueError(f"Not sure how to populate {cls} from {source}") + raise ValueError(f"Not sure how to populate {type(dest)} from {source}") assert isinstance( - fmt, collections.abc.Hashable - ), f"{cls} Format is not hashable: {fmt!r}" + dest.Format, collections.abc.Hashable + ), f"{type(dest)} Format is not hashable: {dest.Format}" assert ( - fmt in cls.convertersByName - ), f"{cls} invalid Format: {fmt!r}" + dest.Format in dest.convertersByName + ), f"{dest.Format} invalid Format of {cls}" - return fmt, remainder + return source class TableBuilder: @@ -88,9 +97,13 @@ class TableBuilder: self._callbackTable = callbackTable def _convert(self, dest, field, converter, value): + tupleClass = getattr(converter, "tupleClass", None) enumClass = getattr(converter, "enumClass", None) - if enumClass: + if tupleClass: + value = convertTupleClass(tupleClass, value) + + elif enumClass: if isinstance(value, enumClass): pass elif isinstance(value, str): @@ -127,11 +140,6 @@ class TableBuilder: return source callbackKey = (cls,) - fmt = None - if issubclass(cls, FormatSwitchingBaseTable): - fmt, source = _split_format(cls, source) - callbackKey = (cls, fmt) - dest = self._callbackTable.get( (BuildCallback.CREATE_DEFAULT,) + callbackKey, lambda: cls() )() @@ -142,9 +150,11 @@ class TableBuilder: # For format switchers we need to resolve converters based on format if issubclass(cls, FormatSwitchingBaseTable): - dest.Format = fmt + source = _set_format(dest, source) + convByName = _assignable(convByName[dest.Format]) skippedFields.add("Format") + callbackKey = (cls, dest.Format) # Convert sequence => mapping so before thunk only has to handle one format if _isNonStrSequence(source): @@ -172,10 +182,6 @@ class TableBuilder: # let's try as a 1-tuple dest = self.build(cls, (source,)) - for field, conv in convByName.items(): - if not hasattr(dest, field) and isinstance(conv, OptionalValue): - setattr(dest, field, conv.DEFAULT) - dest = self._callbackTable.get( (BuildCallback.AFTER_BUILD,) + callbackKey, lambda d: d )(dest) @@ -204,8 +210,11 @@ class TableUnbuilder: continue value = getattr(table, converter.name) + tupleClass = getattr(converter, "tupleClass", None) enumClass = getattr(converter, "enumClass", None) - if enumClass: + if tupleClass: + source[converter.name] = tuple(value) + elif enumClass: source[converter.name] = value.name.lower() elif isinstance(converter, Struct): if converter.repeat: |