_m_a_x_p.py revision ac1b4359467ca3deab03186a15eae1d55eb35567
12b06aaa2a6bcd363c25fb0c43f6bb906906594bdBehdad Esfahbodfrom . import DefaultTable
28413c108d21e8cf0e9059bbfffde8d13f2616340Behdad Esfahbodfrom fontTools.misc import sstruct
37842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools.misc.textTools import safeEval
47842e56b97ce677b83bdab09cda48bc2d89ac75aJust
57842e56b97ce677b83bdab09cda48bc2d89ac75aJustmaxpFormat_0_5 = """
67842e56b97ce677b83bdab09cda48bc2d89ac75aJust		>	# big endian
7898295619d8df4e4422c566cd9499c48d1d6b647jvr		tableVersion:           i
8898295619d8df4e4422c566cd9499c48d1d6b647jvr		numGlyphs:              H
97842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""
107842e56b97ce677b83bdab09cda48bc2d89ac75aJust
117842e56b97ce677b83bdab09cda48bc2d89ac75aJustmaxpFormat_1_0_add = """
127842e56b97ce677b83bdab09cda48bc2d89ac75aJust		>	# big endian
13898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxPoints:              H
14898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxContours:            H
15898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxCompositePoints:     H
16898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxCompositeContours:   H
17898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxZones:               H
18898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxTwilightPoints:      H
19898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxStorage:             H
20898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxFunctionDefs:        H
21898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxInstructionDefs:     H
22898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxStackElements:       H
23898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxSizeOfInstructions:  H
24898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxComponentElements:   H
25898295619d8df4e4422c566cd9499c48d1d6b647jvr		maxComponentDepth:      H
267842e56b97ce677b83bdab09cda48bc2d89ac75aJust"""
277842e56b97ce677b83bdab09cda48bc2d89ac75aJust
287842e56b97ce677b83bdab09cda48bc2d89ac75aJust
297842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass table__m_a_x_p(DefaultTable.DefaultTable):
307842e56b97ce677b83bdab09cda48bc2d89ac75aJust
317842e56b97ce677b83bdab09cda48bc2d89ac75aJust	dependencies = ['glyf']
327842e56b97ce677b83bdab09cda48bc2d89ac75aJust
337842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
347842e56b97ce677b83bdab09cda48bc2d89ac75aJust		dummy, data = sstruct.unpack2(maxpFormat_0_5, data, self)
357842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.numGlyphs = int(self.numGlyphs)
36bc90c7a05b2e5114db9b0c0a6448e68d80ccf622jvr		if self.tableVersion != 0x00005000:
377842e56b97ce677b83bdab09cda48bc2d89ac75aJust			dummy, data = sstruct.unpack2(maxpFormat_1_0_add, data, self)
387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert len(data) == 0
397842e56b97ce677b83bdab09cda48bc2d89ac75aJust
407842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
41bc5e1cb195c0bfa1c8e7507326d5a9ad05aecb4bBehdad Esfahbod		if 'glyf' in ttFont:
423e097c609540944dd9290ad58df346ca86492031Just			if ttFont.isLoaded('glyf') and ttFont.recalcBBoxes:
437842e56b97ce677b83bdab09cda48bc2d89ac75aJust				self.recalc(ttFont)
447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
45bc90c7a05b2e5114db9b0c0a6448e68d80ccf622jvr			pass  # CFF
4607dd0e4504fcdf7bfb0aaee4350435e03ab2c2d8jvr		self.numGlyphs = len(ttFont.getGlyphOrder())
47bc90c7a05b2e5114db9b0c0a6448e68d80ccf622jvr		if self.tableVersion != 0x00005000:
48bc90c7a05b2e5114db9b0c0a6448e68d80ccf622jvr			self.tableVersion = 0x00010000
497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = sstruct.pack(maxpFormat_0_5, self)
507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if self.tableVersion == 0x00010000:
517842e56b97ce677b83bdab09cda48bc2d89ac75aJust			data = data + sstruct.pack(maxpFormat_1_0_add, self)
527842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return data
537842e56b97ce677b83bdab09cda48bc2d89ac75aJust
547842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def recalc(self, ttFont):
557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""Recalculate the font bounding box, and most other maxp values except
567842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for the TT instructions values. Also recalculate the value of bit 1
57fc99ad1513ca5443a29f1cc99df6016325e8dcbbPetr		of the flags field and the font bounding box of the 'head' table.
587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		"""
597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyfTable = ttFont['glyf']
607842e56b97ce677b83bdab09cda48bc2d89ac75aJust		hmtxTable = ttFont['hmtx']
617842e56b97ce677b83bdab09cda48bc2d89ac75aJust		headTable = ttFont['head']
627842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.numGlyphs = len(glyfTable)
63d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader		INFINITY = 100000
64d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader		xMin = +INFINITY
65d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader		yMin = +INFINITY
66d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader		xMax = -INFINITY
67d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader		yMax = -INFINITY
687842e56b97ce677b83bdab09cda48bc2d89ac75aJust		maxPoints = 0
697842e56b97ce677b83bdab09cda48bc2d89ac75aJust		maxContours = 0
707842e56b97ce677b83bdab09cda48bc2d89ac75aJust		maxCompositePoints = 0
717842e56b97ce677b83bdab09cda48bc2d89ac75aJust		maxCompositeContours = 0
727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		maxComponentElements = 0
737842e56b97ce677b83bdab09cda48bc2d89ac75aJust		maxComponentDepth = 0
747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		allXMaxIsLsb = 1
757842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for glyphName in ttFont.getGlyphOrder():
767842e56b97ce677b83bdab09cda48bc2d89ac75aJust			g = glyfTable[glyphName]
777842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if g.numberOfContours:
78180ace6a5ff1399ec53bc696e8bef7cce6eef39aBehdad Esfahbod				if hmtxTable[glyphName][1] != g.xMin:
797842e56b97ce677b83bdab09cda48bc2d89ac75aJust					allXMaxIsLsb = 0
807842e56b97ce677b83bdab09cda48bc2d89ac75aJust				xMin = min(xMin, g.xMin)
817842e56b97ce677b83bdab09cda48bc2d89ac75aJust				yMin = min(yMin, g.yMin)
827842e56b97ce677b83bdab09cda48bc2d89ac75aJust				xMax = max(xMax, g.xMax)
837842e56b97ce677b83bdab09cda48bc2d89ac75aJust				yMax = max(yMax, g.yMax)
847842e56b97ce677b83bdab09cda48bc2d89ac75aJust				if g.numberOfContours > 0:
857842e56b97ce677b83bdab09cda48bc2d89ac75aJust					nPoints, nContours = g.getMaxpValues()
867842e56b97ce677b83bdab09cda48bc2d89ac75aJust					maxPoints = max(maxPoints, nPoints)
877842e56b97ce677b83bdab09cda48bc2d89ac75aJust					maxContours = max(maxContours, nContours)
887842e56b97ce677b83bdab09cda48bc2d89ac75aJust				else:
897842e56b97ce677b83bdab09cda48bc2d89ac75aJust					nPoints, nContours, componentDepth = g.getCompositeMaxpValues(glyfTable)
907842e56b97ce677b83bdab09cda48bc2d89ac75aJust					maxCompositePoints = max(maxCompositePoints, nPoints)
917842e56b97ce677b83bdab09cda48bc2d89ac75aJust					maxCompositeContours = max(maxCompositeContours, nContours)
927842e56b97ce677b83bdab09cda48bc2d89ac75aJust					maxComponentElements = max(maxComponentElements, len(g.components))
937842e56b97ce677b83bdab09cda48bc2d89ac75aJust					maxComponentDepth = max(maxComponentDepth, componentDepth)
94d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader		if xMin == +INFINITY:
95d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader			headTable.xMin = 0
96d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader			headTable.yMin = 0
97d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader			headTable.xMax = 0
98d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader			headTable.yMax = 0
99d7921e33d9d1944c394e6c17b3746e7108dd1da4Roozbeh Pournader		else:
100cff3740f1440997cd013f538fecb06243d13c6a1Denis Jacquerye		    headTable.xMin = xMin
101cff3740f1440997cd013f538fecb06243d13c6a1Denis Jacquerye		    headTable.yMin = yMin
102cff3740f1440997cd013f538fecb06243d13c6a1Denis Jacquerye		    headTable.xMax = xMax
103cff3740f1440997cd013f538fecb06243d13c6a1Denis Jacquerye		    headTable.yMax = yMax
1047842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.maxPoints = maxPoints
1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.maxContours = maxContours
1067842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.maxCompositePoints = maxCompositePoints
1077842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.maxCompositeContours = maxCompositeContours
1087842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.maxComponentDepth = maxComponentDepth
1097842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if allXMaxIsLsb:
1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust			headTable.flags = headTable.flags | 0x2
1117842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust			headTable.flags = headTable.flags & ~0x2
1137842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def testrepr(self):
115ac1b4359467ca3deab03186a15eae1d55eb35567Behdad Esfahbod		items = sorted(self.__dict__.items())
1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust		print ". . . . . . . . ."
1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for combo in items:
1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust			print "  %s: %s" % combo
1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust		print ". . . . . . . . ."
1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
122bc90c7a05b2e5114db9b0c0a6448e68d80ccf622jvr		if self.tableVersion != 0x00005000:
1237842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.comment("Most of this table will be recalculated by the compiler")
1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
1257842e56b97ce677b83bdab09cda48bc2d89ac75aJust		formatstring, names, fixes = sstruct.getformat(maxpFormat_0_5)
126bc90c7a05b2e5114db9b0c0a6448e68d80ccf622jvr		if self.tableVersion != 0x00005000:
1277842e56b97ce677b83bdab09cda48bc2d89ac75aJust			formatstring, names_1_0, fixes = sstruct.getformat(maxpFormat_1_0_add)
1287842e56b97ce677b83bdab09cda48bc2d89ac75aJust			names = names + names_1_0
1297842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for name in names:
1307842e56b97ce677b83bdab09cda48bc2d89ac75aJust			value = getattr(self, name)
1317842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if name == "tableVersion":
1327842e56b97ce677b83bdab09cda48bc2d89ac75aJust				value = hex(value)
1337842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.simpletag(name, value=value)
1347842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
1357842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1363a9fd301808f5a8991ca9ac44028d1ecb22d307fBehdad Esfahbod	def fromXML(self, name, attrs, content, ttFont):
1377842e56b97ce677b83bdab09cda48bc2d89ac75aJust		setattr(self, name, safeEval(attrs["value"]))
1387842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1397842e56b97ce677b83bdab09cda48bc2d89ac75aJust
140