Blender V5.0
blf_font.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2009 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
12
13#include <algorithm>
14#include <cstdio>
15#include <cstdlib>
16#include <cstring>
17
18#include <ft2build.h>
19
20#include FT_FREETYPE_H
21#include FT_CACHE_H /* FreeType Cache. */
22#include FT_GLYPH_H
23#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
24#include FT_TRUETYPE_IDS_H /* Code-point coverage constants. */
25#include FT_TRUETYPE_TABLES_H /* For TT_OS2 */
26
27#include "MEM_guardedalloc.h"
28
29#include "DNA_vec_types.h"
30
31#include "BLI_math_bits.h"
33#include "BLI_math_matrix.h"
34#include "BLI_mutex.hh"
35#include "BLI_path_utils.hh"
36#include "BLI_rect.h"
37#include "BLI_string.h"
39#include "BLI_string_utf8.h"
40#include "BLI_vector.hh"
41
42#include "BLF_api.hh"
43
44#include "GPU_batch.hh"
45#include "GPU_matrix.hh"
46#include "GPU_state.hh"
47
48#include "blf_internal.hh"
49#include "blf_internal_types.hh"
50
51#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
52
53#ifdef WIN32
54# define FT_New_Face FT_New_Face__win32_compat
55#endif
56
57/* Batching buffer for drawing. */
58
60
61/* `freetype2` handle ONLY for this file! */
62static FT_Library ft_lib = nullptr;
63static FTC_Manager ftc_manager = nullptr;
64static FTC_CMapCache ftc_charmap_cache = nullptr;
65
66/* Lock for FreeType library, used around face creation and deletion. */
68
69/* May be set to #UI_widgetbase_draw_cache_flush. */
70static void (*blf_draw_cache_flush)() = nullptr;
71
74
75/* -------------------------------------------------------------------- */
76
79
80static bool blf_setup_face(FontBLF *font);
81
85static void blf_face_finalizer(void *object)
86{
87 FT_Face face = static_cast<FT_Face>(object);
88 FontBLF *font = (FontBLF *)face->generic.data;
89 font->face = nullptr;
90}
91
97static FT_Error blf_cache_face_requester(FTC_FaceID faceID,
98 FT_Library lib,
99 FT_Pointer /*req_data*/,
100 FT_Face *face)
101{
102 FontBLF *font = (FontBLF *)faceID;
103 int err = FT_Err_Cannot_Open_Resource;
104
105 std::scoped_lock lock(ft_lib_mutex);
106 if (font->filepath) {
107 err = FT_New_Face(lib, font->filepath, 0, face);
108 }
109 else if (font->mem) {
110 err = FT_New_Memory_Face(
111 lib, static_cast<const FT_Byte *>(font->mem), (FT_Long)font->mem_size, 0, face);
112 }
113
114 if (err == FT_Err_Ok) {
115 font->face = *face;
116 font->face->generic.data = font;
117 font->face->generic.finalizer = blf_face_finalizer;
118
119 /* More FontBLF setup now that we have a face. */
120 if (!blf_setup_face(font)) {
121 err = FT_Err_Cannot_Open_Resource;
122 }
123 }
124 else {
125 /* Clear this on error to avoid exception in FTC_Manager_LookupFace. */
126 *face = nullptr;
127 }
128
129 return err;
130}
131
135static void blf_size_finalizer(void *object)
136{
137 FT_Size size = static_cast<FT_Size>(object);
138 FontBLF *font = (FontBLF *)size->generic.data;
139 font->ft_size = nullptr;
140}
141
143
144/* -------------------------------------------------------------------- */
147
148uint blf_get_char_index(FontBLF *font, const uint charcode)
149{
150 if (font->flags & BLF_CACHED) {
151 /* Use char-map cache for much faster lookup. */
152 return FTC_CMapCache_Lookup(ftc_charmap_cache, font, -1, charcode);
153 }
154 /* Fonts that are not cached need to use the regular lookup function. */
155 return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0;
156}
157
158/* Convert a FreeType 26.6 value representing an unscaled design size to fractional pixels. */
159static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, const FT_Pos value)
160{
161 /* Make sure we have a valid font->ft_size. */
162 blf_ensure_size(font);
163
164 /* Scale value by font size using integer-optimized multiplication. */
165 FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale);
166
167 /* Copied from FreeType's FT_Get_Kerning (with FT_KERNING_DEFAULT), scaling down. */
168 /* Kerning distances at small PPEM values so that they don't become too big. */
169 if (font->ft_size->metrics.x_ppem < 25) {
170 scaled = FT_MulDiv(scaled, font->ft_size->metrics.x_ppem, 25);
171 }
172
173 return (ft_pix)scaled;
174}
175
177
178/* -------------------------------------------------------------------- */
181
189{
191 sizeof(g_batch.glyph_data), nullptr, GPU_USAGE_STREAM, __func__);
192 g_batch.glyph_len = 0;
193 /* We render a quad as a triangle strip and instance it for each glyph. */
195}
196
198{
200 if (g_batch.glyph_buf) {
201 GPU_storagebuf_free(g_batch.glyph_buf);
202 }
203}
204
206{
207 if (g_batch.batch == nullptr) {
209 }
210
211 const bool font_changed = (g_batch.font != font);
212 const bool simple_shader = ((font->flags & (BLF_ROTATION | BLF_ASPECT)) == 0);
213 const bool shader_changed = (simple_shader != g_batch.simple_shader);
214
215 g_batch.active = g_batch.enabled && simple_shader;
216
217 if (simple_shader) {
218 /* Offset is applied to each glyph. */
219 g_batch.ofs[0] = font->pos[0];
220 g_batch.ofs[1] = font->pos[1];
221 }
222 else {
223 /* Offset is baked in model-view matrix. */
224 zero_v2_int(g_batch.ofs);
225 }
226
227 if (g_batch.active) {
228 float gpumat[4][4];
230
231 bool mat_changed = equals_m4m4(gpumat, g_batch.mat) == false;
232
233 if (mat_changed) {
234 /* Model view matrix is no longer the same.
235 * Flush cache but with the previous matrix. */
238 }
239
240 /* Flush cache if configuration is not the same. */
241 if (mat_changed || font_changed || shader_changed) {
243 g_batch.simple_shader = simple_shader;
244 g_batch.font = font;
245 }
246 else {
247 /* Nothing changed continue batching. */
248 return;
249 }
250
251 if (mat_changed) {
253 /* Save for next `memcmp`. */
254 memcpy(g_batch.mat, gpumat, sizeof(g_batch.mat));
255 }
256 }
257 else {
258 /* Flush cache. */
260 g_batch.font = font;
261 g_batch.simple_shader = simple_shader;
262 }
263}
264
266{
267 GlyphCacheBLF *gc = g_batch.glyph_cache;
268 BLI_assert(gc);
269 BLI_assert(gc->bitmap_len > 0);
270
271 if (gc->bitmap_len > gc->bitmap_len_landed) {
272 const int tex_width = GPU_texture_width(gc->texture);
273
274 int bitmap_len_landed = gc->bitmap_len_landed;
275 int remain = gc->bitmap_len - bitmap_len_landed;
276 int offset_x = bitmap_len_landed % tex_width;
277 int offset_y = bitmap_len_landed / tex_width;
278
279 /* TODO(@germano): Update more than one row in a single call. */
280 while (remain) {
281 int remain_row = tex_width - offset_x;
282 int width = remain > remain_row ? remain_row : remain;
285 &gc->bitmap_result[bitmap_len_landed],
286 offset_x,
287 offset_y,
288 0,
289 width,
290 1,
291 0);
292
293 bitmap_len_landed += width;
294 remain -= width;
295 offset_x = 0;
296 offset_y += 1;
297 }
298
299 gc->bitmap_len_landed = bitmap_len_landed;
300 }
301
302 return gc->texture;
303}
304
306{
307 if (g_batch.glyph_len == 0) {
308 return;
309 }
310
312
313 /* We need to flush widget base first to ensure correct ordering. */
314 if (blf_draw_cache_flush != nullptr) {
316 }
317
319 GPU_storagebuf_usage_size_set(g_batch.glyph_buf, size_t(g_batch.glyph_len) * sizeof(GlyphQuad));
320 GPU_storagebuf_update(g_batch.glyph_buf, g_batch.glyph_data);
321 GPU_storagebuf_bind(g_batch.glyph_buf, 0);
322
324 GPU_batch_texture_bind(g_batch.batch, "glyph", texture);
325 /* Setup texture width mask and shift, so that shader can avoid costly divisions. */
326 int tex_width = GPU_texture_width(texture);
327 BLI_assert_msg(is_power_of_2_i(tex_width), "Font texture width must be power of two");
328 int width_shift = 31 - bitscan_reverse_i(tex_width);
329 GPU_batch_uniform_1i(g_batch.batch, "glyph_tex_width_mask", tex_width - 1);
330 GPU_batch_uniform_1i(g_batch.batch, "glyph_tex_width_shift", width_shift);
331 GPU_batch_draw_advanced(g_batch.batch, 0, 4, 0, g_batch.glyph_len);
332
334
336 g_batch.glyph_len = 0;
337}
338
340{
341 if (!g_batch.active) {
343 }
344}
345
347{
348 if (g_batch.glyph_buf) {
349 GPU_storagebuf_free(g_batch.glyph_buf);
351 sizeof(g_batch.glyph_data), nullptr, GPU_USAGE_STREAM, __func__);
352 }
353}
354
356
357/* -------------------------------------------------------------------- */
360
361BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
362{
363 ft_pix adjustment = 0;
364
365 /* Small adjust if there is hinting. */
366 adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0);
367
368 if (FT_HAS_KERNING(font) && g_prev) {
369 FT_Vector delta = {KERNING_ENTRY_UNSET};
370
371 /* Get unscaled kerning value from our cache if ASCII. */
372 if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
373 delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
374 }
375
376 /* If not ASCII or not found in cache, ask FreeType for kerning. */
377 if (UNLIKELY(font->face && delta.x == KERNING_ENTRY_UNSET)) {
378 /* Note that this function sets delta values to zero on any error. */
379 FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
380 }
381
382 /* If ASCII we save this value to our cache for quicker access next time. */
383 if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
384 font->kerning_cache->ascii_table[g->c][g_prev->c] = int(delta.x);
385 }
386
387 if (delta.x != 0) {
388 /* Convert unscaled design units to pixels and move pen. */
389 adjustment += blf_unscaled_F26Dot6_to_pixels(font, delta.x);
390 }
391 }
392
393 return adjustment;
394}
395
397 GlyphCacheBLF *gc,
398 const GlyphBLF *g_prev,
399 const char *str,
400 const size_t str_len,
401 size_t *i_p,
402 int32_t *pen_x)
403{
404 uint charcode = BLI_str_utf8_as_unicode_step_safe(str, str_len, i_p);
405 /* Invalid unicode sequences return the byte value, stepping forward one.
406 * This allows `latin1` to display (which is sometimes used for file-paths). */
407 BLI_assert(charcode != BLI_UTF8_ERR);
408 GlyphBLF *g = blf_glyph_ensure(font, gc, charcode);
409 if (g && pen_x && !(font->flags & BLF_MONOSPACED)) {
410 *pen_x += blf_kerning(font, g_prev, g);
411
412#ifdef BLF_SUBPIXEL_POSITION
413 if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
414 *pen_x = FT_PIX_ROUND(*pen_x);
415 }
416#else
417 *pen_x = FT_PIX_ROUND(*pen_x);
418#endif
419
420#ifdef BLF_SUBPIXEL_AA
421 g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
422#endif
423 }
424 return g;
425}
426
428
429/* -------------------------------------------------------------------- */
432
436[[maybe_unused]] static int blf_str_is_utf8_valid_lazy_init(const char *str,
437 const size_t str_len,
438 int &is_utf8_valid)
439{
440 if (is_utf8_valid == -1) {
441 is_utf8_valid = BLI_str_utf8_invalid_byte(str, str_len) == -1;
442 }
443 return is_utf8_valid;
444}
445
447
448/* -------------------------------------------------------------------- */
451
452static void blf_font_draw_ex(FontBLF *font,
453 GlyphCacheBLF *gc,
454 const char *str,
455 const size_t str_len,
456 ResultBLF *r_info,
457 const ft_pix pen_y)
458{
459 if (str_len == 0) {
460 /* Early exit, don't do any immediate-mode GPU operations. */
461 return;
462 }
463
464 GlyphBLF *g = nullptr;
465 ft_pix pen_x = 0;
466 size_t i = 0;
467
469
470 while ((i < str_len) && str[i]) {
471 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
472 if (UNLIKELY(g == nullptr)) {
473 continue;
474 }
475 /* Do not return this loop if clipped, we want every character tested. */
476 blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
477 pen_x += g->advance_x;
478 }
479
481
482 if (r_info) {
483 r_info->lines = 1;
484 r_info->width = ft_pix_to_int(pen_x);
485 }
486}
487void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
488{
490 blf_font_draw_ex(font, gc, str, str_len, r_info, 0);
492}
493
495 FontBLF *font, const char *str, const size_t str_len, const int cwidth, const int tab_columns)
496{
497 GlyphBLF *g;
498 int columns = 0;
499 ft_pix pen_x = 0, pen_y = 0;
500 ft_pix cwidth_fpx = ft_pix_from_int(cwidth);
501
502 size_t i = 0;
503
505
507
508 while ((i < str_len) && str[i]) {
509 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i, nullptr);
510
511 if (UNLIKELY(g == nullptr)) {
512 continue;
513 }
514 /* Do not return this loop if clipped, we want every character tested. */
515 blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
516
517 const int col = UNLIKELY(g->c == '\t') ? (tab_columns - (columns % tab_columns)) :
518 BLI_wcwidth_safe(char32_t(g->c));
519 columns += col;
520 pen_x += cwidth_fpx * col;
521 }
522
524
526 return columns;
527}
528
529#ifndef WITH_HEADLESS
531 const uint icon_id,
532 const float x,
533 const float y,
534 const float size,
535 const float color[4],
536 const float outline_alpha,
537 const bool multicolor,
538 blender::FunctionRef<void(std::string &)> edit_source_cb)
539{
540 BLI_assert(outline_alpha <= 1.0f); /* Higher values overflow, caller must ensure. */
541 blf_font_size(font, size);
542 font->pos[0] = int(x);
543 font->pos[1] = int(y);
544 font->pos[2] = 0;
545
546 if (color != nullptr) {
547 rgba_float_to_uchar(font->color, color);
548 }
549
550 if (outline_alpha > 0.0f) {
551 font->flags |= BLF_SHADOW;
553 font->shadow_x = 0;
554 font->shadow_y = 0;
555 font->shadow_color[0] = 0;
556 font->shadow_color[1] = 0;
557 font->shadow_color[2] = 0;
558 font->shadow_color[3] = char(outline_alpha * 255.0f);
559 }
560
563
564 GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor, edit_source_cb);
565 if (g) {
566 blf_glyph_draw(font, gc, g, 0, 0);
567 }
568
569 if (outline_alpha > 0) {
570 font->flags &= ~BLF_SHADOW;
571 }
572
575}
576
578 const uint icon_id,
579 const float size,
580 int *r_width,
581 int *r_height,
582 const bool multicolor,
583 blender::FunctionRef<void(std::string &)> edit_source_cb)
584{
585 blf_font_size(font, size);
587 GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor, edit_source_cb);
588
589 if (!g) {
591 *r_width = 0;
592 *r_height = 0;
593 return {};
594 }
595
596 *r_width = g->dims[0];
597 *r_height = g->dims[1];
598 blender::Array<uchar> bitmap(g->dims[0] * g->dims[1] * 4);
599
600 if (g->num_channels == 4) {
601 memcpy(bitmap.data(), g->bitmap, size_t(bitmap.size()));
602 }
603 else if (g->num_channels == 1) {
604 for (int64_t y = 0; y < int64_t(g->dims[1]); y++) {
605 for (int64_t x = 0; x < int64_t(g->dims[0]); x++) {
606 int64_t offs_in = (y * int64_t(g->pitch)) + x;
607 bitmap[int64_t(offs_in * 4)] = g->bitmap[offs_in];
608 bitmap[int64_t(offs_in * 4 + 1)] = g->bitmap[offs_in];
609 bitmap[int64_t(offs_in * 4 + 2)] = g->bitmap[offs_in];
610 bitmap[int64_t(offs_in * 4 + 3)] = g->bitmap[offs_in];
611 }
612 }
613 }
615 return bitmap;
616}
617#endif /* WITH_HEADLESS */
618
620
621/* -------------------------------------------------------------------- */
624
629 GlyphBLF *g,
630 const ft_pix pen_x,
631 const ft_pix pen_y_basis)
632{
633 const int chx = ft_pix_to_int(pen_x + ft_pix_from_int(g->pos[0]));
634 const int chy = ft_pix_to_int(pen_y_basis + ft_pix_from_int(g->dims[1]));
635
636 ft_pix pen_y = (g->pitch < 0) ? (pen_y_basis + ft_pix_from_int(g->dims[1] - g->pos[1])) :
637 (pen_y_basis - ft_pix_from_int(g->dims[1] - g->pos[1]));
638
639 if ((chx + g->dims[0]) < 0 || /* Out of bounds: left. */
640 chx >= buf_info->dims[0] || /* Out of bounds: right. */
641 (ft_pix_to_int(pen_y) + g->dims[1]) < 0 || /* Out of bounds: bottom. */
642 ft_pix_to_int(pen_y) >= buf_info->dims[1] /* Out of bounds: top. */
643 )
644 {
645 return;
646 }
647
648 /* Don't draw beyond the buffer bounds. */
649 int width_clip = g->dims[0];
650 int height_clip = g->dims[1];
651 int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
652
653 if (width_clip + chx > buf_info->dims[0]) {
654 width_clip -= chx + width_clip - buf_info->dims[0];
655 }
656 if (height_clip + ft_pix_to_int(pen_y) > buf_info->dims[1]) {
657 height_clip -= ft_pix_to_int(pen_y) + height_clip - buf_info->dims[1];
658 }
659
660 /* Clip drawing below the image. */
661 if (pen_y < 0) {
662 yb_start += (g->pitch < 0) ? -ft_pix_to_int(pen_y) : ft_pix_to_int(pen_y);
663 height_clip += ft_pix_to_int(pen_y);
664 pen_y = 0;
665 }
666
667 /* Avoid conversions in the pixel writing loop. */
668 const int pen_y_px = ft_pix_to_int(pen_y);
669
670 const float *b_col_float = buf_info->col_float;
671 const uchar *b_col_char = buf_info->col_char;
672
673 if (buf_info->fbuf) {
674 int yb = yb_start;
675 for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
676 const int x_start = (chx >= 0) ? 0 : -chx;
677 const uchar *a_ptr = g->bitmap + x_start + (yb * g->pitch);
678 const int64_t buf_ofs = (int64_t(buf_info->dims[0]) * (pen_y_px + y) + (chx + x_start)) * 4;
679 float *fbuf = buf_info->fbuf + buf_ofs;
680 for (int x = x_start; x < width_clip; x++, a_ptr++, fbuf += 4) {
681 const char a_byte = *a_ptr;
682 if (a_byte) {
683 const float a = (a_byte / 255.0f) * b_col_float[3];
684
685 float font_pixel[4];
686 font_pixel[0] = b_col_float[0] * a;
687 font_pixel[1] = b_col_float[1] * a;
688 font_pixel[2] = b_col_float[2] * a;
689 font_pixel[3] = a;
690 blend_color_mix_float(fbuf, fbuf, font_pixel);
691 }
692 }
693
694 if (g->pitch < 0) {
695 yb++;
696 }
697 else {
698 yb--;
699 }
700 }
701 }
702
703 if (buf_info->cbuf) {
704 int yb = yb_start;
705 for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
706 const int x_start = (chx >= 0) ? 0 : -chx;
707 const uchar *a_ptr = g->bitmap + x_start + (yb * g->pitch);
708 const int64_t buf_ofs = (int64_t(buf_info->dims[0]) * (pen_y_px + y) + (chx + x_start)) * 4;
709 uchar *cbuf = buf_info->cbuf + buf_ofs;
710 for (int x = x_start; x < width_clip; x++, a_ptr++, cbuf += 4) {
711 const char a_byte = *a_ptr;
712
713 if (a_byte) {
714 const float a = (a_byte / 255.0f) * b_col_float[3];
715
716 uchar font_pixel[4];
717 font_pixel[0] = b_col_char[0];
718 font_pixel[1] = b_col_char[1];
719 font_pixel[2] = b_col_char[2];
720 font_pixel[3] = unit_float_to_uchar_clamp(a);
721 blend_color_mix_byte(cbuf, cbuf, font_pixel);
722 }
723 }
724
725 if (g->pitch < 0) {
726 yb++;
727 }
728 else {
729 yb--;
730 }
731 }
732 }
733}
734
735/* Sanity checks are done by BLF_draw_buffer() */
737 GlyphCacheBLF *gc,
738 const char *str,
739 const size_t str_len,
740 const ft_pix pen_y,
741 ResultBLF *r_info)
742{
743 GlyphBLF *g = nullptr;
744 ft_pix pen_x = ft_pix_from_int(font->pos[0]);
745 ft_pix pen_y_basis = ft_pix_from_int(font->pos[1]) + pen_y;
746 size_t i = 0;
747
748 /* Buffer specific variables. */
749 FontBufInfoBLF *buf_info = &font->buf_info;
750
751 /* Another buffer specific call for color conversion. */
752
753 while ((i < str_len) && str[i]) {
754 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
755
756 if (UNLIKELY(g == nullptr)) {
757 continue;
758 }
759 blf_glyph_draw_buffer(buf_info, g, pen_x, pen_y_basis);
760 pen_x += g->advance_x;
761 }
762
763 if (r_info) {
764 r_info->lines = 1;
765 r_info->width = ft_pix_to_int(pen_x);
766 }
767}
768
769void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
770{
772 blf_font_draw_buffer_ex(font, gc, str, str_len, 0, r_info);
774}
775
777
778/* -------------------------------------------------------------------- */
785
787 GlyphCacheBLF *gc,
788 const GlyphBLF *g_prev,
789 GlyphBLF *g,
790 ft_pix *pen_x,
791 const int width_i)
792{
793 if (UNLIKELY(g == nullptr)) {
794 /* Continue the calling loop. */
795 return false;
796 }
797
798 if (!(font->flags & BLF_MONOSPACED)) {
799 *pen_x += blf_kerning(font, g_prev, g);
800
801#ifdef BLF_SUBPIXEL_POSITION
802 if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
803 *pen_x = FT_PIX_ROUND(*pen_x);
804 }
805#else
806 *pen_x = FT_PIX_ROUND(*pen_x);
807#endif
808
809#ifdef BLF_SUBPIXEL_AA
810 g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
811#endif
812 }
813
814 *pen_x += g->advance_x;
815
816 /* When true, break the calling loop. */
817 return (ft_pix_to_int(*pen_x) >= width_i);
818}
819
821 FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
822{
823 GlyphBLF *g;
824 const GlyphBLF *g_prev;
825 ft_pix pen_x;
826 ft_pix width_new;
827 size_t i, i_prev;
828
830 const int width_i = width;
831
832 for (i_prev = i = 0, width_new = pen_x = 0, g_prev = nullptr; (i < str_len) && str[i];
833 i_prev = i, width_new = pen_x, g_prev = g)
834 {
835 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i, nullptr);
836 if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width_i)) {
837 break;
838 }
839 }
840
841 if (r_width) {
842 *r_width = ft_pix_to_int(width_new);
843 }
844
846 return i_prev;
847}
848
850 FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
851{
852 GlyphBLF *g, *g_prev;
853 ft_pix pen_x, width_new;
854 size_t i, i_prev, i_tmp;
855 std::optional<size_t> i_next = {};
856 const char *s, *s_prev;
857
859#ifndef NDEBUG
860 int is_utf8_valid = -1;
861#endif
862
863 i = BLI_strnlen(str, str_len);
865 i = size_t(s - str);
866 s_prev = BLI_str_find_prev_char_utf8(s, str);
867 i_prev = size_t(s_prev - str);
868
869 i_tmp = i;
870 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i_tmp, nullptr);
871 for (width_new = pen_x = 0; (s != nullptr && i > 0);
872 i_next = i, i = i_prev, s = s_prev, g = g_prev, g_prev = nullptr, width_new = pen_x)
873 {
874 s_prev = BLI_str_find_prev_char_utf8(s, str);
875 i_prev = size_t(s_prev - str);
876
877 i_tmp = i_prev;
878 g_prev = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i_tmp, nullptr);
879 BLI_assert(i_tmp == i ||
880 /* TODO: proper handling of non UTF8 strings. */
881 (blf_str_is_utf8_valid_lazy_init(str, str_len, is_utf8_valid) == 0));
882
883 if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width)) {
884 break;
885 }
886 }
887
888 if (r_width) {
889 *r_width = ft_pix_to_int(width_new);
890 }
891
893 return i_next ? *i_next : i;
894}
895
897
898/* -------------------------------------------------------------------- */
901
903 GlyphCacheBLF *gc,
904 const char *str,
905 const size_t str_len,
906 rcti *r_box,
907 ResultBLF *r_info,
908 ft_pix pen_y)
909{
910 const GlyphBLF *g = nullptr;
911 ft_pix pen_x = 0;
912 size_t i = 0;
913
914 ft_pix box_xmin = ft_pix_from_int(32000);
915 ft_pix box_xmax = ft_pix_from_int(-32000);
916 ft_pix box_ymin = ft_pix_from_int(32000);
917 ft_pix box_ymax = ft_pix_from_int(-32000);
918
919 while ((i < str_len) && str[i]) {
920 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
921
922 if (UNLIKELY(g == nullptr)) {
923 continue;
924 }
925 const ft_pix pen_x_next = pen_x + g->advance_x;
926
927 const ft_pix gbox_xmin = std::min(pen_x, pen_x + g->box_xmin);
928 /* Mono-spaced characters should only use advance. See #130385. */
929 const ft_pix gbox_xmax = (font->flags & BLF_MONOSPACED) ?
930 pen_x_next :
931 std::max(pen_x_next, pen_x + g->box_xmax);
932 const ft_pix gbox_ymin = g->box_ymin + pen_y;
933 const ft_pix gbox_ymax = g->box_ymax + pen_y;
934
935 box_xmin = std::min(gbox_xmin, box_xmin);
936 box_ymin = std::min(gbox_ymin, box_ymin);
937
938 box_xmax = std::max(gbox_xmax, box_xmax);
939 box_ymax = std::max(gbox_ymax, box_ymax);
940
941 pen_x = pen_x_next;
942 }
943
944 if (box_xmin > box_xmax) {
945 box_xmin = 0;
946 box_ymin = 0;
947 box_xmax = 0;
948 box_ymax = 0;
949 }
950
951 r_box->xmin = ft_pix_to_int_floor(box_xmin);
952 r_box->xmax = ft_pix_to_int_ceil(box_xmax);
953 r_box->ymin = ft_pix_to_int_floor(box_ymin);
954 r_box->ymax = ft_pix_to_int_ceil(box_ymax);
955
956 if (r_info) {
957 r_info->lines = 1;
958 r_info->width = ft_pix_to_int(pen_x);
959 }
960}
962 FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
963{
965 blf_font_boundbox_ex(font, gc, str, str_len, r_box, r_info, 0);
967}
968
970 const char *str,
971 const size_t str_len,
972 float *r_width,
973 float *r_height,
974 ResultBLF *r_info)
975{
976 float xa, ya;
977 rcti box;
978
979 if (font->flags & BLF_ASPECT) {
980 xa = font->aspect[0];
981 ya = font->aspect[1];
982 }
983 else {
984 xa = 1.0f;
985 ya = 1.0f;
986 }
987
988 if (font->flags & BLF_WORD_WRAP) {
989 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
990 }
991 else {
992 blf_font_boundbox(font, str, str_len, &box, r_info);
993 }
994 *r_width = (float(BLI_rcti_size_x(&box)) * xa);
995 *r_height = (float(BLI_rcti_size_y(&box)) * ya);
996}
997
998float blf_font_width(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
999{
1000 float xa;
1001 rcti box;
1002
1003 if (font->flags & BLF_ASPECT) {
1004 xa = font->aspect[0];
1005 }
1006 else {
1007 xa = 1.0f;
1008 }
1009
1010 if (font->flags & BLF_WORD_WRAP) {
1011 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
1012 }
1013 else {
1014 blf_font_boundbox(font, str, str_len, &box, r_info);
1015 }
1016 return float(BLI_rcti_size_x(&box)) * xa;
1017}
1018
1019float blf_font_height(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
1020{
1021 float ya;
1022 rcti box;
1023
1024 if (font->flags & BLF_ASPECT) {
1025 ya = font->aspect[1];
1026 }
1027 else {
1028 ya = 1.0f;
1029 }
1030
1031 if (font->flags & BLF_WORD_WRAP) {
1032 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
1033 }
1034 else {
1035 blf_font_boundbox(font, str, str_len, &box, r_info);
1036 }
1037 return float(BLI_rcti_size_y(&box)) * ya;
1038}
1039
1041{
1042 const GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1043 float width = (gc) ? float(gc->fixed_width) : font->size / 2.0f;
1045 return width;
1046}
1047
1048int blf_font_glyph_advance(FontBLF *font, const char *str)
1049{
1051 const uint charcode = BLI_str_utf8_as_unicode_safe(str);
1052 const GlyphBLF *g = blf_glyph_ensure(font, gc, charcode);
1053
1054 if (UNLIKELY(g == nullptr)) {
1056 return 0;
1057 }
1058
1059 const int glyph_advance = ft_pix_to_int(g->advance_x);
1060
1062 return glyph_advance;
1063}
1064
1066 const char *str,
1067 const size_t str_len,
1068 BLF_GlyphBoundsFn user_fn,
1069 void *user_data)
1070{
1071 if (str_len == 0 || str[0] == 0) {
1072 /* Early exit. */
1073 return;
1074 }
1075
1076 const GlyphBLF *g = nullptr;
1077 ft_pix pen_x = 0;
1078 size_t i = 0;
1079
1081
1082 while ((i < str_len) && str[i]) {
1083 const size_t i_curr = i;
1084 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
1085
1086 if (UNLIKELY(g == nullptr || g->advance_x == 0)) {
1087 /* Ignore combining characters like diacritical marks. */
1088 continue;
1089 }
1090 rcti bounds;
1095
1096 if (user_fn(str, i_curr, &bounds, user_data) == false) {
1097 break;
1098 }
1099 pen_x += g->advance_x;
1100 }
1101
1103}
1104
1111
1112static bool blf_cursor_position_foreach_glyph(const char * /*str*/,
1113 const size_t str_step_ofs,
1114 const rcti *bounds,
1115 void *user_data)
1116{
1118 user_data);
1119 if (data->location_x < (bounds->xmin + bounds->xmax) / 2) {
1120 data->r_offset = str_step_ofs;
1121 return false;
1122 }
1123 return true;
1124}
1125
1127 const char *str,
1128 size_t str_len,
1129 int location_x)
1130{
1131 /* Do not early exit if location_x <= 0, as this can result in an incorrect
1132 * offset for RTL text. Instead of offset of character responsible for first
1133 * glyph you'd get offset of first character, which could be the last glyph. */
1134 if (!str || !str[0] || !str_len) {
1135 return 0;
1136 }
1137
1139 data.location_x = location_x;
1140 data.r_offset = size_t(-1);
1141
1143
1144 if (data.r_offset == size_t(-1)) {
1145 /* We are to the right of the string, so return position of null terminator. */
1146 data.r_offset = BLI_strnlen(str, str_len);
1147 }
1148 else if (BLI_str_utf8_char_width_or_error(&str[data.r_offset]) == 0) {
1149 /* This is a combining character, so move to previous visible valid char. */
1150 int offset = int(data.r_offset);
1151 BLI_str_cursor_step_prev_utf8(str, int(str_len), &offset);
1152 data.r_offset = size_t(offset);
1153 }
1154
1155 return data.r_offset;
1156}
1157
1162
1163static bool blf_str_offset_foreach_glyph(const char * /*str*/,
1164 const size_t str_step_ofs,
1165 const rcti *bounds,
1166 void *user_data)
1167{
1169 if (data->str_offset == str_step_ofs) {
1170 data->bounds = *bounds;
1171 return false;
1172 }
1173 return true;
1174}
1175
1177 const char *str,
1178 size_t str_offset,
1179 rcti *r_glyph_bounds)
1180{
1182 data.str_offset = str_offset;
1183 data.bounds = {0};
1184
1186 *r_glyph_bounds = data.bounds;
1187}
1188
1190 const char *str,
1191 const size_t str_len,
1192 const size_t str_offset,
1193 const int cursor_width)
1194{
1195 if (!str || !str[0]) {
1196 return 0;
1197 }
1198
1199 /* Right edge of the previous character, if available. */
1200 rcti prev = {0};
1201 if (str_offset > 0) {
1202 blf_str_offset_to_glyph_bounds(font, str, str_offset - 1, &prev);
1203 }
1204
1205 /* Left edge of the next character, if available. */
1206 rcti next = {0};
1207 if (str_offset < strlen(str)) {
1208 blf_str_offset_to_glyph_bounds(font, str, str_offset, &next);
1209 }
1210
1211 if ((prev.xmax == prev.xmin) && next.xmax) {
1212 /* Nothing (or a space) to the left, so align to right character. */
1213 return next.xmin - (cursor_width / 2);
1214 }
1215 if ((prev.xmax != prev.xmin) && !next.xmax) {
1216 /* End of string, so align to last character. */
1217 return prev.xmax - (cursor_width / 2);
1218 }
1219 if (prev.xmax && next.xmax) {
1220 /* Between two characters, so use the center. */
1221 if (next.xmin >= prev.xmax || next.xmin == next.xmax) {
1222 return ((prev.xmax + next.xmin) - cursor_width) / 2;
1223 }
1224 /* A nicer center if reversed order - RTL. */
1225 return ((next.xmax + prev.xmin) - cursor_width) / 2;
1226 }
1227 if (!str_offset) {
1228 /* Start of string. */
1229 return 0 - cursor_width;
1230 }
1231 return int(blf_font_width(font, str, str_len, nullptr));
1232}
1233
1235 FontBLF *font, const char *str, size_t str_len, size_t sel_start, size_t sel_length)
1236{
1238 const int start = blf_str_offset_to_cursor(font, str, str_len, sel_start, 0);
1239 const int end = blf_str_offset_to_cursor(font, str, str_len, sel_start + sel_length, 0);
1240 boxes.append(blender::Bounds(start, end));
1241 return boxes;
1242}
1243
1245
1246/* -------------------------------------------------------------------- */
1249
1260 const char *str,
1261 const size_t str_len,
1262 const int max_pixel_width,
1263 BLFWrapMode mode,
1264 ResultBLF *r_info,
1265 void (*callback)(FontBLF *font,
1266 GlyphCacheBLF *gc,
1267 const char *str,
1268 const size_t str_len,
1269 ft_pix pen_y,
1270 void *userdata),
1271 void *userdata)
1272{
1273 GlyphBLF *g = nullptr;
1274 const GlyphBLF *g_prev = nullptr;
1275 ft_pix pen_x = 0;
1276 ft_pix pen_y = 0;
1277 size_t i = 0;
1278 int lines = 0;
1279 ft_pix pen_x_next = 0;
1280
1281 /* Size of characters not shown at the end of the wrapped line. */
1282 size_t clip_bytes = 0;
1283
1284 ft_pix line_height = blf_font_height_max_ft_pix(font);
1285
1287
1288 struct WordWrapVars {
1289 ft_pix wrap_width;
1290 size_t start, last[2];
1291 } wrap = {max_pixel_width != -1 ? ft_pix_from_int(max_pixel_width) : INT_MAX, 0, {0, 0}};
1292
1293 // printf("%s wrapping (%d, %d) `%s`:\n", __func__, str_len, strlen(str), str);
1294 while ((i < str_len) && str[i]) {
1295
1296 /* Wrap variables. */
1297 const size_t i_curr = i;
1298 bool do_draw = false;
1299
1300 g = blf_glyph_from_utf8_and_step(font, gc, g_prev, str, str_len, &i, &pen_x);
1301
1302 const ft_pix advance_x = g ? g->advance_x : 0;
1303 const uint codepoint = BLI_str_utf8_as_unicode_safe(&str[i_curr]);
1304 const uint codepoint_prev = g_prev ? g_prev->c : 0;
1305
1314 pen_x_next = pen_x + advance_x;
1315
1316 if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) {
1317 do_draw = true;
1318 }
1319 else if (UNLIKELY((int(mode) & int(BLFWrapMode::HardLimit)) &&
1320 (pen_x_next >= wrap.wrap_width) && (advance_x != 0)))
1321 {
1322 wrap.last[0] = i_curr;
1323 wrap.last[1] = i_curr;
1324 do_draw = true;
1325 clip_bytes = 0;
1326 }
1327 else if (UNLIKELY(((i < str_len) && str[i]) == 0)) {
1328 /* Need check here for trailing newline, else we draw it. */
1329 wrap.last[0] = i + ((codepoint != '\n') ? 1 : 0);
1330 wrap.last[1] = i;
1331 do_draw = true;
1332 clip_bytes = 0;
1333 }
1334 else if (UNLIKELY(codepoint == '\n')) {
1335 wrap.last[0] = i_curr + 1;
1336 wrap.last[1] = i;
1337 do_draw = true;
1338 clip_bytes = 1;
1339 }
1340 else if (UNLIKELY(((int(mode) & int(BLFWrapMode::Minimal)) == int(BLFWrapMode::Minimal)) &&
1341 codepoint != ' ' && (g_prev ? g_prev->c == ' ' : false)))
1342 {
1343 wrap.last[0] = i_curr;
1344 wrap.last[1] = i_curr;
1345 clip_bytes = 1;
1346 }
1347 else if (UNLIKELY(int(mode) & int(BLFWrapMode::Path))) {
1348 if (ELEM(codepoint, SEP, ' ', '?', '&', '=')) {
1349 /* Break and leave at the end of line. */
1350 wrap.last[0] = i;
1351 wrap.last[1] = i;
1352 clip_bytes = 0;
1353 }
1354 else if (ELEM(codepoint, '-', '_', '.', '%')) {
1355 /* Break and move to the next line. */
1356 wrap.last[0] = i_curr;
1357 wrap.last[1] = i_curr;
1358 clip_bytes = 0;
1359 }
1360 }
1361 else if (UNLIKELY((int(mode) & int(BLFWrapMode::Typographical)) &&
1363 BLI_str_utf32_char_is_breaking_space(codepoint_prev)))
1364 {
1365 /* Optional break after space, removing it. */
1366 wrap.last[0] = i_curr;
1367 wrap.last[1] = i_curr;
1368 clip_bytes = BLI_str_utf8_from_unicode_len(codepoint_prev);
1369 }
1370 else if (UNLIKELY((int(mode) & int(BLFWrapMode::Typographical)) &&
1371 BLI_str_utf32_char_is_optional_break_after(codepoint, codepoint_prev)))
1372 {
1373 /* Optional break after various characters, keeping it. */
1374 wrap.last[0] = i;
1375 wrap.last[1] = i;
1376 clip_bytes = 0;
1377 }
1378 else if (UNLIKELY((int(mode) & int(BLFWrapMode::Typographical)) &&
1379 BLI_str_utf32_char_is_optional_break_before(codepoint, codepoint_prev)))
1380 {
1381 /* Optional break before various characters. */
1382 wrap.last[0] = i_curr;
1383 wrap.last[1] = i_curr;
1384 clip_bytes = 0;
1385 }
1386
1387 if (UNLIKELY(do_draw)) {
1388#if 0
1389 printf("(%03d..%03d) `%.*s`\n",
1390 wrap.start,
1391 wrap.last[0],
1392 (wrap.last[0] - wrap.start) - 1,
1393 &str[wrap.start]);
1394#endif
1395
1396 callback(
1397 font, gc, &str[wrap.start], (wrap.last[0] - wrap.start) - clip_bytes, pen_y, userdata);
1398 wrap.start = wrap.last[0];
1399 i = wrap.last[1];
1400 pen_x = 0;
1401 pen_y -= line_height;
1402 g_prev = nullptr;
1403 lines += 1;
1404 continue;
1405 }
1406
1407 pen_x = pen_x_next;
1408 g_prev = g;
1409 }
1410
1411 // printf("done! lines: %d, width, %d\n", lines, pen_x_next);
1412
1413 if (r_info) {
1414 r_info->lines = lines;
1415 /* Width of last line only (with wrapped lines). */
1416 r_info->width = ft_pix_to_int(pen_x_next);
1417 }
1418
1420}
1421
1424 GlyphCacheBLF *gc,
1425 const char *str,
1426 const size_t str_len,
1427 ft_pix pen_y,
1428 void * /*userdata*/)
1429{
1430 blf_font_draw_ex(font, gc, str, str_len, nullptr, pen_y);
1431}
1432void blf_font_draw__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
1433{
1435 str,
1436 str_len,
1437 font->wrap_width,
1438 font->wrap_mode,
1439 r_info,
1441 nullptr);
1442}
1443
1446 GlyphCacheBLF *gc,
1447 const char *str,
1448 const size_t str_len,
1449 ft_pix pen_y,
1450 void *userdata)
1451{
1452 rcti *box = static_cast<rcti *>(userdata);
1453 rcti box_single;
1454
1455 blf_font_boundbox_ex(font, gc, str, str_len, &box_single, nullptr, pen_y);
1456 BLI_rcti_union(box, &box_single);
1457}
1459 FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
1460{
1461 r_box->xmin = 32000;
1462 r_box->xmax = -32000;
1463 r_box->ymin = 32000;
1464 r_box->ymax = -32000;
1465
1467 str,
1468 str_len,
1469 font->wrap_width,
1470 font->wrap_mode,
1471 r_info,
1473 r_box);
1474}
1475
1478 GlyphCacheBLF *gc,
1479 const char *str,
1480 const size_t str_len,
1481 const ft_pix pen_y,
1482 void * /*userdata*/)
1483{
1484 blf_font_draw_buffer_ex(font, gc, str, str_len, pen_y, nullptr);
1485}
1487 const char *str,
1488 const size_t str_len,
1489 ResultBLF *r_info)
1490{
1492 str,
1493 str_len,
1494 font->wrap_width,
1495 font->wrap_mode,
1496 r_info,
1498 nullptr);
1499}
1500
1502static void blf_font_string_wrap_cb(FontBLF * /*font*/,
1503 GlyphCacheBLF * /*gc*/,
1504 const char *str,
1505 const size_t str_len,
1506 const ft_pix /*pen_y*/,
1507 void *str_list_ptr)
1508{
1510 str_list_ptr);
1511 blender::StringRef line(str, str + str_len);
1512 list->append(line);
1513}
1514
1517 int max_pixel_width,
1518 BLFWrapMode mode)
1519{
1522 str.data(),
1523 size_t(str.size()),
1524 max_pixel_width,
1525 mode,
1526 nullptr,
1528 &list);
1529 return list;
1530}
1531
1533
1534/* -------------------------------------------------------------------- */
1537
1539{
1540 blf_ensure_size(font);
1541 /* #Metrics::height is rounded to pixel. Force minimum of one pixel. */
1542 return std::max((ft_pix)font->ft_size->metrics.height, ft_pix_from_int(1));
1543}
1544
1546{
1548}
1549
1551{
1552 blf_ensure_size(font);
1553 /* #Metrics::max_advance is rounded to pixel. Force minimum of one pixel. */
1554 return std::max((ft_pix)font->ft_size->metrics.max_advance, ft_pix_from_int(1));
1555}
1556
1558{
1560}
1561
1563{
1564 blf_ensure_size(font);
1565 return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender);
1566}
1567
1569{
1570 blf_ensure_size(font);
1571 return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender);
1572}
1573
1574bool blf_font_bounds_max(FontBLF *font, rctf *r_bounds)
1575{
1576 if (!blf_ensure_face(font)) {
1577 return false;
1578 }
1579
1580 r_bounds->xmin = float(font->face->bbox.xMin) / float(font->face->units_per_EM) * font->size;
1581 r_bounds->xmax = float(font->face->bbox.xMax) / float(font->face->units_per_EM) * font->size;
1582 r_bounds->ymin = float(font->face->bbox.yMin) / float(font->face->units_per_EM) * font->size;
1583 r_bounds->ymax = float(font->face->bbox.yMax) / float(font->face->units_per_EM) * font->size;
1584 return true;
1585}
1586
1588{
1589 if (!blf_ensure_face(font) || !font->face->family_name) {
1590 return nullptr;
1591 }
1592 return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name);
1593}
1594
1596
1597/* -------------------------------------------------------------------- */
1600
1602{
1603 memset(&g_batch, 0, sizeof(g_batch));
1604 int err = FT_Init_FreeType(&ft_lib);
1605 if (err == FT_Err_Ok) {
1606 /* Create a FreeType cache manager. */
1607 err = FTC_Manager_New(ft_lib,
1612 nullptr,
1613 &ftc_manager);
1614 if (err == FT_Err_Ok) {
1615 /* Create a character-map cache to speed up glyph index lookups. */
1616 err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache);
1617 }
1618 }
1619 return err;
1620}
1621
1623{
1624 if (ftc_manager) {
1625 FTC_Manager_Done(ftc_manager);
1626 }
1627 if (ft_lib) {
1628 FT_Done_FreeType(ft_lib);
1629 }
1631}
1632
1633void BLF_cache_flush_set_fn(void (*cache_flush_fn)())
1634{
1635 blf_draw_cache_flush = cache_flush_fn;
1636}
1637
1639
1640/* -------------------------------------------------------------------- */
1643
1644static void blf_font_fill(FontBLF *font)
1645{
1646 font->aspect[0] = 1.0f;
1647 font->aspect[1] = 1.0f;
1648 font->aspect[2] = 1.0f;
1649 font->pos[0] = 0;
1650 font->pos[1] = 0;
1651 font->angle = 0.0f;
1652
1653 /* Use an easily identifiable bright color (yellow)
1654 * so its clear when #BLF_color calls are missing. */
1655 font->color[0] = 255;
1656 font->color[1] = 255;
1657 font->color[2] = 0;
1658 font->color[3] = 255;
1659
1660 font->clip_rec.xmin = 0;
1661 font->clip_rec.xmax = 0;
1662 font->clip_rec.ymin = 0;
1663 font->clip_rec.ymax = 0;
1664 font->flags = BLF_NONE;
1665 font->size = 0;
1666 font->char_weight = 400;
1667 font->char_slant = 0.0f;
1668 font->char_width = 1.0f;
1669 font->char_spacing = 0.0f;
1670
1671 font->kerning_cache = nullptr;
1672 font->tex_size_max = -1;
1673
1674 font->buf_info.fbuf = nullptr;
1675 font->buf_info.cbuf = nullptr;
1676 font->buf_info.dims[0] = 0;
1677 font->buf_info.dims[1] = 0;
1678 font->buf_info.col_init[0] = 0;
1679 font->buf_info.col_init[1] = 0;
1680 font->buf_info.col_init[2] = 0;
1681 font->buf_info.col_init[3] = 0;
1682}
1683
1688static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
1689{
1690 /* Members with non-zero defaults. */
1691 metrics->weight = 400;
1692 metrics->width = 1.0f;
1693
1694 const TT_OS2 *os2_table = (const TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
1695 if (os2_table) {
1696 /* The default (resting) font weight. */
1697 if (os2_table->usWeightClass >= 1 && os2_table->usWeightClass <= 1000) {
1698 metrics->weight = short(os2_table->usWeightClass);
1699 }
1700
1701 /* Width value is one of integers 1-9 with known values. */
1702 if (os2_table->usWidthClass >= 1 && os2_table->usWidthClass <= 9) {
1703 switch (os2_table->usWidthClass) {
1704 case 1:
1705 metrics->width = 0.5f;
1706 break;
1707 case 2:
1708 metrics->width = 0.625f;
1709 break;
1710 case 3:
1711 metrics->width = 0.75f;
1712 break;
1713 case 4:
1714 metrics->width = 0.875f;
1715 break;
1716 case 5:
1717 metrics->width = 1.0f;
1718 break;
1719 case 6:
1720 metrics->width = 1.125f;
1721 break;
1722 case 7:
1723 metrics->width = 1.25f;
1724 break;
1725 case 8:
1726 metrics->width = 1.5f;
1727 break;
1728 case 9:
1729 metrics->width = 2.0f;
1730 break;
1731 }
1732 }
1733
1734 metrics->strikeout_position = short(os2_table->yStrikeoutPosition);
1735 metrics->strikeout_thickness = short(os2_table->yStrikeoutSize);
1736 metrics->subscript_size = short(os2_table->ySubscriptYSize);
1737 metrics->subscript_xoffset = short(os2_table->ySubscriptXOffset);
1738 metrics->subscript_yoffset = short(os2_table->ySubscriptYOffset);
1739 metrics->superscript_size = short(os2_table->ySuperscriptYSize);
1740 metrics->superscript_xoffset = short(os2_table->ySuperscriptXOffset);
1741 metrics->superscript_yoffset = short(os2_table->ySuperscriptYOffset);
1742 metrics->family_class = short(os2_table->sFamilyClass);
1743 metrics->selection_flags = short(os2_table->fsSelection);
1744 metrics->first_charindex = short(os2_table->usFirstCharIndex);
1745 metrics->last_charindex = short(os2_table->usLastCharIndex);
1746 if (os2_table->version > 1) {
1747 metrics->cap_height = short(os2_table->sCapHeight);
1748 metrics->x_height = short(os2_table->sxHeight);
1749 }
1750 }
1751
1752 /* The Post table usually contains a slant value, but in counter-clockwise degrees. */
1753 const TT_Postscript *post_table = (const TT_Postscript *)FT_Get_Sfnt_Table(face, FT_SFNT_POST);
1754 if (post_table) {
1755 if (post_table->italicAngle != 0) {
1756 metrics->slant = float(post_table->italicAngle) / -65536.0f;
1757 }
1758 }
1759
1760 /* Metrics copied from those gathered by FreeType. */
1761 metrics->units_per_EM = short(face->units_per_EM);
1762 metrics->ascender = short(face->ascender);
1763 metrics->descender = short(face->descender);
1764 metrics->line_height = short(face->height);
1765 metrics->max_advance_width = short(face->max_advance_width);
1766 metrics->max_advance_height = short(face->max_advance_height);
1767 metrics->underline_position = short(face->underline_position);
1768 metrics->underline_thickness = short(face->underline_thickness);
1769 metrics->num_glyphs = int(face->num_glyphs);
1770
1771 if (metrics->cap_height == 0) {
1772 /* Calculate or guess cap height if it is not set in the font. */
1773 FT_UInt gi = FT_Get_Char_Index(face, uint('H'));
1774 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1775 metrics->cap_height = short(face->glyph->metrics.height);
1776 }
1777 else {
1778 metrics->cap_height = short(float(metrics->units_per_EM) * 0.7f);
1779 }
1780 }
1781
1782 if (metrics->x_height == 0) {
1783 /* Calculate or guess x-height if it is not set in the font. */
1784 FT_UInt gi = FT_Get_Char_Index(face, uint('x'));
1785 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1786 metrics->x_height = short(face->glyph->metrics.height);
1787 }
1788 else {
1789 metrics->x_height = short(float(metrics->units_per_EM) * 0.5f);
1790 }
1791 }
1792
1793 FT_UInt gi = FT_Get_Char_Index(face, uint('o'));
1794 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1795 metrics->o_proportion = float(face->glyph->metrics.width) / float(face->glyph->metrics.height);
1796 }
1797
1798 if (metrics->ascender == 0) {
1799 /* Set a sane value for ascender if not set in the font. */
1800 metrics->ascender = short(float(metrics->units_per_EM) * 0.8f);
1801 }
1802
1803 if (metrics->descender == 0) {
1804 /* Set a sane value for descender if not set in the font. */
1805 metrics->descender = metrics->ascender - metrics->units_per_EM;
1806 }
1807
1808 if (metrics->weight == 400 && face->style_flags & FT_STYLE_FLAG_BOLD) {
1809 /* Normal weight yet this is an bold font, so set a sane weight value. */
1810 metrics->weight = 700;
1811 }
1812
1813 if (metrics->slant == 0.0f && face->style_flags & FT_STYLE_FLAG_ITALIC) {
1814 /* No slant yet this is an italic font, so set a sane slant value. */
1815 metrics->slant = 8.0f;
1816 }
1817
1818 if (metrics->underline_position == 0) {
1819 metrics->underline_position = short(float(metrics->units_per_EM) * -0.2f);
1820 }
1821
1822 if (metrics->underline_thickness == 0) {
1823 metrics->underline_thickness = short(float(metrics->units_per_EM) * 0.07f);
1824 }
1825
1826 if (metrics->strikeout_position == 0) {
1827 metrics->strikeout_position = short(float(metrics->x_height) * 0.6f);
1828 }
1829
1830 if (metrics->strikeout_thickness == 0) {
1831 metrics->strikeout_thickness = metrics->underline_thickness;
1832 }
1833
1834 if (metrics->subscript_size == 0) {
1835 metrics->subscript_size = short(float(metrics->units_per_EM) * 0.6f);
1836 }
1837
1838 if (metrics->subscript_yoffset == 0) {
1839 metrics->subscript_yoffset = short(float(metrics->units_per_EM) * 0.075f);
1840 }
1841
1842 if (metrics->superscript_size == 0) {
1843 metrics->superscript_size = short(float(metrics->units_per_EM) * 0.6f);
1844 }
1845
1846 if (metrics->superscript_yoffset == 0) {
1847 metrics->superscript_yoffset = short(float(metrics->units_per_EM) * 0.35f);
1848 }
1849
1850 metrics->valid = true;
1851}
1852
1857static bool blf_setup_face(FontBLF *font)
1858{
1859 font->face_flags = font->face->face_flags;
1860
1861 if (FT_HAS_MULTIPLE_MASTERS(font) && !font->variations) {
1862 FT_Get_MM_Var(font->face, &(font->variations));
1863 }
1864
1865 if (!font->metrics.valid) {
1866 blf_font_metrics(font->face, &font->metrics);
1867 font->char_weight = font->metrics.weight;
1868 font->char_slant = font->metrics.slant;
1869 font->char_width = font->metrics.width;
1870 font->char_spacing = font->metrics.spacing;
1871 }
1872
1873 if (FT_IS_FIXED_WIDTH(font)) {
1874 font->flags |= BLF_MONOSPACED;
1875 }
1876
1877 if (FT_HAS_KERNING(font) && !font->kerning_cache) {
1878 /* Create kerning cache table and fill with value indicating "unset". */
1880 for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
1881 for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) {
1883 }
1884 }
1885 }
1886
1887 return true;
1888}
1889
1891{
1892 if (font->face) {
1893 return true;
1894 }
1895
1896 if (font->flags & BLF_BAD_FONT) {
1897 return false;
1898 }
1899
1900 FT_Error err;
1901
1902 if (font->flags & BLF_CACHED) {
1903 err = FTC_Manager_LookupFace(ftc_manager, font, &font->face);
1904 }
1905 else {
1906 std::scoped_lock lock(ft_lib_mutex);
1907 if (font->filepath) {
1908 err = FT_New_Face(font->ft_lib, font->filepath, 0, &font->face);
1909 }
1910 if (font->mem) {
1911 err = FT_New_Memory_Face(font->ft_lib,
1912 static_cast<const FT_Byte *>(font->mem),
1913 (FT_Long)font->mem_size,
1914 0,
1915 &font->face);
1916 }
1917 if (!err) {
1918 font->face->generic.data = font;
1919 }
1920 }
1921
1922 if (err) {
1923 if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) {
1924 printf("Format of this font file is not supported\n");
1925 }
1926 else {
1927 printf("Error encountered while opening font file\n");
1928 }
1929 font->flags |= BLF_BAD_FONT;
1930 return false;
1931 }
1932
1933 if (font->face && !(font->face->face_flags & FT_FACE_FLAG_SCALABLE)) {
1934 printf("Font is not scalable\n");
1935 return false;
1936 }
1937
1938 err = FT_Select_Charmap(font->face, FT_ENCODING_UNICODE);
1939 if (err) {
1940 err = FT_Select_Charmap(font->face, FT_ENCODING_APPLE_ROMAN);
1941 }
1942 if (err && font->face->num_charmaps > 0) {
1943 err = FT_Select_Charmap(font->face, font->face->charmaps[0]->encoding);
1944 }
1945 if (err) {
1946 printf("Can't set a character map!\n");
1947 font->flags |= BLF_BAD_FONT;
1948 return false;
1949 }
1950
1951 if (font->filepath) {
1952 char *mfile = blf_dir_metrics_search(font->filepath);
1953 if (mfile) {
1954 err = FT_Attach_File(font->face, mfile);
1955 if (err) {
1956 fprintf(stderr,
1957 "FT_Attach_File failed to load '%s' with error %d\n",
1958 font->filepath,
1959 int(err));
1960 }
1961 MEM_freeN(mfile);
1962 }
1963 }
1964
1965 if (!(font->flags & BLF_CACHED)) {
1966 /* Not cached so point at the face's size for convenience. */
1967 font->ft_size = font->face->size;
1968 }
1969
1970 /* Setup Font details that require having a Face. */
1971 return blf_setup_face(font);
1972}
1973
1981
1982/* Details about the fallback fonts we ship, so that we can load only when needed. */
1984 {"Noto Sans CJK Regular.woff2",
1985 0,
1986 TT_UCR_CJK_SYMBOLS | TT_UCR_HIRAGANA | TT_UCR_KATAKANA | TT_UCR_BOPOMOFO | TT_UCR_CJK_MISC |
1987 TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS | TT_UCR_CJK_COMPATIBILITY |
1988 TT_UCR_CJK_UNIFIED_IDEOGRAPHS | TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS,
1989 TT_UCR_CJK_COMPATIBILITY_FORMS,
1990 0},
1991 {"NotoEmoji-VariableFont_wght.woff2", 0x80000003L, 0x241E4ACL, 0x14000000L, 0x4000000L},
1992 {"NotoSansArabic-VariableFont_wdth,wght.woff2",
1993 TT_UCR_ARABIC,
1994 uint(TT_UCR_ARABIC_PRESENTATION_FORMS_A),
1995 TT_UCR_ARABIC_PRESENTATION_FORMS_B,
1996 0},
1997 {"NotoSansArmenian-VariableFont_wdth,wght.woff2", TT_UCR_ARMENIAN, 0, 0, 0},
1998 {"NotoSansBengali-VariableFont_wdth,wght.woff2", TT_UCR_BENGALI, 0, 0, 0},
1999 {"NotoSansDevanagari-Regular.woff2", TT_UCR_DEVANAGARI, 0, 0, 0},
2000 {"NotoSansEthiopic-Regular.woff2", 0, 0, TT_UCR_ETHIOPIC, 0},
2001 {"NotoSansGeorgian-VariableFont_wdth,wght.woff2", TT_UCR_GEORGIAN, 0, 0, 0},
2002 {"NotoSansGujarati-Regular.woff2", TT_UCR_GUJARATI, 0, 0, 0},
2003 {"NotoSansGurmukhi-VariableFont_wdth,wght.woff2", TT_UCR_GURMUKHI, 0, 0, 0},
2004 {"NotoSansHebrew-Regular.woff2", TT_UCR_HEBREW, 0, 0, 0},
2005 {"NotoSansJavanese-Regular.woff2", 0x80000003L, 0x2000L, 0, 0},
2006 {"NotoSansKannada-VariableFont_wdth,wght.woff2", TT_UCR_KANNADA, 0, 0, 0},
2007 {"NotoSansKhmer-VariableFont_wdth,wght.woff2", 0, 0, TT_UCR_KHMER, 0},
2008 {"NotoSansMalayalam-VariableFont_wdth,wght.woff2", TT_UCR_MALAYALAM, 0, 0, 0},
2009 {"NotoSansMath-Regular.woff2", 0, TT_UCR_MATHEMATICAL_OPERATORS, 0, 0},
2010 {"NotoSansMyanmar-Regular.woff2", 0, 0, TT_UCR_MYANMAR, 0},
2011 {"NotoSansSymbols-VariableFont_wght.woff2", 0x3L, 0x200E4B4L, 0, 0},
2012 {"NotoSansSymbols2-Regular.woff2", 0x80000003L, 0x200E3E4L, 0x40020L, 0x580A048L},
2013 {"NotoSansTamil-VariableFont_wdth,wght.woff2", TT_UCR_TAMIL, 0, 0, 0},
2014 {"NotoSansTelugu-VariableFont_wdth,wght.woff2", TT_UCR_TELUGU, 0, 0, 0},
2015 {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0},
2016};
2017
2023static FontBLF *blf_font_new_impl(const char *filepath,
2024 const char *mem_name,
2025 const uchar *mem,
2026 const size_t mem_size,
2027 void *ft_library)
2028{
2029 FontBLF *font = MEM_new<FontBLF>(__func__);
2030
2031 font->mem_name = mem_name ? BLI_strdup(mem_name) : nullptr;
2032 font->filepath = filepath ? BLI_strdup(filepath) : nullptr;
2033 if (mem) {
2034 font->mem = (void *)mem;
2035 font->mem_size = mem_size;
2036 }
2037 blf_font_fill(font);
2038
2039 if (ft_library && ((FT_Library)ft_library != ft_lib)) {
2040 /* Pass. */
2041 }
2042 else {
2043 font->flags |= BLF_CACHED;
2044 }
2045
2046 font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib;
2047
2048 /* If we have static details about this font file, we don't have to load the Face yet. */
2049 bool face_needed = true;
2050
2051 if (font->filepath) {
2052 const char *filename = BLI_path_basename(font->filepath);
2053 for (int i = 0; i < int(ARRAY_SIZE(static_face_details)); i++) {
2054 if (BLI_path_cmp(static_face_details[i].filename, filename) == 0) {
2055 const FaceDetails *static_details = &static_face_details[i];
2056 font->unicode_ranges[0] = static_details->coverage1;
2057 font->unicode_ranges[1] = static_details->coverage2;
2058 font->unicode_ranges[2] = static_details->coverage3;
2059 font->unicode_ranges[3] = static_details->coverage4;
2060 face_needed = false;
2061 break;
2062 }
2063 }
2064 }
2065
2066 if (face_needed) {
2067 if (!blf_ensure_face(font)) {
2068 blf_font_free(font);
2069 return nullptr;
2070 }
2071
2072 /* Save TrueType table with bits to quickly test most unicode block coverage. */
2073 const TT_OS2 *os2_table = (const TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
2074 if (os2_table) {
2075 font->unicode_ranges[0] = uint(os2_table->ulUnicodeRange1);
2076 font->unicode_ranges[1] = uint(os2_table->ulUnicodeRange2);
2077 font->unicode_ranges[2] = uint(os2_table->ulUnicodeRange3);
2078 font->unicode_ranges[3] = uint(os2_table->ulUnicodeRange4);
2079 }
2080 }
2081
2082 /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
2083 if (font->unicode_ranges[0] == 0xffffffffU && font->unicode_ranges[1] == 0xffffffffU &&
2084 font->unicode_ranges[2] == 0xffffffffU && font->unicode_ranges[3] >= 0x7FFFFFFU)
2085 {
2086 font->flags |= BLF_LAST_RESORT;
2087 }
2088
2089 return font;
2090}
2091
2093{
2094 return blf_font_new_impl(filepath, nullptr, nullptr, 0, nullptr);
2095}
2096
2097FontBLF *blf_font_new_from_mem(const char *mem_name, const uchar *mem, const size_t mem_size)
2098{
2099 return blf_font_new_impl(nullptr, mem_name, mem, mem_size, nullptr);
2100}
2101
2102void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_size)
2103{
2104 FT_Open_Args open;
2105
2106 open.flags = FT_OPEN_MEMORY;
2107 open.memory_base = (const FT_Byte *)mem;
2108 open.memory_size = (FT_Long)mem_size;
2109 if (blf_ensure_face(font)) {
2110 FT_Attach_Stream(font->face, &open);
2111 }
2112}
2113
2115{
2117
2118 if (font->kerning_cache) {
2119 MEM_freeN(font->kerning_cache);
2120 }
2121
2122 if (font->variations) {
2123 FT_Done_MM_Var(font->ft_lib, font->variations);
2124 }
2125
2126 if (font->face) {
2127 std::scoped_lock lock(ft_lib_mutex);
2128 if (font->flags & BLF_CACHED) {
2129 FTC_Manager_RemoveFaceID(ftc_manager, font);
2130 }
2131 else {
2132 FT_Done_Face(font->face);
2133 }
2134 font->face = nullptr;
2135 }
2136 if (font->filepath) {
2137 MEM_freeN(font->filepath);
2138 }
2139 if (font->mem_name) {
2140 MEM_freeN(font->mem_name);
2141 }
2142
2143 MEM_delete(font);
2144}
2145
2147
2148/* -------------------------------------------------------------------- */
2151
2153{
2154 if (font->ft_size || !(font->flags & BLF_CACHED)) {
2155 return;
2156 }
2157
2158 FTC_ScalerRec scaler = {nullptr};
2159 scaler.face_id = font;
2160 scaler.width = 0;
2161 scaler.height = round_fl_to_uint(font->size * 64.0f);
2162 scaler.pixel = 0;
2163 scaler.x_res = BLF_DPI;
2164 scaler.y_res = BLF_DPI;
2165 if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) == FT_Err_Ok) {
2166 font->ft_size->generic.data = (void *)font;
2167 font->ft_size->generic.finalizer = blf_size_finalizer;
2168 return;
2169 }
2170
2172}
2173
2174bool blf_font_size(FontBLF *font, float size)
2175{
2176 if (!blf_ensure_face(font)) {
2177 return false;
2178 }
2179
2180 /* FreeType uses fixed-point integers in 64ths. */
2181 FT_UInt ft_size = round_fl_to_uint(size * 64.0f);
2182 /* Adjust our new size to be on even 64ths. */
2183 size = float(ft_size) / 64.0f;
2184
2185 if (font->size != size) {
2186 if (font->flags & BLF_CACHED) {
2187 FTC_ScalerRec scaler = {nullptr};
2188 scaler.face_id = font;
2189 scaler.width = 0;
2190 scaler.height = ft_size;
2191 scaler.pixel = 0;
2192 scaler.x_res = BLF_DPI;
2193 scaler.y_res = BLF_DPI;
2194 if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) != FT_Err_Ok) {
2195 return false;
2196 }
2197 font->ft_size->generic.data = (void *)font;
2198 font->ft_size->generic.finalizer = blf_size_finalizer;
2199 }
2200 else {
2201 if (FT_Set_Char_Size(font->face, 0, ft_size, BLF_DPI, BLF_DPI) != FT_Err_Ok) {
2202 return false;
2203 }
2204 font->ft_size = font->face->size;
2205 }
2206 }
2207
2208 font->size = size;
2209 return true;
2210}
2211
bool(*)(const char *str, size_t str_step_ofs, const rcti *bounds, void *user_dataconst) BLF_GlyphBoundsFn
Definition BLF_api.hh:207
BLFWrapMode
Definition BLF_enums.hh:20
@ BLF_RENDER_SUBPIXELAA
Definition BLF_enums.hh:62
@ BLF_ROTATION
Definition BLF_enums.hh:33
@ BLF_NONE
Definition BLF_enums.hh:32
@ BLF_LAST_RESORT
Definition BLF_enums.hh:52
@ BLF_MONOSPACED
Definition BLF_enums.hh:48
@ BLF_CACHED
Definition BLF_enums.hh:56
@ BLF_WORD_WRAP
Definition BLF_enums.hh:39
@ BLF_BAD_FONT
Definition BLF_enums.hh:54
@ BLF_ASPECT
Definition BLF_enums.hh:38
@ BLF_SHADOW
Definition BLF_enums.hh:35
#define BLI_assert_unreachable()
Definition BLI_assert.h:93
#define BLI_assert(a)
Definition BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:53
#define BLI_INLINE
MINLINE unsigned int round_fl_to_uint(float a)
MINLINE int is_power_of_2_i(int n)
MINLINE int bitscan_reverse_i(int a)
MINLINE void rgba_float_to_uchar(unsigned char r_col[4], const float col_f[4])
MINLINE void blend_color_mix_float(float dst[4], const float src1[4], const float src2[4])
MINLINE void blend_color_mix_byte(unsigned char dst[4], const unsigned char src1[4], const unsigned char src2[4])
bool equals_m4m4(const float mat1[4][4], const float mat2[4][4])
void void void const char * BLI_path_basename(const char *path) ATTR_NONNULL(1) ATTR_WARN_UNUSED_RESULT
#define SEP
#define BLI_path_cmp
void BLI_rcti_union(struct rcti *rct_a, const struct rcti *rct_b)
BLI_INLINE int BLI_rcti_size_y(const struct rcti *rct)
Definition BLI_rect.h:198
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:194
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
char * BLI_strdup(const char *str) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC
Definition string.cc:41
int char char int int int int size_t BLI_strnlen(const char *str, size_t maxlen) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
Definition string.cc:913
bool BLI_str_cursor_step_prev_utf8(const char *str, int str_maxlen, int *pos)
bool BLI_str_utf32_char_is_breaking_space(char32_t codepoint)
bool BLI_str_utf32_char_is_optional_break_before(char32_t codepoint, char32_t codepoint_prev)
int BLI_str_utf8_char_width_or_error(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
ptrdiff_t BLI_str_utf8_invalid_byte(const char *str, size_t str_len) ATTR_NONNULL(1)
const char * BLI_str_find_prev_char_utf8(const char *p, const char *str_start) ATTR_WARN_UNUSED_RESULT ATTR_RETURNS_NONNULL ATTR_NONNULL(1
unsigned int BLI_str_utf8_as_unicode_step_safe(const char *__restrict p, size_t p_len, size_t *__restrict index) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1
#define BLI_UTF8_ERR
bool BLI_str_utf32_char_is_optional_break_after(char32_t codepoint, char32_t codepoint_prev)
unsigned int unsigned int size_t BLI_str_utf8_from_unicode_len(unsigned int c) ATTR_WARN_UNUSED_RESULT
int BLI_wcwidth_safe(char32_t ucs) ATTR_WARN_UNUSED_RESULT
unsigned int BLI_str_utf8_as_unicode_safe(const char *p) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
unsigned char uchar
unsigned int uint
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define ELEM(...)
void GPU_batch_draw_advanced(blender::gpu::Batch *batch, int vertex_first, int vertex_count, int instance_first, int instance_count)
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, GPUBuiltinShader shader_id)
#define GPU_batch_texture_bind(batch, name, tex)
Definition GPU_batch.hh:288
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:197
blender::gpu::Batch * GPU_batch_create_procedural(GPUPrimType primitive_type, int32_t vertex_count)
Definition gpu_batch.cc:83
#define GPU_batch_uniform_1i(batch, name, x)
Definition GPU_batch.hh:269
#define GPU_matrix_model_view_get(x)
#define GPU_matrix_set(x)
void GPU_matrix_push()
void GPU_matrix_pop()
@ GPU_PRIM_TRI_STRIP
@ GPU_SHADER_TEXT
@ GPU_BLEND_NONE
Definition GPU_state.hh:85
@ GPU_BLEND_ALPHA
Definition GPU_state.hh:87
void GPU_blend(GPUBlend blend)
Definition gpu_state.cc:42
void GPU_storagebuf_free(blender::gpu::StorageBuf *ssbo)
blender::gpu::StorageBuf * GPU_storagebuf_create_ex(size_t size, const void *data, GPUUsageType usage, const char *name)
void GPU_storagebuf_update(blender::gpu::StorageBuf *ssbo, const void *data)
void GPU_storagebuf_bind(blender::gpu::StorageBuf *ssbo, int slot)
void GPU_storagebuf_usage_size_set(blender::gpu::StorageBuf *ssbo, size_t size)
void GPU_texture_update_sub(blender::gpu::Texture *texture, eGPUDataFormat data_format, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
void GPU_texture_unbind(blender::gpu::Texture *texture)
int GPU_texture_width(const blender::gpu::Texture *texture)
@ GPU_DATA_UBYTE
@ GPU_USAGE_STREAM
Read Guarded memory(de)allocation.
volatile int lock
char * blf_dir_metrics_search(const char *filepath)
Definition blf_dir.cc:26
static ft_pix blf_font_width_max_ft_pix(FontBLF *font)
Definition blf_font.cc:1550
static void blf_font_string_wrap_cb(FontBLF *, GlyphCacheBLF *, const char *str, const size_t str_len, const ft_pix, void *str_list_ptr)
Definition blf_font.cc:1502
size_t blf_str_offset_from_cursor_position(FontBLF *font, const char *str, size_t str_len, int location_x)
Definition blf_font.cc:1126
static const FaceDetails static_face_details[]
Definition blf_font.cc:1983
void blf_str_offset_to_glyph_bounds(FontBLF *font, const char *str, size_t str_offset, rcti *r_glyph_bounds)
Definition blf_font.cc:1176
BatchBLF g_batch
Definition blf_font.cc:59
size_t blf_font_width_to_rstrlen(FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
Definition blf_font.cc:849
static void blf_font_draw_buffer__wrap_cb(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, const ft_pix pen_y, void *)
Definition blf_font.cc:1477
static void blf_font_fill(FontBLF *font)
Definition blf_font.cc:1644
int blf_font_ascender(FontBLF *font)
Definition blf_font.cc:1568
static void(* blf_draw_cache_flush)()
Definition blf_font.cc:70
blender::Vector< blender::StringRef > blf_font_string_wrap(FontBLF *font, blender::StringRef str, int max_pixel_width, BLFWrapMode mode)
Definition blf_font.cc:1515
static bool blf_str_offset_foreach_glyph(const char *, const size_t str_step_ofs, const rcti *bounds, void *user_data)
Definition blf_font.cc:1163
int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, const int cwidth, const int tab_columns)
Definition blf_font.cc:494
float blf_font_width(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:998
bool blf_ensure_face(FontBLF *font)
Definition blf_font.cc:1890
static FTC_Manager ftc_manager
Definition blf_font.cc:63
static FTC_CMapCache ftc_charmap_cache
Definition blf_font.cc:64
static ft_pix blf_font_height_max_ft_pix(FontBLF *font)
Definition blf_font.cc:1538
static void blf_batch_draw_end()
Definition blf_font.cc:339
static void blf_font_draw__wrap_cb(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, ft_pix pen_y, void *)
Definition blf_font.cc:1423
void blf_ensure_size(FontBLF *font)
Definition blf_font.cc:2152
static void blf_font_boundbox_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info, ft_pix pen_y)
Definition blf_font.cc:902
static void blf_glyph_draw_buffer(FontBufInfoBLF *buf_info, GlyphBLF *g, const ft_pix pen_x, const ft_pix pen_y_basis)
Definition blf_font.cc:628
void BLF_batch_discard()
Definition blf_font.cc:346
bool blf_font_bounds_max(FontBLF *font, rctf *r_bounds)
Definition blf_font.cc:1574
void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:769
static void blf_font_wrap_apply(FontBLF *font, const char *str, const size_t str_len, const int max_pixel_width, BLFWrapMode mode, ResultBLF *r_info, void(*callback)(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, ft_pix pen_y, void *userdata), void *userdata)
Definition blf_font.cc:1259
void BLF_cache_flush_set_fn(void(*cache_flush_fn)())
Definition blf_font.cc:1633
static void blf_batch_draw_exit()
Definition blf_font.cc:197
void blf_font_free(FontBLF *font)
Definition blf_font.cc:2114
void blf_font_boundbox_foreach_glyph(FontBLF *font, const char *str, const size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data)
Definition blf_font.cc:1065
static FT_Library ft_lib
Definition blf_font.cc:62
bool blf_font_size(FontBLF *font, float size)
Definition blf_font.cc:2174
float blf_font_fixed_width(FontBLF *font)
Definition blf_font.cc:1040
static void blf_face_finalizer(void *object)
Definition blf_font.cc:85
static void blf_font_boundbox_wrap_cb(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, ft_pix pen_y, void *userdata)
Definition blf_font.cc:1445
static FT_Error blf_cache_face_requester(FTC_FaceID faceID, FT_Library lib, FT_Pointer, FT_Face *face)
Definition blf_font.cc:97
float blf_font_height(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1019
uint blf_get_char_index(FontBLF *font, const uint charcode)
Definition blf_font.cc:148
static bool blf_font_width_to_strlen_glyph_process(FontBLF *font, GlyphCacheBLF *gc, const GlyphBLF *g_prev, GlyphBLF *g, ft_pix *pen_x, const int width_i)
Definition blf_font.cc:786
int blf_font_init()
Definition blf_font.cc:1601
static void blf_font_draw_buffer_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, const ft_pix pen_y, ResultBLF *r_info)
Definition blf_font.cc:736
BLI_INLINE GlyphBLF * blf_glyph_from_utf8_and_step(FontBLF *font, GlyphCacheBLF *gc, const GlyphBLF *g_prev, const char *str, const size_t str_len, size_t *i_p, int32_t *pen_x)
Definition blf_font.cc:396
int blf_font_width_max(FontBLF *font)
Definition blf_font.cc:1557
blender::Array< uchar > blf_svg_icon_bitmap(FontBLF *font, const uint icon_id, const float size, int *r_width, int *r_height, const bool multicolor, blender::FunctionRef< void(std::string &)> edit_source_cb)
Definition blf_font.cc:577
void blf_draw_svg_icon(FontBLF *font, const uint icon_id, const float x, const float y, const float size, const float color[4], const float outline_alpha, const bool multicolor, blender::FunctionRef< void(std::string &)> edit_source_cb)
Definition blf_font.cc:530
static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, const FT_Pos value)
Definition blf_font.cc:159
void blf_batch_draw()
Definition blf_font.cc:305
void blf_batch_draw_begin(FontBLF *font)
Definition blf_font.cc:205
static void blf_size_finalizer(void *object)
Definition blf_font.cc:135
void blf_font_boundbox__wrap(FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
Definition blf_font.cc:1458
void blf_font_exit()
Definition blf_font.cc:1622
static bool blf_cursor_position_foreach_glyph(const char *, const size_t str_step_ofs, const rcti *bounds, void *user_data)
Definition blf_font.cc:1112
static blender::gpu::Texture * blf_batch_cache_texture_load()
Definition blf_font.cc:265
void blf_font_boundbox(FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
Definition blf_font.cc:961
int blf_font_glyph_advance(FontBLF *font, const char *str)
Definition blf_font.cc:1048
char * blf_display_name(FontBLF *font)
Definition blf_font.cc:1587
FontBLF * blf_font_new_from_mem(const char *mem_name, const uchar *mem, const size_t mem_size)
Definition blf_font.cc:2097
int blf_str_offset_to_cursor(FontBLF *font, const char *str, const size_t str_len, const size_t str_offset, const int cursor_width)
Definition blf_font.cc:1189
static bool blf_setup_face(FontBLF *font)
Definition blf_font.cc:1857
void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_size)
Definition blf_font.cc:2102
static void blf_batch_draw_init()
Definition blf_font.cc:188
BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
Definition blf_font.cc:361
size_t blf_font_width_to_strlen(FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
Definition blf_font.cc:820
int blf_font_descender(FontBLF *font)
Definition blf_font.cc:1562
void blf_font_width_and_height(FontBLF *font, const char *str, const size_t str_len, float *r_width, float *r_height, ResultBLF *r_info)
Definition blf_font.cc:969
void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:487
static blender::Mutex ft_lib_mutex
Definition blf_font.cc:67
static void blf_font_draw_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, ResultBLF *r_info, const ft_pix pen_y)
Definition blf_font.cc:452
FontBLF * blf_font_new_from_filepath(const char *filepath)
Definition blf_font.cc:2092
void blf_font_draw_buffer__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1486
static int blf_str_is_utf8_valid_lazy_init(const char *str, const size_t str_len, int &is_utf8_valid)
Definition blf_font.cc:436
int blf_font_height_max(FontBLF *font)
Definition blf_font.cc:1545
blender::Vector< blender::Bounds< int > > blf_str_selection_boxes(FontBLF *font, const char *str, size_t str_len, size_t sel_start, size_t sel_length)
Definition blf_font.cc:1234
static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
Definition blf_font.cc:1688
static FontBLF * blf_font_new_impl(const char *filepath, const char *mem_name, const uchar *mem, const size_t mem_size, void *ft_library)
Definition blf_font.cc:2023
void blf_font_draw__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1432
void blf_glyph_cache_clear(FontBLF *font)
Definition blf_glyph.cc:162
GlyphCacheBLF * blf_glyph_cache_acquire(FontBLF *font)
Definition blf_glyph.cc:133
void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, const int y)
GlyphBLF * blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int32_t pen_x)
void blf_glyph_cache_release(FontBLF *font)
Definition blf_glyph.cc:146
GlyphBLF * blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode, uint8_t subpixel)
GlyphBLF * blf_glyph_ensure_icon(GlyphCacheBLF *gc, const uint icon_id, bool color, blender::FunctionRef< void(std::string &)> edit_source_cb)
#define BLF_CACHE_BYTES
#define BLF_CACHE_MAX_FACES
#define BLF_CACHE_MAX_SIZES
#define BLF_DPI
ft_pix ft_pix_from_int(int v)
#define FT_PIX_ROUND(x)
int32_t ft_pix
#define KERNING_CACHE_TABLE_SIZE
int ft_pix_to_int_floor(ft_pix v)
int ft_pix_to_int_ceil(ft_pix v)
#define KERNING_ENTRY_UNSET
int ft_pix_to_int(ft_pix v)
BMesh const char void * data
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
btMatrix3x3 scaled(const btVector3 &s) const
Create a scaled copy of the matrix.
int64_t size() const
Definition BLI_array.hh:256
const T * data() const
Definition BLI_array.hh:312
void append(const T &value)
nullptr float
#define str(s)
uint col
#define printf(...)
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
MINLINE unsigned char unit_float_to_uchar_clamp(float val)
MINLINE void zero_v2_int(int r[2])
static ulong * next
std::mutex Mutex
Definition BLI_mutex.hh:47
float wrap(float value, float max, float min)
Definition node_math.h:103
char filename[50]
Definition blf_font.cc:1975
KerningCacheBLF * kerning_cache
uint unicode_ranges[4]
unsigned char color[4]
FontFlags flags
FT_MM_Var * variations
FontMetrics metrics
BLFWrapMode wrap_mode
FT_Library ft_lib
FontBufInfoBLF buf_info
FontShadowType shadow
unsigned char shadow_color[4]
unsigned char col_char[4]
unsigned char * cbuf
unsigned char * bitmap
unsigned int c
blender::gpu::Texture * texture
int ascii_table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE]
int lines
Definition BLF_api.hh:453
int width
Definition BLF_api.hh:457
float xmax
float xmin
float ymax
float ymin
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230
static DynamicLibrary lib