otConverters.py revision ee27eb8517ee53594a6232d110e17403a37ff2d9
1d4d151390d1288f8d2df30f6dfa26a309c7334dajvrfrom types import TupleType 2d4d151390d1288f8d2df30f6dfa26a309c7334dajvrfrom fontTools.misc.textTools import safeEval 3d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 4d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 564b5c80e80444a124da335e8d4d208bffcf2737bjvrdef buildConverters(tableSpec, tableNamespace): 664b5c80e80444a124da335e8d4d208bffcf2737bjvr """Given a table spec from otData.py, build a converter object for each 764b5c80e80444a124da335e8d4d208bffcf2737bjvr field of the table. This is called for each table in otData.py, and 864b5c80e80444a124da335e8d4d208bffcf2737bjvr the results are assigned to the corresponding class in otTables.py.""" 9d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converters = [] 10d4d151390d1288f8d2df30f6dfa26a309c7334dajvr convertersByName = {} 11d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for tp, name, repeat, repeatOffset, descr in tableSpec: 12d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if name.startswith("ValueFormat"): 13d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 14d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = ValueFormat 15d4d151390d1288f8d2df30f6dfa26a309c7334dajvr elif name.endswith("Count"): 16d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 17d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = Count 18d4d151390d1288f8d2df30f6dfa26a309c7334dajvr elif name == "SubTable": 19d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = SubTable 20823f8cd15f16bb9dc3991c2672f16dd90579711bjvr elif name == "ExtSubTable": 21823f8cd15f16bb9dc3991c2672f16dd90579711bjvr converterClass = ExtSubTable 22d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 23d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = converterMapping[tp] 24d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tableClass = tableNamespace.get(name) 25d4d151390d1288f8d2df30f6dfa26a309c7334dajvr conv = converterClass(name, repeat, repeatOffset, tableClass) 26823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if name in ["SubTable", "ExtSubTable"]: 27d4d151390d1288f8d2df30f6dfa26a309c7334dajvr conv.lookupTypes = tableNamespace['lookupTypes'] 28d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # also create reverse mapping 29d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for t in conv.lookupTypes.values(): 30d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for cls in t.values(): 31823f8cd15f16bb9dc3991c2672f16dd90579711bjvr convertersByName[cls.__name__] = Table(name, repeat, repeatOffset, cls) 32d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converters.append(conv) 33d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert not convertersByName.has_key(name) 34d4d151390d1288f8d2df30f6dfa26a309c7334dajvr convertersByName[name] = conv 35d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return converters, convertersByName 36d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 37d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 38d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass BaseConverter: 39d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 4064b5c80e80444a124da335e8d4d208bffcf2737bjvr """Base class for converter objects. Apart from the constructor, this 4164b5c80e80444a124da335e8d4d208bffcf2737bjvr is an abstract class.""" 4264b5c80e80444a124da335e8d4d208bffcf2737bjvr 43d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def __init__(self, name, repeat, repeatOffset, tableClass): 44d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.name = name 45d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.repeat = repeat 46d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.repeatOffset = repeatOffset 47d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.tableClass = tableClass 48d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.isCount = name.endswith("Count") 49ee27eb8517ee53594a6232d110e17403a37ff2d9Behdad Esfahbod self.isPropagatedCount = name in ["ClassCount", "Class2Count"] 50d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 51078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 5264b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from the reader.""" 53d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 54d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 55078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 5664b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to the writer.""" 57d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 58d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 5964b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlRead(self, attrs, content, font): 6064b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from XML.""" 61d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 62d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 6364b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 6464b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to XML.""" 65d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 66d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 67d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 68d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SimpleValue(BaseConverter): 69d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 70d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 71d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 72d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 73d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return attrs["value"] 74d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 75d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass IntValue(SimpleValue): 76d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 77ffc3cfeed12e67b383ed5f540d05cab01b33bb77Behdad Esfahbod return int(attrs["value"], 0) 78d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 79d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Long(IntValue): 80078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 81d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readLong() 82078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 83d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeLong(value) 84d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 85a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbodclass Version(BaseConverter): 86078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 87a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = reader.readLong() 88a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod assert (value >> 16) == 1, "Unsupported version 0x%08x" % value 89a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod return float(value) / 0x10000 90078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 91a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value < 0x10000: 92a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value *= 0x10000 93a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = int(round(value)) 94a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod assert (value >> 16) == 1, "Unsupported version 0x%08x" % value 95a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod writer.writeLong(value) 967007a0854548f744c44bb9c35380efcba7894bfbjvr def xmlRead(self, attrs, content, font): 97a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = attrs["value"] 98a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = float(int(value, 0)) if value.startswith("0") else float(value) 99a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value >= 0x10000: 100a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = float(value) / 0x10000 101a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod return value 102a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod def xmlWrite(self, xmlWriter, font, value, name, attrs): 103a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value >= 0x10000: 104a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = float(value) / 0x10000 105a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value % 1 != 0: 106a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod # Write as hex 107a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = "0x%08x" % (int(round(value * 0x10000))) 108a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod xmlWriter.simpletag(name, attrs + [("value", value)]) 109a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod xmlWriter.newline() 110b776a882ee55fff8c39543f352c528bb5d338177jvr 111d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Short(IntValue): 112078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 113d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readShort() 114078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 115d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeShort(value) 116d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 117d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass UShort(IntValue): 118078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 119d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readUShort() 120078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 121d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(value) 122d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 123d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Count(Short): 124d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 125d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.comment("%s=%s" % (name, value)) 126d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 127d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 128d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Tag(SimpleValue): 129078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 130d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readTag() 131078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 132d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeTag(value) 133d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 134d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass GlyphID(SimpleValue): 135078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 136823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = reader.readUShort() 137823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphName(value) 138823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return value 139823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 140078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 141823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphID(value) 142823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeUShort(value) 143d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 144b776a882ee55fff8c39543f352c528bb5d338177jvr 145d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Struct(BaseConverter): 146d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 147078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 148d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 149078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod table.decompile(reader, font) 150d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 151d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 152078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 153078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod value.compile(writer, font) 154d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 155d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 156d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 157d4d151390d1288f8d2df30f6dfa26a309c7334dajvr pass # NULL table, ignore 158d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 159d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.toXML(xmlWriter, font, attrs) 160d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 161d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 162d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 163d4d151390d1288f8d2df30f6dfa26a309c7334dajvr Format = attrs.get("Format") 164d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if Format is not None: 165d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table.Format = int(Format) 166d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for element in content: 16752966bb14409b558dc46b52d34953fbde7dc1bcajvr if type(element) == TupleType: 16852966bb14409b558dc46b52d34953fbde7dc1bcajvr name, attrs, content = element 16952966bb14409b558dc46b52d34953fbde7dc1bcajvr table.fromXML((name, attrs, content), font) 17052966bb14409b558dc46b52d34953fbde7dc1bcajvr else: 17152966bb14409b558dc46b52d34953fbde7dc1bcajvr pass 172d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 173d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 174d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 175d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Table(Struct): 176d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 177078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict, lazy=True): 178d4d151390d1288f8d2df30f6dfa26a309c7334dajvr offset = reader.readUShort() 179d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset == 0: 180d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 181d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset <= 3: 182d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # XXX hack to work around buggy pala.ttf 183d4d151390d1288f8d2df30f6dfa26a309c7334dajvr print "*** Warning: offset is not 0, yet suspiciously low (%s). table: %s" \ 184d4d151390d1288f8d2df30f6dfa26a309c7334dajvr % (offset, self.tableClass.__name__) 185d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 186d01c44a59bcf8f8e75e8606142da422319d281e2Behdad Esfahbod subReader = reader.getSubReader(offset, persistent=lazy) 187d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 188d01c44a59bcf8f8e75e8606142da422319d281e2Behdad Esfahbod if lazy: 189f50d0dff869a8b74bcff028721204a284cadff12Behdad Esfahbod table.reader = subReader 190f50d0dff869a8b74bcff028721204a284cadff12Behdad Esfahbod table.font = font 191f50d0dff869a8b74bcff028721204a284cadff12Behdad Esfahbod table.compileStatus = 1 192f50d0dff869a8b74bcff028721204a284cadff12Behdad Esfahbod else: 193078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod table.decompile(subReader, font) 194d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 195d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 196078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 197d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 198d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(0) 199d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 200d4d151390d1288f8d2df30f6dfa26a309c7334dajvr subWriter = writer.getSubWriter() 201823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.name = self.name 202823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if repeatIndex is not None: 203823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.repeatIndex = repeatIndex 204823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value.preCompile() 205d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeSubTable(subWriter) 206078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod value.compile(subWriter, font) 207d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 208d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SubTable(Table): 209d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def getConverter(self, tableType, lookupType): 210d4d151390d1288f8d2df30f6dfa26a309c7334dajvr lookupTypes = self.lookupTypes[tableType] 211d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tableClass = lookupTypes[lookupType] 212823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return SubTable(self.name, self.repeat, self.repeatOffset, tableClass) 213823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 214823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 215823f8cd15f16bb9dc3991c2672f16dd90579711bjvrclass ExtSubTable(Table): 216823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def getConverter(self, tableType, lookupType): 217823f8cd15f16bb9dc3991c2672f16dd90579711bjvr lookupTypes = self.lookupTypes[tableType] 218823f8cd15f16bb9dc3991c2672f16dd90579711bjvr tableClass = lookupTypes[lookupType] 219823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return ExtSubTable(self.name, self.repeat, self.repeatOffset, tableClass) 220823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 221078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict, lazy=True): 222823f8cd15f16bb9dc3991c2672f16dd90579711bjvr offset = reader.readULong() 223823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if offset == 0: 224823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return None 225823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subReader = reader.getSubReader(offset) 226823f8cd15f16bb9dc3991c2672f16dd90579711bjvr table = self.tableClass() 2270585b64f70cca15aab3483f529c8faf1b7b825fdBehdad Esfahbod table.start = subReader.offset 2280585b64f70cca15aab3483f529c8faf1b7b825fdBehdad Esfahbod if lazy: 2290585b64f70cca15aab3483f529c8faf1b7b825fdBehdad Esfahbod table.reader = subReader 2300585b64f70cca15aab3483f529c8faf1b7b825fdBehdad Esfahbod table.font = font 2310585b64f70cca15aab3483f529c8faf1b7b825fdBehdad Esfahbod table.compileStatus = 1 2320585b64f70cca15aab3483f529c8faf1b7b825fdBehdad Esfahbod else: 233078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod table.decompile(subReader, font) 234823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return table 235823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 236078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 237823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer. 238823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if value is None: 239823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeULong(0) 240823f8cd15f16bb9dc3991c2672f16dd90579711bjvr else: 2413ac875aa1df2c773a973aa8f15852c4551ce20f4pabs subWriter = writer.getSubWriter() 242823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.name = self.name 243823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeSubTable(subWriter) 244823f8cd15f16bb9dc3991c2672f16dd90579711bjvr # If the subtable has been sorted and we can just write the original 245823f8cd15f16bb9dc3991c2672f16dd90579711bjvr # data, then do so. 246823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if value.compileStatus == 3: 247823f8cd15f16bb9dc3991c2672f16dd90579711bjvr data = value.reader.data[value.start:value.end] 248823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.writeData(data) 249823f8cd15f16bb9dc3991c2672f16dd90579711bjvr else: 250078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod value.compile(subWriter, font) 251d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 252d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 253d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueFormat(IntValue): 254d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def __init__(self, name, repeat, repeatOffset, tableClass): 255d4d151390d1288f8d2df30f6dfa26a309c7334dajvr BaseConverter.__init__(self, name, repeat, repeatOffset, tableClass) 256d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.which = name[-1] == "2" 257078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 258d4d151390d1288f8d2df30f6dfa26a309c7334dajvr format = reader.readUShort() 259d4d151390d1288f8d2df30f6dfa26a309c7334dajvr reader.setValueFormat(format, self.which) 260d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return format 261078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, format, repeatIndex=None): 262d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(format) 263d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.setValueFormat(format, self.which) 264d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 265b776a882ee55fff8c39543f352c528bb5d338177jvr 266d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueRecord(ValueFormat): 267078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 268d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readValueRecord(font, self.which) 269078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 270d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeValueRecord(value, font, self.which) 271d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 272d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 273d4d151390d1288f8d2df30f6dfa26a309c7334dajvr pass # NULL table, ignore 274d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 275d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.toXML(xmlWriter, font, self.name, attrs) 276d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 277d4d151390d1288f8d2df30f6dfa26a309c7334dajvr from otBase import ValueRecord 278d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = ValueRecord() 279d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.fromXML((None, attrs, content), font) 280d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return value 281d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 282d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 283d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass DeltaValue(BaseConverter): 284d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 285078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 2862edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod StartSize = tableDict["StartSize"] 2872edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod EndSize = tableDict["EndSize"] 2882edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod DeltaFormat = tableDict["DeltaFormat"] 289d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 290d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 291d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 292d4d151390d1288f8d2df30f6dfa26a309c7334dajvr minusOffset = 1 << nBits 293d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 294d4d151390d1288f8d2df30f6dfa26a309c7334dajvr signMask = 1 << (nBits - 1) 295d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 296d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue = [] 297d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 0 298d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for i in range(nItems): 299d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 300d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = reader.readUShort(), 16 301d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 302d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = (tmp >> shift) & mask 303d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value & signMask: 304d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = value - minusOffset 305d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue.append(value) 306d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return DeltaValue 307d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 308078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 3092edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod StartSize = tableDict["StartSize"] 3102edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod EndSize = tableDict["EndSize"] 3112edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod DeltaFormat = tableDict["DeltaFormat"] 3126f9b64f2966d18cccad3fcf6e03f44f208dbc2a4Behdad Esfahbod DeltaValue = value 313d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 314d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 315d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 316d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert len(DeltaValue) == nItems 317d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 318d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 319d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 320d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for value in DeltaValue: 321d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 322d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp = tmp | ((value & mask) << shift) 323d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 324d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 325d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 326d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift <> 16: 327d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 328d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 329d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 33064b5c80e80444a124da335e8d4d208bffcf2737bjvr # XXX this could do with a nicer format 331d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 332d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 333d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 334d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 335d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return safeEval(attrs["value"]) 336d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 337d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 338d4d151390d1288f8d2df30f6dfa26a309c7334dajvrconverterMapping = { 339d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # type class 340d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "int16": Short, 341d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "uint16": UShort, 342a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod "Version": Version, 343d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Tag": Tag, 344d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "GlyphID": GlyphID, 345d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "struct": Struct, 346d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Offset": Table, 347823f8cd15f16bb9dc3991c2672f16dd90579711bjvr "LOffset": ExtSubTable, 348d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "ValueRecord": ValueRecord, 3497d130307e6e6094e40a841a3c41fc74b203b7e8eBehdad Esfahbod "DeltaValue": DeltaValue, 350d4d151390d1288f8d2df30f6dfa26a309c7334dajvr} 351d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 352