• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# coding: utf-8
2from __future__ import print_function, division, absolute_import, unicode_literals
3from fontTools.misc.py23 import *
4from fontTools.misc.testTools import FakeFont, getXML, parseXML
5from fontTools.misc.textTools import deHexStr, hexStr
6from fontTools.ttLib import newTable
7import unittest
8
9
10# This is the anchor points table of the first font file in
11# “/Library/Fonts/Devanagari Sangam MN.ttc” on macOS 10.12.6.
12# For testing, we’ve changed the GlyphIDs to smaller values.
13# Also, in the AATLookup, we’ve changed GlyphDataOffset value
14# for the end-of-table marker from 0xFFFF to 0 since that is
15# what our encoder emits. (The value for end-of-table markers
16# does not actually matter).
17ANKR_FORMAT_0_DATA = deHexStr(
18    '0000 0000 '       #  0: Format=0, Flags=0
19    '0000 000C '       #  4: LookupTableOffset=12
20    '0000 0024 '       #  8: GlyphDataTableOffset=36
21    '0006 0004 0002 '  # 12: LookupFormat=6, UnitSize=4, NUnits=2
22    '0008 0001 0000 '  # 18: SearchRange=8, EntrySelector=1, RangeShift=0
23    '0001 0000 '       # 24: Glyph=A, Offset=0 (+GlyphDataTableOffset=36)
24    '0003 0008 '       # 28: Glyph=C, Offset=8 (+GlyphDataTableOffset=44)
25    'FFFF 0000 '       # 32: Glyph=<end>, Offset=<n/a>
26    '0000 0001 '       # 36: GlyphData[A].NumPoints=1
27    '0235 045E '       # 40: GlyphData[A].Points[0].X=565, .Y=1118
28    '0000 0001 '       # 44: GlyphData[C].NumPoints=1
29    'FED2 045E '       # 48: GlyphData[C].Points[0].X=-302, .Y=1118
30)                      # 52: <end>
31assert len(ANKR_FORMAT_0_DATA) == 52
32
33
34ANKR_FORMAT_0_XML = [
35    '<AnchorPoints Format="0">',
36    '  <Flags value="0"/>',
37    '  <Anchors>',
38    '    <Lookup glyph="A">',
39    '      <!-- AnchorPointCount=1 -->',
40    '      <AnchorPoint index="0">',
41    '        <XCoordinate value="565"/>',
42    '        <YCoordinate value="1118"/>',
43    '      </AnchorPoint>',
44    '    </Lookup>',
45    '    <Lookup glyph="C">',
46    '      <!-- AnchorPointCount=1 -->',
47    '      <AnchorPoint index="0">',
48    '        <XCoordinate value="-302"/>',
49    '        <YCoordinate value="1118"/>',
50    '      </AnchorPoint>',
51    '    </Lookup>',
52    '  </Anchors>',
53    '</AnchorPoints>',
54]
55
56
57# Same data as ANKR_FORMAT_0_DATA, but with chunks of unused data
58# whose presence should not stop us from decompiling the table.
59ANKR_FORMAT_0_STRAY_DATA = deHexStr(
60    '0000 0000 '       #  0: Format=0, Flags=0
61    '0000 0018 '       #  4: LookupTableOffset=24
62    '0000 0034 '       #  8: GlyphDataTableOffset=52
63    'DEAD BEEF CAFE '  # 12: <stray data>
64    'DEAD BEEF CAFE '  # 18: <stray data>
65    '0006 0004 0002 '  # 24: LookupFormat=6, UnitSize=4, NUnits=2
66    '0008 0001 0000 '  # 30: SearchRange=8, EntrySelector=1, RangeShift=0
67    '0001 0000 '       # 36: Glyph=A, Offset=0 (+GlyphDataTableOffset=52)
68    '0003 0008 '       # 40: Glyph=C, Offset=8 (+GlyphDataTableOffset=60)
69    'FFFF 0000 '       # 44: Glyph=<end>, Offset=<n/a>
70    'BEEF F00D '       # 48: <stray data>
71    '0000 0001 '       # 52: GlyphData[A].NumPoints=1
72    '0235 045E '       # 56: GlyphData[A].Points[0].X=565, .Y=1118
73    '0000 0001 '       # 60: GlyphData[C].NumPoints=1
74    'FED2 045E '       # 64: GlyphData[C].Points[0].X=-302, .Y=1118
75)                      # 68: <end>
76assert len(ANKR_FORMAT_0_STRAY_DATA) == 68
77
78
79# Constructed test case where glyphs A and D share the same anchor data.
80ANKR_FORMAT_0_SHARING_DATA = deHexStr(
81    '0000 0000 '       #  0: Format=0, Flags=0
82    '0000 000C '       #  4: LookupTableOffset=12
83    '0000 0028 '       #  8: GlyphDataTableOffset=40
84    '0006 0004 0003 '  # 12: LookupFormat=6, UnitSize=4, NUnits=3
85    '0008 0001 0004 '  # 18: SearchRange=8, EntrySelector=1, RangeShift=4
86    '0001 0000 '       # 24: Glyph=A, Offset=0 (+GlyphDataTableOffset=36)
87    '0003 0008 '       # 28: Glyph=C, Offset=8 (+GlyphDataTableOffset=44)
88    '0004 0000 '       # 32: Glyph=D, Offset=0 (+GlyphDataTableOffset=36)
89    'FFFF 0000 '       # 36: Glyph=<end>, Offset=<n/a>
90    '0000 0001 '       # 40: GlyphData[A].NumPoints=1
91    '0235 045E '       # 44: GlyphData[A].Points[0].X=565, .Y=1118
92    '0000 0002 '       # 48: GlyphData[C].NumPoints=2
93    '000B 000C '       # 52: GlyphData[C].Points[0].X=11, .Y=12
94    '001B 001C '       # 56: GlyphData[C].Points[1].X=27, .Y=28
95)                      # 60: <end>
96assert len(ANKR_FORMAT_0_SHARING_DATA) == 60
97
98
99ANKR_FORMAT_0_SHARING_XML = [
100    '<AnchorPoints Format="0">',
101    '  <Flags value="0"/>',
102    '  <Anchors>',
103    '    <Lookup glyph="A">',
104    '      <!-- AnchorPointCount=1 -->',
105    '      <AnchorPoint index="0">',
106    '        <XCoordinate value="565"/>',
107    '        <YCoordinate value="1118"/>',
108    '      </AnchorPoint>',
109    '    </Lookup>',
110    '    <Lookup glyph="C">',
111    '      <!-- AnchorPointCount=2 -->',
112    '      <AnchorPoint index="0">',
113    '        <XCoordinate value="11"/>',
114    '        <YCoordinate value="12"/>',
115    '      </AnchorPoint>',
116    '      <AnchorPoint index="1">',
117    '        <XCoordinate value="27"/>',
118    '        <YCoordinate value="28"/>',
119    '      </AnchorPoint>',
120    '    </Lookup>',
121    '    <Lookup glyph="D">',
122    '      <!-- AnchorPointCount=1 -->',
123    '      <AnchorPoint index="0">',
124    '        <XCoordinate value="565"/>',
125    '        <YCoordinate value="1118"/>',
126    '      </AnchorPoint>',
127    '    </Lookup>',
128    '  </Anchors>',
129    '</AnchorPoints>',
130]
131
132
133class ANKRTest(unittest.TestCase):
134
135    @classmethod
136    def setUpClass(cls):
137        cls.maxDiff = None
138        cls.font = FakeFont(['.notdef', 'A', 'B', 'C', 'D'])
139
140    def decompileToXML(self, data, xml):
141        table = newTable('ankr')
142        table.decompile(data, self.font)
143        self.assertEqual(getXML(table.toXML), xml)
144
145    def compileFromXML(self, xml, data):
146        table = newTable('ankr')
147        for name, attrs, content in parseXML(xml):
148            table.fromXML(name, attrs, content, font=self.font)
149        self.assertEqual(hexStr(table.compile(self.font)), hexStr(data))
150
151    def roundtrip(self, data, xml):
152        self.decompileToXML(data, xml)
153        self.compileFromXML(xml, data)
154
155    def testFormat0(self):
156        self.roundtrip(ANKR_FORMAT_0_DATA, ANKR_FORMAT_0_XML)
157
158    def testFormat0_stray(self):
159        self.decompileToXML(ANKR_FORMAT_0_STRAY_DATA, ANKR_FORMAT_0_XML)
160
161    def testFormat0_sharing(self):
162        self.roundtrip(ANKR_FORMAT_0_SHARING_DATA, ANKR_FORMAT_0_SHARING_XML)
163
164
165if __name__ == '__main__':
166    import sys
167    sys.exit(unittest.main())
168