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