1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.misc import sstruct
4from fontTools.misc.textTools import safeEval
5from . import DefaultTable
6
7GMAPFormat = """
8		>	# big endian
9		tableVersionMajor:	H
10		tableVersionMinor: 	H
11		flags:	H
12		recordsCount:		H
13		recordsOffset:		H
14		fontNameLength:		H
15"""
16# psFontName is a byte string which follows the record above. This is zero padded
17# to the beginning of the records array. The recordsOffsst is 32 bit aligned.
18
19GMAPRecordFormat1 = """
20		>	# big endian
21		UV:			L
22		cid:		H
23		gid:		H
24		ggid:		H
25		name:		32s
26"""
27
28
29
30class GMAPRecord(object):
31	def __init__(self, uv = 0, cid = 0, gid = 0, ggid = 0, name = ""):
32		self.UV = uv
33		self.cid = cid
34		self.gid = gid
35		self.ggid = ggid
36		self.name = name
37
38	def toXML(self, writer, ttFont):
39		writer.begintag("GMAPRecord")
40		writer.newline()
41		writer.simpletag("UV", value=self.UV)
42		writer.newline()
43		writer.simpletag("cid", value=self.cid)
44		writer.newline()
45		writer.simpletag("gid", value=self.gid)
46		writer.newline()
47		writer.simpletag("glyphletGid", value=self.gid)
48		writer.newline()
49		writer.simpletag("GlyphletName", value=self.name)
50		writer.newline()
51		writer.endtag("GMAPRecord")
52		writer.newline()
53
54
55	def fromXML(self, name, attrs, content, ttFont):
56		value = attrs["value"]
57		if name == "GlyphletName":
58			self.name = value
59		else:
60			setattr(self, name, safeEval(value))
61
62
63	def compile(self, ttFont):
64		if 	self.UV is None:
65			self.UV = 0
66		nameLen =  len(self.name)
67		if nameLen < 32:
68			self.name = self.name + "\0"*(32 - nameLen)
69		data = sstruct.pack(GMAPRecordFormat1, self)
70		return data
71
72	def __repr__(self):
73		return "GMAPRecord[ UV: " + str(self.UV) + ", cid: " + str(self.cid) + ", gid: " + str(self.gid) + ", ggid: " + str(self.ggid) + ", Glyphlet Name: " + str(self.name) + " ]"
74
75
76class table_G_M_A_P_(DefaultTable.DefaultTable):
77
78	dependencies = []
79
80	def decompile(self, data, ttFont):
81		dummy, newData = sstruct.unpack2(GMAPFormat, data, self)
82		self.psFontName = tostr(newData[:self.fontNameLength])
83		assert (self.recordsOffset % 4) == 0, "GMAP error: recordsOffset is not 32 bit aligned."
84		newData = data[self.recordsOffset:]
85		self.gmapRecords = []
86		for i in range (self.recordsCount):
87			gmapRecord, newData = sstruct.unpack2(GMAPRecordFormat1, newData, GMAPRecord())
88			gmapRecord.name = gmapRecord.name.strip('\0')
89			self.gmapRecords.append(gmapRecord)
90
91
92	def compile(self, ttFont):
93		self.recordsCount = len(self.gmapRecords)
94		self.fontNameLength = len(self.psFontName)
95		self.recordsOffset = 4 *(((self.fontNameLength + 12)  + 3) // 4)
96		data = sstruct.pack(GMAPFormat, self)
97		data = data + tobytes(self.psFontName)
98		data = data + b"\0" * (self.recordsOffset - len(data))
99		for record in self.gmapRecords:
100			data = data + record.compile(ttFont)
101		return data
102
103
104	def toXML(self, writer, ttFont):
105		writer.comment("Most of this table will be recalculated by the compiler")
106		writer.newline()
107		formatstring, names, fixes = sstruct.getformat(GMAPFormat)
108		for name in names:
109			value = getattr(self, name)
110			writer.simpletag(name, value=value)
111			writer.newline()
112		writer.simpletag("PSFontName", value=self.psFontName)
113		writer.newline()
114		for gmapRecord in self.gmapRecords:
115			gmapRecord.toXML(writer, ttFont)
116
117	def fromXML(self, name, attrs, content, ttFont):
118		if name == "GMAPRecord":
119			if not hasattr(self, "gmapRecords"):
120				self.gmapRecords = []
121			gmapRecord = GMAPRecord()
122			self.gmapRecords.append(gmapRecord)
123			for element in content:
124				if isinstance(element, basestring):
125					continue
126				name, attrs, content = element
127				gmapRecord.fromXML(name, attrs, content, ttFont)
128		else:
129			value = attrs["value"]
130			if name == "PSFontName":
131				self.psFontName = value
132			else:
133				setattr(self, name, safeEval(value))
134