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