1 from __future__ import print_function, division, absolute_import 2 from fontTools.misc.py23 import * 3 from fontTools.misc import sstruct 4 from fontTools.misc.textTools import safeEval, num2binary, binary2num 5 from . import DefaultTable 6 import warnings 7 8 9 # panose classification 10 11 panoseFormat = """ 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 24 class 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 38 OS2_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 72 OS2_format_1_addition = """ 73 ulCodePageRange1: L 74 ulCodePageRange2: L 75 """ 76 77 OS2_format_2_addition = OS2_format_1_addition + """ 78 sxHeight: h 79 sCapHeight: h 80 usDefaultChar: H 81 usBreakChar: H 82 usMaxContex: H 83 """ 84 85 OS2_format_5_addition = OS2_format_2_addition + """ 86 usLowerOpticalPointSize: H 87 usUpperOpticalPointSize: H 88 """ 89 90 bigendian = " > # big endian\n" 91 92 OS2_format_1 = OS2_format_0 + OS2_format_1_addition 93 OS2_format_2 = OS2_format_0 + OS2_format_2_addition 94 OS2_format_5 = OS2_format_0 + OS2_format_5_addition 95 OS2_format_1_addition = bigendian + OS2_format_1_addition 96 OS2_format_2_addition = bigendian + OS2_format_2_addition 97 OS2_format_5_addition = bigendian + OS2_format_5_addition 98 99 100 class 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