• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.ttLib import TTFont
4from fontTools.varLib import build
5from fontTools.varLib.mutator import main as mutator
6from fontTools.varLib.mutator import instantiateVariableFont as make_instance
7import difflib
8import os
9import shutil
10import sys
11import tempfile
12import unittest
13
14
15class MutatorTest(unittest.TestCase):
16    def __init__(self, methodName):
17        unittest.TestCase.__init__(self, methodName)
18        # Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
19        # and fires deprecation warnings if a program uses the old name.
20        if not hasattr(self, "assertRaisesRegex"):
21            self.assertRaisesRegex = self.assertRaisesRegexp
22
23    def setUp(self):
24        self.tempdir = None
25        self.num_tempfiles = 0
26
27    def tearDown(self):
28        if self.tempdir:
29            shutil.rmtree(self.tempdir)
30
31    @staticmethod
32    def get_test_input(test_file_or_folder):
33        path, _ = os.path.split(__file__)
34        return os.path.join(path, "data", test_file_or_folder)
35
36    @staticmethod
37    def get_test_output(test_file_or_folder):
38        path, _ = os.path.split(__file__)
39        return os.path.join(path, "data", "test_results", test_file_or_folder)
40
41    @staticmethod
42    def get_file_list(folder, suffix, prefix=''):
43        all_files = os.listdir(folder)
44        file_list = []
45        for p in all_files:
46            if p.startswith(prefix) and p.endswith(suffix):
47                file_list.append(os.path.abspath(os.path.join(folder, p)))
48        return file_list
49
50    def temp_path(self, suffix):
51        self.temp_dir()
52        self.num_tempfiles += 1
53        return os.path.join(self.tempdir,
54                            "tmp%d%s" % (self.num_tempfiles, suffix))
55
56    def temp_dir(self):
57        if not self.tempdir:
58            self.tempdir = tempfile.mkdtemp()
59
60    def read_ttx(self, path):
61        lines = []
62        with open(path, "r", encoding="utf-8") as ttx:
63            for line in ttx.readlines():
64                # Elide ttFont attributes because ttLibVersion may change,
65                # and use os-native line separators so we can run difflib.
66                if line.startswith("<ttFont "):
67                    lines.append("<ttFont>" + os.linesep)
68                else:
69                    lines.append(line.rstrip() + os.linesep)
70        return lines
71
72    def expect_ttx(self, font, expected_ttx, tables):
73        path = self.temp_path(suffix=".ttx")
74        font.saveXML(path, tables=tables)
75        actual = self.read_ttx(path)
76        expected = self.read_ttx(expected_ttx)
77        if actual != expected:
78            for line in difflib.unified_diff(
79                    expected, actual, fromfile=expected_ttx, tofile=path):
80                sys.stdout.write(line)
81            self.fail("TTX output is different from expected")
82
83    def compile_font(self, path, suffix, temp_dir):
84        ttx_filename = os.path.basename(path)
85        savepath = os.path.join(temp_dir, ttx_filename.replace('.ttx', suffix))
86        font = TTFont(recalcBBoxes=False, recalcTimestamp=False)
87        font.importXML(path)
88        font.save(savepath, reorderTables=None)
89        return font, savepath
90
91# -----
92# Tests
93# -----
94
95    def test_varlib_mutator_ttf(self):
96        suffix = '.ttf'
97        ds_path = self.get_test_input('Build.designspace')
98        ufo_dir = self.get_test_input('master_ufo')
99        ttx_dir = self.get_test_input('master_ttx_interpolatable_ttf')
100
101        self.temp_dir()
102        ttx_paths = self.get_file_list(ttx_dir, '.ttx', 'TestFamily-')
103        for path in ttx_paths:
104            self.compile_font(path, suffix, self.tempdir)
105
106        finder = lambda s: s.replace(ufo_dir, self.tempdir).replace('.ufo', suffix)
107        varfont, _, _ = build(ds_path, finder)
108        varfont_name = 'Mutator'
109        varfont_path = os.path.join(self.tempdir, varfont_name + suffix)
110        varfont.save(varfont_path)
111
112        args = [varfont_path, 'wght=500', 'cntr=50']
113        mutator(args)
114
115        instfont_path = os.path.splitext(varfont_path)[0] + '-instance' + suffix
116        instfont = TTFont(instfont_path)
117        tables = [table_tag for table_tag in instfont.keys() if table_tag != 'head']
118        expected_ttx_path = self.get_test_output(varfont_name + '.ttx')
119        self.expect_ttx(instfont, expected_ttx_path, tables)
120
121    def test_varlib_mutator_getvar_ttf(self):
122        suffix = '.ttf'
123        ttx_dir = self.get_test_input('master_ttx_getvar_ttf')
124
125        self.temp_dir()
126        ttx_paths = self.get_file_list(ttx_dir, '.ttx', 'Mutator_Getvar')
127        for path in ttx_paths:
128            self.compile_font(path, suffix, self.tempdir)
129
130        varfont_name = 'Mutator_Getvar'
131        varfont_path = os.path.join(self.tempdir, varfont_name + suffix)
132
133        args = [varfont_path, 'wdth=80', 'ASCN=628']
134        mutator(args)
135
136        instfont_path = os.path.splitext(varfont_path)[0] + '-instance' + suffix
137        instfont = TTFont(instfont_path)
138        tables = [table_tag for table_tag in instfont.keys() if table_tag != 'head']
139        expected_ttx_path = self.get_test_output(varfont_name + '-instance.ttx')
140        self.expect_ttx(instfont, expected_ttx_path, tables)
141
142    def test_varlib_mutator_iup_ttf(self):
143        suffix = '.ttf'
144        ufo_dir = self.get_test_input('master_ufo')
145        ttx_dir = self.get_test_input('master_ttx_varfont_ttf')
146
147        self.temp_dir()
148        ttx_paths = self.get_file_list(ttx_dir, '.ttx', 'Mutator_IUP')
149        for path in ttx_paths:
150            self.compile_font(path, suffix, self.tempdir)
151
152        varfont_name = 'Mutator_IUP'
153        varfont_path = os.path.join(self.tempdir, varfont_name + suffix)
154
155        args = [varfont_path, 'wdth=80', 'ASCN=628']
156        mutator(args)
157
158        instfont_path = os.path.splitext(varfont_path)[0] + '-instance' + suffix
159        instfont = TTFont(instfont_path)
160        tables = [table_tag for table_tag in instfont.keys() if table_tag != 'head']
161        expected_ttx_path = self.get_test_output(varfont_name + '-instance.ttx')
162        self.expect_ttx(instfont, expected_ttx_path, tables)
163
164    def test_varlib_mutator_CFF2(self):
165
166        otf_vf_path = self.get_test_input('TestCFF2VF.otf')
167        expected_ttx_name = 'InterpolateTestCFF2VF'
168        tables = ["hmtx", "CFF2"]
169        loc = {'wght':float(200)}
170
171        varfont = TTFont(otf_vf_path)
172        new_font = make_instance(varfont, loc)
173        expected_ttx_path = self.get_test_output(expected_ttx_name + '.ttx')
174        self.expect_ttx(new_font, expected_ttx_path, tables)
175
176
177if __name__ == "__main__":
178    sys.exit(unittest.main())
179