• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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