[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 io import BytesIO
from math import floor, log2
from typing import Callable, Generic, List, Optional, Tuple, TypeVar, BinaryIO
from typing_extensions import Self
from types import TracebackType
from typing import Callable, Generic, List, Optional, Tuple, Type, TypeVar, BinaryIO, Self
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
@ -28,7 +28,7 @@ def read_long_datetime(f: BinaryIO) -> datetime:
Tag_ = TypeVar('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)
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:
@ -38,14 +38,14 @@ def parse_tag_with_conditions(f: BinaryIO, *conditions: Tuple[Callable[[str], bo
else:
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, ...
"""
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_:
return parse_tag_cascading(f, tagCls, umbrellaTagCls=tagCls, strict=strict)
def read_tag(f: BinaryIO, tagCls: SomeTag[Tag_], *, strict:bool=True) -> Tag_:
return read_tag_from_tags(f, tagCls, umbrellaTagCls=tagCls, strict=strict)
ID_ = TypeVar('ID_')
SomeID = Callable[[int], ID_]
@ -53,7 +53,7 @@ SomeID = Callable[[int], ID_]
T = TypeVar('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"
id = reader(f)
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
assert False, f"Invalid {umbrellaIdCls.__name__}: {id}"
def parse_id(f: BinaryIO, idCls: SomeID[ID_], *, reader: Parser[int]=read_u16) -> ID_:
return parse_id_ranges(f, (None, idCls), umbrellaIdCls=idCls, reader=reader)
def read_id(f: BinaryIO, idCls: SomeID[ID_], *, reader: Parser[int]=read_u16) -> ID_:
return read_id_from_ranges(f, (None, idCls), umbrellaIdCls=idCls, reader=reader)
class SaveTell:
def __init__(self, f: BinaryIO):
self.f = f
def __enter__(self):
def __enter__(self) -> int:
self.tell = self.f.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)
# 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
class SetTable(Table, Generic[SomeTable]):
count: int
elements: List[SomeTable]
tableCount: int
tables: List[SomeTable]
def parse_set_table(f: BinaryIO, parser: Parser[SomeTable], *, offset_reader: Parser[int]=read_u16) -> SetTable[SomeTable]:
start_tell = f.tell()
@ -237,6 +237,9 @@ class TableTag(Enum):
def __str__(self) -> str: return self._value_
def parse_table_tag(f: BinaryIO) -> TableTag:
return read_tag(f, TableTag)
@dataclass
class TableDirectoryEntry:
tableTag: TableTag
@ -245,7 +248,7 @@ class TableDirectoryEntry:
length: int
def parse_table_directory_entry(f: BinaryIO) -> TableDirectoryEntry:
tableTag = parse_tag(f, TableTag)
tableTag = parse_table_tag(f)
checkSum = read_u32(f)
offset = read_u32(f)
length = read_u32(f)
@ -435,12 +438,12 @@ class CmapSubtable_Format_12(CmapSubtable):
groups: List[SequentialMapGroup]
@dataclass
class UnicodeRangeRecord:
class UnicodeRangeRecord(Record):
startUnicodeValue: int
additionalCount: int
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:
startUnicodeValue = read_u24(f)
@ -461,7 +464,7 @@ def parse_default_UVS_table(f: BinaryIO) -> DefaultUVSTable:
return DefaultUVSTable(numUnicodeValueRanges, ranges)
@dataclass
class UVSMappingRecord:
class UVSMappingRecord(Record):
unicodeValue: int
glyphID: int
@ -483,7 +486,7 @@ def parse_non_default_UVS_table(f: BinaryIO) -> NonDefaultUVSTable:
return NonDefaultUVSTable(numUVSMappings, uvsMappings)
@dataclass
class VariationSelectorRecord:
class VariationSelectorRecord(Record):
varSelector: int
defaultUVS: Optional[DefaultUVSTable]
nonDefaultUVS: Optional[NonDefaultUVSTable]
@ -637,8 +640,8 @@ def encoding_ID_cls_from_platform_ID(platformID: PlatformID) -> Callable[[int],
assert False, platformID
def parse_encoding_ID(f: BinaryIO, platformID: PlatformID):
return parse_id(f, encoding_ID_cls_from_platform_ID(platformID))
def parse_encoding_ID(f: BinaryIO, platformID: PlatformID) -> EncodingID:
return read_id(f, encoding_ID_cls_from_platform_ID(platformID))
def parse_string_with_encoding_ID(f: BinaryIO, length: int, encodingID: EncodingID) -> str:
bytes = f.read(length)
@ -653,13 +656,13 @@ def parse_string_with_encoding_ID(f: BinaryIO, length: int, encodingID: Encoding
assert False, encodingID
@dataclass
class EncodingRecord:
class EncodingRecord(Record):
platformID: PlatformID
encodingID: EncodingID
subtable: CmapSubtable
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)
subtableOffset = read_u32(f)
with SaveTell(f):
@ -1086,7 +1089,7 @@ def languageID_cls_from_platform_ID(platformID: PlatformID) -> Callable[[int], L
assert False, platformID
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
@ -1123,7 +1126,7 @@ class FontSpecificNameID(NameID):
nameID: int
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
class NameRecord:
@ -1135,7 +1138,7 @@ class NameRecord:
string: str
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)
languageID = parse_language_ID(f, platformID)
nameID = parse_name_ID(f)
@ -1178,6 +1181,9 @@ def parse_name_table(f: BinaryIO, length: int) -> NameTable:
class VendorTag:
achVendID: str
def parse_vendor_tag(f: BinaryIO) -> VendorTag:
return read_tag(f, VendorTag, strict=False)
@dataclass
class OS2Table(Table, ABD):
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)]
panose = (panose0, panose1, panose2, panose3, panose4, panose5, panose6, panose7, panose8, panose9)
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)
usFirstCharIndex, usLastCharIndex = read_u16(f), read_u16(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 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
class LangSysRecord:
@ -2508,7 +2514,7 @@ class ScriptRecord:
script: ScriptTable
def parse_script_record(f: BinaryIO, start_tell:int) -> ScriptRecord:
tag = parse_tag(f, ScriptTag)
tag = read_tag(f, ScriptTag)
scriptOffset = read_u16(f)
with SaveTell(f):
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
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
class FeatureParamsTable(Table, ABD): pass
@ -2711,7 +2717,7 @@ class SizeFeatureParamsTable(FeatureParamsTable):
subfamily_nameID: Optional[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:
case CvXXFeatureTag(num=_):
format = read_u16(f)
@ -2840,7 +2846,7 @@ def parse_lookup_table(f: BinaryIO, _lookupType: Callable[[int], LookupType], lo
start_tell = f.tell()
lookupType = parse_id(f, _lookupType)
lookupType = read_id(f, _lookupType)
lookupFlag = parse_lookup_flag(f)
subTableCount = read_u16(f)
subTableOffsets = [read_u16(f) for _ in range(subTableCount)]
@ -2893,20 +2899,18 @@ def parse_condition_table(f: BinaryIO) -> ConditionTable:
assert False, format
@dataclass
class ConditionSetTable(Table):
conditionCount: int
conditions: List[ConditionTable]
ConditionSetTable = SetTable[ConditionTable]
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)
conditionOffsets = [read_u32(f) for _ in range(conditionCount)]
with SaveTell(f):
conditions = parse_at_offsets(f, start_tell, conditionOffsets, parse_condition_table)
# conditionCount = read_u16(f)
# conditionOffsets = [read_u32(f) for _ in range(conditionCount)]
# with SaveTell(f):
# conditions = parse_at_offsets(f, start_tell, conditionOffsets, parse_condition_table)
return ConditionSetTable(conditionCount, conditions)
# return ConditionSetTable(conditionCount, conditions)
@dataclass
class FeatureTableSubstitutionRecord:
@ -2949,14 +2953,14 @@ def parse_feature_table_substitution_table(f: BinaryIO, featureList: FeatureList
@dataclass
class FeatureVariationRecord:
conditionSet: SetTable[ConditionTable]
conditionSet: ConditionSetTable
featureTableSubstitution: FeatureTableSubstitutionTable
def parse_feature_variation_record(f: BinaryIO, start_tell: int, featureList: FeatureListTable) -> FeatureVariationRecord:
conditionSetOffset = read_u32(f)
featureTableSubstitutionOffset = read_u32(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))
return FeatureVariationRecord(conditionSet, featureTableSubstitution)
@ -2997,7 +3001,7 @@ class CoverageTable_Format_1(CoverageTable):
glyphArray: List[int]
@dataclass
class RangeRecord:
class RangeRecord(Record):
startGlyphID: int
endGlyphID: int
startCoverageIndex: int
@ -3045,7 +3049,7 @@ class ClassRangeRecord:
endGlyphID: int
classValue: int
def parse_class_range_record(f) -> ClassRangeRecord:
def parse_class_range_record(f: BinaryIO) -> ClassRangeRecord:
startGlyphID = read_u16(f)
endGlyphID = 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 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)
assert valueFormat & 0xFF00 == 0, "Reserved"
@ -3142,7 +3146,7 @@ class BaseTagListTable(Table):
def parse_base_tag_list_table(f: BinaryIO) -> BaseTagListTable:
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)
@ -3225,7 +3229,7 @@ class BaseScriptRecord:
baseScript: BaseScriptTable
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)
with SaveTell(f):
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)
ChainPosRuleSetTable = SetTable[ChainPosRuleTable]
def parse_chain_pos_rule_set_table(f: BinaryIO) -> ChainPosRuleSetTable:
return parse_set_table(f, parse_chain_pos_rule_table)
@dataclass
class ChainContextPosSubtable_Format_1(ChainContextPosSubtable):
coverage: CoverageTable
chainPosRuleSetCount: int
chainPosRuleSets: List[SetTable[ChainPosRuleTable]]
chainPosRuleSets: List[ChainPosRuleSetTable]
@dataclass
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)
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
class ChainContextPosSubtable_Format_2(ChainContextPosSubtable):
coverage: CoverageTable
@ -3915,7 +3929,7 @@ class ChainContextPosSubtable_Format_2(ChainContextPosSubtable):
inputClassDef: ClassDefTable
lookaheadClassDef: ClassDefTable
chainPosClassSetCount: int
chainPosClassSets: List[Optional[SetTable[ChainPosClassRuleTable]]]
chainPosClassSets: List[Optional[ChainPosClassRuleSetTable]]
@dataclass
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)]
with SaveTell(f):
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)
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)
inputClassDef = parse_at_offset(f, start_tell, inputClassDefOffset, 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)
case 3:
@ -4156,7 +4170,7 @@ def parse_GPOS_lookup_subtable(f: BinaryIO, lookupType: GPOSLookupType) -> GPOSL
match posFormat:
case 1:
extensionLookupType = parse_id(f, GPOSLookupType)
extensionLookupType = read_id(f, GPOSLookupType)
assert extensionLookupType != GPOSLookupType.ExtensionPos, f"ExtensionPos subtable cannot reference another ExtensionPos subtable"
extensionOffset = read_u32(f)
with SaveTell(f):
@ -4323,11 +4337,16 @@ def parse_ligature_table(f: BinaryIO) -> LigatureTable:
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
class LigatureSubstSubtable_Format_1(LigatureSubstSubtable):
coverage: CoverageTable
ligatureSetCount: int
ligatureSets: List[SetTable[LigatureTable]]
ligatureSets: List[LigatureSetTable]
# 5
@ -4350,11 +4369,16 @@ def parse_sub_rule_table(f: BinaryIO) -> SubRuleTable:
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
class ContextSubstSubtable_Format_1(ContextSubstSubtable):
coverage: CoverageTable
subRuleSetCount: int
subRuleSets: List[SetTable[SubRuleTable]]
subRuleSets: List[SubRuleSetTable]
@dataclass
class SubClassRuleTable(Table):
@ -4371,12 +4395,17 @@ def parse_sub_class_rule_table(f: BinaryIO) -> SubClassRuleTable:
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
class ContextSubstSubtable_Format_2(ContextSubstSubtable):
coverage: CoverageTable
classDef: ClassDefTable
subClassSetCount: int
subClassSets: List[Optional[SetTable[SubClassRuleTable]]]
subClassSets: List[Optional[SubClassRuleSetTable]]
@dataclass
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)
ChainSubRuleSetTable = SetTable[ChainSubRuleTable]
def parse_chain_sub_rule_set_table(f: BinaryIO) -> ChainSubRuleSetTable:
return parse_set_table(f, parse_chain_sub_rule_table)
@dataclass
class ChainContextSubstSubtable_Format_1(ChainContextSubstSubtable):
coverage: CoverageTable
chainSubRuleSetCount: int
chainSubRuleSets: List[SetTable[ChainSubRuleTable]]
chainSubRuleSets: List[ChainSubRuleSetTable]
@dataclass
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)
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
class ChainContextSubstSubtable_Format_2(ChainContextSubstSubtable):
coverage: CoverageTable
@ -4456,7 +4495,7 @@ class ChainContextSubstSubtable_Format_2(ChainContextSubstSubtable):
inputClassDef: ClassDefTable
lookaheadClassDef: ClassDefTable
chainSubClassSetCount: int
chainSubClassSets: List[Optional[SetTable[ChainSubClassRuleTable]]]
chainSubClassSets: List[Optional[ChainSubClassRuleSetTable]]
@dataclass
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)]
with SaveTell(f):
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)
case 2:
@ -4608,7 +4647,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
with SaveTell(f):
coverage = parse_at_offset(f, start_tell, coverageOffset, parse_coverage_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)
case 3:
@ -4636,7 +4675,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
chainSubRuleSetOffsets = [read_u16(f) for _ in range(chainSubRuleSetCount)]
with SaveTell(f):
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)
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)
inputClassDef = parse_at_offset(f, start_tell, inputClassDefOffset, 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)
case 3:
@ -4685,7 +4724,7 @@ def parse_GSUB_lookup_subtable(f: BinaryIO, lookupType: GSUBLookupType) -> GSUBL
match substFormat:
case 1:
extensionLookupType = parse_id(f, GSUBLookupType)
extensionLookupType = read_id(f, GSUBLookupType)
extensionOffset = read_u32(f)
with SaveTell(f):
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:]))
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
class AxisValueMapRecord: