1 #include "benchmark/benchmark.h"
2 #include <cstring>
3
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
7
8 #include <cassert>
9
10 #include "hb.h"
11 #include "hb-ot.h"
12 #ifdef HAVE_FREETYPE
13 #include "hb-ft.h"
14 #endif
15
16 #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
17
18 struct test_input_t
19 {
20 const char *font_path;
21 const char *text_path;
22 bool is_variable;
23 } default_tests[] =
24 {
25
26 {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
27 "perf/texts/fa-thelittleprince.txt",
28 false},
29
30 {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
31 "perf/texts/fa-words.txt",
32 false},
33
34 {"perf/fonts/Amiri-Regular.ttf",
35 "perf/texts/fa-thelittleprince.txt",
36 false},
37
38 {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf",
39 "perf/texts/hi-words.txt",
40 false},
41
42 {"perf/fonts/Roboto-Regular.ttf",
43 "perf/texts/en-thelittleprince.txt",
44 false},
45
46 {"perf/fonts/Roboto-Regular.ttf",
47 "perf/texts/en-words.txt",
48 false},
49
50 {SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
51 "perf/texts/en-thelittleprince.txt",
52 true},
53 };
54
55 static test_input_t *tests = default_tests;
56 static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
57
58 enum backend_t { HARFBUZZ, FREETYPE };
59
BM_Shape(benchmark::State & state,bool is_var,backend_t backend,const test_input_t & input)60 static void BM_Shape (benchmark::State &state,
61 bool is_var,
62 backend_t backend,
63 const test_input_t &input)
64 {
65 hb_font_t *font;
66 {
67 hb_blob_t *blob = hb_blob_create_from_file_or_fail (input.font_path);
68 assert (blob);
69 hb_face_t *face = hb_face_create (blob, 0);
70 hb_blob_destroy (blob);
71 font = hb_font_create (face);
72 hb_face_destroy (face);
73 }
74
75 if (is_var)
76 {
77 hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
78 hb_font_set_variations (font, &wght, 1);
79 }
80
81 switch (backend)
82 {
83 case HARFBUZZ:
84 hb_ot_font_set_funcs (font);
85 break;
86
87 case FREETYPE:
88 #ifdef HAVE_FREETYPE
89 hb_ft_font_set_funcs (font);
90 #endif
91 break;
92 }
93
94 hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
95 assert (text_blob);
96 unsigned orig_text_length;
97 const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length);
98
99 hb_buffer_t *buf = hb_buffer_create ();
100 for (auto _ : state)
101 {
102 unsigned text_length = orig_text_length;
103 const char *text = orig_text;
104
105 const char *end;
106 while ((end = (const char *) memchr (text, '\n', text_length)))
107 {
108 hb_buffer_clear_contents (buf);
109 hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
110 hb_buffer_guess_segment_properties (buf);
111 hb_shape (font, buf, nullptr, 0);
112
113 unsigned skip = end - text + 1;
114 text_length -= skip;
115 text += skip;
116 }
117 }
118 hb_buffer_destroy (buf);
119
120 hb_blob_destroy (text_blob);
121 hb_font_destroy (font);
122 }
123
test_backend(backend_t backend,const char * backend_name,bool variable,const test_input_t & test_input)124 static void test_backend (backend_t backend,
125 const char *backend_name,
126 bool variable,
127 const test_input_t &test_input)
128 {
129 char name[1024] = "BM_Shape";
130 const char *p;
131 strcat (name, "/");
132 p = strrchr (test_input.font_path, '/');
133 strcat (name, p ? p + 1 : test_input.font_path);
134 strcat (name, "/");
135 p = strrchr (test_input.text_path, '/');
136 strcat (name, p ? p + 1 : test_input.text_path);
137 strcat (name, variable ? "/var" : "");
138 strcat (name, "/");
139 strcat (name, backend_name);
140
141 benchmark::RegisterBenchmark (name, BM_Shape, variable, backend, test_input)
142 ->Unit(benchmark::kMillisecond);
143 }
144
main(int argc,char ** argv)145 int main(int argc, char** argv)
146 {
147 benchmark::Initialize(&argc, argv);
148
149 if (argc > 2)
150 {
151 num_tests = (argc - 1) / 2;
152 tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
153 for (unsigned i = 0; i < num_tests; i++)
154 {
155 tests[i].is_variable = true;
156 tests[i].font_path = argv[1 + i * 2];
157 tests[i].text_path = argv[2 + i * 2];
158 }
159 }
160
161 for (unsigned i = 0; i < num_tests; i++)
162 {
163 auto& test_input = tests[i];
164 for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
165 {
166 bool is_var = (bool) variable;
167
168 test_backend (HARFBUZZ, "hb", is_var, test_input);
169 #ifdef HAVE_FREETYPE
170 test_backend (FREETYPE, "ft", is_var, test_input);
171 #endif
172 }
173 }
174
175 benchmark::RunSpecifiedBenchmarks();
176 benchmark::Shutdown();
177
178 if (tests != default_tests)
179 free (tests);
180 }
181