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