G_P_O_S_.py revision a36fd88a20e9441bef930a870b7e4ce7c9ef597c
1import otCommon
2
3
4class table_G_P_O_S_(otCommon.base_GPOS_GSUB):
5
6	def getLookupTypeClass(self, lookupType):
7		return lookupTypeClasses[lookupType]
8
9
10class SinglePos:
11
12	def decompile(self, reader, otFont):
13		self.format = reader.readUShort()
14		if self.format == 1:
15			self.decompileFormat1(reader, otFont)
16		elif self.format == 2:
17			self.decompileFormat2(reader, otFont)
18		else:
19			from fontTools import ttLib
20			raise ttLib.TTLibError, "unknown SinglePos format: %d" % self.format
21
22	def decompileFormat1(self, reader, otFont):
23		coverage = reader.readTable(otCommon.CoverageTable, otFont)
24		valueFactory = ValueRecordFactory(reader.readUShort())
25		self.coverage = coverage.getGlyphNames()
26		self.value = valueFactory.readValueRecord(reader, otFont)
27
28	def decompileFormat2(self, reader, otFont):
29		coverage = reader.readTable(otCommon.CoverageTable, otFont)
30		valueFactory = ValueRecordFactory(reader.readUShort())
31		valueCount = reader.readUShort()
32		glyphNames = coverage.getGlyphNames()
33		self.pos = pos = {}
34		for i in range(valueCount):
35			pos[glyphNames[i]] = valueFactory.readValueRecord(reader, otFont)
36
37	def compile(self, writer, otFont):
38		xxx
39
40	def toXML(self, xmlWriter, otFont):
41		xmlWriter.comment("NotImplemented")
42		xmlWriter.newline()
43
44	def fromXML(self, (name, attrs, content), otFont):
45		raise NotImplementedError
46
47
48class PairPos:
49
50	def decompile(self, reader, otFont):
51		self.format = reader.readUShort()
52		if self.format == 1:
53			self.decompileFormat1(reader, otFont)
54		elif self.format == 2:
55			self.decompileFormat2(reader, otFont)
56		else:
57			from fontTools import ttLib
58			raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format
59
60	def decompileFormat1(self, reader, otFont):
61		coverage = reader.readTable(otCommon.CoverageTable, otFont)
62		glyphNames = coverage.glyphNames
63		valueFactory1 = ValueRecordFactory(reader.readUShort())
64		valueFactory2 = ValueRecordFactory(reader.readUShort())
65		self.pairs = pairs = {}
66		for i in range(reader.readUShort()):
67			firstGlyphName = glyphNames[i]
68			set = reader.readTable(PairSet, otFont, valueFactory1, valueFactory2)
69			pairs[firstGlyphName] = set.getValues()
70
71	def decompileFormat2(self, reader, otFont):
72		coverage = reader.readTable(otCommon.CoverageTable, otFont)
73		glyphNames = coverage.glyphNames
74		valueFactory1 = ValueRecordFactory(reader.readUShort())
75		valueFactory2 = ValueRecordFactory(reader.readUShort())
76		self.classDef1 = reader.readTable(otCommon.ClassDefinitionTable, otFont)
77		self.classDef2 = reader.readTable(otCommon.ClassDefinitionTable, otFont)
78		class1Count = reader.readUShort()
79		class2Count = reader.readUShort()
80		self.pairs = pairs = {}  # sparse matrix
81		for i in range(class1Count):
82			row = {}
83			for j in range(class2Count):
84				value1 = valueFactory1.readValueRecord(reader, otFont)
85				value2 = valueFactory2.readValueRecord(reader, otFont)
86				if value1 or value2:
87					row[j] = (value1, value2)
88			if row:
89				pairs[i] = row
90
91	def compile(self, writer, otFont):
92		if self.format == 1:
93			self.compileFormat1(writer, otFont)
94		elif self.format == 2:
95			self.compileFormat2(writer, otFont)
96		else:
97			from fontTools import ttLib
98			raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format
99
100	def compileFormat1(self, writer, otFont):
101		pairs = self.pairs
102		glyphNames = pairs.keys()
103		coverage = otCommon.CoverageTable()
104		glyphNames = coverage.setGlyphNames(glyphNames, otFont)
105		writer.writeTable(coverage, otFont)
106		# dumb approach: just take the first pair and grab the value.
107		dummy, sample1, sample2 = pairs[pairs.keys()[0]][0]
108		valueFormat1 = valueFormat2 = 0
109		if sample1:
110			valueFormat1 = sample1.getFormat()
111		if sample2:
112			valueFormat2 = sample2.getFormat()
113		writer.writeUShort(valueFormat1)
114		writer.writeUShort(valueFormat2)
115
116		valueFactory1 = ValueRecordFactory(valueFormat1)
117		valueFactory2 = ValueRecordFactory(valueFormat2)
118
119		writer.writeUShort(len(pairs))
120		for glyphName in glyphNames:
121			set = PairSet(valueFactory1, valueFactory2)
122			set.setValues(pairs[glyphName])
123			writer.writeTable(set, otFont)
124
125	def compileFormat2(self, writer, otFont):
126		xxx
127
128	def toXML(self, xmlWriter, otFont):
129		if self.format == 1:
130			self.toXMLFormat1(xmlWriter, otFont)
131		elif self.format == 2:
132			self.toXMLFormat2(xmlWriter, otFont)
133		else:
134			from fontTools import ttLib
135			raise ttLib.TTLibError, "unknown PairPos format: %d" % self.format
136
137	def toXMLFormat1(self, xmlWriter, otFont):
138		pairs = self.pairs.items()
139		pairs.sort()
140		for firstGlyph, secondGlyphs in pairs:
141			for secondGlyph, value1, value2 in secondGlyphs:
142				xmlWriter.begintag("Pair", pair=firstGlyph+","+secondGlyph)
143				if value1:
144					value1.toXML(xmlWriter, otFont)
145				else:
146					xmlWriter.simpletag("Value")
147				if value2:
148					value2.toXML(xmlWriter, otFont)
149				#else:  # the second value can be omitted
150				#	xmlWriter.simpletag("Value")
151				xmlWriter.endtag("Pair")
152				xmlWriter.newline()
153
154	def toXMLFormat2(self, xmlWriter, otFont):
155		xmlWriter.comment("NotImplemented")
156		xmlWriter.newline()
157
158	def fromXML(self, (name, attrs, content), otFont):
159		raise NotImplementedError
160
161
162class PairSet:
163
164	def __init__(self, valueFactory1=None, valueFactory2=None):
165		self.valueFactory1 = valueFactory1
166		self.valueFactory2 = valueFactory2
167
168	def getValues(self):
169		return self.values
170
171	def setValues(self, values):
172		self.values = values
173
174	def decompile(self, reader, otFont):
175		pairValueCount = reader.readUShort()
176		self.values = values = []
177		for j in range(pairValueCount):
178			secondGlyphID = reader.readUShort()
179			secondGlyphName = otFont.getGlyphName(secondGlyphID)
180			value1 = self.valueFactory1.readValueRecord(reader, otFont)
181			value2 = self.valueFactory2.readValueRecord(reader, otFont)
182			values.append((secondGlyphName, value1, value2))
183
184	def compile(self, writer, otFont):
185		values = self.values
186		writer.writeUShort(len(values))
187		for secondGlyphName, value1, value2 in values:
188			writer.writeUShort(otFont.getGlyphID(secondGlyphName))
189			self.valueFactory1.writeValuerecord(value1, writer, otFont)
190			self.valueFactory2.writeValuerecord(value2, writer, otFont)
191
192
193#
194# ------------------
195#
196
197class CursivePos:
198
199	def decompile(self, reader, otFont):
200		xxx
201
202	def compile(self, writer, otFont):
203		xxx
204
205	def toXML(self, xmlWriter, otFont):
206		xmlWriter.comment("NotImplemented")
207		xmlWriter.newline()
208
209
210class MarkBasePos:
211
212	def decompile(self, reader, otFont):
213		xxx
214
215	def compile(self, writer, otFont):
216		xxx
217
218	def toXML(self, xmlWriter, otFont):
219		xmlWriter.comment("NotImplemented")
220		xmlWriter.newline()
221
222
223class MarkLigPos:
224
225	def decompile(self, reader, otFont):
226		xxx
227
228	def compile(self, writer, otFont):
229		xxx
230
231	def toXML(self, xmlWriter, otFont):
232		xmlWriter.comment("NotImplemented")
233		xmlWriter.newline()
234
235
236class MarkMarkPos:
237
238	def decompile(self, reader, otFont):
239		xxx
240
241	def compile(self, writer, otFont):
242		xxx
243
244	def toXML(self, xmlWriter, otFont):
245		xmlWriter.comment("NotImplemented")
246		xmlWriter.newline()
247
248
249class ContextPos:
250
251	def decompile(self, reader, otFont):
252		xxx
253
254	def compile(self, writer, otFont):
255		xxx
256
257	def toXML(self, xmlWriter, otFont):
258		xmlWriter.comment("NotImplemented")
259		xmlWriter.newline()
260
261
262class ChainContextPos:
263
264	def decompile(self, reader, otFont):
265		xxx
266
267	def compile(self, writer, otFont):
268		xxx
269
270	def toXML(self, xmlWriter, otFont):
271		xmlWriter.comment("NotImplemented")
272		xmlWriter.newline()
273
274
275valueRecordFormat = [
276#	Mask	 Name		     isDevice  struct format char
277	(0x0001, "XPlacement",   0,        "h"),
278	(0x0002, "YPlacement",   0,        "h"),
279	(0x0004, "XAdvance",     0,        "h"),
280	(0x0008, "YAdvance",     0,        "h"),
281	(0x0010, "XPlaDevice",   1,        "H"),
282	(0x0020, "YPlaDevice",   1,        "H"),
283	(0x0040, "XAdvDevice",   1,        "H"),
284	(0x0080, "YAdvDevice",   1,        "H"),
285# 	reserved:
286	(0x0100, "Reserved1",    0,        "H"),
287	(0x0200, "Reserved2",    0,        "H"),
288	(0x0400, "Reserved3",    0,        "H"),
289	(0x0800, "Reserved4",    0,        "H"),
290	(0x1000, "Reserved5",    0,        "H"),
291	(0x2000, "Reserved6",    0,        "H"),
292	(0x4000, "Reserved7",    0,        "H"),
293	(0x8000, "Reserved8",    0,        "H"),
294]
295
296valueRecordFormatDict = {}
297for mask, name, isDevice, format in valueRecordFormat:
298	valueRecordFormatDict[name] = mask, isDevice, format
299
300
301class ValueRecordFactory:
302
303	def __init__(self, valueFormat):
304		format = ">"
305		names = []
306		for mask, name, isDevice, formatChar in valueRecordFormat:
307			if valueFormat & mask:
308				names.append((name, isDevice))
309				format = format + formatChar
310		self.names, self.format = names, format
311		self.size = 2 * len(names)
312
313	def readValueRecord(self, reader, otFont):
314		names = self.names
315		if not names:
316			return None
317		values = reader.readStruct(self.format, self.size)
318		values = map(int, values)
319		valueRecord = ValueRecord()
320		items = map(None, names, values)
321		for (name, isDevice), value in items:
322			if isDevice:
323				if value:
324					device = otCommon.DeviceTable()
325					device.decompile(reader.getSubString(value), otFont)
326				else:
327					device = None
328				setattr(valueRecord, name, device)
329			else:
330				setattr(valueRecord, name, value)
331		return valueRecord
332
333	def writeValuerecord(self, valueRecord, writer, otFont):
334		values = []
335		for (name, isDevice) in self.names:
336			if isDevice:
337				raise NotImplementedError
338			else:
339				values.append(valueRecord.__dict__.get(name, 0))
340		writer.writeStruct(self.format, tuple(values))
341
342
343class ValueRecord:
344	# see ValueRecordFactory
345
346	def getFormat(self):
347		format = 0
348		for name in self.__dict__.keys():
349			format = format | valueRecordFormatDict[name][0]
350		return format
351
352	def toXML(self, xmlWriter, otFont):
353		simpleItems = []
354		for mask, name, isDevice, format in valueRecordFormat[:4]:  # "simple" values
355			if hasattr(self, name):
356				simpleItems.append((name, getattr(self, name)))
357		deviceItems = []
358		for mask, name, isDevice, format in valueRecordFormat[4:8]:  # device records
359			if hasattr(self, name):
360				deviceItems.append((name, getattr(self, name)))
361		if deviceItems:
362			xmlWriter.begintag("Value", simpleItems)
363			xmlWriter.newline()
364			for name, deviceRecord in deviceItems:
365				xxx
366			xmlWriter.endtag("Value")
367		else:
368			xmlWriter.simpletag("Value", simpleItems)
369
370	def __repr__(self):
371		return "<ValueRecord>"
372
373
374lookupTypeClasses = {
375	1: SinglePos,
376	2: PairPos,
377	3: CursivePos,
378	4: MarkBasePos,
379	5: MarkLigPos,
380	6: MarkMarkPos,
381	7: ContextPos,
382	8: ChainContextPos,
383}
384
385