_c_m_a_p.py revision 1f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3
17842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport DefaultTable
27842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport struct
37842e56b97ce677b83bdab09cda48bc2d89ac75aJustimport array
47842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools import ttLib
57842e56b97ce677b83bdab09cda48bc2d89ac75aJustfrom fontTools.misc.textTools import safeEval, readHex
622dcb9e6f9a9d087e87cece6caca6aa5d92f4d91jvrfrom types import TupleType
77842e56b97ce677b83bdab09cda48bc2d89ac75aJust
87842e56b97ce677b83bdab09cda48bc2d89ac75aJust
97842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass table__c_m_a_p(DefaultTable.DefaultTable):
107842e56b97ce677b83bdab09cda48bc2d89ac75aJust
117842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def getcmap(self, platformID, platEncID):
127842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for subtable in self.tables:
137842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if (subtable.platformID == platformID and
147842e56b97ce677b83bdab09cda48bc2d89ac75aJust					subtable.platEncID == platEncID):
157842e56b97ce677b83bdab09cda48bc2d89ac75aJust				return subtable
167842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return None # not found
177842e56b97ce677b83bdab09cda48bc2d89ac75aJust
187842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
197842e56b97ce677b83bdab09cda48bc2d89ac75aJust		tableVersion, numSubTables = struct.unpack(">HH", data[:4])
207842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.tableVersion = int(tableVersion)
217842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.tables = tables = []
227842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(numSubTables):
237842e56b97ce677b83bdab09cda48bc2d89ac75aJust			platformID, platEncID, offset = struct.unpack(
247842e56b97ce677b83bdab09cda48bc2d89ac75aJust					">HHl", data[4+i*8:4+(i+1)*8])
257842e56b97ce677b83bdab09cda48bc2d89ac75aJust			platformID, platEncID = int(platformID), int(platEncID)
267842e56b97ce677b83bdab09cda48bc2d89ac75aJust			format, length = struct.unpack(">HH", data[offset:offset+4])
27ae180248fdc1abcd10f782c8e32b77a62594d349Just			if not length:
28ae180248fdc1abcd10f782c8e32b77a62594d349Just				continue  # bogus cmap subtable?
297842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if not cmap_classes.has_key(format):
307842e56b97ce677b83bdab09cda48bc2d89ac75aJust				table = cmap_format_unknown(format)
317842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
327842e56b97ce677b83bdab09cda48bc2d89ac75aJust				table = cmap_classes[format](format)
337842e56b97ce677b83bdab09cda48bc2d89ac75aJust			table.platformID = platformID
347842e56b97ce677b83bdab09cda48bc2d89ac75aJust			table.platEncID = platEncID
357842e56b97ce677b83bdab09cda48bc2d89ac75aJust			table.decompile(data[offset:offset+int(length)], ttFont)
367842e56b97ce677b83bdab09cda48bc2d89ac75aJust			tables.append(table)
377842e56b97ce677b83bdab09cda48bc2d89ac75aJust
387842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
397842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.tables.sort()    # sort according to the spec; see CmapSubtable.__cmp__()
407842e56b97ce677b83bdab09cda48bc2d89ac75aJust		numSubTables = len(self.tables)
417842e56b97ce677b83bdab09cda48bc2d89ac75aJust		totalOffset = 4 + 8 * numSubTables
427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = struct.pack(">HH", self.tableVersion, numSubTables)
437842e56b97ce677b83bdab09cda48bc2d89ac75aJust		tableData = ""
447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		done = {}  # remember the data so we can reuse the "pointers"
457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for table in self.tables:
467842e56b97ce677b83bdab09cda48bc2d89ac75aJust			chunk = table.compile(ttFont)
477842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if done.has_key(chunk):
487842e56b97ce677b83bdab09cda48bc2d89ac75aJust				offset = done[chunk]
497842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
507842e56b97ce677b83bdab09cda48bc2d89ac75aJust				offset = done[chunk] = totalOffset + len(tableData)
511b850986ef5611934a43bd31104a398e311af713Just				tableData = tableData + chunk
527842e56b97ce677b83bdab09cda48bc2d89ac75aJust			data = data + struct.pack(">HHl", table.platformID, table.platEncID, offset)
537842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return data + tableData
547842e56b97ce677b83bdab09cda48bc2d89ac75aJust
557842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
567842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.simpletag("tableVersion", version=self.tableVersion)
577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for table in self.tables:
597842e56b97ce677b83bdab09cda48bc2d89ac75aJust			table.toXML(writer, ttFont)
607842e56b97ce677b83bdab09cda48bc2d89ac75aJust
617842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def fromXML(self, (name, attrs, content), ttFont):
627842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if name == "tableVersion":
637842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.tableVersion = safeEval(attrs["version"])
647842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return
657842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if name[:12] <> "cmap_format_":
667842e56b97ce677b83bdab09cda48bc2d89ac75aJust			return
677842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if not hasattr(self, "tables"):
687842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.tables = []
697842e56b97ce677b83bdab09cda48bc2d89ac75aJust		format = safeEval(name[12])
707842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if not cmap_classes.has_key(format):
717842e56b97ce677b83bdab09cda48bc2d89ac75aJust			table = cmap_format_unknown(format)
727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		else:
737842e56b97ce677b83bdab09cda48bc2d89ac75aJust			table = cmap_classes[format](format)
747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		table.platformID = safeEval(attrs["platformID"])
757842e56b97ce677b83bdab09cda48bc2d89ac75aJust		table.platEncID = safeEval(attrs["platEncID"])
767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		table.fromXML((name, attrs, content), ttFont)
777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.tables.append(table)
787842e56b97ce677b83bdab09cda48bc2d89ac75aJust
797842e56b97ce677b83bdab09cda48bc2d89ac75aJust
807842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass CmapSubtable:
817842e56b97ce677b83bdab09cda48bc2d89ac75aJust
827842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __init__(self, format):
837842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.format = format
847842e56b97ce677b83bdab09cda48bc2d89ac75aJust
857842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
867842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.begintag(self.__class__.__name__, [
877842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platformID", self.platformID),
887842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platEncID", self.platEncID),
897842e56b97ce677b83bdab09cda48bc2d89ac75aJust				])
907842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
917842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.dumphex(self.compile(ttFont))
927842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.endtag(self.__class__.__name__)
937842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
947842e56b97ce677b83bdab09cda48bc2d89ac75aJust
957842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def fromXML(self, (name, attrs, content), ttFont):
967842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.decompile(readHex(content), ttFont)
977842e56b97ce677b83bdab09cda48bc2d89ac75aJust
987842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def __cmp__(self, other):
997842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# implemented so that list.sort() sorts according to the cmap spec.
1007842e56b97ce677b83bdab09cda48bc2d89ac75aJust		selfTuple = (
1017842e56b97ce677b83bdab09cda48bc2d89ac75aJust					self.platformID,
1027842e56b97ce677b83bdab09cda48bc2d89ac75aJust					self.platEncID,
1037842e56b97ce677b83bdab09cda48bc2d89ac75aJust					self.version,
1047842e56b97ce677b83bdab09cda48bc2d89ac75aJust					self.__dict__)
1057842e56b97ce677b83bdab09cda48bc2d89ac75aJust		otherTuple = (
1067842e56b97ce677b83bdab09cda48bc2d89ac75aJust					other.platformID,
1077842e56b97ce677b83bdab09cda48bc2d89ac75aJust					other.platEncID,
1087842e56b97ce677b83bdab09cda48bc2d89ac75aJust					other.version,
1097842e56b97ce677b83bdab09cda48bc2d89ac75aJust					other.__dict__)
1107842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return cmp(selfTuple, otherTuple)
1117842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1127842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1137842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass cmap_format_0(CmapSubtable):
1147842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1157842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
1167842e56b97ce677b83bdab09cda48bc2d89ac75aJust		format, length, version = struct.unpack(">HHH", data[:6])
1177842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.version = int(version)
1187842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert len(data) == 262 == length
1197842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphIdArray = array.array("B")
1207842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphIdArray.fromstring(data[6:])
1217842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.cmap = cmap = {}
1227842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for charCode in range(len(glyphIdArray)):
1237842e56b97ce677b83bdab09cda48bc2d89ac75aJust			cmap[charCode] = ttFont.getGlyphName(glyphIdArray[charCode])
1247842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1257842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
1267842e56b97ce677b83bdab09cda48bc2d89ac75aJust		charCodes = self.cmap.keys()
1277842e56b97ce677b83bdab09cda48bc2d89ac75aJust		charCodes.sort()
1287842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert charCodes == range(256)  # charCodes[charCode] == charCode
1297842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for charCode in charCodes:
1307842e56b97ce677b83bdab09cda48bc2d89ac75aJust			# reusing the charCodes list!
1317842e56b97ce677b83bdab09cda48bc2d89ac75aJust			charCodes[charCode] = ttFont.getGlyphID(self.cmap[charCode])
1327842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphIdArray = array.array("B", charCodes)
1337842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = struct.pack(">HHH", 0, 262, self.version) + glyphIdArray.tostring()
1347842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert len(data) == 262
1357842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return data
1367842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1377842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
1387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.begintag(self.__class__.__name__, [
1397842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platformID", self.platformID),
1407842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platEncID", self.platEncID),
1417842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("version", self.version),
1427842e56b97ce677b83bdab09cda48bc2d89ac75aJust				])
1437842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
1447842e56b97ce677b83bdab09cda48bc2d89ac75aJust		items = self.cmap.items()
1457842e56b97ce677b83bdab09cda48bc2d89ac75aJust		items.sort()
1467842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for code, name in items:
1477842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.simpletag("map", code=hex(code), name=name)
1487842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
1497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.endtag(self.__class__.__name__)
1507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
1517842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1527842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def fromXML(self, (name, attrs, content), ttFont):
1537842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.version = safeEval(attrs["version"])
1547842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.cmap = {}
1557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for element in content:
15622dcb9e6f9a9d087e87cece6caca6aa5d92f4d91jvr			if type(element) <> TupleType:
1577842e56b97ce677b83bdab09cda48bc2d89ac75aJust				continue
1587842e56b97ce677b83bdab09cda48bc2d89ac75aJust			name, attrs, content = element
1597842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if name <> "map":
1607842e56b97ce677b83bdab09cda48bc2d89ac75aJust				continue
1617842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.cmap[safeEval(attrs["code"])] = attrs["name"]
1627842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1637842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1647842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass cmap_format_2(CmapSubtable):
1657842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1667842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
1677842e56b97ce677b83bdab09cda48bc2d89ac75aJust		format, length, version = struct.unpack(">HHH", data[:6])
1687842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.version = int(version)
1697842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.data = data
1707842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1717842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
1727842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.data
1737842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1747842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1757842e56b97ce677b83bdab09cda48bc2d89ac75aJustcmap_format_4_format = ">7H"
1767842e56b97ce677b83bdab09cda48bc2d89ac75aJust
1771f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr#uint16  endCode[segCount]          # Ending character code for each segment, last = 0xFFFF.
1781f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr#uint16  reservedPad                # This value should be zero
1791f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr#uint16  startCode[segCount]        # Starting character code for each segment
1801f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr#uint16  idDelta[segCount]          # Delta for all character codes in segment
1811f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr#uint16  idRangeOffset[segCount]    # Offset in bytes to glyph indexArray, or 0
1821f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr#uint16  glyphIndexArray[variable]  # Glyph index array
1837842e56b97ce677b83bdab09cda48bc2d89ac75aJust
184542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvrdef splitRange(startCode, endCode, cmap):
1851f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# Try to split a range of character codes into subranges with consecutive
1861f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# glyph IDs in such a way that the cmap4 subtable can be stored "most"
1871f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# efficiently. I can't prove I've got the optimal solution, but it seems
1881f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# to do well with the fonts I tested: none became bigger, many became smaller.
189542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	if startCode == endCode:
190542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		return [], [endCode]
191542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
192542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	lastID = cmap[startCode]
193542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	lastCode = startCode
194542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	inOrder = None
195542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	orderedBegin = None
1961f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	subRanges = []
197542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
1981f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# Gather subranges in which the glyph IDs are consecutive.
199542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	for code in range(startCode + 1, endCode + 1):
200542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		glyphID = cmap[code]
201542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
202542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		if glyphID - 1 == lastID:
203542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			if inOrder is None or not inOrder:
204542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr				inOrder = 1
205542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr				orderedBegin = lastCode
206542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		else:
207542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			if inOrder:
208542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr				inOrder = 0
2091f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr				subRanges.append((orderedBegin, lastCode))
210542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr				orderedBegin = None
211542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
212542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		lastID = glyphID
213542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		lastCode = code
214542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
215542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	if inOrder:
2161f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		subRanges.append((orderedBegin, lastCode))
217542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	assert lastCode == endCode
218542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
2191f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# Now filter out those new subranges that would only make the data bigger.
2201f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# A new segment cost 8 bytes, not using a new segment costs 2 bytes per
2211f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# character.
2221f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	newRanges = []
2231f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	for b, e in subRanges:
224542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		if b == startCode and e == endCode:
225542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			break  # the whole range, we're fine
226542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		if b == startCode or e == endCode:
227542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			threshold = 4  # split costs one more segment
228542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		else:
229542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			threshold = 8  # split costs two more segments
230542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		if (e - b + 1) > threshold:
2311f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr			newRanges.append((b, e))
2321f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	subRanges = newRanges
233542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
2341f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	if not subRanges:
235542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		return [], [endCode]
236542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
2371f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	if subRanges[0][0] != startCode:
2381f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		subRanges.insert(0, (startCode, subRanges[0][0] - 1))
2391f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	if subRanges[-1][1] != endCode:
2401f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		subRanges.append((subRanges[-1][1] + 1, endCode))
2411f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr
2421f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# Fill the "holes" in the segments list -- those are the segments in which
2431f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# the glyph IDs are _not_ consecutive.
244542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	i = 1
2451f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	while i < len(subRanges):
2461f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		if subRanges[i-1][1] + 1 != subRanges[i][0]:
2471f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr			subRanges.insert(i, (subRanges[i-1][1] + 1, subRanges[i][0] - 1))
248542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			i = i + 1
249542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		i = i + 1
250542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
2511f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	# Transform the ranges into startCode/endCode lists.
252542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	start = []
253542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	end = []
2541f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr	for b, e in subRanges:
255542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		start.append(b)
256542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		end.append(e)
257542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	start.pop(0)
258542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
259542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	assert len(start) + 1 == len(end)
260542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr	return start, end
261542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
262542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
2637842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass cmap_format_4(CmapSubtable):
2647842e56b97ce677b83bdab09cda48bc2d89ac75aJust
2657842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
2667842e56b97ce677b83bdab09cda48bc2d89ac75aJust		(format, length, self.version, segCountX2,
2677842e56b97ce677b83bdab09cda48bc2d89ac75aJust				searchRange, entrySelector, rangeShift) = \
2687842e56b97ce677b83bdab09cda48bc2d89ac75aJust					struct.unpack(cmap_format_4_format, data[:14])
2697842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert len(data) == length, "corrupt cmap table (%d, %d)" % (len(data), length)
2707842e56b97ce677b83bdab09cda48bc2d89ac75aJust		segCount = segCountX2 / 2
2717842e56b97ce677b83bdab09cda48bc2d89ac75aJust
272542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		allCodes = array.array("H")
273542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		allCodes.fromstring(data[14:])
2747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if ttLib.endian <> "big":
275542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			allCodes.byteswap()
2767842e56b97ce677b83bdab09cda48bc2d89ac75aJust
2777842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# divide the data
278542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		endCode = allCodes[:segCount]
279542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		allCodes = allCodes[segCount+1:]  # the +1 is skipping the reservedPad field
280542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		startCode = allCodes[:segCount]
281542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		allCodes = allCodes[segCount:]
282542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		idDelta = allCodes[:segCount]
283542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		allCodes = allCodes[segCount:]
284542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		idRangeOffset = allCodes[:segCount]
285542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		glyphIndexArray = allCodes[segCount:]
286542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr
2877842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# build 2-byte character mapping
2887842e56b97ce677b83bdab09cda48bc2d89ac75aJust		cmap = {}
2897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(len(startCode) - 1):	# don't do 0xffff!
2907842e56b97ce677b83bdab09cda48bc2d89ac75aJust			for charCode in range(startCode[i], endCode[i] + 1):
2917842e56b97ce677b83bdab09cda48bc2d89ac75aJust				rangeOffset = idRangeOffset[i]
2927842e56b97ce677b83bdab09cda48bc2d89ac75aJust				if rangeOffset == 0:
2937842e56b97ce677b83bdab09cda48bc2d89ac75aJust					glyphID = charCode + idDelta[i]
2947842e56b97ce677b83bdab09cda48bc2d89ac75aJust				else:
2957842e56b97ce677b83bdab09cda48bc2d89ac75aJust					# *someone* needs to get killed.
2967842e56b97ce677b83bdab09cda48bc2d89ac75aJust					index = idRangeOffset[i] / 2 + (charCode - startCode[i]) + i - len(idRangeOffset)
2977842e56b97ce677b83bdab09cda48bc2d89ac75aJust					if glyphIndexArray[index] <> 0:  # if not missing glyph
2987842e56b97ce677b83bdab09cda48bc2d89ac75aJust						glyphID = glyphIndexArray[index] + idDelta[i]
2997842e56b97ce677b83bdab09cda48bc2d89ac75aJust					else:
3007842e56b97ce677b83bdab09cda48bc2d89ac75aJust						glyphID = 0  # missing glyph
3017842e56b97ce677b83bdab09cda48bc2d89ac75aJust				cmap[charCode] = ttFont.getGlyphName(glyphID % 0x10000)
3027842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.cmap = cmap
3037842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3047842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
305ea9dfa9fb28966175bf2275d20aeb62c3040c86djvr		from fontTools.ttLib.sfnt import maxPowerOfTwo
3067842e56b97ce677b83bdab09cda48bc2d89ac75aJust
307542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		cmap = {}  # code:glyphID mapping
308542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		for code, glyphName in self.cmap.items():
309542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			cmap[code] = ttFont.getGlyphID(glyphName)
310542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		codes = cmap.keys()
3117842e56b97ce677b83bdab09cda48bc2d89ac75aJust		codes.sort()
3127842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3131f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		# Build startCode and endCode lists.
3141f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		# Split the char codes in ranges of consecutive char codes, then split
3151f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		# each range in more ranges of consecutive/not consecutive glyph IDs.
3161f8a4bb02ac37fb92f3dbe9eca5d66ecee6755f3jvr		# See splitRange().
317542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		lastCode = codes[0]
3187842e56b97ce677b83bdab09cda48bc2d89ac75aJust		endCode = []
319542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		startCode = [lastCode]
320542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		for charCode in codes[1:]:  # skip the first code, it's the first start code
321542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			if charCode == lastCode + 1:
322542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr				lastCode = charCode
3237842e56b97ce677b83bdab09cda48bc2d89ac75aJust				continue
324542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			start, end = splitRange(startCode[-1], lastCode, cmap)
325542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			startCode.extend(start)
326542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			endCode.extend(end)
3277842e56b97ce677b83bdab09cda48bc2d89ac75aJust			startCode.append(charCode)
328542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			lastCode = charCode
329542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		endCode.append(lastCode)
3307842e56b97ce677b83bdab09cda48bc2d89ac75aJust		startCode.append(0xffff)
3317842e56b97ce677b83bdab09cda48bc2d89ac75aJust		endCode.append(0xffff)
3327842e56b97ce677b83bdab09cda48bc2d89ac75aJust
333542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		# build up rest of cruft
3347842e56b97ce677b83bdab09cda48bc2d89ac75aJust		idDelta = []
3357842e56b97ce677b83bdab09cda48bc2d89ac75aJust		idRangeOffset = []
3367842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphIndexArray = []
3377842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3387842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(len(endCode)-1):  # skip the closing codes (0xffff)
3397842e56b97ce677b83bdab09cda48bc2d89ac75aJust			indices = []
340542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			for charCode in range(startCode[i], endCode[i] + 1):
341542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr				indices.append(cmap[charCode])
3427842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if indices == range(indices[0], indices[0] + len(indices)):
3437842e56b97ce677b83bdab09cda48bc2d89ac75aJust				idDelta.append((indices[0] - startCode[i]) % 0x10000)
3447842e56b97ce677b83bdab09cda48bc2d89ac75aJust				idRangeOffset.append(0)
3457842e56b97ce677b83bdab09cda48bc2d89ac75aJust			else:
3467842e56b97ce677b83bdab09cda48bc2d89ac75aJust				# someone *definitely* needs to get killed.
3477842e56b97ce677b83bdab09cda48bc2d89ac75aJust				idDelta.append(0)
3487842e56b97ce677b83bdab09cda48bc2d89ac75aJust				idRangeOffset.append(2 * (len(endCode) + len(glyphIndexArray) - i))
349542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr				glyphIndexArray.extend(indices)
3507842e56b97ce677b83bdab09cda48bc2d89ac75aJust		idDelta.append(1)  # 0xffff + 1 == (tadaa!) 0. So this end code maps to .notdef
3517842e56b97ce677b83bdab09cda48bc2d89ac75aJust		idRangeOffset.append(0)
3527842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3537842e56b97ce677b83bdab09cda48bc2d89ac75aJust		# Insane.
3547842e56b97ce677b83bdab09cda48bc2d89ac75aJust		segCount = len(endCode)
3557842e56b97ce677b83bdab09cda48bc2d89ac75aJust		segCountX2 = segCount * 2
356542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		maxExponent = maxPowerOfTwo(segCount)
357542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		searchRange = 2 * (2 ** maxExponent)
358542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		entrySelector = maxExponent
3597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		rangeShift = 2 * segCount - searchRange
3607842e56b97ce677b83bdab09cda48bc2d89ac75aJust
361542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		allCodes = array.array("H",
3627842e56b97ce677b83bdab09cda48bc2d89ac75aJust				endCode + [0] + startCode + idDelta + idRangeOffset + glyphIndexArray)
3637842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if ttLib.endian <> "big":
364542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr			allCodes.byteswap()
365542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		data = allCodes.tostring()
3667842e56b97ce677b83bdab09cda48bc2d89ac75aJust		length = struct.calcsize(cmap_format_4_format) + len(data)
3677842e56b97ce677b83bdab09cda48bc2d89ac75aJust		header = struct.pack(cmap_format_4_format, self.format, length, self.version,
3687842e56b97ce677b83bdab09cda48bc2d89ac75aJust				segCountX2, searchRange, entrySelector, rangeShift)
369542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		data = header + data
370542b9510e6a8909e35e99a5279b7c2ec57c78e3cjvr		return data
3717842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3727842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
3737842e56b97ce677b83bdab09cda48bc2d89ac75aJust		from fontTools.unicode import Unicode
3747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		codes = self.cmap.items()
3757842e56b97ce677b83bdab09cda48bc2d89ac75aJust		codes.sort()
3767842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.begintag(self.__class__.__name__, [
3777842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platformID", self.platformID),
3787842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platEncID", self.platEncID),
3797842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("version", self.version),
3807842e56b97ce677b83bdab09cda48bc2d89ac75aJust				])
3817842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
3827842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3837842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for code, name in codes:
3847842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.simpletag("map", code=hex(code), name=name)
3857842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.comment(Unicode[code])
3867842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
3877842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3887842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.endtag(self.__class__.__name__)
3897842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
3907842e56b97ce677b83bdab09cda48bc2d89ac75aJust
3917842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def fromXML(self, (name, attrs, content), ttFont):
3927842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.version = safeEval(attrs["version"])
3937842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.cmap = {}
3947842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for element in content:
39522dcb9e6f9a9d087e87cece6caca6aa5d92f4d91jvr			if type(element) <> TupleType:
3967842e56b97ce677b83bdab09cda48bc2d89ac75aJust				continue
3977842e56b97ce677b83bdab09cda48bc2d89ac75aJust			name, attrs, content = element
3987842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if name <> "map":
3997842e56b97ce677b83bdab09cda48bc2d89ac75aJust				continue
4007842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.cmap[safeEval(attrs["code"])] = attrs["name"]
4017842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4027842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4037842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass cmap_format_6(CmapSubtable):
4047842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4057842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
4067842e56b97ce677b83bdab09cda48bc2d89ac75aJust		format, length, version, firstCode, entryCount = struct.unpack(
4077842e56b97ce677b83bdab09cda48bc2d89ac75aJust				">HHHHH", data[:10])
4087842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.version = int(version)
4097842e56b97ce677b83bdab09cda48bc2d89ac75aJust		firstCode = int(firstCode)
4107842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.version = int(version)
4117842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = data[10:]
412f6b1563e0dc4e396264d62598cac856b0959c0f7Just		#assert len(data) == 2 * entryCount  # XXX not true in Apple's Helvetica!!!
4137842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphIndexArray = array.array("H")
41443fa4be9483ec7cfc2f3c183be8bed746862b7f3Just		glyphIndexArray.fromstring(data[:2 * int(entryCount)])
4157842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if ttLib.endian <> "big":
4167842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphIndexArray.byteswap()
4177842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.cmap = cmap = {}
4187842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(len(glyphIndexArray)):
4197842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphID = glyphIndexArray[i]
4207842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphName = ttFont.getGlyphName(glyphID)
4217842e56b97ce677b83bdab09cda48bc2d89ac75aJust			cmap[i+firstCode] = glyphName
4227842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4237842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
4247842e56b97ce677b83bdab09cda48bc2d89ac75aJust		codes = self.cmap.keys()
4257842e56b97ce677b83bdab09cda48bc2d89ac75aJust		codes.sort()
4267842e56b97ce677b83bdab09cda48bc2d89ac75aJust		assert codes == range(codes[0], codes[0] + len(codes))
4277842e56b97ce677b83bdab09cda48bc2d89ac75aJust		glyphIndexArray = array.array("H", [0] * len(codes))
4287842e56b97ce677b83bdab09cda48bc2d89ac75aJust		firstCode = codes[0]
4297842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for i in range(len(codes)):
4307842e56b97ce677b83bdab09cda48bc2d89ac75aJust			code = codes[i]
4317842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphIndexArray[code-firstCode] = ttFont.getGlyphID(self.cmap[code])
4327842e56b97ce677b83bdab09cda48bc2d89ac75aJust		if ttLib.endian <> "big":
4337842e56b97ce677b83bdab09cda48bc2d89ac75aJust			glyphIndexArray.byteswap()
4347842e56b97ce677b83bdab09cda48bc2d89ac75aJust		data = glyphIndexArray.tostring()
4357842e56b97ce677b83bdab09cda48bc2d89ac75aJust		header = struct.pack(">HHHHH",
4367842e56b97ce677b83bdab09cda48bc2d89ac75aJust				6, len(data) + 10, self.version, firstCode, len(self.cmap))
4377842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return header + data
4387842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4397842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def toXML(self, writer, ttFont):
4407842e56b97ce677b83bdab09cda48bc2d89ac75aJust		codes = self.cmap.items()
4417842e56b97ce677b83bdab09cda48bc2d89ac75aJust		codes.sort()
4427842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.begintag(self.__class__.__name__, [
4437842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platformID", self.platformID),
4447842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("platEncID", self.platEncID),
4457842e56b97ce677b83bdab09cda48bc2d89ac75aJust				("version", self.version),
4467842e56b97ce677b83bdab09cda48bc2d89ac75aJust				])
4477842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
4487842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4497842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for code, name in codes:
4507842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.simpletag("map", code=hex(code), name=name)
4517842e56b97ce677b83bdab09cda48bc2d89ac75aJust			writer.newline()
4527842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4537842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.endtag(self.__class__.__name__)
4547842e56b97ce677b83bdab09cda48bc2d89ac75aJust		writer.newline()
4557842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4567842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def fromXML(self, (name, attrs, content), ttFont):
4577842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.version = safeEval(attrs["version"])
4587842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.cmap = {}
4597842e56b97ce677b83bdab09cda48bc2d89ac75aJust		for element in content:
46022dcb9e6f9a9d087e87cece6caca6aa5d92f4d91jvr			if type(element) <> TupleType:
4617842e56b97ce677b83bdab09cda48bc2d89ac75aJust				continue
4627842e56b97ce677b83bdab09cda48bc2d89ac75aJust			name, attrs, content = element
4637842e56b97ce677b83bdab09cda48bc2d89ac75aJust			if name <> "map":
4647842e56b97ce677b83bdab09cda48bc2d89ac75aJust				continue
4657842e56b97ce677b83bdab09cda48bc2d89ac75aJust			self.cmap[safeEval(attrs["code"])] = attrs["name"]
4667842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4677842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4687842e56b97ce677b83bdab09cda48bc2d89ac75aJustclass cmap_format_unknown(CmapSubtable):
4697842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4707842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def decompile(self, data, ttFont):
4717842e56b97ce677b83bdab09cda48bc2d89ac75aJust		self.data = data
4727842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4737842e56b97ce677b83bdab09cda48bc2d89ac75aJust	def compile(self, ttFont):
4747842e56b97ce677b83bdab09cda48bc2d89ac75aJust		return self.data
4757842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4767842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4777842e56b97ce677b83bdab09cda48bc2d89ac75aJustcmap_classes = {
4787842e56b97ce677b83bdab09cda48bc2d89ac75aJust		0: cmap_format_0,
4797842e56b97ce677b83bdab09cda48bc2d89ac75aJust		2: cmap_format_2,
4807842e56b97ce677b83bdab09cda48bc2d89ac75aJust		4: cmap_format_4,
4817842e56b97ce677b83bdab09cda48bc2d89ac75aJust		6: cmap_format_6,
4827842e56b97ce677b83bdab09cda48bc2d89ac75aJust		}
4837842e56b97ce677b83bdab09cda48bc2d89ac75aJust
4847842e56b97ce677b83bdab09cda48bc2d89ac75aJust
485