[OpenFontFormat] Clean up OpenFont.py

This commit is contained in:
germax26 2024-05-04 11:34:37 +10:00
parent 6a33053dfc
commit 33e9714d34
Signed by: germax26
SSH Key Fingerprint: SHA256:N3w+8798IMWBt7SYH8G1C0iJlIa2HIIcRCXwILT5FvM

View File

@ -3,8 +3,8 @@ from datetime import datetime, timedelta, timezone
from enum import Enum, EnumMeta from enum import Enum, EnumMeta
from io import BytesIO from io import BytesIO
from math import floor, log2 from math import floor, log2
from typing import Callable, Generic, List, Optional, Tuple, TypeVar, BinaryIO from types import TracebackType
from typing_extensions import Self from typing import Callable, Generic, List, Optional, Tuple, Type, TypeVar, BinaryIO, Self
from abcde import ABD, ABE from abcde import ABD, ABE
from read_utils import read_ascii, read_fixed_point, read_i16, read_i32, read_i8, read_int, read_pascal_string, read_u16, read_u24, read_u32, read_u64, read_u8 from read_utils import read_ascii, read_fixed_point, read_i16, read_i32, read_i8, read_int, read_pascal_string, read_u16, read_u24, read_u32, read_u64, read_u8
@ -28,7 +28,7 @@ def read_long_datetime(f: BinaryIO) -> datetime:
Tag_ = TypeVar('Tag_') Tag_ = TypeVar('Tag_')
SomeTag = Callable[[str], Tag_] # If SomeTag is not an EnumMeta, it should throw a ValueError to indicate an invalid tag SomeTag = Callable[[str], Tag_] # If SomeTag is not an EnumMeta, it should throw a ValueError to indicate an invalid tag
def parse_tag_with_conditions(f: BinaryIO, *conditions: Tuple[Callable[[str], bool], SomeTag[Tag_]], umbrellaTagCls: type | SomeTag[Tag_], strict:bool=True) -> Tag_: def read_tag_with_conditions(f: BinaryIO, *conditions: Tuple[Callable[[str], bool], SomeTag[Tag_]], umbrellaTagCls: type | SomeTag[Tag_], strict:bool=True) -> Tag_:
tag = read_ascii(f, 4) tag = read_ascii(f, 4)
assert not strict or all([0x20 <= ord(c) <= 0x7e for c in tag]), f"Invalid tag: {[f.seek(-4, 1), f.read(4)][1]}" assert not strict or all([0x20 <= ord(c) <= 0x7e for c in tag]), f"Invalid tag: {[f.seek(-4, 1), f.read(4)][1]}"
for (condition, tagCls) in conditions: for (condition, tagCls) in conditions:
@ -38,14 +38,14 @@ def parse_tag_with_conditions(f: BinaryIO, *conditions: Tuple[Callable[[str], bo
else: else:
assert False, f"Invalid {umbrellaTagCls.__name__}: '{tag}'" assert False, f"Invalid {umbrellaTagCls.__name__}: '{tag}'"
def parse_tag_cascading(f: BinaryIO, *tagClss: SomeTag[Tag_], umbrellaTagCls: type | SomeTag[Tag_], strict:bool=True) -> Tag_: def read_tag_from_tags(f: BinaryIO, *tagClss: SomeTag[Tag_], umbrellaTagCls: type | SomeTag[Tag_], strict:bool=True) -> Tag_:
""" """
This is meant to be used for when some instances of an Enum are just CC01, CC02, CC03, ... This is meant to be used for when some instances of an Enum are just CC01, CC02, CC03, ...
""" """
return parse_tag_with_conditions(f, *[(lambda _: True, tagCls) for tagCls in tagClss], umbrellaTagCls=umbrellaTagCls, strict=strict) return read_tag_with_conditions(f, *[(lambda _: True, tagCls) for tagCls in tagClss], umbrellaTagCls=umbrellaTagCls, strict=strict)
def parse_tag(f: BinaryIO, tagCls: SomeTag[Tag_], *, strict:bool=True) -> Tag_: def read_tag(f: BinaryIO, tagCls: SomeTag[Tag_], *, strict:bool=True) -> Tag_:
return parse_tag_cascading(f, tagCls, umbrellaTagCls=tagCls, strict=strict) return read_tag_from_tags(f, tagCls, umbrellaTagCls=tagCls, strict=strict)
ID_ = TypeVar('ID_') ID_ = TypeVar('ID_')
SomeID = Callable[[int], ID_] SomeID = Callable[[int], ID_]
@ -53,7 +53,7 @@ SomeID = Callable[[int], ID_]
T = TypeVar('T') T = TypeVar('T')
Parser = Callable[[BinaryIO], T] Parser = Callable[[BinaryIO], T]
def parse_id_ranges(f: BinaryIO, *ranges: Tuple[Optional[int], SomeID[ID_]], umbrellaIdCls: SomeID[ID_], reader: Parser[int]=read_u16) -> ID_: # must be in ascending order def read_id_from_ranges(f: BinaryIO, *ranges: Tuple[Optional[int], SomeID[ID_]], umbrellaIdCls: SomeID[ID_], reader: Parser[int]=read_u16) -> ID_: # must be in ascending order
assert len(ranges) > 0, f"Must have at least one range" assert len(ranges) > 0, f"Must have at least one range"
id = reader(f) id = reader(f)
for (num, idCls) in ranges: for (num, idCls) in ranges:
@ -62,18 +62,18 @@ def parse_id_ranges(f: BinaryIO, *ranges: Tuple[Optional[int], SomeID[ID_]], umb
except ValueError: pass except ValueError: pass
assert False, f"Invalid {umbrellaIdCls.__name__}: {id}" assert False, f"Invalid {umbrellaIdCls.__name__}: {id}"
def parse_id(f: BinaryIO, idCls: SomeID[ID_], *, reader: Parser[int]=read_u16) -> ID_: def read_id(f: BinaryIO, idCls: SomeID[ID_], *, reader: Parser[int]=read_u16) -> ID_:
return parse_id_ranges(f, (None, idCls), umbrellaIdCls=idCls, reader=reader) return read_id_from_ranges(f, (None, idCls), umbrellaIdCls=idCls, reader=reader)
class SaveTell: class SaveTell:
def __init__(self, f: BinaryIO): def __init__(self, f: BinaryIO):
self.f = f self.f = f
def __enter__(self): def __enter__(self) -> int:
self.tell = self.f.tell() self.tell = self.f.tell()
return self.tell return self.tell
def __exit__(self, exc_type, exc_value, exc_tb): def __exit__(self, exc_type: Optional[Type[BaseException]], exc_value: Optional[BaseException], exc_tb: Optional[TracebackType]) -> None:
self.f.seek(self.tell) self.f.seek(self.tell)
# The following `parse_at_...` functions all move the BinaryIO away from wherever it was, so use `with SaveTell(f): ...` to save the tell # The following `parse_at_...` functions all move the BinaryIO away from wherever it was, so use `with SaveTell(f): ...` to save the tell
@ -128,8 +128,8 @@ SomeTable = TypeVar('SomeTable', bound=Table)
@dataclass @dataclass
class SetTable(Table, Generic[SomeTable]): class SetTable(Table, Generic[SomeTable]):
count: int tableCount: int
elements: List[SomeTable] tables: List[SomeTable]
def parse_set_table(f: BinaryIO, parser: Parser[SomeTable], *, offset_reader: Parser[int]=read_u16) -> SetTable[SomeTable]: def parse_set_table(f: BinaryIO, parser: Parser[SomeTable], *, offset_reader: Parser[int]=read_u16) -> SetTable[SomeTable]:
start_tell = f.tell() start_tell = f.tell()
@ -237,6 +237,9 @@ class TableTag(Enum):
def __str__(self) -> str: return self._value_ def __str__(self) -> str: return self._value_
def parse_table_tag(f: BinaryIO) -> TableTag:
return read_tag(f, TableTag)
@dataclass @dataclass
class TableDirectoryEntry: class TableDirectoryEntry:
tableTag: TableTag tableTag: TableTag
@ -245,7 +248,7 @@ class TableDirectoryEntry:
length: int length: int
def parse_table_directory_entry(f: BinaryIO) -> TableDirectoryEntry: def parse_table_directory_entry(f: BinaryIO) -> TableDirectoryEntry:
tableTag = parse_tag(f, TableTag) tableTag = parse_table_tag(f)
checkSum = read_u32(f) checkSum = read_u32(f)
offset = read_u32(f) offset = read_u32(f)
length = read_u32(f) length = read_u32(f)
@ -435,12 +438,12 @@ class CmapSubtable_Format_12(CmapSubtable):
groups: List[SequentialMapGroup] groups: List[SequentialMapGroup]
@dataclass @dataclass
class UnicodeRangeRecord: class UnicodeRangeRecord(Record):
startUnicodeValue: int startUnicodeValue: int
additionalCount: int additionalCount: int
def __repr__(self) -> str: def __repr__(self) -> str:
return f"U+{hex(self.startUnicodeValue)[2:]:0>4}" + (f"-U+{hex(self.startUnicodeValue+self.additionalCount)[2:]:0>4}" if self.additionalCount > 0 else '') return f"<U+{hex(self.startUnicodeValue)[2:]:0>4}" + (f"-U+{hex(self.startUnicodeValue+self.additionalCount)[2:]:0>4}" if self.additionalCount > 0 else '')+">"
def parse_unicode_range_record(f: BinaryIO) -> UnicodeRangeRecord: def parse_unicode_range_record(f: BinaryIO) -> UnicodeRangeRecord:
startUnicodeValue = read_u24(f) startUnicodeValue = read_u24(f)
@ -461,7 +464,7 @@ def parse_default_UVS_table(f: BinaryIO) -> DefaultUVSTable:
return DefaultUVSTable(numUnicodeValueRanges, ranges) return DefaultUVSTable(numUnicodeValueRanges, ranges)
@dataclass @dataclass
class UVSMappingRecord: class UVSMappingRecord(Record):
unicodeValue: int unicodeValue: int
glyphID: int glyphID: int
@ -483,7 +486,7 @@ def parse_non_default_UVS_table(f: BinaryIO) -> NonDefaultUVSTable:
return NonDefaultUVSTable(numUVSMappings, uvsMappings) return NonDefaultUVSTable(numUVSMappings, uvsMappings)
@dataclass @dataclass
class VariationSelectorRecord: class VariationSelectorRecord(Record):
varSelector: int varSelector: int
defaultUVS: Optional[DefaultUVSTable] defaultUVS: Optional[DefaultUVSTable]
nonDefaultUVS: Optional[NonDefaultUVSTable] nonDefaultUVS: Optional[NonDefaultUVSTable]
@ -637,8 +640,8 @@ def encoding_ID_cls_from_platform_ID(platformID: PlatformID) -> Callable[[int],
assert False, platformID assert False, platformID
def parse_encoding_ID(f: BinaryIO, platformID: PlatformID): def parse_encoding_ID(f: BinaryIO, platformID: PlatformID) -> EncodingID:
return parse_id(f, encoding_ID_cls_from_platform_ID(platformID)) return read_id(f, encoding_ID_cls_from_platform_ID(platformID))
def parse_string_with_encoding_ID(f: BinaryIO, length: int, encodingID: EncodingID) -> str: def parse_string_with_encoding_ID(f: BinaryIO, length: int, encodingID: EncodingID) -> str:
bytes = f.read(length) bytes = f.read(length)
@ -653,13 +656,13 @@ def parse_string_with_encoding_ID(f: BinaryIO, length: int, encodingID: Encoding
assert False, encodingID assert False, encodingID
@dataclass @dataclass
class EncodingRecord: class EncodingRecord(Record):
platformID: PlatformID platformID: PlatformID
encodingID: EncodingID encodingID: EncodingID
subtable: CmapSubtable subtable: CmapSubtable
def parse_encoding_record(f: BinaryIO, start_tell:int) -> EncodingRecord: def parse_encoding_record(f: BinaryIO, start_tell:int) -> EncodingRecord:
platformID = parse_id(f, PlatformID) platformID = read_id(f, PlatformID)
encodingID = parse_encoding_ID(f, platformID) encodingID = parse_encoding_ID(f, platformID)
subtableOffset = read_u32(f) subtableOffset = read_u32(f)
with SaveTell(f): with SaveTell(f):
@ -1086,7 +1089,7 @@ def languageID_cls_from_platform_ID(platformID: PlatformID) -> Callable[[int], L
assert False, platformID assert False, platformID
def parse_language_ID(f: BinaryIO, platformID: PlatformID) -> LanguageID: def parse_language_ID(f: BinaryIO, platformID: PlatformID) -> LanguageID:
return parse_id(f, languageID_cls_from_platform_ID(platformID)) return read_id(f, languageID_cls_from_platform_ID(platformID))
class NameID(ABE): pass class NameID(ABE): pass
@ -1123,7 +1126,7 @@ class FontSpecificNameID(NameID):
nameID: int nameID: int
def parse_name_ID(f: BinaryIO) -> NameID: def parse_name_ID(f: BinaryIO) -> NameID:
return parse_id_ranges(f, (255, PredefinedNameID), (32767, FontSpecificNameID), umbrellaIdCls=NameID) return read_id_from_ranges(f, (255, PredefinedNameID), (32767, FontSpecificNameID), umbrellaIdCls=NameID)
@dataclass @dataclass
class NameRecord: class NameRecord:
@ -1135,7 +1138,7 @@ class NameRecord:
string: str string: str
def parse_name_record(f: BinaryIO, stringBytes: BinaryIO) -> NameRecord: def parse_name_record(f: BinaryIO, stringBytes: BinaryIO) -> NameRecord:
platformID = parse_id(f, PlatformID) platformID = read_id(f, PlatformID)
encodingID = parse_encoding_ID(f, platformID) encodingID = parse_encoding_ID(f, platformID)
languageID = parse_language_ID(f, platformID) languageID = parse_language_ID(f, platformID)
nameID = parse_name_ID(f) nameID = parse_name_ID(f)
@ -1178,6 +1181,9 @@ def parse_name_table(f: BinaryIO, length: int) -> NameTable:
class VendorTag: class VendorTag:
achVendID: str achVendID: str
def parse_vendor_tag(f: BinaryIO) -> VendorTag:
return read_tag(f, VendorTag, strict=False)
@dataclass @dataclass
class OS2Table(Table, ABD): class OS2Table(Table, ABD):
version: int version: int
@ -1251,7 +1257,7 @@ def parse_OS2_table(f: BinaryIO) -> OS2Table:
panose0, panose1, panose2, panose3, panose4, panose5, panose6, panose7, panose8, panose9 = [read_u8(f) for _ in range(10)] panose0, panose1, panose2, panose3, panose4, panose5, panose6, panose7, panose8, panose9 = [read_u8(f) for _ in range(10)]
panose = (panose0, panose1, panose2, panose3, panose4, panose5, panose6, panose7, panose8, panose9) panose = (panose0, panose1, panose2, panose3, panose4, panose5, panose6, panose7, panose8, panose9)
ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4 = [read_u32(f) for _ in range(4)] ulUnicodeRange1, ulUnicodeRange2, ulUnicodeRange3, ulUnicodeRange4 = [read_u32(f) for _ in range(4)]
achVendID = parse_tag(f, VendorTag, strict=False) achVendID = parse_vendor_tag(f)
fsSelection = read_u16(f) fsSelection = read_u16(f)
usFirstCharIndex, usLastCharIndex = read_u16(f), read_u16(f) usFirstCharIndex, usLastCharIndex = read_u16(f), read_u16(f)
sTypoAscender, sTypoDescender, sTypoLineGap = read_i16(f), read_i16(f), read_i16(f) sTypoAscender, sTypoDescender, sTypoLineGap = read_i16(f), read_i16(f), read_i16(f)
@ -2470,7 +2476,7 @@ class ValidLangSysTag(LangSysTag, Enum):
def __str__(self) -> str: return self._name_ def __str__(self) -> str: return self._name_
def parse_lang_sys_tag(f: BinaryIO) -> LangSysTag: def parse_lang_sys_tag(f: BinaryIO) -> LangSysTag:
return parse_tag_cascading(f, ValidLangSysTag, MS_VOLT_Tag, umbrellaTagCls=LangSysTag) return read_tag_from_tags(f, ValidLangSysTag, MS_VOLT_Tag, umbrellaTagCls=LangSysTag)
@dataclass @dataclass
class LangSysRecord: class LangSysRecord:
@ -2508,7 +2514,7 @@ class ScriptRecord:
script: ScriptTable script: ScriptTable
def parse_script_record(f: BinaryIO, start_tell:int) -> ScriptRecord: def parse_script_record(f: BinaryIO, start_tell:int) -> ScriptRecord:
tag = parse_tag(f, ScriptTag) tag = read_tag(f, ScriptTag)
scriptOffset = read_u16(f) scriptOffset = read_u16(f)
with SaveTell(f): with SaveTell(f):
script = parse_at_offset(f, start_tell, scriptOffset, parse_script_table) script = parse_at_offset(f, start_tell, scriptOffset, parse_script_table)
@ -2677,7 +2683,7 @@ class MS_VOLT_Tag(CCXXTag, LangSysTag, FeatureTag):
__range__ = (0, 99) # I don't know if zz00 is valid or not, but I am letting it be, so that it can be caught, because zzXX is not a valid tag for anything __range__ = (0, 99) # I don't know if zz00 is valid or not, but I am letting it be, so that it can be caught, because zzXX is not a valid tag for anything
def parse_feature_tag(f: BinaryIO) -> FeatureTag: def parse_feature_tag(f: BinaryIO) -> FeatureTag:
return parse_tag_cascading(f, SimpleFeatureTag, CvXXFeatureTag, SsXXFeatureTag, MS_VOLT_Tag, umbrellaTagCls=FeatureTag) return read_tag_from_tags(f, SimpleFeatureTag, CvXXFeatureTag, SsXXFeatureTag, MS_VOLT_Tag, umbrellaTagCls=FeatureTag)
@dataclass @dataclass
class FeatureParamsTable(Table, ABD): pass class FeatureParamsTable(Table, ABD): pass
@ -2711,7 +2717,7 @@ class SizeFeatureParamsTable(FeatureParamsTable):
subfamily_nameID: Optional[int] subfamily_nameID: Optional[int]
recommended_usage_range: Optional[Tuple[int, int]] recommended_usage_range: Optional[Tuple[int, int]]
def parse_feature_params_table(f: BinaryIO, featureTag: FeatureTag): def parse_feature_params_table(f: BinaryIO, featureTag: FeatureTag) -> FeatureParamsTable:
match featureTag: match featureTag:
case CvXXFeatureTag(num=_): case CvXXFeatureTag(num=_):
format = read_u16(f) format = read_u16(f)
@ -2840,7 +2846,7 @@ def parse_lookup_table(f: BinaryIO, _lookupType: Callable[[int], LookupType], lo
start_tell = f.tell() start_tell = f.tell()
lookupType = parse_id(f, _lookupType) lookupType = read_id(f, _lookupType)
lookupFlag = parse_lookup_flag(f) lookupFlag = parse_lookup_flag(f)
subTableCount = read_u16(f) subTableCount = read_u16(f)
subTableOffsets = [read_u16(f) for _ in range(subTableCount)] subTableOffsets = [read_u16(f) for _ in range(subTableCount)]
@ -2893,20 +2899,18 @@ def parse_condition_table(f: BinaryIO) -> ConditionTable:
assert False, format assert False, format
@dataclass ConditionSetTable = SetTable[ConditionTable]
class ConditionSetTable(Table):
conditionCount: int
conditions: List[ConditionTable]
def parse_condition_set_table(f: BinaryIO) -> ConditionSetTable: def parse_condition_set_table(f: BinaryIO) -> ConditionSetTable:
start_tell = f.tell() return parse_set_table(f, parse_condition_table, offset_reader=read_u32)
# start_tell = f.tell()
conditionCount = read_u16(f) # conditionCount = read_u16(f)
conditionOffsets = [read_u32(f) for _ in range(conditionCount)] # conditionOffsets = [read_u32(f) for _ in range(conditionCount)]
with SaveTell(f): # with SaveTell(f):
conditions = parse_at_offsets(f, start_tell, conditionOffsets, parse_condition_table) # conditions = parse_at_offsets(f, start_tell, conditionOffsets, parse_condition_table)
return ConditionSetTable(conditionCount, conditions) # return ConditionSetTable(conditionCount, conditions)
@dataclass @dataclass
class FeatureTableSubstitutionRecord: class FeatureTableSubstitutionRecord:
@ -2949,14 +2953,14 @@ def parse_feature_table_substitution_table(f: BinaryIO, featureList: FeatureList
@dataclass @dataclass
class FeatureVariationRecord: class FeatureVariationRecord:
conditionSet: SetTable[ConditionTable] conditionSet: ConditionSetTable
featureTableSubstitution: FeatureTableSubstitutionTable featureTableSubstitution: FeatureTableSubstitutionTable
def parse_feature_variation_record(f: BinaryIO, start_tell: int, featureList: FeatureListTable) -> FeatureVariationRecord: def parse_feature_variation_record(f: BinaryIO, start_tell: int, featureList: FeatureListTable) -> FeatureVariationRecord:
conditionSetOffset = read_u32(f) conditionSetOffset = read_u32(f)
featureTableSubstitutionOffset = read_u32(f) featureTableSubstitutionOffset = read_u32(f)
with SaveTell(f): with SaveTell(f):
conditionSet = parse_at_offset(f, start_tell, conditionSetOffset, lambda f: parse_set_table(f, parse_condition_table, offset_reader=read_u32)) conditionSet = parse_at_offset(f, start_tell, conditionSetOffset, parse_condition_set_table)
featureTableSubstitution = parse_at_offset(f, start_tell, featureTableSubstitutionOffset, lambda f: parse_feature_table_substitution_table(f, featureList)) featureTableSubstitution = parse_at_offset(f, start_tell, featureTableSubstitutionOffset, lambda f: parse_feature_table_substitution_table(f, featureList))
return FeatureVariationRecord(conditionSet, featureTableSubstitution) return FeatureVariationRecord(conditionSet, featureTableSubstitution)
@ -2997,7 +3001,7 @@ class CoverageTable_Format_1(CoverageTable):
glyphArray: List[int] glyphArray: List[int]
@dataclass @dataclass
class RangeRecord: class RangeRecord(Record):
startGlyphID: int startGlyphID: int
endGlyphID: int endGlyphID: int
startCoverageIndex: int startCoverageIndex: int
@ -3045,7 +3049,7 @@ class ClassRangeRecord:
endGlyphID: int endGlyphID: int
classValue: int classValue: int
def parse_class_range_record(f) -> ClassRangeRecord: def parse_class_range_record(f: BinaryIO) -> ClassRangeRecord:
startGlyphID = read_u16(f) startGlyphID = read_u16(f)
endGlyphID = read_u16(f) endGlyphID = read_u16(f)
classValue = read_u16(f) classValue = read_u16(f)
@ -3087,7 +3091,7 @@ class ValueFormatFlags:
def x_advance_device(self) -> bool: return (self.bytes & 0x0040)!=0 def x_advance_device(self) -> bool: return (self.bytes & 0x0040)!=0
def y_advance_device(self) -> bool: return (self.bytes & 0x0080)!=0 def y_advance_device(self) -> bool: return (self.bytes & 0x0080)!=0
def parse_value_format(f) -> ValueFormatFlags: def parse_value_format(f: BinaryIO) -> ValueFormatFlags:
valueFormat = read_u16(f) valueFormat = read_u16(f)
assert valueFormat & 0xFF00 == 0, "Reserved" assert valueFormat & 0xFF00 == 0, "Reserved"
@ -3142,7 +3146,7 @@ class BaseTagListTable(Table):
def parse_base_tag_list_table(f: BinaryIO) -> BaseTagListTable: def parse_base_tag_list_table(f: BinaryIO) -> BaseTagListTable:
baseTagCount = read_u16(f) baseTagCount = read_u16(f)
baselineTags = [parse_tag(f, BaselineTag) for _ in range(baseTagCount)] baselineTags = [read_tag(f, BaselineTag) for _ in range(baseTagCount)]
return BaseTagListTable(baseTagCount, baselineTags) return BaseTagListTable(baseTagCount, baselineTags)
@ -3225,7 +3229,7 @@ class BaseScriptRecord:
baseScript: BaseScriptTable baseScript: BaseScriptTable
def parse_base_script_record(f: BinaryIO, start_tell: int) -> BaseScriptRecord: def parse_base_script_record(f: BinaryIO, start_tell: int) -> BaseScriptRecord:
baseScriptTag = parse_tag(f, ScriptTag) baseScriptTag = read_tag(f, ScriptTag)
baseScriptOffset = read_u16(f) baseScriptOffset = read_u16(f)
with SaveTell(f): with SaveTell(f):
baseScript = parse_at_offset(f, start_tell, baseScriptOffset, parse_base_script_table) baseScript = parse_at_offset(f, start_tell, baseScriptOffset, parse_base_script_table)
@ -3879,11 +3883,16 @@ def parse_chain_pos_rule_table(f: BinaryIO) -> ChainPosRuleTable:
return ChainPosRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, posCount, posLookupRecords) return ChainPosRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, posCount, posLookupRecords)
ChainPosRuleSetTable = SetTable[ChainPosRuleTable]
def parse_chain_pos_rule_set_table(f: BinaryIO) -> ChainPosRuleSetTable:
return parse_set_table(f, parse_chain_pos_rule_table)
@dataclass @dataclass
class ChainContextPosSubtable_Format_1(ChainContextPosSubtable): class ChainContextPosSubtable_Format_1(ChainContextPosSubtable):
coverage: CoverageTable coverage: CoverageTable
chainPosRuleSetCount: int chainPosRuleSetCount: int
chainPosRuleSets: List[SetTable[ChainPosRuleTable]] chainPosRuleSets: List[ChainPosRuleSetTable]
@dataclass @dataclass
class ChainPosClassRuleTable(Table): class ChainPosClassRuleTable(Table):
@ -3908,6 +3917,11 @@ def parse_chain_pos_class_rule_table(f: BinaryIO) -> ChainPosClassRuleTable:
return ChainPosClassRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, posCount, posLookupRecords) return ChainPosClassRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, posCount, posLookupRecords)
ChainPosClassRuleSetTable = SetTable[ChainPosClassRuleTable]
def parse_chain_pos_class_rule_set_table(f: BinaryIO) -> ChainPosClassRuleSetTable:
return parse_set_table(f, parse_chain_pos_class_rule_table)
@dataclass @dataclass
class ChainContextPosSubtable_Format_2(ChainContextPosSubtable): class ChainContextPosSubtable_Format_2(ChainContextPosSubtable):
coverage: CoverageTable coverage: CoverageTable
@ -3915,7 +3929,7 @@ class ChainContextPosSubtable_Format_2(ChainContextPosSubtable):
inputClassDef: ClassDefTable inputClassDef: ClassDefTable
lookaheadClassDef: ClassDefTable lookaheadClassDef: ClassDefTable
chainPosClassSetCount: int chainPosClassSetCount: int
chainPosClassSets: List[Optional[SetTable[ChainPosClassRuleTable]]] chainPosClassSets: List[Optional[ChainPosClassRuleSetTable]]
@dataclass @dataclass
class ChainContextPosSubtable_Format_3(ChainContextPosSubtable): class ChainContextPosSubtable_Format_3(ChainContextPosSubtable):
@ -4112,7 +4126,7 @@ def parse_GPOS_lookup_subtable(f: BinaryIO, lookupType: GPOSLookupType) -> GPOSL
chainPosRuleSetOffsets = [read_u16(f) for _ in range(chainPosRuleSetCount)] chainPosRuleSetOffsets = [read_u16(f) for _ in range(chainPosRuleSetCount)]
with SaveTell(f): with SaveTell(f):
coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table) coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table)
chainPosRuleSets = parse_at_offsets(f, start_tell, chainPosRuleSetOffsets, lambda f: parse_set_table(f, parse_chain_pos_rule_table)) chainPosRuleSets = parse_at_offsets(f, start_tell, chainPosRuleSetOffsets, parse_chain_pos_rule_set_table)
return ChainContextPosSubtable_Format_1(posFormat, coverage, chainPosRuleSetCount, chainPosRuleSets) return ChainContextPosSubtable_Format_1(posFormat, coverage, chainPosRuleSetCount, chainPosRuleSets)
case 2: case 2:
@ -4127,7 +4141,7 @@ def parse_GPOS_lookup_subtable(f: BinaryIO, lookupType: GPOSLookupType) -> GPOSL
backtrackClassDef = parse_at_offset(f, start_tell, backtrackClassDefOffset, parse_class_def_table) backtrackClassDef = parse_at_offset(f, start_tell, backtrackClassDefOffset, parse_class_def_table)
inputClassDef = parse_at_offset(f, start_tell, inputClassDefOffset, parse_class_def_table) inputClassDef = parse_at_offset(f, start_tell, inputClassDefOffset, parse_class_def_table)
lookaheadClassDef = parse_at_offset(f, start_tell, lookaheadClassDefOffset, parse_class_def_table) lookaheadClassDef = parse_at_offset(f, start_tell, lookaheadClassDefOffset, parse_class_def_table)
chainPosClassSets = parse_at_optional_offsets(f, start_tell, chainPosClassSetOffsets, lambda f: parse_set_table(f, parse_chain_pos_class_rule_table)) chainPosClassSets = parse_at_optional_offsets(f, start_tell, chainPosClassSetOffsets, parse_chain_pos_class_rule_set_table)
return ChainContextPosSubtable_Format_2(posFormat, coverage, backtrackClassDef, inputClassDef, lookaheadClassDef, chainPosClassSetCount, chainPosClassSets) return ChainContextPosSubtable_Format_2(posFormat, coverage, backtrackClassDef, inputClassDef, lookaheadClassDef, chainPosClassSetCount, chainPosClassSets)
case 3: case 3:
@ -4156,7 +4170,7 @@ def parse_GPOS_lookup_subtable(f: BinaryIO, lookupType: GPOSLookupType) -> GPOSL
match posFormat: match posFormat:
case 1: case 1:
extensionLookupType = parse_id(f, GPOSLookupType) extensionLookupType = read_id(f, GPOSLookupType)
assert extensionLookupType != GPOSLookupType.ExtensionPos, f"ExtensionPos subtable cannot reference another ExtensionPos subtable" assert extensionLookupType != GPOSLookupType.ExtensionPos, f"ExtensionPos subtable cannot reference another ExtensionPos subtable"
extensionOffset = read_u32(f) extensionOffset = read_u32(f)
with SaveTell(f): with SaveTell(f):
@ -4323,11 +4337,16 @@ def parse_ligature_table(f: BinaryIO) -> LigatureTable:
return LigatureTable(ligatureGlyph, componentCount, componentGlyphIDs) return LigatureTable(ligatureGlyph, componentCount, componentGlyphIDs)
LigatureSetTable = SetTable[LigatureTable]
def parse_ligature_set_table(f: BinaryIO) -> LigatureSetTable:
return parse_set_table(f, parse_ligature_table)
@dataclass @dataclass
class LigatureSubstSubtable_Format_1(LigatureSubstSubtable): class LigatureSubstSubtable_Format_1(LigatureSubstSubtable):
coverage: CoverageTable coverage: CoverageTable
ligatureSetCount: int ligatureSetCount: int
ligatureSets: List[SetTable[LigatureTable]] ligatureSets: List[LigatureSetTable]
# 5 # 5
@ -4350,11 +4369,16 @@ def parse_sub_rule_table(f: BinaryIO) -> SubRuleTable:
return SubRuleTable(glyphCount, substitutionCount, inputSequence, substLookupRecords) return SubRuleTable(glyphCount, substitutionCount, inputSequence, substLookupRecords)
SubRuleSetTable = SetTable[SubRuleTable]
def parse_sub_rule_set_table(f: BinaryIO) -> SubRuleSetTable:
return parse_set_table(f, parse_sub_rule_table)
@dataclass @dataclass
class ContextSubstSubtable_Format_1(ContextSubstSubtable): class ContextSubstSubtable_Format_1(ContextSubstSubtable):
coverage: CoverageTable coverage: CoverageTable
subRuleSetCount: int subRuleSetCount: int
subRuleSets: List[SetTable[SubRuleTable]] subRuleSets: List[SubRuleSetTable]
@dataclass @dataclass
class SubClassRuleTable(Table): class SubClassRuleTable(Table):
@ -4371,12 +4395,17 @@ def parse_sub_class_rule_table(f: BinaryIO) -> SubClassRuleTable:
return SubClassRuleTable(glyphCount, substitutionCount, inputSequence, substLookupRecords) return SubClassRuleTable(glyphCount, substitutionCount, inputSequence, substLookupRecords)
SubClassRuleSetTable = SetTable[SubClassRuleTable]
def parse_sub_class_rule_set_table(f: BinaryIO) -> SubClassRuleSetTable:
return parse_set_table(f, parse_sub_class_rule_table)
@dataclass @dataclass
class ContextSubstSubtable_Format_2(ContextSubstSubtable): class ContextSubstSubtable_Format_2(ContextSubstSubtable):
coverage: CoverageTable coverage: CoverageTable
classDef: ClassDefTable classDef: ClassDefTable
subClassSetCount: int subClassSetCount: int
subClassSets: List[Optional[SetTable[SubClassRuleTable]]] subClassSets: List[Optional[SubClassRuleSetTable]]
@dataclass @dataclass
class ContextSubstSubtable_Format_3(ContextSubstSubtable): class ContextSubstSubtable_Format_3(ContextSubstSubtable):
@ -4417,11 +4446,16 @@ def parse_chain_sub_rule_table(f: BinaryIO) -> ChainSubRuleTable:
return ChainSubRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, substitutionCount, substLookupRecords) return ChainSubRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, substitutionCount, substLookupRecords)
ChainSubRuleSetTable = SetTable[ChainSubRuleTable]
def parse_chain_sub_rule_set_table(f: BinaryIO) -> ChainSubRuleSetTable:
return parse_set_table(f, parse_chain_sub_rule_table)
@dataclass @dataclass
class ChainContextSubstSubtable_Format_1(ChainContextSubstSubtable): class ChainContextSubstSubtable_Format_1(ChainContextSubstSubtable):
coverage: CoverageTable coverage: CoverageTable
chainSubRuleSetCount: int chainSubRuleSetCount: int
chainSubRuleSets: List[SetTable[ChainSubRuleTable]] chainSubRuleSets: List[ChainSubRuleSetTable]
@dataclass @dataclass
class ChainSubClassRuleTable(Table): class ChainSubClassRuleTable(Table):
@ -4449,6 +4483,11 @@ def parse_chain_sub_class_rule_table(f: BinaryIO) -> ChainSubClassRuleTable:
return ChainSubClassRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, substitutionCount, substLookupRecords) return ChainSubClassRuleTable(backtrackGlyphCount, backtrackSequence, inputGlyphCount, inputSequence, lookaheadGlyphCount, lookAheadSequence, substitutionCount, substLookupRecords)
ChainSubClassRuleSetTable = SetTable[ChainSubClassRuleTable]
def parse_chain_sub_class_rule_set_table(f: BinaryIO) -> ChainSubClassRuleSetTable:
return parse_set_table(f, parse_chain_sub_class_rule_table)
@dataclass @dataclass
class ChainContextSubstSubtable_Format_2(ChainContextSubstSubtable): class ChainContextSubstSubtable_Format_2(ChainContextSubstSubtable):
coverage: CoverageTable coverage: CoverageTable
@ -4456,7 +4495,7 @@ class ChainContextSubstSubtable_Format_2(ChainContextSubstSubtable):
inputClassDef: ClassDefTable inputClassDef: ClassDefTable
lookaheadClassDef: ClassDefTable lookaheadClassDef: ClassDefTable
chainSubClassSetCount: int chainSubClassSetCount: int
chainSubClassSets: List[Optional[SetTable[ChainSubClassRuleTable]]] chainSubClassSets: List[Optional[ChainSubClassRuleSetTable]]
@dataclass @dataclass
class ChainContextSubstSubtable_Format_3(ChainContextSubstSubtable): class ChainContextSubstSubtable_Format_3(ChainContextSubstSubtable):
@ -4597,7 +4636,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
subRuleSetOffsets = [read_u16(f) for _ in range(subRuleSetCount)] subRuleSetOffsets = [read_u16(f) for _ in range(subRuleSetCount)]
with SaveTell(f): with SaveTell(f):
coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table) coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table)
subRuleSets = parse_at_offsets(f, start_tell, subRuleSetOffsets, lambda f: parse_set_table(f, parse_sub_rule_table)) subRuleSets = parse_at_offsets(f, start_tell, subRuleSetOffsets, parse_sub_rule_set_table)
return ContextSubstSubtable_Format_1(substFormat, coverage, subRuleSetCount, subRuleSets) return ContextSubstSubtable_Format_1(substFormat, coverage, subRuleSetCount, subRuleSets)
case 2: case 2:
@ -4608,7 +4647,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
with SaveTell(f): with SaveTell(f):
coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table) coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table)
classDef = parse_at_offset(f, start_tell, classDefOffset, parse_class_def_table) classDef = parse_at_offset(f, start_tell, classDefOffset, parse_class_def_table)
subClassSets = parse_at_optional_offsets(f, start_tell, subClassSetOffsets, lambda f: parse_set_table(f, parse_sub_class_rule_table)) subClassSets = parse_at_optional_offsets(f, start_tell, subClassSetOffsets, parse_sub_class_rule_set_table)
return ContextSubstSubtable_Format_2(substFormat, coverage, classDef, subClassSetCount, subClassSets) return ContextSubstSubtable_Format_2(substFormat, coverage, classDef, subClassSetCount, subClassSets)
case 3: case 3:
@ -4636,7 +4675,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
chainSubRuleSetOffsets = [read_u16(f) for _ in range(chainSubRuleSetCount)] chainSubRuleSetOffsets = [read_u16(f) for _ in range(chainSubRuleSetCount)]
with SaveTell(f): with SaveTell(f):
coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table) coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_table)
chainSubRuleSets = parse_at_offsets(f, start_tell, chainSubRuleSetOffsets, lambda f: parse_set_table(f, parse_chain_sub_rule_table)) chainSubRuleSets = parse_at_offsets(f, start_tell, chainSubRuleSetOffsets, parse_chain_sub_rule_set_table)
return ChainContextSubstSubtable_Format_1(substFormat, coverage, chainSubRuleSetCount, chainSubRuleSets) return ChainContextSubstSubtable_Format_1(substFormat, coverage, chainSubRuleSetCount, chainSubRuleSets)
case 2: case 2:
@ -4651,7 +4690,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
backtrackClassDef = parse_at_offset(f, start_tell, backtrackClassDefOffset, parse_class_def_table) backtrackClassDef = parse_at_offset(f, start_tell, backtrackClassDefOffset, parse_class_def_table)
inputClassDef = parse_at_offset(f, start_tell, inputClassDefOffset, parse_class_def_table) inputClassDef = parse_at_offset(f, start_tell, inputClassDefOffset, parse_class_def_table)
lookaheadClassDef = parse_at_offset(f, start_tell, lookaheadClassDefOffset, parse_class_def_table) lookaheadClassDef = parse_at_offset(f, start_tell, lookaheadClassDefOffset, parse_class_def_table)
chainSubClassSets = parse_at_optional_offsets(f, start_tell, chainSubClassSetOffsets, lambda f: parse_set_table(f, parse_chain_sub_class_rule_table)) chainSubClassSets = parse_at_optional_offsets(f, start_tell, chainSubClassSetOffsets, parse_chain_sub_class_rule_set_table)
return ChainContextSubstSubtable_Format_2(substFormat, coverage, backtrackClassDef, inputClassDef, lookaheadClassDef, chainSubClassSetCount, chainSubClassSets) return ChainContextSubstSubtable_Format_2(substFormat, coverage, backtrackClassDef, inputClassDef, lookaheadClassDef, chainSubClassSetCount, chainSubClassSets)
case 3: case 3:
@ -4685,7 +4724,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
match substFormat: match substFormat:
case 1: case 1:
extensionLookupType = parse_id(f, GSUBLookupType) extensionLookupType = read_id(f, GSUBLookupType)
extensionOffset = read_u32(f) extensionOffset = read_u32(f)
with SaveTell(f): with SaveTell(f):
extension = parse_at_offset(f, start_tell, extensionOffset, lambda f: parse_GSUB_lookup_subtable(f, extensionLookupType)) extension = parse_at_offset(f, start_tell, extensionOffset, lambda f: parse_GSUB_lookup_subtable(f, extensionLookupType))
@ -5370,7 +5409,7 @@ def is_valid_possible_foundry_defined_axis_tag(tag: str) -> bool:
return len(tag) == 4 and is_upper(tag[0]) and all(map(lambda s: is_upper(s) or is_digit(s), tag[1:])) return len(tag) == 4 and is_upper(tag[0]) and all(map(lambda s: is_upper(s) or is_digit(s), tag[1:]))
def parse_axis_tag(f: BinaryIO) -> AxisTag: def parse_axis_tag(f: BinaryIO) -> AxisTag:
return parse_tag_with_conditions(f, (is_valid_possible_registed_axis_tag, RegisteredAxisTag), (is_valid_possible_foundry_defined_axis_tag, FoundryDefinedAxisTag), umbrellaTagCls=AxisTag) return read_tag_with_conditions(f, (is_valid_possible_registed_axis_tag, RegisteredAxisTag), (is_valid_possible_foundry_defined_axis_tag, FoundryDefinedAxisTag), umbrellaTagCls=AxisTag)
@dataclass @dataclass
class AxisValueMapRecord: class AxisValueMapRecord: