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