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