Blender V5.0
BLF_tests.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2025 Blender Authors
2 *
3 * SPDX-License-Identifier: Apache-2.0 */
4
5#include "BLF_api.hh"
6#include "BLI_path_utils.hh"
7#include "testing/testing.h"
8
9namespace blender::tests {
10
11static std::string font_path(std::string font_name)
12{
13 char path[FILE_MAX];
14 BLI_path_join(path,
15 sizeof(path),
16 blender::tests::flags_test_asset_dir().c_str(),
17 "blenfont",
18 font_name.c_str());
19 return std::string(path);
20}
21
22static int open_font(std::string font_name)
23{
24 BLF_init();
25 return BLF_load(font_path(font_name).c_str());
26}
27
28static void close_font(int id)
29{
30 BLF_unload_id(id);
31 BLF_exit();
32}
33
34TEST(blf_load, load)
35{
36 const int id = open_font("Ahem.ttf");
37 EXPECT_TRUE(id != -1);
38 close_font(id);
39}
40
41TEST(blf_load, font_is_loaded_path)
42{
43 BLF_init();
44 std::string path = font_path("Ahem.ttf");
45 const int id = BLF_load(path.c_str());
46 EXPECT_TRUE(BLF_is_loaded(path.c_str()));
47 close_font(id);
48}
49
50TEST(blf_load, font_is_loaded_id)
51{
52 const int id = open_font("Ahem.ttf");
53 EXPECT_TRUE(BLF_is_loaded_id(id));
54 close_font(id);
55}
56
57TEST(blf_load, display_name_from_file)
58{
59 std::string path = font_path("Ahem.ttf");
60 const char *name = BLF_display_name_from_file(path.c_str());
61 EXPECT_TRUE(STREQ(name, "Ahem Regular"));
62 /* BLF_display_name result must be freed. */
64}
65
66TEST(blf_load, display_name_from_id)
67{
68 const int id = open_font("Ahem.ttf");
69 const char *name = BLF_display_name_from_id(id);
70 EXPECT_TRUE(STREQ(name, "Ahem Regular"));
71 /* BLF_display_name result must be freed. */
73 close_font(id);
74}
75
76TEST(blf_load, has_glyph)
77{
78 const int id = open_font("Ahem.ttf");
79 const bool has_glyph = BLF_has_glyph(id, 0x0058); /* 'X' */
80 EXPECT_TRUE(has_glyph);
81 close_font(id);
82}
83
84TEST(blf_metrics, get_vfont_metrics)
85{
86 const int id = open_font("Ahem.ttf");
87 float ascend_ratio = 0.0f;
88 float em_ratio = 0.0f;
89 float scale = 0.0f;
90 const bool has_metrics = BLF_get_vfont_metrics(id, &ascend_ratio, &em_ratio, &scale);
91 EXPECT_TRUE(has_metrics);
92 EXPECT_TRUE(ascend_ratio == 0.8f);
93 EXPECT_TRUE(em_ratio == 1.0f);
94 EXPECT_TRUE(scale == 0.001f);
95 close_font(id);
96}
97
98TEST(blf_metrics, default_weight)
99{
100 const int id = open_font("Ahem.ttf");
101 const int weight = BLF_default_weight(id);
102 EXPECT_TRUE(weight == 400);
103 close_font(id);
104}
105
106TEST(blf_metrics, has_variable_weight)
107{
108 const int id = open_font("Roboto.ttf");
109 const bool has_variable_weight = BLF_has_variable_weight(id);
110 EXPECT_TRUE(has_variable_weight);
111 close_font(id);
112}
113
114TEST(blf_metrics, variable_weight)
115{
116 const int id = open_font("Roboto.ttf");
117 const char sample[] = "MM";
118 BLF_size(id, 100.0f);
119 BLF_character_weight(id, 300);
120 const float width_thin = BLF_width(id, sample, sizeof(sample));
121 BLF_character_weight(id, 600);
122 const float width_wide = BLF_width(id, sample, sizeof(sample));
123 EXPECT_TRUE(width_wide > width_thin);
124 close_font(id);
125}
126
127TEST(blf_dimensions, width_max)
128{
129 const int id = open_font("Ahem.ttf");
130 BLF_size(id, 100.0f);
131 const int width = BLF_width_max(id);
132 EXPECT_TRUE(width == 100.0f);
133 close_font(id);
134}
135
136TEST(blf_dimensions, height_max)
137{
138 const int id = open_font("Ahem.ttf");
139 BLF_size(id, 100.0f);
140 const int height = BLF_height_max(id);
141 EXPECT_TRUE(height == 100.0f);
142 close_font(id);
143}
144
145TEST(blf_dimensions, descender)
146{
147 const int id = open_font("Ahem.ttf");
148 BLF_size(id, 100.0f);
149 const int descender = BLF_descender(id);
150 EXPECT_TRUE(descender == -20);
151 close_font(id);
152}
153
154TEST(blf_dimensions, ascender)
155{
156 const int id = open_font("Ahem.ttf");
157 BLF_size(id, 100.0f);
158 const int ascender = BLF_ascender(id);
159 EXPECT_TRUE(ascender == 80);
160 close_font(id);
161}
162
163TEST(blf_dimensions, fixed_width)
164{
165 /* Ahem does not have all the characters needed for calculation. */
166 const int id = open_font("Roboto.ttf");
167 BLF_size(id, 100.0f);
168 const float width = BLF_fixed_width(id);
169 EXPECT_TRUE(width == 56.0f);
170 close_font(id);
171}
172
173TEST(blf_dimensions, width_em)
174{
175 /* In this test font, 'X' is exactly one em wide. */
176 const char sample[] = "XX";
177 int id = open_font("Ahem.ttf");
178 BLF_size(id, 100.0f);
179 const float width = BLF_width(id, sample, sizeof(sample));
180 EXPECT_TRUE(width == 200.0f);
181 close_font(id);
182}
183
184TEST(blf_dimensions, height_em)
185{
186 /* In this test font, 'X' is exactly one em high. */
187 const char sample[] = "X";
188 int id = open_font("Ahem.ttf");
189 BLF_size(id, 100.0f);
190 const float width = BLF_height(id, sample, sizeof(sample));
191 EXPECT_TRUE(width == 100.0f);
192 close_font(id);
193}
194
195TEST(blf_dimensions, advance)
196{
197 /* In this test font, 'X' has advance of exactly one em. */
198 const char sample[] = "X";
199 int id = open_font("Ahem.ttf");
200 BLF_size(id, 100.0f);
201 const float width = BLF_glyph_advance(id, sample);
202 EXPECT_NEAR(width, 100.0f, 0.000001f);
203 close_font(id);
204}
205
206TEST(blf_wrapping_minimal, wrap_overflow_ascii)
207{
208 /* Do not break, even though over the wrap limit. */
209 const char sample[] =
210 "xxxxxxxxxxxxxxxxxxx!\"#$%&\'()*+,-./"
211 "0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
212 /* Ahem does not contain all the characters included in above string. */
213 int id = open_font("Roboto.ttf");
214 BLF_size(id, 10.0f);
215 const float width = BLF_width(id, sample, sizeof(sample));
217 id, sample, int(float(width) * 0.05f));
218 EXPECT_TRUE(wrapped.size() == 1);
219 close_font(id);
220}
221
222TEST(blf_wrapping_minimal, wrap_space)
223{
224 /* Must break at the center spaces into two, one space trailing, one leading. */
225 const char sample[] = "x xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx ";
226 int id = open_font("Ahem.ttf");
227 BLF_size(id, 10.0f);
228 const float width = BLF_width(id, sample, sizeof(sample));
230 id, sample, int(float(width) * 0.7f));
231 EXPECT_TRUE(wrapped.size() == 2 && wrapped[0].back() == ' ' && wrapped[1].substr(0, 1) != " ");
232 close_font(id);
233}
234
235TEST(blf_wrapping_minimal, wrap_linefeed)
236{
237 /* Must break on every line feed except at end of string. */
238 const char sample[] = "x\nxxxxxxxxxxxxxxxx\n\nxxxxxxxxxxxxxxxxxxx\n";
239 int id = open_font("Ahem.ttf");
240 BLF_size(id, 10.0f);
241 const float width = BLF_width(id, sample, sizeof(sample));
243 id, sample, int(float(width) * 0.7f));
244 EXPECT_TRUE(wrapped.size() == 4 && wrapped[2].is_empty());
245 close_font(id);
246}
247
248TEST(blf_wrapping_minimal, wrap_hardlimit)
249{
250 /* Must break at limit. */
251 const char sample[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
252 int id = open_font("Ahem.ttf");
253 BLF_size(id, 10.0f);
254 const float width = BLF_width(id, sample, sizeof(sample));
256 id, sample, int(float(width) * 0.7f), BLFWrapMode::HardLimit);
257 EXPECT_TRUE(wrapped.size() == 2);
258 close_font(id);
259}
260
261TEST(blf_wrapping_path, wrap_path_overflow_ascii)
262{
263 /* Do not break, even though over the wrap limit. */
264 const char sample[] =
265 "xxxxxxxxxxxxxxxxxxx!\"#$\'()*+,"
266 "0123456789:;<>@ABCDEFGHIJKLMNOPQRSTUVWXYZ[]^`abcdefghijklmnopqrstuvwxyz{|}~";
267 /* Ahem does not contain all the characters included in above string. */
268 int id = open_font("Roboto.ttf");
269 BLF_size(id, 10.0f);
270 const float width = BLF_width(id, sample, sizeof(sample));
272 id, sample, int(float(width) * 0.05f), BLFWrapMode::Path);
273 EXPECT_TRUE(wrapped.size() == 1);
274 close_font(id);
275}
276
277TEST(blf_wrapping_path, wrap_path_space)
278{
279 /* Must break at the center space. */
280 const char sample[] = "x xxxxxxxxxxxxxxxx xxxxxxxxxxxxxxxxxxx ";
281 int id = open_font("Ahem.ttf");
282 BLF_size(id, 10.0f);
283 const float width = BLF_width(id, sample, sizeof(sample));
285 id, sample, int(float(width) * 0.7f), BLFWrapMode::Path);
286 EXPECT_TRUE(wrapped.size() == 2);
287 close_font(id);
288}
289
290TEST(blf_wrapping_path, wrap_path_separators_underscore)
291{
292 /* Must break at middle underscore. */
293 int id = open_font("Roboto.ttf");
294 /* Ahem does not contain all the characters included in tested string. */
295 BLF_size(id, 10.0f);
296 const char sample[] = "x_xx_xxxxxxxxxxxxx_xxxxxxxxxxxxxxxxxxx_";
297 float width = BLF_width(id, sample, sizeof(sample));
299 id, sample, int(float(width) * 0.7f), BLFWrapMode::Path);
300 EXPECT_TRUE(wrapped.size() == 2);
301 close_font(id);
302}
303
304TEST(blf_wrapping_path, wrap_path_separators_slash)
305{
306 /* Wrap at backslash path separators. */
307 int id = open_font("Roboto.ttf");
308 /* Ahem does not contain all the characters included in tested string. */
309 BLF_size(id, 10.0f);
310 const char sample[] = "xxxxxxxxxx" SEP_STR "xxxxxxxxxxxxxxxxxxxxxx";
311 float width = BLF_width(id, sample, sizeof(sample));
313 id, sample, int(float(width) * 0.7f), BLFWrapMode::Path);
314 EXPECT_TRUE(wrapped.size() == 2);
315 close_font(id);
316}
317
318TEST(blf_wrapping_path, wrap_path_hardlimit)
319{
320 /* Must break at limit. */
321 const char sample[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
322 int id = open_font("Ahem.ttf");
323 BLF_size(id, 10.0f);
324 const float width = BLF_width(id, sample, sizeof(sample));
326 id,
327 sample,
328 int(float(width) * 0.7f),
330 EXPECT_TRUE(wrapped.size() == 2);
331 close_font(id);
332}
333
334TEST(blf_wrapping_typographical, wrap_typographical_thinspace)
335{
336 /* Must break at thinspace. */
337 const char sample[] = "xxxxxxxxxxx xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
338 int id = open_font("Roboto.ttf");
339 BLF_size(id, 10.0f);
340 const float width = BLF_width(id, sample, sizeof(sample));
342 id, sample, int(float(width) * 0.7f), BLFWrapMode::Typographical);
343 EXPECT_TRUE(wrapped.size() == 2);
344 close_font(id);
345}
346
347TEST(blf_wrapping_typographical, wrap_typographical_backslash)
348{
349 /* Optional break at any backslash. */
350 const char sample[] = "xxxxxxxxxxx\\xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
351 int id = open_font("Roboto.ttf");
352 BLF_size(id, 10.0f);
353 const float width = BLF_width(id, sample, sizeof(sample));
355 id, sample, int(float(width) * 0.7f), BLFWrapMode::Typographical);
356 EXPECT_TRUE(wrapped.size() == 2);
357 close_font(id);
358}
359
360TEST(blf_wrapping_typographical, wrap_typographical_underscore)
361{
362 /* Optional break at any underscore. */
363 const char sample[] = "xxxxxxxxxxx_xxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
364 int id = open_font("Roboto.ttf");
365 BLF_size(id, 10.0f);
366 const float width = BLF_width(id, sample, sizeof(sample));
368 id, sample, int(float(width) * 0.7f), BLFWrapMode::Typographical);
369 EXPECT_TRUE(wrapped.size() == 2);
370 close_font(id);
371}
372
373TEST(blf_wrapping_typographical, wrap_typographical_forward_slash)
374{
375 /* Do not break on solidus if previous is a number. */
376 const char sample[] = "xxxxxxxxxxxxxx/xx3/xxxxxxxxxxxxxxxxxxxxx";
377 int id = open_font("Roboto.ttf");
378 BLF_size(id, 10.0f);
379 const float width = BLF_width(id, sample, sizeof(sample));
381 id, sample, int(float(width) * 0.7f), BLFWrapMode::Typographical);
382 EXPECT_TRUE(wrapped.size() == 2 && wrapped[0].back() != '3');
383 close_font(id);
384}
385
386TEST(blf_wrapping_typographical, wrap_typographical_dash)
387{
388 /* Do not break on dash, hyphen, em dash if previous is space. */
389 const char sample[] = "xxxxxxxxxxxxxx-xx /xxxxxxxxxxxxxxxxxxxxx";
390 int id = open_font("Roboto.ttf");
391 BLF_size(id, 10.0f);
392 const float width = BLF_width(id, sample, sizeof(sample));
394 id, sample, int(float(width) * 0.7f), BLFWrapMode::Typographical);
395 EXPECT_TRUE(wrapped.size() == 2 && wrapped[0].back() != ' ');
396 close_font(id);
397}
398
399TEST(blf_wrapping_typographical, wrap_typographical_CJK)
400{
401 /* Do not break on dash, hyphen, em dash if previous is space. */
402 const char sample[] =
403 "xxxxxxxxxxxxxx"
404 "断"
405 "xxxxxxxxxxxxxxxxxxxxx";
406 int id = open_font("Roboto.ttf");
407 BLF_size(id, 10.0f);
408 const float width = BLF_width(id, sample, sizeof(sample));
410 id, sample, int(float(width) * 0.7f), BLFWrapMode::Typographical);
411 EXPECT_TRUE(wrapped.size() == 2);
412 close_font(id);
413}
414
415TEST(blf_wrapping_typographical, wrap_typographical_Tibetan)
416{
417 /* Do not break on dash, hyphen, em dash if previous is space. */
418 const char sample[] =
419 "xxxxxxxxxxxxxx"
420 "།"
421 "xxxxxxxxxxxxxxxxxxxxx";
422 int id = open_font("Roboto.ttf");
423 BLF_size(id, 10.0f);
424 const float width = BLF_width(id, sample, sizeof(sample));
426 id, sample, int(float(width) * 0.7f), BLFWrapMode::Typographical);
427 EXPECT_TRUE(wrapped.size() == 2);
428 close_font(id);
429}
430
431TEST(blf_wrapping_typographical, wrap_typographical_hardlimit)
432{
433 /* Must break at limit. */
434 const char sample[] = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
435 int id = open_font("Ahem.ttf");
436 BLF_size(id, 10.0f);
437 const float width = BLF_width(id, sample, sizeof(sample));
439 id,
440 sample,
441 int(float(width) * 0.7f),
443 EXPECT_TRUE(wrapped.size() == 2);
444 close_font(id);
445}
446
447} // namespace blender::tests
bool BLF_has_glyph(int fontid, unsigned int unicode) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:151
void BLF_size(int fontid, float size)
Definition blf.cc:443
int BLF_descender(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:872
blender::Vector< blender::StringRef > BLF_string_wrap(int fontid, blender::StringRef str, const int max_pixel_width, BLFWrapMode mode=BLFWrapMode::Minimal)
Definition blf.cc:1061
int BLF_width_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:861
float BLF_height(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:837
bool BLF_is_loaded_id(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:170
char * BLF_display_name_from_id(int fontid)
Definition blf.cc:1093
bool BLF_get_vfont_metrics(int fontid, float *ascend_ratio, float *em_ratio, float *scale)
Definition blf.cc:1103
int BLF_default_weight(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:355
float BLF_fixed_width(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:815
int BLF_glyph_advance(int fontid, const char *str)
Definition blf.cc:826
int BLF_load(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition blf.cc:175
void BLF_exit()
Definition blf.cc:70
int bool BLF_is_loaded(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition blf.cc:160
float BLF_width(int fontid, const char *str, size_t str_len, ResultBLF *r_info=nullptr) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(2)
Definition blf.cc:802
bool BLF_unload_id(int fontid)
Definition blf.cc:280
bool BLF_has_variable_weight(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:364
int BLF_height_max(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:850
int BLF_init()
Definition blf.cc:61
char * BLF_display_name_from_file(const char *filepath) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition blf.cc:1073
int BLF_ascender(int fontid) ATTR_WARN_UNUSED_RESULT
Definition blf.cc:883
void BLF_character_weight(int fontid, int weight)
Definition blf.cc:347
BLFWrapMode
Definition BLF_enums.hh:20
#define FILE_MAX
#define BLI_path_join(...)
#define STREQ(a, b)
int64_t size() const
bool is_empty() const
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
MatBase< T, NumCol, NumRow > scale(const MatBase< T, NumCol, NumRow > &mat, const VectorT &scale)
static std::string font_path(std::string font_name)
Definition BLF_tests.cc:11
static void close_font(int id)
Definition BLF_tests.cc:28
TEST(blf_load, load)
Definition BLF_tests.cc:34
static int open_font(std::string font_name)
Definition BLF_tests.cc:22
const char * name
#define SEP_STR
Definition unit.cc:39