11ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import 230e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import * 3d4d151390d1288f8d2df30f6dfa26a309c7334dajvrfrom fontTools.misc.textTools import safeEval 43fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbodfrom fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi 52b06aaa2a6bcd363c25fb0c43f6bb906906594bdBehdad Esfahbodfrom .otBase import ValueRecordFactory 6d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 7d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 864b5c80e80444a124da335e8d4d208bffcf2737bjvrdef buildConverters(tableSpec, tableNamespace): 964b5c80e80444a124da335e8d4d208bffcf2737bjvr """Given a table spec from otData.py, build a converter object for each 1064b5c80e80444a124da335e8d4d208bffcf2737bjvr field of the table. This is called for each table in otData.py, and 1164b5c80e80444a124da335e8d4d208bffcf2737bjvr the results are assigned to the corresponding class in otTables.py.""" 12d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converters = [] 13d4d151390d1288f8d2df30f6dfa26a309c7334dajvr convertersByName = {} 146b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod for tp, name, repeat, aux, descr in tableSpec: 15d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod tableName = name 16d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if name.startswith("ValueFormat"): 17d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 18d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = ValueFormat 196ed2eb409231a7fe3e0c2a135f9a89796206f639Behdad Esfahbod elif name.endswith("Count") or name.endswith("LookupType"): 20d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 216ed2eb409231a7fe3e0c2a135f9a89796206f639Behdad Esfahbod converterClass = ComputedUShort 22d4d151390d1288f8d2df30f6dfa26a309c7334dajvr elif name == "SubTable": 23d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = SubTable 24823f8cd15f16bb9dc3991c2672f16dd90579711bjvr elif name == "ExtSubTable": 25823f8cd15f16bb9dc3991c2672f16dd90579711bjvr converterClass = ExtSubTable 269e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod elif name == "FeatureParams": 279e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod converterClass = FeatureParams 28d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 29d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod if not tp in converterMapping: 30d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod tableName = tp 31d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod converterClass = Struct 32d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod else: 33d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod converterClass = converterMapping[tp] 34d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod tableClass = tableNamespace.get(tableName) 356b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod conv = converterClass(name, repeat, aux, tableClass) 36823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if name in ["SubTable", "ExtSubTable"]: 37d4d151390d1288f8d2df30f6dfa26a309c7334dajvr conv.lookupTypes = tableNamespace['lookupTypes'] 38d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # also create reverse mapping 39d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for t in conv.lookupTypes.values(): 40d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for cls in t.values(): 416b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod convertersByName[cls.__name__] = Table(name, repeat, aux, cls) 429e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod if name == "FeatureParams": 439e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod conv.featureParamTypes = tableNamespace['featureParamTypes'] 449e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod conv.defaultFeatureParams = tableNamespace['FeatureParams'] 459e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod for cls in conv.featureParamTypes.values(): 469e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod convertersByName[cls.__name__] = Table(name, repeat, aux, cls) 47d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converters.append(conv) 48d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod assert name not in convertersByName, name 49d4d151390d1288f8d2df30f6dfa26a309c7334dajvr convertersByName[name] = conv 50d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return converters, convertersByName 51d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 52d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 53d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass BaseConverter(object): 54d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 5564b5c80e80444a124da335e8d4d208bffcf2737bjvr """Base class for converter objects. Apart from the constructor, this 5664b5c80e80444a124da335e8d4d208bffcf2737bjvr is an abstract class.""" 5764b5c80e80444a124da335e8d4d208bffcf2737bjvr 586b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod def __init__(self, name, repeat, aux, tableClass): 59d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.name = name 60d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.repeat = repeat 616b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod self.aux = aux 62d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.tableClass = tableClass 63d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.isCount = name.endswith("Count") 645fec22bfcd53fe9a10fa066e17d0a0d18cf2d74aBehdad Esfahbod self.isLookupType = name.endswith("LookupType") 659e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag"] 66d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 67078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 6864b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from the reader.""" 69cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise NotImplementedError(self) 70d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 71078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 7264b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to the writer.""" 73cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise NotImplementedError(self) 74d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 7564b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlRead(self, attrs, content, font): 7664b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from XML.""" 77cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise NotImplementedError(self) 78d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 7964b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 8064b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to XML.""" 81cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod raise NotImplementedError(self) 82d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 83d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 84d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SimpleValue(BaseConverter): 85d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 86d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 87d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 88d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 89d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return attrs["value"] 90d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 91d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass IntValue(SimpleValue): 92d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 93ffc3cfeed12e67b383ed5f540d05cab01b33bb77Behdad Esfahbod return int(attrs["value"], 0) 94d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 95d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Long(IntValue): 96078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 97d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readLong() 98078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 99d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeLong(value) 100d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 101a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbodclass Version(BaseConverter): 102078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 103a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = reader.readLong() 104a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod assert (value >> 16) == 1, "Unsupported version 0x%08x" % value 1053fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod return fi2fl(value, 16) 106078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 107a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value < 0x10000: 1083fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod value = fl2fi(value, 16) 109a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = int(round(value)) 110a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod assert (value >> 16) == 1, "Unsupported version 0x%08x" % value 111a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod writer.writeLong(value) 1127007a0854548f744c44bb9c35380efcba7894bfbjvr def xmlRead(self, attrs, content, font): 113a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = attrs["value"] 114a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = float(int(value, 0)) if value.startswith("0") else float(value) 115a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value >= 0x10000: 1163fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod value = fi2fl(value, 16) 117a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod return value 118a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod def xmlWrite(self, xmlWriter, font, value, name, attrs): 119a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value >= 0x10000: 1203fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod value = fi2fl(value, 16) 121a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value % 1 != 0: 122a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod # Write as hex 1233fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod value = "0x%08x" % fl2fi(value, 16) 124a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod xmlWriter.simpletag(name, attrs + [("value", value)]) 125a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod xmlWriter.newline() 126b776a882ee55fff8c39543f352c528bb5d338177jvr 127d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Short(IntValue): 128078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 129d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readShort() 130078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 131d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeShort(value) 132d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 133d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass UShort(IntValue): 134078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 135d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readUShort() 136078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 137d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(value) 138d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 1399e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbodclass UInt24(IntValue): 1409e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod def read(self, reader, font, tableDict): 1419e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod return reader.readUInt24() 1429e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 1439e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod writer.writeUInt24(value) 1449e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod 1456ed2eb409231a7fe3e0c2a135f9a89796206f639Behdad Esfahbodclass ComputedUShort(UShort): 146d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 147d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.comment("%s=%s" % (name, value)) 148d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 149d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 150d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Tag(SimpleValue): 151078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 152d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readTag() 153078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 154d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeTag(value) 155d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 156d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass GlyphID(SimpleValue): 157078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 158823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = reader.readUShort() 159823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphName(value) 160823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return value 161823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 162078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 163823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphID(value) 164823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeUShort(value) 165d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 1663ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbodclass FloatValue(SimpleValue): 1673ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod def xmlRead(self, attrs, content, font): 1683ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod return float(attrs["value"]) 1693ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod 1703ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbodclass DeciPoints(FloatValue): 1713ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod def read(self, reader, font, tableDict): 1723ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod value = reader.readUShort() 17332c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod return value / 10 1743ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod 1753ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 1763ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod writer.writeUShort(int(round(value * 10))) 177b776a882ee55fff8c39543f352c528bb5d338177jvr 178d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Struct(BaseConverter): 179d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 180078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 181d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 182078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod table.decompile(reader, font) 183d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 184d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 185078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 186078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod value.compile(writer, font) 187d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 188d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 189d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 190cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod if attrs: 191cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod # If there are attributes (probably index), then 192cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod # don't drop this even if it's NULL. It will mess 193cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod # up the array indices of the containing element. 194cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod xmlWriter.simpletag(name, attrs + [("empty", True)]) 195cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod xmlWriter.newline() 196cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod else: 197cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod pass # NULL table, ignore 198d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 199d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod value.toXML(xmlWriter, font, attrs, name=name) 200d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 201d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 202d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 203cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod if attrs.get("empty"): 204cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod return None 205d4d151390d1288f8d2df30f6dfa26a309c7334dajvr Format = attrs.get("Format") 206d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if Format is not None: 207d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table.Format = int(Format) 208d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for element in content: 209b774f9f684c5a0f91f5fa177c9a461968789123fBehdad Esfahbod if isinstance(element, tuple): 21052966bb14409b558dc46b52d34953fbde7dc1bcajvr name, attrs, content = element 2113a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod table.fromXML(name, attrs, content, font) 21252966bb14409b558dc46b52d34953fbde7dc1bcajvr else: 21352966bb14409b558dc46b52d34953fbde7dc1bcajvr pass 214d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 215d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 216d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 217d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Table(Struct): 218fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod 219d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod longOffset = False 220d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 221fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod def readOffset(self, reader): 222fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod return reader.readUShort() 223fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod 224fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod def writeNullOffset(self, writer): 225e0c2e8e2af82f79c25026bb8e603ca5bd560c552Behdad Esfahbod if self.longOffset: 226fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod writer.writeULong(0) 227fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod else: 228fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod writer.writeUShort(0) 229d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 2307ef23a85ae49039ae491e337be173caba7bdd534Behdad Esfahbod def read(self, reader, font, tableDict): 231fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod offset = self.readOffset(reader) 232d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset == 0: 233d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 234d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset <= 3: 235d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # XXX hack to work around buggy pala.ttf 2363ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod print("*** Warning: offset is not 0, yet suspiciously low (%s). table: %s" \ 2373ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod % (offset, self.tableClass.__name__)) 238d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 239d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 240dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod reader = reader.getSubReader(offset) 241dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod if font.lazy: 242dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod table.reader = reader 243dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod table.font = font 244dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod else: 245dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod table.decompile(reader, font) 246d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 247d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 248078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 249d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 250fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod self.writeNullOffset(writer) 251d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 252d4d151390d1288f8d2df30f6dfa26a309c7334dajvr subWriter = writer.getSubWriter() 253e0c2e8e2af82f79c25026bb8e603ca5bd560c552Behdad Esfahbod subWriter.longOffset = self.longOffset 254823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.name = self.name 255823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if repeatIndex is not None: 256823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.repeatIndex = repeatIndex 257d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeSubTable(subWriter) 258078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod value.compile(subWriter, font) 259d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 260d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass LTable(Table): 261d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 262d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod longOffset = True 263d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 264d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod def readOffset(self, reader): 265d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod return reader.readULong() 266d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 267d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 268d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SubTable(Table): 269d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def getConverter(self, tableType, lookupType): 270fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod tableClass = self.lookupTypes[tableType][lookupType] 2716b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod return self.__class__(self.name, self.repeat, self.aux, tableClass) 272823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 273823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 274d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass ExtSubTable(LTable, SubTable): 275823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 276078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 277823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer. 278fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod Table.write(self, writer, font, tableDict, value, repeatIndex) 279d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 2809e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbodclass FeatureParams(Table): 2819e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod def getConverter(self, featureTag): 2829e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod tableClass = self.featureParamTypes.get(featureTag, self.defaultFeatureParams) 2839e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod return self.__class__(self.name, self.repeat, self.aux, tableClass) 2849e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod 285d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 286d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueFormat(IntValue): 2876b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod def __init__(self, name, repeat, aux, tableClass): 2886b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod BaseConverter.__init__(self, name, repeat, aux, tableClass) 28979f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod self.which = "ValueFormat" + ("2" if name[-1] == "2" else "1") 290078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 291d4d151390d1288f8d2df30f6dfa26a309c7334dajvr format = reader.readUShort() 29279f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod reader[self.which] = ValueRecordFactory(format) 293d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return format 294078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, format, repeatIndex=None): 295d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(format) 29679f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod writer[self.which] = ValueRecordFactory(format) 297d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 298b776a882ee55fff8c39543f352c528bb5d338177jvr 299d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueRecord(ValueFormat): 300078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 30179f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod return reader[self.which].readValueRecord(reader, font) 302078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 30379f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod writer[self.which].writeValueRecord(writer, font, value) 304d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 305d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 306d4d151390d1288f8d2df30f6dfa26a309c7334dajvr pass # NULL table, ignore 307d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 308d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.toXML(xmlWriter, font, self.name, attrs) 309d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 3102b06aaa2a6bcd363c25fb0c43f6bb906906594bdBehdad Esfahbod from .otBase import ValueRecord 311d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = ValueRecord() 3123a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod value.fromXML(None, attrs, content, font) 313d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return value 314d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 315d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 316d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass DeltaValue(BaseConverter): 317d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 318078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 3192edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod StartSize = tableDict["StartSize"] 3202edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod EndSize = tableDict["EndSize"] 3212edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod DeltaFormat = tableDict["DeltaFormat"] 322d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 323d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 324d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 325d4d151390d1288f8d2df30f6dfa26a309c7334dajvr minusOffset = 1 << nBits 326d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 327d4d151390d1288f8d2df30f6dfa26a309c7334dajvr signMask = 1 << (nBits - 1) 328d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 329d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue = [] 330d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 0 331d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for i in range(nItems): 332d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 333d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = reader.readUShort(), 16 334d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 335d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = (tmp >> shift) & mask 336d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value & signMask: 337d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = value - minusOffset 338d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue.append(value) 339d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return DeltaValue 340d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 341078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 3422edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod StartSize = tableDict["StartSize"] 3432edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod EndSize = tableDict["EndSize"] 3442edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod DeltaFormat = tableDict["DeltaFormat"] 3456f9b64f2966d18cccad3fcf6e03f44f208dbc2a4Behdad Esfahbod DeltaValue = value 346d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 347d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 348d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 349d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert len(DeltaValue) == nItems 350d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 351d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 352d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 353d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for value in DeltaValue: 354d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 355d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp = tmp | ((value & mask) << shift) 356d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 357d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 358d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 359180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod if shift != 16: 360d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 361d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 362d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 363d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 364d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 365d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 366d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 367d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return safeEval(attrs["value"]) 368d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 369d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 370d4d151390d1288f8d2df30f6dfa26a309c7334dajvrconverterMapping = { 371d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # type class 372d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "int16": Short, 373d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "uint16": UShort, 3749e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod "uint24": UInt24, 375a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod "Version": Version, 376d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Tag": Tag, 377d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "GlyphID": GlyphID, 3783ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod "DeciPoints": DeciPoints, 379d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "struct": Struct, 380d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Offset": Table, 381d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod "LOffset": LTable, 382d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "ValueRecord": ValueRecord, 3837d130307e6e6094e40a841a3c41fc74b203b7e8eBehdad Esfahbod "DeltaValue": DeltaValue, 384d4d151390d1288f8d2df30f6dfa26a309c7334dajvr} 385d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 386