otConverters.py revision 823f8cd15f16bb9dc3991c2672f16dd90579711b
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 == "DeltaValue": 16d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 17d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = DeltaValue 18d4d151390d1288f8d2df30f6dfa26a309c7334dajvr elif name.endswith("Count"): 19d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert tp == "uint16" 20d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = Count 21d4d151390d1288f8d2df30f6dfa26a309c7334dajvr elif name == "SubTable": 22d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = SubTable 23823f8cd15f16bb9dc3991c2672f16dd90579711bjvr elif name == "ExtSubTable": 24823f8cd15f16bb9dc3991c2672f16dd90579711bjvr converterClass = ExtSubTable 25d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 26d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converterClass = converterMapping[tp] 27d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tableClass = tableNamespace.get(name) 28d4d151390d1288f8d2df30f6dfa26a309c7334dajvr conv = converterClass(name, repeat, repeatOffset, tableClass) 29823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if name in ["SubTable", "ExtSubTable"]: 30d4d151390d1288f8d2df30f6dfa26a309c7334dajvr conv.lookupTypes = tableNamespace['lookupTypes'] 31d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # also create reverse mapping 32d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for t in conv.lookupTypes.values(): 33d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for cls in t.values(): 34823f8cd15f16bb9dc3991c2672f16dd90579711bjvr convertersByName[cls.__name__] = Table(name, repeat, repeatOffset, cls) 35d4d151390d1288f8d2df30f6dfa26a309c7334dajvr converters.append(conv) 36d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert not convertersByName.has_key(name) 37d4d151390d1288f8d2df30f6dfa26a309c7334dajvr convertersByName[name] = conv 38d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return converters, convertersByName 39d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 40d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 41d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass BaseConverter: 42d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 4364b5c80e80444a124da335e8d4d208bffcf2737bjvr """Base class for converter objects. Apart from the constructor, this 4464b5c80e80444a124da335e8d4d208bffcf2737bjvr is an abstract class.""" 4564b5c80e80444a124da335e8d4d208bffcf2737bjvr 46d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def __init__(self, name, repeat, repeatOffset, tableClass): 47d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.name = name 48d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.repeat = repeat 49d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.repeatOffset = repeatOffset 50d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.tableClass = tableClass 51d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.isCount = name.endswith("Count") 52d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 53d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 5464b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from the reader.""" 55d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 56d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 57823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 5864b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to the writer.""" 59d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 60d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 6164b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlRead(self, attrs, content, font): 6264b5c80e80444a124da335e8d4d208bffcf2737bjvr """Read a value from XML.""" 63d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 64d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 6564b5c80e80444a124da335e8d4d208bffcf2737bjvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 6664b5c80e80444a124da335e8d4d208bffcf2737bjvr """Write a value to XML.""" 67d4d151390d1288f8d2df30f6dfa26a309c7334dajvr raise NotImplementedError, self 68d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 69d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 70d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SimpleValue(BaseConverter): 71d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 72d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 73d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 74d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 75d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return attrs["value"] 76d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 77d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass IntValue(SimpleValue): 78d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 79d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return int(attrs["value"]) 80d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 81d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Long(IntValue): 82d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 83d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readLong() 84823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 85d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeLong(value) 86d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 87b776a882ee55fff8c39543f352c528bb5d338177jvrclass Fixed(IntValue): 88b776a882ee55fff8c39543f352c528bb5d338177jvr def read(self, reader, font, tableStack): 89b776a882ee55fff8c39543f352c528bb5d338177jvr return float(reader.readLong()) / 0x10000 90823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 91b776a882ee55fff8c39543f352c528bb5d338177jvr writer.writeLong(int(round(value * 0x10000))) 927007a0854548f744c44bb9c35380efcba7894bfbjvr def xmlRead(self, attrs, content, font): 937007a0854548f744c44bb9c35380efcba7894bfbjvr return float(attrs["value"]) 94b776a882ee55fff8c39543f352c528bb5d338177jvr 95d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Short(IntValue): 96d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 97d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readShort() 98823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 99d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeShort(value) 100d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 101d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass UShort(IntValue): 102d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 103d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readUShort() 104823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 105d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(value) 106d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 107d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Count(Short): 108d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 109d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.comment("%s=%s" % (name, value)) 110d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 111d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 112d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Tag(SimpleValue): 113d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 114d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readTag() 115823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 116d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeTag(value) 117d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 118d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass GlyphID(SimpleValue): 119d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 120823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = reader.readUShort() 121823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphName(value) 122823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return value 123823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 124823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 125823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value = font.getGlyphID(value) 126823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeUShort(value) 127d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 128b776a882ee55fff8c39543f352c528bb5d338177jvr 129d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Struct(BaseConverter): 130d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 131d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 132d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 133d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table.decompile(reader, font, tableStack) 134d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 135d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 136823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 137d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.compile(writer, font, tableStack) 138d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 139d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 140d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 141d4d151390d1288f8d2df30f6dfa26a309c7334dajvr pass # NULL table, ignore 142d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 143d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.toXML(xmlWriter, font, attrs) 144d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 145d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 146d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 147d4d151390d1288f8d2df30f6dfa26a309c7334dajvr Format = attrs.get("Format") 148d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if Format is not None: 149d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table.Format = int(Format) 150d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for element in content: 15152966bb14409b558dc46b52d34953fbde7dc1bcajvr if type(element) == TupleType: 15252966bb14409b558dc46b52d34953fbde7dc1bcajvr name, attrs, content = element 15352966bb14409b558dc46b52d34953fbde7dc1bcajvr table.fromXML((name, attrs, content), font) 15452966bb14409b558dc46b52d34953fbde7dc1bcajvr else: 15552966bb14409b558dc46b52d34953fbde7dc1bcajvr pass 156d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 157d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 158d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 159d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Table(Struct): 160d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 161d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 162d4d151390d1288f8d2df30f6dfa26a309c7334dajvr offset = reader.readUShort() 163d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset == 0: 164d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 165d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if offset <= 3: 166d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # XXX hack to work around buggy pala.ttf 167d4d151390d1288f8d2df30f6dfa26a309c7334dajvr print "*** Warning: offset is not 0, yet suspiciously low (%s). table: %s" \ 168d4d151390d1288f8d2df30f6dfa26a309c7334dajvr % (offset, self.tableClass.__name__) 169d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return None 170d4d151390d1288f8d2df30f6dfa26a309c7334dajvr subReader = reader.getSubReader(offset) 171d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = self.tableClass() 172d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table.decompile(subReader, font, tableStack) 173d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return table 174d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 175823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 176d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 177d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(0) 178d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 179d4d151390d1288f8d2df30f6dfa26a309c7334dajvr subWriter = writer.getSubWriter() 180823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.name = self.name 181823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if repeatIndex is not None: 182823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.repeatIndex = repeatIndex 183823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value.preCompile() 184d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeSubTable(subWriter) 185d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.compile(subWriter, font, tableStack) 186d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 187d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SubTable(Table): 188d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def getConverter(self, tableType, lookupType): 189d4d151390d1288f8d2df30f6dfa26a309c7334dajvr lookupTypes = self.lookupTypes[tableType] 190d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tableClass = lookupTypes[lookupType] 191823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return SubTable(self.name, self.repeat, self.repeatOffset, tableClass) 192823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 193823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 194823f8cd15f16bb9dc3991c2672f16dd90579711bjvrclass ExtSubTable(Table): 195823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def getConverter(self, tableType, lookupType): 196823f8cd15f16bb9dc3991c2672f16dd90579711bjvr lookupTypes = self.lookupTypes[tableType] 197823f8cd15f16bb9dc3991c2672f16dd90579711bjvr tableClass = lookupTypes[lookupType] 198823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return ExtSubTable(self.name, self.repeat, self.repeatOffset, tableClass) 199823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 200823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def read(self, reader, font, tableStack): 201823f8cd15f16bb9dc3991c2672f16dd90579711bjvr offset = reader.readULong() 202823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if offset == 0: 203823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return None 204823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subReader = reader.getSubReader(offset) 205823f8cd15f16bb9dc3991c2672f16dd90579711bjvr table = self.tableClass() 206823f8cd15f16bb9dc3991c2672f16dd90579711bjvr table.reader = subReader 207823f8cd15f16bb9dc3991c2672f16dd90579711bjvr table.font = font 208823f8cd15f16bb9dc3991c2672f16dd90579711bjvr table.compileStatus = 1 209823f8cd15f16bb9dc3991c2672f16dd90579711bjvr table.start = table.reader.offset 210823f8cd15f16bb9dc3991c2672f16dd90579711bjvr return table 211823f8cd15f16bb9dc3991c2672f16dd90579711bjvr 212823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 213823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer. 214823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if value is None: 215823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeULong(0) 216823f8cd15f16bb9dc3991c2672f16dd90579711bjvr else: 217823f8cd15f16bb9dc3991c2672f16dd90579711bjvr # If the subtable has not yet been decompiled, we need to do so. 218823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if value.compileStatus == 1: 219823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value.decompile(value.reader, value.font, tableStack) 220823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter = writer.getSubWriter() 221823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.name = self.name 222823f8cd15f16bb9dc3991c2672f16dd90579711bjvr writer.writeSubTable(subWriter) 223823f8cd15f16bb9dc3991c2672f16dd90579711bjvr # If the subtable has been sorted and we can just write the original 224823f8cd15f16bb9dc3991c2672f16dd90579711bjvr # data, then do so. 225823f8cd15f16bb9dc3991c2672f16dd90579711bjvr if value.compileStatus == 3: 226823f8cd15f16bb9dc3991c2672f16dd90579711bjvr data = value.reader.data[value.start:value.end] 227823f8cd15f16bb9dc3991c2672f16dd90579711bjvr subWriter.writeData(data) 228823f8cd15f16bb9dc3991c2672f16dd90579711bjvr else: 229823f8cd15f16bb9dc3991c2672f16dd90579711bjvr value.compile(subWriter, font, tableStack) 230d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 231d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 232d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueFormat(IntValue): 233d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def __init__(self, name, repeat, repeatOffset, tableClass): 234d4d151390d1288f8d2df30f6dfa26a309c7334dajvr BaseConverter.__init__(self, name, repeat, repeatOffset, tableClass) 235d4d151390d1288f8d2df30f6dfa26a309c7334dajvr self.which = name[-1] == "2" 236d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 237d4d151390d1288f8d2df30f6dfa26a309c7334dajvr format = reader.readUShort() 238d4d151390d1288f8d2df30f6dfa26a309c7334dajvr reader.setValueFormat(format, self.which) 239d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return format 240823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, format, repeatIndex=None): 241d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(format) 242d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.setValueFormat(format, self.which) 243d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 244b776a882ee55fff8c39543f352c528bb5d338177jvr 245d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueRecord(ValueFormat): 246d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 247d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return reader.readValueRecord(font, self.which) 248823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 249d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeValueRecord(value, font, self.which) 250d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 251d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value is None: 252d4d151390d1288f8d2df30f6dfa26a309c7334dajvr pass # NULL table, ignore 253d4d151390d1288f8d2df30f6dfa26a309c7334dajvr else: 254d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.toXML(xmlWriter, font, self.name, attrs) 255d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 256d4d151390d1288f8d2df30f6dfa26a309c7334dajvr from otBase import ValueRecord 257d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = ValueRecord() 258d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value.fromXML((None, attrs, content), font) 259d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return value 260d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 261d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 262d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass DeltaValue(BaseConverter): 263d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 264d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def read(self, reader, font, tableStack): 265d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = tableStack.getTop() 266d4d151390d1288f8d2df30f6dfa26a309c7334dajvr StartSize = table["StartSize"] 267d4d151390d1288f8d2df30f6dfa26a309c7334dajvr EndSize = table["EndSize"] 268d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaFormat = table["DeltaFormat"] 269d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 270d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 271d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 272d4d151390d1288f8d2df30f6dfa26a309c7334dajvr minusOffset = 1 << nBits 273d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 274d4d151390d1288f8d2df30f6dfa26a309c7334dajvr signMask = 1 << (nBits - 1) 275d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 276d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue = [] 277d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 0 278d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for i in range(nItems): 279d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 280d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = reader.readUShort(), 16 281d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 282d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = (tmp >> shift) & mask 283d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if value & signMask: 284d4d151390d1288f8d2df30f6dfa26a309c7334dajvr value = value - minusOffset 285d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue.append(value) 286d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return DeltaValue 287d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 288823f8cd15f16bb9dc3991c2672f16dd90579711bjvr def write(self, writer, font, tableStack, value, repeatIndex=None): 289d4d151390d1288f8d2df30f6dfa26a309c7334dajvr table = tableStack.getTop() 290d4d151390d1288f8d2df30f6dfa26a309c7334dajvr StartSize = table["StartSize"] 291d4d151390d1288f8d2df30f6dfa26a309c7334dajvr EndSize = table["EndSize"] 292d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaFormat = table["DeltaFormat"] 293d4d151390d1288f8d2df30f6dfa26a309c7334dajvr DeltaValue = table["DeltaValue"] 294d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat" 295d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nItems = EndSize - StartSize + 1 296d4d151390d1288f8d2df30f6dfa26a309c7334dajvr nBits = 1 << DeltaFormat 297d4d151390d1288f8d2df30f6dfa26a309c7334dajvr assert len(DeltaValue) == nItems 298d4d151390d1288f8d2df30f6dfa26a309c7334dajvr mask = (1 << nBits) - 1 299d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 300d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 301d4d151390d1288f8d2df30f6dfa26a309c7334dajvr for value in DeltaValue: 302d4d151390d1288f8d2df30f6dfa26a309c7334dajvr shift = shift - nBits 303d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp = tmp | ((value & mask) << shift) 304d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift == 0: 305d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 306d4d151390d1288f8d2df30f6dfa26a309c7334dajvr tmp, shift = 0, 16 307d4d151390d1288f8d2df30f6dfa26a309c7334dajvr if shift <> 16: 308d4d151390d1288f8d2df30f6dfa26a309c7334dajvr writer.writeUShort(tmp) 309d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 310d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlWrite(self, xmlWriter, font, value, name, attrs): 31164b5c80e80444a124da335e8d4d208bffcf2737bjvr # XXX this could do with a nicer format 312d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.simpletag(name, attrs + [("value", value)]) 313d4d151390d1288f8d2df30f6dfa26a309c7334dajvr xmlWriter.newline() 314d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 315d4d151390d1288f8d2df30f6dfa26a309c7334dajvr def xmlRead(self, attrs, content, font): 316d4d151390d1288f8d2df30f6dfa26a309c7334dajvr return safeEval(attrs["value"]) 317d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 318d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 319d4d151390d1288f8d2df30f6dfa26a309c7334dajvrconverterMapping = { 320d4d151390d1288f8d2df30f6dfa26a309c7334dajvr # type class 321d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "int16": Short, 322d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "uint16": UShort, 323d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "ULONG": Long, 324b776a882ee55fff8c39543f352c528bb5d338177jvr "Fixed": Fixed, 325d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Tag": Tag, 326d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "GlyphID": GlyphID, 327d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "struct": Struct, 328d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "Offset": Table, 329823f8cd15f16bb9dc3991c2672f16dd90579711bjvr "LOffset": ExtSubTable, 330d4d151390d1288f8d2df30f6dfa26a309c7334dajvr "ValueRecord": ValueRecord, 331d4d151390d1288f8d2df30f6dfa26a309c7334dajvr} 332d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 333d4d151390d1288f8d2df30f6dfa26a309c7334dajvr# equivalents: 334d4d151390d1288f8d2df30f6dfa26a309c7334dajvrconverterMapping["USHORT"] = converterMapping["uint16"] 335b776a882ee55fff8c39543f352c528bb5d338177jvrconverterMapping["fixed32"] = converterMapping["Fixed"] 336d4d151390d1288f8d2df30f6dfa26a309c7334dajvr 337