blob: 70696e829def586392a73a31c940b1d27326fb9a [file] [log] [blame]
from __future__ import print_function, division, absolute_import, unicode_literals
from fontTools.misc.py23 import *
from fontTools.misc.testTools import FakeFont, getXML, parseXML
from fontTools.misc.textTools import deHexStr, hexStr
from fontTools.ttLib import newTable
import unittest
# Glyph Metamorphosis Table Examples
# Example 1: Non-contextual Glyph Substitution
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6mort.html
# The example given by Apple's 'mort' specification is suboptimally
# encoded: it uses AAT lookup format 6 even though format 8 would be
# more compact. Because our encoder always uses the most compact
# encoding, this breaks our round-trip testing. Therefore, we changed
# the example to use GlyphID 13 instead of 12 for the 'parenright'
# character; the non-contiguous glyph range for the AAT lookup makes
# format 6 to be most compact.
MORT_NONCONTEXTUAL_DATA = deHexStr(
'0001 0000 ' # 0: Version=1.0
'0000 0001 ' # 4: MorphChainCount=1
'0000 0001 ' # 8: DefaultFlags=1
'0000 0050 ' # 12: StructLength=80
'0003 0001 ' # 16: MorphFeatureCount=3, MorphSubtableCount=1
'0004 0000 ' # 20: Feature[0].FeatureType=4/VertSubst, .FeatureSetting=on
'0000 0001 ' # 24: Feature[0].EnableFlags=0x00000001
'FFFF FFFF ' # 28: Feature[0].DisableFlags=0xFFFFFFFF
'0004 0001 ' # 32: Feature[1].FeatureType=4/VertSubst, .FeatureSetting=off
'0000 0000 ' # 36: Feature[1].EnableFlags=0x00000000
'FFFF FFFE ' # 40: Feature[1].DisableFlags=0xFFFFFFFE
'0000 0001 ' # 44: Feature[2].FeatureType=0/GlyphEffects, .FeatSetting=off
'0000 0000 ' # 48: Feature[2].EnableFlags=0 (required for last feature)
'0000 0000 ' # 52: Feature[2].EnableFlags=0 (required for last feature)
'0020 ' # 56: Subtable[0].StructLength=32
'80 ' # 58: Subtable[0].CoverageFlags=0x80
'04 ' # 59: Subtable[0].MorphType=4/NoncontextualMorph
'0000 0001 ' # 60: Subtable[0].SubFeatureFlags=0x1
'0006 0004 ' # 64: LookupFormat=6, UnitSize=4
'0002 0008 ' # 68: NUnits=2, SearchRange=8
'0001 0000 ' # 72: EntrySelector=1, RangeShift=0
'000B 0087 ' # 76: Glyph=11 (parenleft); Value=135 (parenleft.vertical)
'000D 0088 ' # 80: Glyph=13 (parenright); Value=136 (parenright.vertical)
'FFFF 0000 ' # 84: Glyph=<end>; Value=0
) # 88: <end>
assert len(MORT_NONCONTEXTUAL_DATA) == 88
MORT_NONCONTEXTUAL_XML = [
'<Version value="0x00010000"/>',
'<!-- MorphChainCount=1 -->',
'<MorphChain index="0">',
' <DefaultFlags value="0x00000001"/>',
' <!-- StructLength=80 -->',
' <!-- MorphFeatureCount=3 -->',
' <!-- MorphSubtableCount=1 -->',
' <MorphFeature index="0">',
' <FeatureType value="4"/>',
' <FeatureSetting value="0"/>',
' <EnableFlags value="0x00000001"/>',
' <DisableFlags value="0xFFFFFFFF"/>',
' </MorphFeature>',
' <MorphFeature index="1">',
' <FeatureType value="4"/>',
' <FeatureSetting value="1"/>',
' <EnableFlags value="0x00000000"/>',
' <DisableFlags value="0xFFFFFFFE"/>',
' </MorphFeature>',
' <MorphFeature index="2">',
' <FeatureType value="0"/>',
' <FeatureSetting value="1"/>',
' <EnableFlags value="0x00000000"/>',
' <DisableFlags value="0x00000000"/>',
' </MorphFeature>',
' <MorphSubtable index="0">',
' <!-- StructLength=32 -->',
' <CoverageFlags value="128"/>',
' <!-- MorphType=4 -->',
' <SubFeatureFlags value="0x00000001"/>',
' <NoncontextualMorph>',
' <Substitution>',
' <Lookup glyph="parenleft" value="parenleft.vertical"/>',
' <Lookup glyph="parenright" value="parenright.vertical"/>',
' </Substitution>',
' </NoncontextualMorph>',
' </MorphSubtable>',
'</MorphChain>',
]
class MORTNoncontextualGlyphSubstitutionTest(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.maxDiff = None
glyphs = ['.notdef'] + ['g.%d' % i for i in range (1, 140)]
glyphs[11], glyphs[13] = 'parenleft', 'parenright'
glyphs[135], glyphs[136] = 'parenleft.vertical', 'parenright.vertical'
cls.font = FakeFont(glyphs)
def test_decompile_toXML(self):
table = newTable('mort')
table.decompile(MORT_NONCONTEXTUAL_DATA, self.font)
self.assertEqual(getXML(table.toXML), MORT_NONCONTEXTUAL_XML)
def test_compile_fromXML(self):
table = newTable('mort')
for name, attrs, content in parseXML(MORT_NONCONTEXTUAL_XML):
table.fromXML(name, attrs, content, font=self.font)
self.assertEqual(hexStr(table.compile(self.font)),
hexStr(MORT_NONCONTEXTUAL_DATA))
if __name__ == '__main__':
import sys
sys.exit(unittest.main())