1from __future__ import print_function, division, absolute_import, unicode_literals 2from fontTools.misc.py23 import * 3from fontTools.misc.testTools import FakeFont, getXML, parseXML 4from fontTools.misc.textTools import deHexStr, hexStr 5from fontTools.ttLib import newTable 6import unittest 7 8 9# Example: Format 0 Optical Bounds Table 10# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html 11OPBD_FORMAT_0_DATA = deHexStr( 12 '0001 0000 0000 ' # 0: Version=1.0, Format=0 13 '0006 0004 0002 ' # 6: LookupFormat=6, UnitSize=4, NUnits=2 14 '0008 0001 0000 ' # 12: SearchRange=8, EntrySelector=1, RangeShift=0 15 '000A 001E ' # 18: Glyph=10(=C), OffsetOfOpticalBoundsDeltas=30 16 '002B 0026 ' # 22: Glyph=43(=A), OffsetOfOpticalBoundsDeltas=38 17 'FFFF 0000 ' # 26: Glyph=<end>, OffsetOfOpticalBoundsDeltas=0 18 'FFCE 0005 0037 FFFB ' # 30: Bounds[C].Left=-50 .Top=5 .Right=55 .Bottom=-5 19 'FFF6 000F 0000 0000 ' # 38: Bounds[A].Left=-10 .Top=15 .Right=0 .Bottom=0 20) # 46: <end> 21assert(len(OPBD_FORMAT_0_DATA) == 46) 22 23 24OPBD_FORMAT_0_XML = [ 25 '<Version value="0x00010000"/>', 26 '<OpticalBounds Format="0">', 27 ' <OpticalBoundsDeltas>', 28 ' <Lookup glyph="A">', 29 ' <Left value="-10"/>', 30 ' <Top value="15"/>', 31 ' <Right value="0"/>', 32 ' <Bottom value="0"/>', 33 ' </Lookup>', 34 ' <Lookup glyph="C">', 35 ' <Left value="-50"/>', 36 ' <Top value="5"/>', 37 ' <Right value="55"/>', 38 ' <Bottom value="-5"/>', 39 ' </Lookup>', 40 ' </OpticalBoundsDeltas>', 41 '</OpticalBounds>', 42] 43 44 45# Example: Format 1 Optical Bounds Table 46# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6opbd.html 47OPBD_FORMAT_1_DATA = deHexStr( 48 '0001 0000 0001 ' # 0: Version=1.0, Format=1 49 '0006 0004 0002 ' # 6: LookupFormat=6, UnitSize=4, NUnits=2 50 '0008 0001 0000 ' # 12: SearchRange=8, EntrySelector=1, RangeShift=0 51 '000A 001E ' # 18: Glyph=10(=C), OffsetOfOpticalBoundsPoints=30 52 '002B 0026 ' # 22: Glyph=43(=A), OffsetOfOpticalBoundsPoints=38 53 'FFFF 0000 ' # 26: Glyph=<end>, OffsetOfOpticalBoundsPoints=0 54 '0024 0025 0026 0027 ' # 30: Bounds[C].Left=36 .Top=37 .Right=38 .Bottom=39 55 '0020 0029 FFFF FFFF ' # 38: Bounds[A].Left=32 .Top=41 .Right=-1 .Bottom=-1 56) # 46: <end> 57assert(len(OPBD_FORMAT_1_DATA) == 46) 58 59 60OPBD_FORMAT_1_XML = [ 61 '<Version value="0x00010000"/>', 62 '<OpticalBounds Format="1">', 63 ' <OpticalBoundsPoints>', 64 ' <Lookup glyph="A">', 65 ' <Left value="32"/>', 66 ' <Top value="41"/>', 67 ' <Right value="-1"/>', 68 ' <Bottom value="-1"/>', 69 ' </Lookup>', 70 ' <Lookup glyph="C">', 71 ' <Left value="36"/>', 72 ' <Top value="37"/>', 73 ' <Right value="38"/>', 74 ' <Bottom value="39"/>', 75 ' </Lookup>', 76 ' </OpticalBoundsPoints>', 77 '</OpticalBounds>', 78] 79 80 81# This is the content of the Optical Bounds table in AppleChancery.ttf, 82# font version 8.0d1e1 of 2013-02-06. An early version of fontTools 83# was crashing when trying to decompile this table. 84# https://github.com/fonttools/fonttools/issues/1031 85OPBD_APPLE_CHANCERY_DATA = deHexStr( 86 '0001 0000 0000 ' # 0: Version=1.0, Format=0 87 '0004 0006 0011 ' # 6: LookupFormat=4, UnitSize=6, NUnits=17 88 '0060 0004 0006 ' # 12: SearchRange=96, EntrySelector=4, RangeShift=6 89 '017d 017d 0072 ' # 18: Seg[0].LastGlyph=381, FirstGlyph=381, Off=114(+6) 90 '0183 0180 0074 ' # 24: Seg[1].LastGlyph=387, FirstGlyph=384, Off=116(+6) 91 '0186 0185 007c ' # 30: Seg[2].LastGlyph=390, FirstGlyph=389, Off=124(+6) 92 '018f 018b 0080 ' # 36: Seg[3].LastGlyph=399, FirstGlyph=395, Off=128(+6) 93 '01a0 0196 008a ' # 42: Seg[4].LastGlyph=416, FirstGlyph=406, Off=138(+6) 94 '01a5 01a3 00a0 ' # 48: Seg[5].LastGlyph=421, FirstGlyph=419, Off=160(+6) 95 '01aa 01aa 00a6 ' # 54: Seg[6].LastGlyph=426, FirstGlyph=426, Off=166(+6) 96 '01ac 01ac 00a8 ' # 60: Seg[7].LastGlyph=428, FirstGlyph=428, Off=168(+6) 97 '01fb 01f1 00aa ' # 66: Seg[8].LastGlyph=507, FirstGlyph=497, Off=170(+6) 98 '0214 0209 00c0 ' # 72: Seg[9].LastGlyph=532, FirstGlyph=521, Off=192(+6) 99 '021d 0216 00d8 ' # 78: Seg[10].LastGlyph=541, FirstGlyph=534, Off=216(+6) 100 '0222 0220 00e8 ' # 84: Seg[11].LastGlyph=546, FirstGlyph=544, Off=232(+6) 101 '0227 0225 00ee ' # 90: Seg[12].LastGlyph=551, FirstGlyph=549, Off=238(+6) 102 '0229 0229 00f4 ' # 96: Seg[13].LastGlyph=553, FirstGlyph=553, Off=244(+6) 103 '023b 023b 00f6 ' # 102: Seg[14].LastGlyph=571, FirstGlyph=571, Off=246(+6) 104 '023e 023e 00f8 ' # 108: Seg[15].LastGlyph=574, FirstGlyph=574, Off=248(+6) 105 'ffff ffff 00fa ' # 114: Seg[16]=<end> 106 '0100 0108 0110 0118 0120 0128 0130 0138 0140 0148 0150 0158 ' 107 '0160 0168 0170 0178 0180 0188 0190 0198 01a0 01a8 01b0 01b8 ' 108 '01c0 01c8 01d0 01d8 01e0 01e8 01f0 01f8 0200 0208 0210 0218 ' 109 '0220 0228 0230 0238 0240 0248 0250 0258 0260 0268 0270 0278 ' 110 '0280 0288 0290 0298 02a0 02a8 02b0 02b8 02c0 02c8 02d0 02d8 ' 111 '02e0 02e8 02f0 02f8 0300 0308 0310 0318 fd98 0000 0000 0000 ' 112 'fdbc 0000 0000 0000 fdbc 0000 0000 0000 fdbf 0000 0000 0000 ' 113 'fdbc 0000 0000 0000 fd98 0000 0000 0000 fda9 0000 0000 0000 ' 114 'fd98 0000 0000 0000 fd98 0000 0000 0000 fd98 0000 0000 0000 ' 115 '0000 0000 0205 0000 0000 0000 0205 0000 0000 0000 02a4 0000 ' 116 '0000 0000 027e 0000 0000 0000 02f4 0000 0000 0000 02a4 0000 ' 117 '0000 0000 0365 0000 0000 0000 0291 0000 0000 0000 0291 0000 ' 118 '0000 0000 026a 0000 0000 0000 02b8 0000 0000 0000 02cb 0000 ' 119 '0000 0000 02a4 0000 0000 0000 01a9 0000 0000 0000 0244 0000 ' 120 '0000 0000 02a4 0000 0000 0000 02cb 0000 0000 0000 0244 0000 ' 121 '0000 0000 0307 0000 0000 0000 0307 0000 0000 0000 037f 0000 ' 122 '0000 0000 0307 0000 0000 0000 0307 0000 0000 0000 0307 0000 ' 123 '0000 0000 0307 0000 0000 0000 0307 0000 0000 0000 03e3 0000 ' 124 '0000 0000 030c 0000 0000 0000 0307 0000 fe30 0000 0000 0000 ' 125 'fe7e 0000 0000 0000 fe91 0000 0000 0000 fe6a 0000 0000 0000 ' 126 'fe6a 0000 0000 0000 fecb 0000 0000 0000 fe6a 0000 0000 0000 ' 127 'fe7e 0000 0000 0000 fea4 0000 0000 0000 fe7e 0000 0000 0000 ' 128 'fe44 0000 0000 0000 fea4 0000 0000 0000 feb8 0000 0000 0000 ' 129 'fe7e 0000 0000 0000 fe5e 0000 0000 0000 fe37 0000 0000 0000 ' 130 'fe37 0000 0000 0000 fcbd 0000 0000 0000 fd84 0000 0000 0000 ' 131 'fd98 0000 0000 0000 fd82 0000 0000 0000 fcbd 0000 0000 0000 ' 132 'fd84 0000 0000 0000 fcbd 0000 0000 0000 fcbd 0000 0000 0000 ' 133 'fe72 0000 0000 0000 ff9d 0000 0000 0000 0000 0000 032f 0000 ' 134 '0000 0000 03ba 0000 ' 135) 136assert len(OPBD_APPLE_CHANCERY_DATA) == 800 137 138 139class OPBDTest(unittest.TestCase): 140 141 @classmethod 142 def setUpClass(cls): 143 cls.maxDiff = None 144 glyphs = ['.notdef'] + ['X.alt%d' for g in range(1, 50)] 145 glyphs[10] = 'C' 146 glyphs[43] = 'A' 147 cls.font = FakeFont(glyphs) 148 149 def test_decompile_toXML_format0(self): 150 table = newTable('opbd') 151 table.decompile(OPBD_FORMAT_0_DATA, self.font) 152 self.assertEqual(getXML(table.toXML), OPBD_FORMAT_0_XML) 153 154 def test_compile_fromXML_format0(self): 155 table = newTable('opbd') 156 for name, attrs, content in parseXML(OPBD_FORMAT_0_XML): 157 table.fromXML(name, attrs, content, font=self.font) 158 self.assertEqual(hexStr(table.compile(self.font)), 159 hexStr(OPBD_FORMAT_0_DATA)) 160 161 def test_decompile_toXML_format1(self): 162 table = newTable('opbd') 163 table.decompile(OPBD_FORMAT_1_DATA, self.font) 164 self.assertEqual(getXML(table.toXML), OPBD_FORMAT_1_XML) 165 166 def test_compile_fromXML_format1(self): 167 table = newTable('opbd') 168 for name, attrs, content in parseXML(OPBD_FORMAT_1_XML): 169 table.fromXML(name, attrs, content, font=self.font) 170 self.assertEqual(hexStr(table.compile(self.font)), 171 hexStr(OPBD_FORMAT_1_DATA)) 172 173 def test_decompile_AppleChancery(self): 174 # Make sure we do not crash when decompiling the 'opbd' table of 175 # AppleChancery.ttf. https://github.com/fonttools/fonttools/issues/1031 176 table = newTable('opbd') 177 table.decompile(OPBD_APPLE_CHANCERY_DATA, self.font) 178 self.assertIn('<OpticalBounds Format="0">', getXML(table.toXML)) 179 180 181if __name__ == '__main__': 182 import sys 183 sys.exit(unittest.main()) 184