1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.misc import sstruct
4from fontTools.misc.textTools import safeEval, num2binary, binary2num
5from . import DefaultTable
6import warnings
7
8
9# panose classification
10
11panoseFormat = """
12	bFamilyType:        B
13	bSerifStyle:        B
14	bWeight:            B
15	bProportion:        B
16	bContrast:          B
17	bStrokeVariation:   B
18	bArmStyle:          B
19	bLetterForm:        B
20	bMidline:           B
21	bXHeight:           B
22"""
23
24class Panose(object):
25
26	def toXML(self, writer, ttFont):
27		formatstring, names, fixes = sstruct.getformat(panoseFormat)
28		for name in names:
29			writer.simpletag(name, value=getattr(self, name))
30			writer.newline()
31
32	def fromXML(self, name, attrs, content, ttFont):
33		setattr(self, name, safeEval(attrs["value"]))
34
35
36# 'sfnt' OS/2 and Windows Metrics table - 'OS/2'
37
38OS2_format_0 = """
39	>   # big endian
40	version:                H       # version
41	xAvgCharWidth:          h       # average character width
42	usWeightClass:          H       # degree of thickness of strokes
43	usWidthClass:           H       # aspect ratio
44	fsType:                 h       # type flags
45	ySubscriptXSize:        h       # subscript horizontal font size
46	ySubscriptYSize:        h       # subscript vertical font size
47	ySubscriptXOffset:      h       # subscript x offset
48	ySubscriptYOffset:      h       # subscript y offset
49	ySuperscriptXSize:      h       # superscript horizontal font size
50	ySuperscriptYSize:      h       # superscript vertical font size
51	ySuperscriptXOffset:    h       # superscript x offset
52	ySuperscriptYOffset:    h       # superscript y offset
53	yStrikeoutSize:         h       # strikeout size
54	yStrikeoutPosition:     h       # strikeout position
55	sFamilyClass:           h       # font family class and subclass
56	panose:                 10s     # panose classification number
57	ulUnicodeRange1:        L       # character range
58	ulUnicodeRange2:        L       # character range
59	ulUnicodeRange3:        L       # character range
60	ulUnicodeRange4:        L       # character range
61	achVendID:              4s      # font vendor identification
62	fsSelection:            H       # font selection flags
63	fsFirstCharIndex:       H       # first unicode character index
64	fsLastCharIndex:        H       # last unicode character index
65	sTypoAscender:          h       # typographic ascender
66	sTypoDescender:         h       # typographic descender
67	sTypoLineGap:           h       # typographic line gap
68	usWinAscent:            H       # Windows ascender
69	usWinDescent:           H       # Windows descender
70"""
71
72OS2_format_1_addition =  """
73	ulCodePageRange1:   L
74	ulCodePageRange2:   L
75"""
76
77OS2_format_2_addition =  OS2_format_1_addition + """
78	sxHeight:           h
79	sCapHeight:         h
80	usDefaultChar:      H
81	usBreakChar:        H
82	usMaxContex:        H
83"""
84
85OS2_format_5_addition =  OS2_format_2_addition + """
86	usLowerOpticalPointSize:    H
87	usUpperOpticalPointSize:    H
88"""
89
90bigendian = "	>	# big endian\n"
91
92OS2_format_1 = OS2_format_0 + OS2_format_1_addition
93OS2_format_2 = OS2_format_0 + OS2_format_2_addition
94OS2_format_5 = OS2_format_0 + OS2_format_5_addition
95OS2_format_1_addition = bigendian + OS2_format_1_addition
96OS2_format_2_addition = bigendian + OS2_format_2_addition
97OS2_format_5_addition = bigendian + OS2_format_5_addition
98
99
100class table_O_S_2f_2(DefaultTable.DefaultTable):
101
102	"""the OS/2 table"""
103
104	def decompile(self, data, ttFont):
105		dummy, data = sstruct.unpack2(OS2_format_0, data, self)
106
107		if self.version == 1:
108			dummy, data = sstruct.unpack2(OS2_format_1_addition, data, self)
109		elif self.version in (2, 3, 4):
110			dummy, data = sstruct.unpack2(OS2_format_2_addition, data, self)
111		elif self.version == 5:
112			dummy, data = sstruct.unpack2(OS2_format_5_addition, data, self)
113			self.usLowerOpticalPointSize /= 20
114			self.usUpperOpticalPointSize /= 20
115		elif self.version != 0:
116			from fontTools import ttLib
117			raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version)
118		if len(data):
119			warnings.warn("too much 'OS/2' table data")
120
121		self.panose = sstruct.unpack(panoseFormat, self.panose, Panose())
122
123	def compile(self, ttFont):
124		panose = self.panose
125		self.panose = sstruct.pack(panoseFormat, self.panose)
126		if self.version == 0:
127			data = sstruct.pack(OS2_format_0, self)
128		elif self.version == 1:
129			data = sstruct.pack(OS2_format_1, self)
130		elif self.version in (2, 3, 4):
131			data = sstruct.pack(OS2_format_2, self)
132		elif self.version == 5:
133			d = self.__dict__.copy()
134			d['usLowerOpticalPointSize'] = int(round(self.usLowerOpticalPointSize * 20))
135			d['usUpperOpticalPointSize'] = int(round(self.usUpperOpticalPointSize * 20))
136			data = sstruct.pack(OS2_format_5, d)
137		else:
138			from fontTools import ttLib
139			raise ttLib.TTLibError("unknown format for OS/2 table: version %s" % self.version)
140		self.panose = panose
141		return data
142
143	def toXML(self, writer, ttFont):
144		if self.version == 1:
145			format = OS2_format_1
146		elif self.version in (2, 3, 4):
147			format = OS2_format_2
148		elif self.version == 5:
149			format = OS2_format_5
150		else:
151			format = OS2_format_0
152		formatstring, names, fixes = sstruct.getformat(format)
153		for name in names:
154			value = getattr(self, name)
155			if name=="panose":
156				writer.begintag("panose")
157				writer.newline()
158				value.toXML(writer, ttFont)
159				writer.endtag("panose")
160			elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
161					"ulUnicodeRange3", "ulUnicodeRange4",
162					"ulCodePageRange1", "ulCodePageRange2"):
163				writer.simpletag(name, value=num2binary(value))
164			elif name in ("fsType", "fsSelection"):
165				writer.simpletag(name, value=num2binary(value, 16))
166			elif name == "achVendID":
167				writer.simpletag(name, value=repr(value)[1:-1])
168			else:
169				writer.simpletag(name, value=value)
170			writer.newline()
171
172	def fromXML(self, name, attrs, content, ttFont):
173		if name == "panose":
174			self.panose = panose = Panose()
175			for element in content:
176				if isinstance(element, tuple):
177					name, attrs, content = element
178					panose.fromXML(name, attrs, content, ttFont)
179		elif name in ("ulUnicodeRange1", "ulUnicodeRange2",
180				"ulUnicodeRange3", "ulUnicodeRange4",
181				"ulCodePageRange1", "ulCodePageRange2",
182				"fsType", "fsSelection"):
183			setattr(self, name, binary2num(attrs["value"]))
184		elif name == "achVendID":
185			setattr(self, name, safeEval("'''" + attrs["value"] + "'''"))
186		else:
187			setattr(self, name, safeEval(attrs["value"]))
188
189
190