1#!/usr/bin/env python3 2 3# Pre-generates the expected output subset files (via fonttools) for 4# specified subset test suite(s). 5 6import os 7import sys 8import shutil 9import io 10import re 11import tempfile 12 13from difflib import unified_diff 14from fontTools.ttLib import TTFont 15 16from subprocess import check_call 17from subset_test_suite import SubsetTestSuite 18 19 20def usage(): 21 print("Usage: generate-expected-outputs.py hb-subset <test suite file> ...") 22 23 24def strip_check_sum (ttx_string): 25 return re.sub ('checkSumAdjustment value=["]0x([0-9a-fA-F])+["]', 26 'checkSumAdjustment value="0x00000000"', 27 ttx_string, count=1) 28 29 30def generate_expected_output(input_file, unicodes, profile_flags, instance_flags, output_directory, font_name, no_fonttools): 31 input_path = input_file 32 if not no_fonttools and instance_flags: 33 instance_path = os.path.join(tempfile.mkdtemp (), font_name) 34 args = ["fonttools", "varLib.instancer", 35 "--no-overlap-flag", 36 "--no-recalc-timestamp", 37 "--no-optimize", 38 "--output=%s" % instance_path, 39 input_file] 40 args.extend(instance_flags) 41 check_call(args) 42 input_path = instance_path 43 44 fonttools_path = os.path.join(tempfile.mkdtemp (), font_name) 45 args = ["fonttools", "subset", input_path] 46 if instance_flags: 47 args.extend(["--recalc-bounds"]) 48 args.extend(["--drop-tables+=DSIG", 49 "--drop-tables-=sbix", 50 "--no-harfbuzz-repacker", # disable harfbuzz repacker so we aren't comparing to ourself. 51 "--output-file=%s" % fonttools_path]) 52 if unicodes != "": 53 args.extend(["--unicodes=%s" % unicodes,]) 54 55 # --gid-map is unsupported in fonttools so don't send it. Tests using 56 # it are crafted to work without fonttools knowing about the flag. 57 args.extend([f for f in profile_flags if not f.startswith("--gid-map")]) 58 if not no_fonttools: 59 check_call(args) 60 61 with io.StringIO () as fp: 62 with TTFont (fonttools_path) as font: 63 font.saveXML (fp) 64 fonttools_ttx = strip_check_sum (fp.getvalue ()) 65 66 harfbuzz_path = os.path.join(tempfile.mkdtemp (), font_name) 67 args = [ 68 hb_subset, 69 "--font-file=" + input_file, 70 "--output-file=" + harfbuzz_path, 71 "--drop-tables+=DSIG", 72 "--drop-tables-=sbix"] 73 if unicodes != "": 74 args.extend(["--unicodes=%s" % unicodes,]) 75 args.extend(profile_flags) 76 if instance_flags: 77 args.extend(["--instance=%s" % ','.join(instance_flags)]) 78 check_call(args) 79 80 with io.StringIO () as fp: 81 with TTFont (harfbuzz_path) as font: 82 font.saveXML (fp) 83 harfbuzz_ttx = strip_check_sum (fp.getvalue ()) 84 85 if not no_fonttools and harfbuzz_ttx != fonttools_ttx: 86 for line in unified_diff (fonttools_ttx.splitlines (1), harfbuzz_ttx.splitlines (1), fonttools_path, harfbuzz_path): 87 sys.stdout.write (line) 88 sys.stdout.flush () 89 raise Exception ('ttx for fonttools and harfbuzz does not match.') 90 91 output_path = os.path.join(output_directory, font_name) 92 shutil.copy(harfbuzz_path, output_path) 93 94 95args = sys.argv[1:] 96if not args: 97 usage() 98hb_subset, args = args[0], args[1:] 99if not args: 100 usage() 101 102for path in args: 103 with open(path, mode="r", encoding="utf-8") as f: 104 test_suite = SubsetTestSuite(path, f.read()) 105 output_directory = test_suite.get_output_directory() 106 107 print("Generating output files for %s" % output_directory) 108 for test in test_suite.tests(): 109 unicodes = test.unicodes() 110 font_name = test.get_font_name() 111 no_fonttools = ("no_fonttools" in test.options) 112 print("Creating subset %s/%s" % (output_directory, font_name)) 113 generate_expected_output(test.font_path, unicodes, test.get_profile_flags(), 114 test.get_instance_flags(), output_directory, font_name, no_fonttools=no_fonttools) 115