1*2d1272b8SAndroid Build Coastguard Worker #include <cassert>
2*2d1272b8SAndroid Build Coastguard Worker #include <cstdio>
3*2d1272b8SAndroid Build Coastguard Worker #include <cstdlib>
4*2d1272b8SAndroid Build Coastguard Worker #include <cstring>
5*2d1272b8SAndroid Build Coastguard Worker #include <thread>
6*2d1272b8SAndroid Build Coastguard Worker #include <condition_variable>
7*2d1272b8SAndroid Build Coastguard Worker #include <vector>
8*2d1272b8SAndroid Build Coastguard Worker
9*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_CONFIG_H
10*2d1272b8SAndroid Build Coastguard Worker #include "config.h"
11*2d1272b8SAndroid Build Coastguard Worker #endif
12*2d1272b8SAndroid Build Coastguard Worker
13*2d1272b8SAndroid Build Coastguard Worker #include "hb.h"
14*2d1272b8SAndroid Build Coastguard Worker #include "hb-ot.h"
15*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_FREETYPE
16*2d1272b8SAndroid Build Coastguard Worker #include "hb-ft.h"
17*2d1272b8SAndroid Build Coastguard Worker #endif
18*2d1272b8SAndroid Build Coastguard Worker
19*2d1272b8SAndroid Build Coastguard Worker #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
20*2d1272b8SAndroid Build Coastguard Worker
21*2d1272b8SAndroid Build Coastguard Worker struct test_input_t
22*2d1272b8SAndroid Build Coastguard Worker {
23*2d1272b8SAndroid Build Coastguard Worker const char *font_path;
24*2d1272b8SAndroid Build Coastguard Worker const char *text_path;
25*2d1272b8SAndroid Build Coastguard Worker bool is_variable;
26*2d1272b8SAndroid Build Coastguard Worker } default_tests[] =
27*2d1272b8SAndroid Build Coastguard Worker {
28*2d1272b8SAndroid Build Coastguard Worker
29*2d1272b8SAndroid Build Coastguard Worker {"perf/fonts/NotoNastaliqUrdu-Regular.ttf",
30*2d1272b8SAndroid Build Coastguard Worker "perf/texts/fa-thelittleprince.txt",
31*2d1272b8SAndroid Build Coastguard Worker false},
32*2d1272b8SAndroid Build Coastguard Worker
33*2d1272b8SAndroid Build Coastguard Worker {"perf/fonts/Amiri-Regular.ttf",
34*2d1272b8SAndroid Build Coastguard Worker "perf/texts/fa-thelittleprince.txt",
35*2d1272b8SAndroid Build Coastguard Worker false},
36*2d1272b8SAndroid Build Coastguard Worker
37*2d1272b8SAndroid Build Coastguard Worker {"perf/fonts/Roboto-Regular.ttf",
38*2d1272b8SAndroid Build Coastguard Worker "perf/texts/en-thelittleprince.txt",
39*2d1272b8SAndroid Build Coastguard Worker false},
40*2d1272b8SAndroid Build Coastguard Worker
41*2d1272b8SAndroid Build Coastguard Worker {"perf/fonts/Roboto-Regular.ttf",
42*2d1272b8SAndroid Build Coastguard Worker "perf/texts/en-words.txt",
43*2d1272b8SAndroid Build Coastguard Worker false},
44*2d1272b8SAndroid Build Coastguard Worker
45*2d1272b8SAndroid Build Coastguard Worker {SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf",
46*2d1272b8SAndroid Build Coastguard Worker "perf/texts/en-thelittleprince.txt",
47*2d1272b8SAndroid Build Coastguard Worker true},
48*2d1272b8SAndroid Build Coastguard Worker };
49*2d1272b8SAndroid Build Coastguard Worker
50*2d1272b8SAndroid Build Coastguard Worker
51*2d1272b8SAndroid Build Coastguard Worker static test_input_t *tests = default_tests;
52*2d1272b8SAndroid Build Coastguard Worker static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
53*2d1272b8SAndroid Build Coastguard Worker
54*2d1272b8SAndroid Build Coastguard Worker enum backend_t { HARFBUZZ, FREETYPE };
55*2d1272b8SAndroid Build Coastguard Worker
56*2d1272b8SAndroid Build Coastguard Worker // https://en.cppreference.com/w/cpp/thread/condition_variable/wait
57*2d1272b8SAndroid Build Coastguard Worker static std::condition_variable cv;
58*2d1272b8SAndroid Build Coastguard Worker static std::mutex cv_m;
59*2d1272b8SAndroid Build Coastguard Worker static bool ready = false;
60*2d1272b8SAndroid Build Coastguard Worker
61*2d1272b8SAndroid Build Coastguard Worker static unsigned num_repetitions = 1;
62*2d1272b8SAndroid Build Coastguard Worker static unsigned num_threads = 3;
63*2d1272b8SAndroid Build Coastguard Worker
shape(const test_input_t & input,hb_font_t * font)64*2d1272b8SAndroid Build Coastguard Worker static void shape (const test_input_t &input,
65*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font)
66*2d1272b8SAndroid Build Coastguard Worker {
67*2d1272b8SAndroid Build Coastguard Worker // Wait till all threads are ready.
68*2d1272b8SAndroid Build Coastguard Worker {
69*2d1272b8SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lk (cv_m);
70*2d1272b8SAndroid Build Coastguard Worker cv.wait(lk, [] {return ready;});
71*2d1272b8SAndroid Build Coastguard Worker }
72*2d1272b8SAndroid Build Coastguard Worker
73*2d1272b8SAndroid Build Coastguard Worker const char *lang_str = strrchr (input.text_path, '/');
74*2d1272b8SAndroid Build Coastguard Worker lang_str = lang_str ? lang_str + 1 : input.text_path;
75*2d1272b8SAndroid Build Coastguard Worker hb_language_t language = hb_language_from_string (lang_str, -1);
76*2d1272b8SAndroid Build Coastguard Worker
77*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *text_blob = hb_blob_create_from_file_or_fail (input.text_path);
78*2d1272b8SAndroid Build Coastguard Worker assert (text_blob);
79*2d1272b8SAndroid Build Coastguard Worker unsigned orig_text_length;
80*2d1272b8SAndroid Build Coastguard Worker const char *orig_text = hb_blob_get_data (text_blob, &orig_text_length);
81*2d1272b8SAndroid Build Coastguard Worker
82*2d1272b8SAndroid Build Coastguard Worker hb_buffer_t *buf = hb_buffer_create ();
83*2d1272b8SAndroid Build Coastguard Worker hb_buffer_set_flags (buf, HB_BUFFER_FLAG_VERIFY);
84*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_repetitions; i++)
85*2d1272b8SAndroid Build Coastguard Worker {
86*2d1272b8SAndroid Build Coastguard Worker unsigned text_length = orig_text_length;
87*2d1272b8SAndroid Build Coastguard Worker const char *text = orig_text;
88*2d1272b8SAndroid Build Coastguard Worker
89*2d1272b8SAndroid Build Coastguard Worker const char *end;
90*2d1272b8SAndroid Build Coastguard Worker while ((end = (const char *) memchr (text, '\n', text_length)))
91*2d1272b8SAndroid Build Coastguard Worker {
92*2d1272b8SAndroid Build Coastguard Worker hb_buffer_clear_contents (buf);
93*2d1272b8SAndroid Build Coastguard Worker hb_buffer_add_utf8 (buf, text, text_length, 0, end - text);
94*2d1272b8SAndroid Build Coastguard Worker hb_buffer_guess_segment_properties (buf);
95*2d1272b8SAndroid Build Coastguard Worker hb_buffer_set_language (buf, language);
96*2d1272b8SAndroid Build Coastguard Worker hb_shape (font, buf, nullptr, 0);
97*2d1272b8SAndroid Build Coastguard Worker
98*2d1272b8SAndroid Build Coastguard Worker unsigned skip = end - text + 1;
99*2d1272b8SAndroid Build Coastguard Worker text_length -= skip;
100*2d1272b8SAndroid Build Coastguard Worker text += skip;
101*2d1272b8SAndroid Build Coastguard Worker }
102*2d1272b8SAndroid Build Coastguard Worker }
103*2d1272b8SAndroid Build Coastguard Worker hb_buffer_destroy (buf);
104*2d1272b8SAndroid Build Coastguard Worker
105*2d1272b8SAndroid Build Coastguard Worker hb_blob_destroy (text_blob);
106*2d1272b8SAndroid Build Coastguard Worker }
107*2d1272b8SAndroid Build Coastguard Worker
test_backend(backend_t backend,const char * backend_name,bool variable,const test_input_t & test_input)108*2d1272b8SAndroid Build Coastguard Worker static void test_backend (backend_t backend,
109*2d1272b8SAndroid Build Coastguard Worker const char *backend_name,
110*2d1272b8SAndroid Build Coastguard Worker bool variable,
111*2d1272b8SAndroid Build Coastguard Worker const test_input_t &test_input)
112*2d1272b8SAndroid Build Coastguard Worker {
113*2d1272b8SAndroid Build Coastguard Worker char name[1024] = "shape";
114*2d1272b8SAndroid Build Coastguard Worker const char *p;
115*2d1272b8SAndroid Build Coastguard Worker strcat (name, "/");
116*2d1272b8SAndroid Build Coastguard Worker p = strrchr (test_input.font_path, '/');
117*2d1272b8SAndroid Build Coastguard Worker strcat (name, p ? p + 1 : test_input.font_path);
118*2d1272b8SAndroid Build Coastguard Worker strcat (name, "/");
119*2d1272b8SAndroid Build Coastguard Worker p = strrchr (test_input.text_path, '/');
120*2d1272b8SAndroid Build Coastguard Worker strcat (name, p ? p + 1 : test_input.text_path);
121*2d1272b8SAndroid Build Coastguard Worker strcat (name, variable ? "/var" : "");
122*2d1272b8SAndroid Build Coastguard Worker strcat (name, "/");
123*2d1272b8SAndroid Build Coastguard Worker strcat (name, backend_name);
124*2d1272b8SAndroid Build Coastguard Worker
125*2d1272b8SAndroid Build Coastguard Worker printf ("Testing %s\n", name);
126*2d1272b8SAndroid Build Coastguard Worker
127*2d1272b8SAndroid Build Coastguard Worker hb_font_t *font;
128*2d1272b8SAndroid Build Coastguard Worker {
129*2d1272b8SAndroid Build Coastguard Worker hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
130*2d1272b8SAndroid Build Coastguard Worker assert (blob);
131*2d1272b8SAndroid Build Coastguard Worker hb_face_t *face = hb_face_create (blob, 0);
132*2d1272b8SAndroid Build Coastguard Worker hb_blob_destroy (blob);
133*2d1272b8SAndroid Build Coastguard Worker font = hb_font_create (face);
134*2d1272b8SAndroid Build Coastguard Worker hb_face_destroy (face);
135*2d1272b8SAndroid Build Coastguard Worker }
136*2d1272b8SAndroid Build Coastguard Worker
137*2d1272b8SAndroid Build Coastguard Worker if (variable)
138*2d1272b8SAndroid Build Coastguard Worker {
139*2d1272b8SAndroid Build Coastguard Worker hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
140*2d1272b8SAndroid Build Coastguard Worker hb_font_set_variations (font, &wght, 1);
141*2d1272b8SAndroid Build Coastguard Worker }
142*2d1272b8SAndroid Build Coastguard Worker
143*2d1272b8SAndroid Build Coastguard Worker switch (backend)
144*2d1272b8SAndroid Build Coastguard Worker {
145*2d1272b8SAndroid Build Coastguard Worker case HARFBUZZ:
146*2d1272b8SAndroid Build Coastguard Worker hb_ot_font_set_funcs (font);
147*2d1272b8SAndroid Build Coastguard Worker break;
148*2d1272b8SAndroid Build Coastguard Worker
149*2d1272b8SAndroid Build Coastguard Worker case FREETYPE:
150*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_FREETYPE
151*2d1272b8SAndroid Build Coastguard Worker hb_ft_font_set_funcs (font);
152*2d1272b8SAndroid Build Coastguard Worker #endif
153*2d1272b8SAndroid Build Coastguard Worker break;
154*2d1272b8SAndroid Build Coastguard Worker }
155*2d1272b8SAndroid Build Coastguard Worker
156*2d1272b8SAndroid Build Coastguard Worker std::vector<std::thread> threads;
157*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_threads; i++)
158*2d1272b8SAndroid Build Coastguard Worker threads.push_back (std::thread (shape, test_input, font));
159*2d1272b8SAndroid Build Coastguard Worker
160*2d1272b8SAndroid Build Coastguard Worker {
161*2d1272b8SAndroid Build Coastguard Worker std::unique_lock<std::mutex> lk (cv_m);
162*2d1272b8SAndroid Build Coastguard Worker ready = true;
163*2d1272b8SAndroid Build Coastguard Worker }
164*2d1272b8SAndroid Build Coastguard Worker cv.notify_all();
165*2d1272b8SAndroid Build Coastguard Worker
166*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_threads; i++)
167*2d1272b8SAndroid Build Coastguard Worker threads[i].join ();
168*2d1272b8SAndroid Build Coastguard Worker
169*2d1272b8SAndroid Build Coastguard Worker hb_font_destroy (font);
170*2d1272b8SAndroid Build Coastguard Worker }
171*2d1272b8SAndroid Build Coastguard Worker
main(int argc,char ** argv)172*2d1272b8SAndroid Build Coastguard Worker int main(int argc, char** argv)
173*2d1272b8SAndroid Build Coastguard Worker {
174*2d1272b8SAndroid Build Coastguard Worker if (argc > 1)
175*2d1272b8SAndroid Build Coastguard Worker num_threads = atoi (argv[1]);
176*2d1272b8SAndroid Build Coastguard Worker if (argc > 2)
177*2d1272b8SAndroid Build Coastguard Worker num_repetitions = atoi (argv[2]);
178*2d1272b8SAndroid Build Coastguard Worker
179*2d1272b8SAndroid Build Coastguard Worker /* Dummy call to alleviate _guess_segment_properties thread safety-ness
180*2d1272b8SAndroid Build Coastguard Worker * https://github.com/harfbuzz/harfbuzz/issues/1191 */
181*2d1272b8SAndroid Build Coastguard Worker hb_language_get_default ();
182*2d1272b8SAndroid Build Coastguard Worker
183*2d1272b8SAndroid Build Coastguard Worker if (argc > 4)
184*2d1272b8SAndroid Build Coastguard Worker {
185*2d1272b8SAndroid Build Coastguard Worker num_tests = (argc - 3) / 2;
186*2d1272b8SAndroid Build Coastguard Worker tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
187*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_tests; i++)
188*2d1272b8SAndroid Build Coastguard Worker {
189*2d1272b8SAndroid Build Coastguard Worker tests[i].is_variable = true;
190*2d1272b8SAndroid Build Coastguard Worker tests[i].font_path = argv[3 + i * 2];
191*2d1272b8SAndroid Build Coastguard Worker tests[i].text_path = argv[4 + i * 2];
192*2d1272b8SAndroid Build Coastguard Worker }
193*2d1272b8SAndroid Build Coastguard Worker }
194*2d1272b8SAndroid Build Coastguard Worker
195*2d1272b8SAndroid Build Coastguard Worker printf ("Num threads %u; num repetitions %u\n", num_threads, num_repetitions);
196*2d1272b8SAndroid Build Coastguard Worker for (unsigned i = 0; i < num_tests; i++)
197*2d1272b8SAndroid Build Coastguard Worker {
198*2d1272b8SAndroid Build Coastguard Worker auto& test_input = tests[i];
199*2d1272b8SAndroid Build Coastguard Worker for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
200*2d1272b8SAndroid Build Coastguard Worker {
201*2d1272b8SAndroid Build Coastguard Worker bool is_var = (bool) variable;
202*2d1272b8SAndroid Build Coastguard Worker
203*2d1272b8SAndroid Build Coastguard Worker test_backend (HARFBUZZ, "hb", is_var, test_input);
204*2d1272b8SAndroid Build Coastguard Worker #ifdef HAVE_FREETYPE
205*2d1272b8SAndroid Build Coastguard Worker test_backend (FREETYPE, "ft", is_var, test_input);
206*2d1272b8SAndroid Build Coastguard Worker #endif
207*2d1272b8SAndroid Build Coastguard Worker }
208*2d1272b8SAndroid Build Coastguard Worker }
209*2d1272b8SAndroid Build Coastguard Worker
210*2d1272b8SAndroid Build Coastguard Worker if (tests != default_tests)
211*2d1272b8SAndroid Build Coastguard Worker free (tests);
212*2d1272b8SAndroid Build Coastguard Worker }
213