11ae29591efbb29492ce05378909ccf4028d7c1eeBehdad Esfahbodfrom __future__ import print_function, division, absolute_import
230e691edd056ba22fa8970280e986747817bec3dBehdad Esfahbodfrom fontTools.misc.py23 import *
3d4d151390d1288f8d2df30f6dfa26a309c7334dajvrfrom fontTools.misc.textTools import safeEval
43fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbodfrom fontTools.misc.fixedTools import fixedToFloat as fi2fl, floatToFixed as fl2fi
52b06aaa2a6bcd363c25fb0c43f6bb906906594bdBehdad Esfahbodfrom .otBase import ValueRecordFactory
6d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
7d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
864b5c80e80444a124da335e8d4d208bffcf2737bjvrdef buildConverters(tableSpec, tableNamespace):
964b5c80e80444a124da335e8d4d208bffcf2737bjvr	"""Given a table spec from otData.py, build a converter object for each
1064b5c80e80444a124da335e8d4d208bffcf2737bjvr	field of the table. This is called for each table in otData.py, and
1164b5c80e80444a124da335e8d4d208bffcf2737bjvr	the results are assigned to the corresponding class in otTables.py."""
12d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	converters = []
13d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	convertersByName = {}
146b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod	for tp, name, repeat, aux, descr in tableSpec:
15d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod		tableName = name
16d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		if name.startswith("ValueFormat"):
17d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			assert tp == "uint16"
18d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			converterClass = ValueFormat
196ed2eb409231a7fe3e0c2a135f9a89796206f639Behdad Esfahbod		elif name.endswith("Count") or name.endswith("LookupType"):
20d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			assert tp == "uint16"
216ed2eb409231a7fe3e0c2a135f9a89796206f639Behdad Esfahbod			converterClass = ComputedUShort
22d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		elif name == "SubTable":
23d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			converterClass = SubTable
24823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		elif name == "ExtSubTable":
25823f8cd15f16bb9dc3991c2672f16dd90579711bjvr			converterClass = ExtSubTable
269e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod		elif name == "FeatureParams":
279e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod			converterClass = FeatureParams
28d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		else:
29d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod			if not tp in converterMapping:
30d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod				tableName = tp
31d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod				converterClass = Struct
32d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod			else:
33d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod				converterClass = converterMapping[tp]
34d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod		tableClass = tableNamespace.get(tableName)
356b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod		conv = converterClass(name, repeat, aux, tableClass)
36823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		if name in ["SubTable", "ExtSubTable"]:
37d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			conv.lookupTypes = tableNamespace['lookupTypes']
38d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			# also create reverse mapping
39d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			for t in conv.lookupTypes.values():
40d4d151390d1288f8d2df30f6dfa26a309c7334dajvr				for cls in t.values():
416b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod					convertersByName[cls.__name__] = Table(name, repeat, aux, cls)
429e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod		if name == "FeatureParams":
439e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod			conv.featureParamTypes = tableNamespace['featureParamTypes']
449e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod			conv.defaultFeatureParams = tableNamespace['FeatureParams']
459e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod			for cls in conv.featureParamTypes.values():
469e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod				convertersByName[cls.__name__] = Table(name, repeat, aux, cls)
47d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		converters.append(conv)
48d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod		assert name not in convertersByName, name
49d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		convertersByName[name] = conv
50d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	return converters, convertersByName
51d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
52d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
53d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass BaseConverter(object):
54d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
5564b5c80e80444a124da335e8d4d208bffcf2737bjvr	"""Base class for converter objects. Apart from the constructor, this
5664b5c80e80444a124da335e8d4d208bffcf2737bjvr	is an abstract class."""
5764b5c80e80444a124da335e8d4d208bffcf2737bjvr
586b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod	def __init__(self, name, repeat, aux, tableClass):
59d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		self.name = name
60d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		self.repeat = repeat
616b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod		self.aux = aux
62d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		self.tableClass = tableClass
63d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		self.isCount = name.endswith("Count")
645fec22bfcd53fe9a10fa066e17d0a0d18cf2d74aBehdad Esfahbod		self.isLookupType = name.endswith("LookupType")
659e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod		self.isPropagated = name in ["ClassCount", "Class2Count", "FeatureTag"]
66d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
67078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
6864b5c80e80444a124da335e8d4d208bffcf2737bjvr		"""Read a value from the reader."""
69cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod		raise NotImplementedError(self)
70d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
71078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
7264b5c80e80444a124da335e8d4d208bffcf2737bjvr		"""Write a value to the writer."""
73cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod		raise NotImplementedError(self)
74d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
7564b5c80e80444a124da335e8d4d208bffcf2737bjvr	def xmlRead(self, attrs, content, font):
7664b5c80e80444a124da335e8d4d208bffcf2737bjvr		"""Read a value from XML."""
77cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod		raise NotImplementedError(self)
78d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
7964b5c80e80444a124da335e8d4d208bffcf2737bjvr	def xmlWrite(self, xmlWriter, font, value, name, attrs):
8064b5c80e80444a124da335e8d4d208bffcf2737bjvr		"""Write a value to XML."""
81cd5aad92f23737ff93a110d5c73d624658a28da8Behdad Esfahbod		raise NotImplementedError(self)
82d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
83d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
84d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SimpleValue(BaseConverter):
85d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlWrite(self, xmlWriter, font, value, name, attrs):
86d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		xmlWriter.simpletag(name, attrs + [("value", value)])
87d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		xmlWriter.newline()
88d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlRead(self, attrs, content, font):
89d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return attrs["value"]
90d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
91d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass IntValue(SimpleValue):
92d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlRead(self, attrs, content, font):
93ffc3cfeed12e67b383ed5f540d05cab01b33bb77Behdad Esfahbod		return int(attrs["value"], 0)
94d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
95d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Long(IntValue):
96078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
97d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return reader.readLong()
98078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
99d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		writer.writeLong(value)
100d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
101a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbodclass Version(BaseConverter):
102078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
103a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		value = reader.readLong()
104a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		assert (value >> 16) == 1, "Unsupported version 0x%08x" % value
1053fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod		return  fi2fl(value, 16)
106078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
107a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		if value < 0x10000:
1083fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod			value = fl2fi(value, 16)
109a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		value = int(round(value))
110a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		assert (value >> 16) == 1, "Unsupported version 0x%08x" % value
111a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		writer.writeLong(value)
1127007a0854548f744c44bb9c35380efcba7894bfbjvr	def xmlRead(self, attrs, content, font):
113a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		value = attrs["value"]
114a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		value = float(int(value, 0)) if value.startswith("0") else float(value)
115a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		if value >= 0x10000:
1163fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod			value = fi2fl(value, 16)
117a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		return value
118a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod	def xmlWrite(self, xmlWriter, font, value, name, attrs):
119a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		if value >= 0x10000:
1203fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod			value = fi2fl(value, 16)
121a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		if value % 1 != 0:
122a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod			# Write as hex
1233fa26d783f6a2ab5103df66a99d0322491e1d8a6Behdad Esfahbod			value = "0x%08x" % fl2fi(value, 16)
124a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		xmlWriter.simpletag(name, attrs + [("value", value)])
125a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod		xmlWriter.newline()
126b776a882ee55fff8c39543f352c528bb5d338177jvr
127d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Short(IntValue):
128078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
129d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return reader.readShort()
130078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
131d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		writer.writeShort(value)
132d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
133d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass UShort(IntValue):
134078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
135d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return reader.readUShort()
136078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
137d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		writer.writeUShort(value)
138d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
1399e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbodclass UInt24(IntValue):
1409e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod	def read(self, reader, font, tableDict):
1419e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod		return reader.readUInt24()
1429e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
1439e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod		writer.writeUInt24(value)
1449e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod
1456ed2eb409231a7fe3e0c2a135f9a89796206f639Behdad Esfahbodclass ComputedUShort(UShort):
146d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlWrite(self, xmlWriter, font, value, name, attrs):
147d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		xmlWriter.comment("%s=%s" % (name, value))
148d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		xmlWriter.newline()
149d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
150d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Tag(SimpleValue):
151078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
152d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return reader.readTag()
153078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
154d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		writer.writeTag(value)
155d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
156d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass GlyphID(SimpleValue):
157078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
158823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		value = reader.readUShort()
159823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		value =  font.getGlyphName(value)
160823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		return value
161823f8cd15f16bb9dc3991c2672f16dd90579711bjvr
162078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
163823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		value =  font.getGlyphID(value)
164823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		writer.writeUShort(value)
165d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
1663ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbodclass FloatValue(SimpleValue):
1673ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod	def xmlRead(self, attrs, content, font):
1683ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod		return float(attrs["value"])
1693ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod
1703ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbodclass DeciPoints(FloatValue):
1713ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod	def read(self, reader, font, tableDict):
1723ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod		value = reader.readUShort()
17332c10eecffb4923e0721c395e4b80fb732543f18Behdad Esfahbod		return value / 10
1743ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod
1753ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
1763ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod		writer.writeUShort(int(round(value * 10)))
177b776a882ee55fff8c39543f352c528bb5d338177jvr
178d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Struct(BaseConverter):
179d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
180078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
181d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		table = self.tableClass()
182078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod		table.decompile(reader, font)
183d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return table
184d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
185078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
186078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod		value.compile(writer, font)
187d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
188d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlWrite(self, xmlWriter, font, value, name, attrs):
189d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		if value is None:
190cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod			if attrs:
191cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod				# If there are attributes (probably index), then
192cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod				# don't drop this even if it's NULL.  It will mess
193cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod				# up the array indices of the containing element.
194cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod				xmlWriter.simpletag(name, attrs + [("empty", True)])
195cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod				xmlWriter.newline()
196cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod			else:
197cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod				pass # NULL table, ignore
198d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		else:
199d76fa68785bc843ad83e2901ada96f2a5b02397dBehdad Esfahbod			value.toXML(xmlWriter, font, attrs, name=name)
200d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
201d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlRead(self, attrs, content, font):
202d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		table = self.tableClass()
203cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod		if attrs.get("empty"):
204cb4adf682848103b25f955d19a892fb33fbde9e3Behdad Esfahbod			return None
205d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		Format = attrs.get("Format")
206d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		if Format is not None:
207d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			table.Format = int(Format)
208d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		for element in content:
209b774f9f684c5a0f91f5fa177c9a461968789123fBehdad Esfahbod			if isinstance(element, tuple):
21052966bb14409b558dc46b52d34953fbde7dc1bcajvr				name, attrs, content = element
2113a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod				table.fromXML(name, attrs, content, font)
21252966bb14409b558dc46b52d34953fbde7dc1bcajvr			else:
21352966bb14409b558dc46b52d34953fbde7dc1bcajvr				pass
214d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return table
215d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
216d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
217d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass Table(Struct):
218fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod
219d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod	longOffset = False
220d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod
221fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod	def readOffset(self, reader):
222fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod		return reader.readUShort()
223fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod
224fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod	def writeNullOffset(self, writer):
225e0c2e8e2af82f79c25026bb8e603ca5bd560c552Behdad Esfahbod		if self.longOffset:
226fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod			writer.writeULong(0)
227fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod		else:
228fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod			writer.writeUShort(0)
229d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
2307ef23a85ae49039ae491e337be173caba7bdd534Behdad Esfahbod	def read(self, reader, font, tableDict):
231fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod		offset = self.readOffset(reader)
232d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		if offset == 0:
233d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			return None
234d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		if offset <= 3:
235d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			# XXX hack to work around buggy pala.ttf
2363ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod			print("*** Warning: offset is not 0, yet suspiciously low (%s). table: %s" \
2373ec6a258238b6068e4eef3fe579f1f5c0a06bbbaBehdad Esfahbod					% (offset, self.tableClass.__name__))
238d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			return None
239d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		table = self.tableClass()
240dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod		reader = reader.getSubReader(offset)
241dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod		if font.lazy:
242dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod			table.reader = reader
243dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod			table.font = font
244dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod		else:
245dafdb2933a9d4ef7ef5365c5e8ecfba39b4d3c57Behdad Esfahbod			table.decompile(reader, font)
246d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return table
247d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
248078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
249d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		if value is None:
250fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod			self.writeNullOffset(writer)
251d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		else:
252d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			subWriter = writer.getSubWriter()
253e0c2e8e2af82f79c25026bb8e603ca5bd560c552Behdad Esfahbod			subWriter.longOffset = self.longOffset
254823f8cd15f16bb9dc3991c2672f16dd90579711bjvr			subWriter.name = self.name
255823f8cd15f16bb9dc3991c2672f16dd90579711bjvr			if repeatIndex is not None:
256823f8cd15f16bb9dc3991c2672f16dd90579711bjvr				subWriter.repeatIndex = repeatIndex
257d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			writer.writeSubTable(subWriter)
258078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod			value.compile(subWriter, font)
259d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
260d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass LTable(Table):
261d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod
262d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod	longOffset = True
263d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod
264d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod	def readOffset(self, reader):
265d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod		return reader.readULong()
266d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod
267d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod
268d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass SubTable(Table):
269d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def getConverter(self, tableType, lookupType):
270fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod		tableClass = self.lookupTypes[tableType][lookupType]
2716b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod		return self.__class__(self.name, self.repeat, self.aux, tableClass)
272823f8cd15f16bb9dc3991c2672f16dd90579711bjvr
273823f8cd15f16bb9dc3991c2672f16dd90579711bjvr
274d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbodclass ExtSubTable(LTable, SubTable):
275823f8cd15f16bb9dc3991c2672f16dd90579711bjvr
276078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
277823f8cd15f16bb9dc3991c2672f16dd90579711bjvr		writer.Extension = 1 # actually, mere presence of the field flags it as an Ext Subtable writer.
278fe67e3121e421e8f146c7b4df8b7188c620d1e5aBehdad Esfahbod		Table.write(self, writer, font, tableDict, value, repeatIndex)
279d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
2809e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbodclass FeatureParams(Table):
2819e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod	def getConverter(self, featureTag):
2829e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod		tableClass = self.featureParamTypes.get(featureTag, self.defaultFeatureParams)
2839e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod		return self.__class__(self.name, self.repeat, self.aux, tableClass)
2849e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod
285d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
286d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueFormat(IntValue):
2876b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod	def __init__(self, name, repeat, aux, tableClass):
2886b6e9fae23499de4d17372d0bd7ce4a8f194b4d7Behdad Esfahbod		BaseConverter.__init__(self, name, repeat, aux, tableClass)
28979f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod		self.which = "ValueFormat" + ("2" if name[-1] == "2" else "1")
290078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
291d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		format = reader.readUShort()
29279f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod		reader[self.which] = ValueRecordFactory(format)
293d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return format
294078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, format, repeatIndex=None):
295d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		writer.writeUShort(format)
29679f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod		writer[self.which] = ValueRecordFactory(format)
297d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
298b776a882ee55fff8c39543f352c528bb5d338177jvr
299d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass ValueRecord(ValueFormat):
300078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
30179f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod		return reader[self.which].readValueRecord(reader, font)
302078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
30379f734414c2a8d6851fb1b3ec69287ff0e0077b9Behdad Esfahbod		writer[self.which].writeValueRecord(writer, font, value)
304d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlWrite(self, xmlWriter, font, value, name, attrs):
305d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		if value is None:
306d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			pass  # NULL table, ignore
307d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		else:
308d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			value.toXML(xmlWriter, font, self.name, attrs)
309d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlRead(self, attrs, content, font):
3102b06aaa2a6bcd363c25fb0c43f6bb906906594bdBehdad Esfahbod		from .otBase import ValueRecord
311d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		value = ValueRecord()
3123a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod		value.fromXML(None, attrs, content, font)
313d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return value
314d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
315d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
316d4d151390d1288f8d2df30f6dfa26a309c7334dajvrclass DeltaValue(BaseConverter):
317d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
318078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def read(self, reader, font, tableDict):
3192edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod		StartSize = tableDict["StartSize"]
3202edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod		EndSize = tableDict["EndSize"]
3212edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod		DeltaFormat = tableDict["DeltaFormat"]
322d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat"
323d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		nItems = EndSize - StartSize + 1
324d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		nBits = 1 << DeltaFormat
325d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		minusOffset = 1 << nBits
326d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		mask = (1 << nBits) - 1
327d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		signMask = 1 << (nBits - 1)
328d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
329d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		DeltaValue = []
330d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		tmp, shift = 0, 0
331d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		for i in range(nItems):
332d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			if shift == 0:
333d4d151390d1288f8d2df30f6dfa26a309c7334dajvr				tmp, shift = reader.readUShort(), 16
334d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			shift = shift - nBits
335d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			value = (tmp >> shift) & mask
336d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			if value & signMask:
337d4d151390d1288f8d2df30f6dfa26a309c7334dajvr				value = value - minusOffset
338d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			DeltaValue.append(value)
339d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return DeltaValue
340d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
341078b36325d7f64ae989e7db22e4910bf6550562dBehdad Esfahbod	def write(self, writer, font, tableDict, value, repeatIndex=None):
3422edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod		StartSize = tableDict["StartSize"]
3432edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod		EndSize = tableDict["EndSize"]
3442edc2da303716b9e401fd8dc808f54456d8137f2Behdad Esfahbod		DeltaFormat = tableDict["DeltaFormat"]
3456f9b64f2966d18cccad3fcf6e03f44f208dbc2a4Behdad Esfahbod		DeltaValue = value
346d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		assert DeltaFormat in (1, 2, 3), "illegal DeltaFormat"
347d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		nItems = EndSize - StartSize + 1
348d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		nBits = 1 << DeltaFormat
349d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		assert len(DeltaValue) == nItems
350d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		mask = (1 << nBits) - 1
351d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
352d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		tmp, shift = 0, 16
353d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		for value in DeltaValue:
354d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			shift = shift - nBits
355d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			tmp = tmp | ((value & mask) << shift)
356d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			if shift == 0:
357d4d151390d1288f8d2df30f6dfa26a309c7334dajvr				writer.writeUShort(tmp)
358d4d151390d1288f8d2df30f6dfa26a309c7334dajvr				tmp, shift = 0, 16
359180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod		if shift != 16:
360d4d151390d1288f8d2df30f6dfa26a309c7334dajvr			writer.writeUShort(tmp)
361d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
362d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlWrite(self, xmlWriter, font, value, name, attrs):
363d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		xmlWriter.simpletag(name, attrs + [("value", value)])
364d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		xmlWriter.newline()
365d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
366d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	def xmlRead(self, attrs, content, font):
367d4d151390d1288f8d2df30f6dfa26a309c7334dajvr		return safeEval(attrs["value"])
368d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
369d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
370d4d151390d1288f8d2df30f6dfa26a309c7334dajvrconverterMapping = {
371d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	# type         class
372d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	"int16":       Short,
373d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	"uint16":      UShort,
3749e1bd2d0b4416acc7fce623a3bae37064d61d15bBehdad Esfahbod	"uint24":      UInt24,
375a221a57ccdeefc752384778444ee737d4559a516Behdad Esfahbod	"Version":     Version,
376d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	"Tag":         Tag,
377d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	"GlyphID":     GlyphID,
3783ac9e63fce920ca3cf12f53e067641849c9cdbb4Behdad Esfahbod	"DeciPoints":  DeciPoints,
379d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	"struct":      Struct,
380d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	"Offset":      Table,
381d58c38dc3660f764b659ec13fcbc6e54c1ec2078Behdad Esfahbod	"LOffset":     LTable,
382d4d151390d1288f8d2df30f6dfa26a309c7334dajvr	"ValueRecord": ValueRecord,
3837d130307e6e6094e40a841a3c41fc74b203b7e8eBehdad Esfahbod	"DeltaValue":  DeltaValue,
384d4d151390d1288f8d2df30f6dfa26a309c7334dajvr}
385d4d151390d1288f8d2df30f6dfa26a309c7334dajvr
386