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