otConverters.py revision 79f734414c2a8d6851fb1b3ec69287ff0e0077b9
1d4d151390d1288f8d2df30f6dfa26a309c7334dajvrfrom types import TupleType 2d4d151390d1288f8d2df30f6dfa26a309c7334dajvrfrom fontTools.misc.textTools import safeEval 379f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbodfrom otBase import ValueRecordFactory 4d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 5d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 664b5c80e80444a124da335e8d4d208bffcf2737bjvrdef buildConverters(tableSpec, tableNamespace): 764b5c80e80444a124da335e8d4d208bffcf2737bjvr """Given a table spec from otData.py, build a converter object for each 864b5c80e80444a124da335e8d4d208bffcf2737bjvr field of the table. This is called for each table in otData.py, and 964b5c80e80444a124da335e8d4d208bffcf2737bjvr the results are assigned to the corresponding class in otTables.py.""" 10d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converters = [] 11d4d151390d1288f8d2df30f6dfa26a309c7334dajvr convertersByName = {} 126b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod for tp, name, repeat, aux, descr in tableSpec: 13d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if name.startswith("ValueFormat"): 14d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 15d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = ValueFormat 16d4d151390d1288f8d2df30f6dfa26a309c7334dajvr elif name.endswith("Count"): 17d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 18d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = Count 19d4d151390d1288f8d2df30f6dfa26a309c7334dajvr elif name == "SubTable": 20d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = SubTable 21823f8cd15f16bb9dc3991c2672f16dd90579711bjvr elif name == "ExtSubTable": 22823f8cd15f16bb9dc3991c2672f16dd90579711bjvr converterClass = ExtSubTable 23d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 24d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = converterMapping[tp] 25d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tableClass = tableNamespace.get(name) 266b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod conv = converterClass(name, repeat, aux, tableClass) 27823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if name in ["SubTable", "ExtSubTable"]: 28d4d151390d1288f8d2df30f6dfa26a309c7334dajvr conv.lookupTypes = tableNamespace['lookupTypes'] 29d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # also create reverse mapping 30d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for t in conv.lookupTypes.values(): 31d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for cls in t.values(): 326b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod convertersByName[cls.__name__] = Table(name, repeat, aux, cls) 33d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converters.append(conv) 34d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert not convertersByName.has_key(name) 35d4d151390d1288f8d2df30f6dfa26a309c7334dajvr convertersByName[name] = conv 36d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return converters, convertersByName 37d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 38d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 39d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass BaseConverter(object): 40d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 4164b5c80e80444a124da335e8d4d208bffcf2737bjvr """Base class for converter objects. Apart from the constructor, this 4264b5c80e80444a124da335e8d4d208bffcf2737bjvr is an abstract class.""" 4364b5c80e80444a124da335e8d4d208bffcf2737bjvr 446b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod def __init__(self, name, repeat, aux, tableClass): 45d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.name = name 46d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.repeat = repeat 476b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod self.aux = aux 48d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.tableClass = tableClass 49d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.isCount = name.endswith("Count") 50ee27eb8517ee53594a6232d110e17403a37ff2d9Behdad Esfahbod self.isPropagatedCount = name in ["ClassCount", "Class2Count"] 51d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 52078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 5364b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from the reader.""" 54d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 55d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 56078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 5764b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to the writer.""" 58d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 59d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 6064b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlRead(self, attrs, content, font): 6164b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from XML.""" 62d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 63d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 6464b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 6564b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to XML.""" 66d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 67d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 68d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 69d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SimpleValue(BaseConverter): 70d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 71d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 72d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 73d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 74d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return attrs["value"] 75d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 76d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass IntValue(SimpleValue): 77d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 78ffc3cfeed12e67b383ed5f540d05cab01b33bb77Behdad Esfahbod return int(attrs["value"], 0) 79d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 80d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Long(IntValue): 81078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 82d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readLong() 83078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 84d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeLong(value) 85d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 86a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbodclass Version(BaseConverter): 87078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 88a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = reader.readLong() 89a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod assert (value >> 16) == 1, "Unsupported version 0x%08x" % value 90a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod return float(value) / 0x10000 91078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 92a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value < 0x10000: 93a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value *= 0x10000 94a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = int(round(value)) 95a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod assert (value >> 16) == 1, "Unsupported version 0x%08x" % value 96a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod writer.writeLong(value) 977007a0854548f744c44bb9c35380efcba7894bfbjvr def xmlRead(self, attrs, content, font): 98a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = attrs["value"] 99a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = float(int(value, 0)) if value.startswith("0") else float(value) 100a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value >= 0x10000: 101a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = float(value) / 0x10000 102a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod return value 103a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod def xmlWrite(self, xmlWriter, font, value, name, attrs): 104a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value >= 0x10000: 105a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = float(value) / 0x10000 106a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod if value % 1 != 0: 107a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod # Write as hex 108a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod value = "0x%08x" % (int(round(value * 0x10000))) 109a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod xmlWriter.simpletag(name, attrs + [("value", value)]) 110a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod xmlWriter.newline() 111b776a882ee55fff8c39543f352c528bb5d338177jvr 112d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Short(IntValue): 113078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 114d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readShort() 115078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 116d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeShort(value) 117d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 118d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass UShort(IntValue): 119078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 120d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readUShort() 121078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 122d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(value) 123d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 124d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Count(Short): 125d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 126d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.comment("%s=%s" % (name, value)) 127d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 128d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 129d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Tag(SimpleValue): 130078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 131d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readTag() 132078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 133d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeTag(value) 134d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 135d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass GlyphID(SimpleValue): 136078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 137823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = reader.readUShort() 138823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphName(value) 139823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return value 140823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 141078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 142823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphID(value) 143823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeUShort(value) 144d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 145b776a882ee55fff8c39543f352c528bb5d338177jvr 146d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Struct(BaseConverter): 147d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 148078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 149d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 150078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod table.decompile(reader, font) 151d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 152d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 153078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 154078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod value.compile(writer, font) 155d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 156d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 157d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 158d4d151390d1288f8d2df30f6dfa26a309c7334dajvr pass # NULL table, ignore 159d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 160d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.toXML(xmlWriter, font, attrs) 161d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 162d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 163d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 164d4d151390d1288f8d2df30f6dfa26a309c7334dajvr Format = attrs.get("Format") 165d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if Format is not None: 166d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table.Format = int(Format) 167d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for element in content: 16852966bb14409b558dc46b52d34953fbde7dc1bcajvr if type(element) == TupleType: 16952966bb14409b558dc46b52d34953fbde7dc1bcajvr name, attrs, content = element 17052966bb14409b558dc46b52d34953fbde7dc1bcajvr table.fromXML((name, attrs, content), font) 17152966bb14409b558dc46b52d34953fbde7dc1bcajvr else: 17252966bb14409b558dc46b52d34953fbde7dc1bcajvr pass 173d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 174d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 175d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 176d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Table(Struct): 177fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod 178d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod longOffset = False 179d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 180fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod def readOffset(self, reader): 181fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod return reader.readUShort() 182fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod 183fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod def writeNullOffset(self, writer): 184e0c2e8e2af82f79c25026bb8e603ca5bd560c552Behdad Esfahbod if self.longOffset: 185fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod writer.writeULong(0) 186fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod else: 187fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod writer.writeUShort(0) 188d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 1897ef23a85ae49039ae491e337be173caba7bdd534Behdad Esfahbod def read(self, reader, font, tableDict): 190fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod offset = self.readOffset(reader) 191d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset == 0: 192d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 193d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset <= 3: 194d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # XXX hack to work around buggy pala.ttf 195d4d151390d1288f8d2df30f6dfa26a309c7334dajvr print "*** Warning: offset is not 0, yet suspiciously low (%s). table: %s" \ 196d4d151390d1288f8d2df30f6dfa26a309c7334dajvr % (offset, self.tableClass.__name__) 197d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 198d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 199c491f45eff9a884e69a44cbf9ae69288be9478b5Behdad Esfahbod table.reader = reader 200c491f45eff9a884e69a44cbf9ae69288be9478b5Behdad Esfahbod table.offset = offset 201c491f45eff9a884e69a44cbf9ae69288be9478b5Behdad Esfahbod table.font = font 202c491f45eff9a884e69a44cbf9ae69288be9478b5Behdad Esfahbod table.compileStatus = 1 2037ef23a85ae49039ae491e337be173caba7bdd534Behdad Esfahbod if not font.lazy: 204c491f45eff9a884e69a44cbf9ae69288be9478b5Behdad Esfahbod table.ensureDecompiled() 205d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 206d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 207078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 208d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 209fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod self.writeNullOffset(writer) 210d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 211d4d151390d1288f8d2df30f6dfa26a309c7334dajvr subWriter = writer.getSubWriter() 212e0c2e8e2af82f79c25026bb8e603ca5bd560c552Behdad Esfahbod subWriter.longOffset = self.longOffset 213823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.name = self.name 214823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if repeatIndex is not None: 215823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.repeatIndex = repeatIndex 216d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeSubTable(subWriter) 217078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod value.compile(subWriter, font) 218d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 219d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass LTable(Table): 220d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 221d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod longOffset = True 222d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 223d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod def readOffset(self, reader): 224d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod return reader.readULong() 225d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 226d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod 227d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SubTable(Table): 228d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def getConverter(self, tableType, lookupType): 229fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod tableClass = self.lookupTypes[tableType][lookupType] 2306b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod return self.__class__(self.name, self.repeat, self.aux, tableClass) 231823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 232823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 233d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass ExtSubTable(LTable, SubTable): 234823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 235078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 236823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer. 237fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod Table.write(self, writer, font, tableDict, value, repeatIndex) 238d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 239d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 240d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueFormat(IntValue): 2416b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod def __init__(self, name, repeat, aux, tableClass): 2426b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod BaseConverter.__init__(self, name, repeat, aux, tableClass) 24379f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod self.which = "ValueFormat" + ("2" if name[-1] == "2" else "1") 244078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 245d4d151390d1288f8d2df30f6dfa26a309c7334dajvr format = reader.readUShort() 24679f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod reader[self.which] = ValueRecordFactory(format) 247d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return format 248078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, format, repeatIndex=None): 249d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(format) 25079f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod writer[self.which] = ValueRecordFactory(format) 251d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 252b776a882ee55fff8c39543f352c528bb5d338177jvr 253d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueRecord(ValueFormat): 254078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 25579f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod return reader[self.which].readValueRecord(reader, font) 256078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 25779f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod writer[self.which].writeValueRecord(writer, font, value) 258d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 259d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 260d4d151390d1288f8d2df30f6dfa26a309c7334dajvr pass # NULL table, ignore 261d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 262d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.toXML(xmlWriter, font, self.name, attrs) 263d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 264d4d151390d1288f8d2df30f6dfa26a309c7334dajvr from otBase import ValueRecord 265d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = ValueRecord() 266d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.fromXML((None, attrs, content), font) 267d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return value 268d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 269d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 270d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass DeltaValue(BaseConverter): 271d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 272078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def read(self, reader, font, tableDict): 2732edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod StartSize = tableDict["StartSize"] 2742edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod EndSize = tableDict["EndSize"] 2752edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod DeltaFormat = tableDict["DeltaFormat"] 276d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 277d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 278d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 279d4d151390d1288f8d2df30f6dfa26a309c7334dajvr minusOffset = 1 << nBits 280d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 281d4d151390d1288f8d2df30f6dfa26a309c7334dajvr signMask = 1 << (nBits - 1) 282d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 283d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue = [] 284d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 0 285d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for i in range(nItems): 286d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 287d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = reader.readUShort(), 16 288d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 289d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = (tmp >> shift) & mask 290d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value & signMask: 291d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = value - minusOffset 292d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue.append(value) 293d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return DeltaValue 294d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 295078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod def write(self, writer, font, tableDict, value, repeatIndex=None): 2962edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod StartSize = tableDict["StartSize"] 2972edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod EndSize = tableDict["EndSize"] 2982edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod DeltaFormat = tableDict["DeltaFormat"] 2996f9b64f2966d18cccad3fcf6e03f44f208dbc2a4Behdad Esfahbod DeltaValue = value 300d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 301d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 302d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 303d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert len(DeltaValue) == nItems 304d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 305d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 306d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 307d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for value in DeltaValue: 308d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 309d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp = tmp | ((value & mask) << shift) 310d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 311d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 312d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 313d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift <> 16: 314d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 315d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 316d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 31764b5c80e80444a124da335e8d4d208bffcf2737bjvr # XXX this could do with a nicer format 318d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 319d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 320d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 321d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 322d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return safeEval(attrs["value"]) 323d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 324d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 325d4d151390d1288f8d2df30f6dfa26a309c7334dajvrconverterMapping = { 326d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # type class 327d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "int16": Short, 328d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "uint16": UShort, 329a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod "Version": Version, 330d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Tag": Tag, 331d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "GlyphID": GlyphID, 332d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "struct": Struct, 333d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Offset": Table, 334d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod "LOffset": LTable, 335d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "ValueRecord": ValueRecord, 3367d130307e6e6094e40a841a3c41fc74b203b7e8eBehdad Esfahbod "DeltaValue": DeltaValue, 337d4d151390d1288f8d2df30f6dfa26a309c7334dajvr} 338d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 339