Home | History | Annotate | Download | only in tables
      1 from __future__ import print_function, division, absolute_import, unicode_literals
      2 from fontTools.misc.py23 import *
      3 from fontTools.misc.testTools import FakeFont, getXML, parseXML
      4 from fontTools.misc.textTools import deHexStr, hexStr
      5 from fontTools.ttLib import newTable
      6 import unittest
      7 
      8 
      9 # Glyph Metamorphosis Table Examples
     10 # Example 1: Non-contextual Glyph Substitution
     11 # https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
     12 # The example given by Apple's 'mort' specification is suboptimally
     13 # encoded: it uses AAT lookup format 6 even though format 8 would be
     14 # more compact.  Because our encoder always uses the most compact
     15 # encoding, this breaks our round-trip testing. Therefore, we changed
     16 # the example to use GlyphID 13 instead of 12 for the 'parenright'
     17 # character; the non-contiguous glyph range for the AAT lookup makes
     18 # format 6 to be most compact.
     19 MORT_NONCONTEXTUAL_DATA = deHexStr(
     20     '0001 0000 '  #  0: Version=1.0
     21     '0000 0001 '  #  4: MorphChainCount=1
     22     '0000 0001 '  #  8: DefaultFlags=1
     23     '0000 0050 '  # 12: StructLength=80
     24     '0003 0001 '  # 16: MorphFeatureCount=3, MorphSubtableCount=1
     25     '0004 0000 '  # 20: Feature[0].FeatureType=4/VertSubst, .FeatureSetting=on
     26     '0000 0001 '  # 24: Feature[0].EnableFlags=0x00000001
     27     'FFFF FFFF '  # 28: Feature[0].DisableFlags=0xFFFFFFFF
     28     '0004 0001 '  # 32: Feature[1].FeatureType=4/VertSubst, .FeatureSetting=off
     29     '0000 0000 '  # 36: Feature[1].EnableFlags=0x00000000
     30     'FFFF FFFE '  # 40: Feature[1].DisableFlags=0xFFFFFFFE
     31     '0000 0001 '  # 44: Feature[2].FeatureType=0/GlyphEffects, .FeatSetting=off
     32     '0000 0000 '  # 48: Feature[2].EnableFlags=0 (required for last feature)
     33     '0000 0000 '  # 52: Feature[2].EnableFlags=0 (required for last feature)
     34     '0020 '       # 56: Subtable[0].StructLength=32
     35     '80 '         # 58: Subtable[0].CoverageFlags=0x80
     36     '04 '         # 59: Subtable[0].MorphType=4/NoncontextualMorph
     37     '0000 0001 '  # 60: Subtable[0].SubFeatureFlags=0x1
     38     '0006 0004 '  # 64: LookupFormat=6, UnitSize=4
     39     '0002 0008 '  # 68: NUnits=2, SearchRange=8
     40     '0001 0000 '  # 72: EntrySelector=1, RangeShift=0
     41     '000B 0087 '  # 76: Glyph=11 (parenleft); Value=135 (parenleft.vertical)
     42     '000D 0088 '  # 80: Glyph=13 (parenright); Value=136 (parenright.vertical)
     43     'FFFF 0000 '  # 84: Glyph=<end>; Value=0
     44 )                 # 88: <end>
     45 assert len(MORT_NONCONTEXTUAL_DATA) == 88
     46 
     47 
     48 MORT_NONCONTEXTUAL_XML = [
     49     '<Version value="0x00010000"/>',
     50     '<!-- MorphChainCount=1 -->',
     51     '<MorphChain index="0">',
     52     '  <DefaultFlags value="0x00000001"/>',
     53     '  <!-- StructLength=80 -->',
     54     '  <!-- MorphFeatureCount=3 -->',
     55     '  <!-- MorphSubtableCount=1 -->',
     56     '  <MorphFeature index="0">',
     57     '    <FeatureType value="4"/>',
     58     '    <FeatureSetting value="0"/>',
     59     '    <EnableFlags value="0x00000001"/>',
     60     '    <DisableFlags value="0xFFFFFFFF"/>',
     61     '  </MorphFeature>',
     62     '  <MorphFeature index="1">',
     63     '    <FeatureType value="4"/>',
     64     '    <FeatureSetting value="1"/>',
     65     '    <EnableFlags value="0x00000000"/>',
     66     '    <DisableFlags value="0xFFFFFFFE"/>',
     67     '  </MorphFeature>',
     68     '  <MorphFeature index="2">',
     69     '    <FeatureType value="0"/>',
     70     '    <FeatureSetting value="1"/>',
     71     '    <EnableFlags value="0x00000000"/>',
     72     '    <DisableFlags value="0x00000000"/>',
     73     '  </MorphFeature>',
     74     '  <MorphSubtable index="0">',
     75     '    <!-- StructLength=32 -->',
     76     '    <CoverageFlags value="128"/>',
     77     '    <!-- MorphType=4 -->',
     78     '    <SubFeatureFlags value="0x00000001"/>',
     79     '    <NoncontextualMorph>',
     80     '      <Substitution>',
     81     '        <Lookup glyph="parenleft" value="parenleft.vertical"/>',
     82     '        <Lookup glyph="parenright" value="parenright.vertical"/>',
     83     '      </Substitution>',
     84     '    </NoncontextualMorph>',
     85     '  </MorphSubtable>',
     86     '</MorphChain>',
     87 ]
     88 
     89 
     90 class MORTNoncontextualGlyphSubstitutionTest(unittest.TestCase):
     91 
     92     @classmethod
     93     def setUpClass(cls):
     94         cls.maxDiff = None
     95         glyphs = ['.notdef'] + ['g.%d' % i for i in range (1, 140)]
     96         glyphs[11], glyphs[13] = 'parenleft', 'parenright'
     97         glyphs[135], glyphs[136] = 'parenleft.vertical', 'parenright.vertical'
     98         cls.font = FakeFont(glyphs)
     99 
    100     def test_decompile_toXML(self):
    101         table = newTable('mort')
    102         table.decompile(MORT_NONCONTEXTUAL_DATA, self.font)
    103         self.assertEqual(getXML(table.toXML), MORT_NONCONTEXTUAL_XML)
    104 
    105     def test_compile_fromXML(self):
    106         table = newTable('mort')
    107         for name, attrs, content in parseXML(MORT_NONCONTEXTUAL_XML):
    108             table.fromXML(name, attrs, content, font=self.font)
    109         self.assertEqual(hexStr(table.compile(self.font)),
    110                          hexStr(MORT_NONCONTEXTUAL_DATA))
    111 
    112 
    113 if __name__ == '__main__':
    114     import sys
    115     sys.exit(unittest.main())
    116