Blender V4.3
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
13#include <cmath>
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_listbase.h"
32#include "BLI_math_bits.h"
34#include "BLI_math_matrix.h"
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_threads.h"
41#include "BLI_vector.hh"
42
43#include "BLF_api.hh"
44
45#include "GPU_batch.hh"
46#include "GPU_matrix.hh"
47
48#include "blf_internal.hh"
49#include "blf_internal_types.hh"
50
51#include "BLI_strict_flags.h" /* 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
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
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 }
114
115 if (err == FT_Err_Ok) {
116 font->face = *face;
117 font->face->generic.data = font;
118 font->face->generic.finalizer = blf_face_finalizer;
119
120 /* More FontBLF setup now that we have a face. */
121 if (!blf_setup_face(font)) {
122 err = FT_Err_Cannot_Open_Resource;
123 }
124 }
125 else {
126 /* Clear this on error to avoid exception in FTC_Manager_LookupFace. */
127 *face = nullptr;
128 }
129
130 return err;
131}
132
136static void blf_size_finalizer(void *object)
137{
138 FT_Size size = static_cast<FT_Size>(object);
139 FontBLF *font = (FontBLF *)size->generic.data;
140 font->ft_size = nullptr;
141}
142
145/* -------------------------------------------------------------------- */
150{
151 if (font->flags & BLF_CACHED) {
152 /* Use char-map cache for much faster lookup. */
153 return FTC_CMapCache_Lookup(ftc_charmap_cache, font, -1, charcode);
154 }
155 /* Fonts that are not cached need to use the regular lookup function. */
156 return blf_ensure_face(font) ? FT_Get_Char_Index(font->face, charcode) : 0;
157}
158
159/* Convert a FreeType 26.6 value representing an unscaled design size to fractional pixels. */
161{
162 /* Make sure we have a valid font->ft_size. */
163 blf_ensure_size(font);
164
165 /* Scale value by font size using integer-optimized multiplication. */
166 FT_Long scaled = FT_MulFix(value, font->ft_size->metrics.x_scale);
167
168 /* Copied from FreeType's FT_Get_Kerning (with FT_KERNING_DEFAULT), scaling down. */
169 /* Kerning distances at small PPEM values so that they don't become too big. */
170 if (font->ft_size->metrics.x_ppem < 25) {
171 scaled = FT_MulDiv(scaled, font->ft_size->metrics.x_ppem, 25);
172 }
173
174 return (ft_pix)scaled;
175}
176
179/* -------------------------------------------------------------------- */
190{
191 GPUVertFormat format = {0};
197 &format, "glyph_size", GPU_COMP_I32, 2, GPU_FETCH_INT);
199 &format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
200
203
209 g_batch.glyph_len = 0;
210
211 /* A dummy VBO containing 4 points, attributes are not used. */
213 GPU_vertbuf_data_alloc(*vbo, 4);
214
215 /* We render a quad as a triangle strip and instance it for each glyph. */
218}
219
224
226{
227 if (g_batch.batch == nullptr) {
229 }
230
231 const bool font_changed = (g_batch.font != font);
232 const bool simple_shader = ((font->flags & (BLF_ROTATION | BLF_ASPECT)) == 0);
233 const bool shader_changed = (simple_shader != g_batch.simple_shader);
234
235 g_batch.active = g_batch.enabled && simple_shader;
236
237 if (simple_shader) {
238 /* Offset is applied to each glyph. */
239 g_batch.ofs[0] = font->pos[0];
240 g_batch.ofs[1] = font->pos[1];
241 }
242 else {
243 /* Offset is baked in model-view matrix. */
245 }
246
247 if (g_batch.active) {
248 float gpumat[4][4];
250
251 bool mat_changed = equals_m4m4(gpumat, g_batch.mat) == false;
252
253 if (mat_changed) {
254 /* Model view matrix is no longer the same.
255 * Flush cache but with the previous matrix. */
258 }
259
260 /* Flush cache if configuration is not the same. */
261 if (mat_changed || font_changed || shader_changed) {
263 g_batch.simple_shader = simple_shader;
264 g_batch.font = font;
265 }
266 else {
267 /* Nothing changed continue batching. */
268 return;
269 }
270
271 if (mat_changed) {
273 /* Save for next `memcmp`. */
274 memcpy(g_batch.mat, gpumat, sizeof(g_batch.mat));
275 }
276 }
277 else {
278 /* Flush cache. */
280 g_batch.font = font;
281 g_batch.simple_shader = simple_shader;
282 }
283}
284
286{
288 BLI_assert(gc);
289 BLI_assert(gc->bitmap_len > 0);
290
291 if (gc->bitmap_len > gc->bitmap_len_landed) {
292 const int tex_width = GPU_texture_width(gc->texture);
293
294 int bitmap_len_landed = gc->bitmap_len_landed;
295 int remain = gc->bitmap_len - bitmap_len_landed;
296 int offset_x = bitmap_len_landed % tex_width;
297 int offset_y = bitmap_len_landed / tex_width;
298
299 /* TODO(@germano): Update more than one row in a single call. */
300 while (remain) {
301 int remain_row = tex_width - offset_x;
302 int width = remain > remain_row ? remain_row : remain;
305 &gc->bitmap_result[bitmap_len_landed],
306 offset_x,
307 offset_y,
308 0,
309 width,
310 1,
311 0);
312
313 bitmap_len_landed += width;
314 remain -= width;
315 offset_x = 0;
316 offset_y += 1;
317 }
318
319 gc->bitmap_len_landed = bitmap_len_landed;
320 }
321
322 return gc->texture;
323}
324
326{
327 if (g_batch.glyph_len == 0) {
328 return;
329 }
330
332
333 /* We need to flush widget base first to ensure correct ordering. */
334 if (blf_draw_cache_flush != nullptr) {
336 }
337
338 GPUTexture *texture = blf_batch_cache_texture_load();
340 GPU_vertbuf_use(g_batch.verts); /* Send data. */
341
343 GPU_batch_texture_bind(g_batch.batch, "glyph", texture);
344 /* Setup texture width mask and shift, so that shader can avoid costly divisions. */
345 int tex_width = GPU_texture_width(texture);
346 BLI_assert_msg(is_power_of_2_i(tex_width), "Font texture width must be power of two");
347 int width_shift = 31 - bitscan_reverse_i(tex_width);
348 GPU_batch_uniform_1i(g_batch.batch, "glyph_tex_width_mask", tex_width - 1);
349 GPU_batch_uniform_1i(g_batch.batch, "glyph_tex_width_shift", width_shift);
351
353
354 GPU_texture_unbind(texture);
355
356 /* Restart to 1st vertex data pointers. */
362 g_batch.glyph_len = 0;
363}
364
366{
367 if (!g_batch.active) {
369 }
370}
371
374/* -------------------------------------------------------------------- */
378BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
379{
380 ft_pix adjustment = 0;
381
382 /* Small adjust if there is hinting. */
383 adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0);
384
385 if (FT_HAS_KERNING(font) && g_prev) {
386 FT_Vector delta = {KERNING_ENTRY_UNSET};
387
388 /* Get unscaled kerning value from our cache if ASCII. */
389 if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
390 delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
391 }
392
393 /* If not ASCII or not found in cache, ask FreeType for kerning. */
394 if (UNLIKELY(font->face && delta.x == KERNING_ENTRY_UNSET)) {
395 /* Note that this function sets delta values to zero on any error. */
396 FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
397 }
398
399 /* If ASCII we save this value to our cache for quicker access next time. */
400 if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
401 font->kerning_cache->ascii_table[g->c][g_prev->c] = int(delta.x);
402 }
403
404 if (delta.x != 0) {
405 /* Convert unscaled design units to pixels and move pen. */
406 adjustment += blf_unscaled_F26Dot6_to_pixels(font, delta.x);
407 }
408 }
409
410 return adjustment;
411}
412
414 GlyphCacheBLF *gc,
415 const GlyphBLF *g_prev,
416 const char *str,
417 size_t str_len,
418 size_t *i_p,
419 int32_t *pen_x)
420{
421 uint charcode = BLI_str_utf8_as_unicode_step_safe(str, str_len, i_p);
422 /* Invalid unicode sequences return the byte value, stepping forward one.
423 * This allows `latin1` to display (which is sometimes used for file-paths). */
424 BLI_assert(charcode != BLI_UTF8_ERR);
425 GlyphBLF *g = blf_glyph_ensure(font, gc, charcode);
426 if (g && pen_x && !(font->flags & BLF_MONOSPACED)) {
427 *pen_x += blf_kerning(font, g_prev, g);
428
429#ifdef BLF_SUBPIXEL_POSITION
430 if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
431 *pen_x = FT_PIX_ROUND(*pen_x);
432 }
433#else
434 *pen_x = FT_PIX_ROUND(*pen_x);
435#endif
436
437#ifdef BLF_SUBPIXEL_AA
438 g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
439#endif
440 }
441 return g;
442}
443
446/* -------------------------------------------------------------------- */
450static void blf_font_draw_ex(FontBLF *font,
451 GlyphCacheBLF *gc,
452 const char *str,
453 const size_t str_len,
454 ResultBLF *r_info,
455 const ft_pix pen_y)
456{
457 if (str_len == 0) {
458 /* Early exit, don't do any immediate-mode GPU operations. */
459 return;
460 }
461
462 GlyphBLF *g = nullptr;
463 ft_pix pen_x = 0;
464 size_t i = 0;
465
467
468 while ((i < str_len) && str[i]) {
469 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
470 if (UNLIKELY(g == nullptr)) {
471 continue;
472 }
473 /* Do not return this loop if clipped, we want every character tested. */
474 blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
475 pen_x += g->advance_x;
476 }
477
479
480 if (r_info) {
481 r_info->lines = 1;
482 r_info->width = ft_pix_to_int(pen_x);
483 }
484}
485void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
486{
488 blf_font_draw_ex(font, gc, str, str_len, r_info, 0);
490}
491
493 FontBLF *font, const char *str, const size_t str_len, int cwidth, int tab_columns)
494{
495 GlyphBLF *g;
496 int columns = 0;
497 ft_pix pen_x = 0, pen_y = 0;
498 ft_pix cwidth_fpx = ft_pix_from_int(cwidth);
499
500 size_t i = 0;
501
503
505
506 while ((i < str_len) && str[i]) {
507 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i, nullptr);
508
509 if (UNLIKELY(g == nullptr)) {
510 continue;
511 }
512 /* Do not return this loop if clipped, we want every character tested. */
513 blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
514
515 const int col = UNLIKELY(g->c == '\t') ? (tab_columns - (columns % tab_columns)) :
516 BLI_wcwidth_safe(char32_t(g->c));
517 columns += col;
518 pen_x += cwidth_fpx * col;
519 }
520
522
524 return columns;
525}
526
527#ifndef WITH_HEADLESS
529 uint icon_id,
530 float x,
531 float y,
532 float size,
533 const float color[4],
534 float outline_alpha,
535 bool multicolor,
536 blender::FunctionRef<void(std::string &)> edit_source_cb)
537{
538 blf_font_size(font, size);
539 font->pos[0] = int(x);
540 font->pos[1] = int(y);
541 font->pos[2] = 0;
542
543 if (color != nullptr) {
544 rgba_float_to_uchar(font->color, color);
545 }
546
547 if (outline_alpha > 0.0f) {
548 font->flags |= BLF_SHADOW;
549 font->shadow = FontShadowType::Outline;
550 font->shadow_x = 0;
551 font->shadow_y = 0;
552 font->shadow_color[0] = 0;
553 font->shadow_color[1] = 0;
554 font->shadow_color[2] = 0;
555 font->shadow_color[3] = char(outline_alpha * 255.0f);
556 }
557
560
561 GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor, edit_source_cb);
562 if (g) {
563 blf_glyph_draw(font, gc, g, 0, 0);
564 }
565
566 if (outline_alpha > 0) {
567 font->flags &= ~BLF_SHADOW;
568 }
569
572}
573
575 uint icon_id,
576 float size,
577 int *r_width,
578 int *r_height,
579 bool multicolor,
580 blender::FunctionRef<void(std::string &)> edit_source_cb)
581{
582 blf_font_size(font, size);
584 GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor, edit_source_cb);
585
586 if (!g) {
588 *r_width = 0;
589 *r_height = 0;
590 return {};
591 }
592
593 *r_width = g->dims[0];
594 *r_height = g->dims[1];
595 blender::Array<uchar> bitmap(g->dims[0] * g->dims[1] * 4);
596
597 if (g->num_channels == 4) {
598 memcpy(bitmap.data(), g->bitmap, size_t(bitmap.size()));
599 }
600 else if (g->num_channels == 1) {
601 for (int64_t y = 0; y < int64_t(g->dims[1]); y++) {
602 for (int64_t x = 0; x < int64_t(g->dims[0]); x++) {
603 int64_t offs_in = (y * int64_t(g->pitch)) + x;
604 bitmap[int64_t(offs_in * 4)] = g->bitmap[offs_in];
605 bitmap[int64_t(offs_in * 4 + 1)] = g->bitmap[offs_in];
606 bitmap[int64_t(offs_in * 4 + 2)] = g->bitmap[offs_in];
607 bitmap[int64_t(offs_in * 4 + 3)] = g->bitmap[offs_in];
608 }
609 }
610 }
612 return bitmap;
613}
614#endif /* WITH_HEADLESS */
615
618/* -------------------------------------------------------------------- */
626 GlyphBLF *g,
627 const ft_pix pen_x,
628 const ft_pix pen_y_basis)
629{
630 const int chx = ft_pix_to_int(pen_x + ft_pix_from_int(g->pos[0]));
631 const int chy = ft_pix_to_int(pen_y_basis + ft_pix_from_int(g->dims[1]));
632
633 ft_pix pen_y = (g->pitch < 0) ? (pen_y_basis + ft_pix_from_int(g->dims[1] - g->pos[1])) :
634 (pen_y_basis - ft_pix_from_int(g->dims[1] - g->pos[1]));
635
636 if ((chx + g->dims[0]) < 0 || /* Out of bounds: left. */
637 chx >= buf_info->dims[0] || /* Out of bounds: right. */
638 (ft_pix_to_int(pen_y) + g->dims[1]) < 0 || /* Out of bounds: bottom. */
639 ft_pix_to_int(pen_y) >= buf_info->dims[1] /* Out of bounds: top. */
640 )
641 {
642 return;
643 }
644
645 /* Don't draw beyond the buffer bounds. */
646 int width_clip = g->dims[0];
647 int height_clip = g->dims[1];
648 int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
649
650 if (width_clip + chx > buf_info->dims[0]) {
651 width_clip -= chx + width_clip - buf_info->dims[0];
652 }
653 if (height_clip + ft_pix_to_int(pen_y) > buf_info->dims[1]) {
654 height_clip -= ft_pix_to_int(pen_y) + height_clip - buf_info->dims[1];
655 }
656
657 /* Clip drawing below the image. */
658 if (pen_y < 0) {
659 yb_start += (g->pitch < 0) ? -ft_pix_to_int(pen_y) : ft_pix_to_int(pen_y);
660 height_clip += ft_pix_to_int(pen_y);
661 pen_y = 0;
662 }
663
664 /* Avoid conversions in the pixel writing loop. */
665 const int pen_y_px = ft_pix_to_int(pen_y);
666
667 const float *b_col_float = buf_info->col_float;
668 const uchar *b_col_char = buf_info->col_char;
669
670 if (buf_info->fbuf) {
671 int yb = yb_start;
672 for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
673 const int x_start = (chx >= 0) ? 0 : -chx;
674 const uchar *a_ptr = g->bitmap + x_start + (yb * g->pitch);
675 const int64_t buf_ofs = (int64_t(buf_info->dims[0]) * (pen_y_px + y) + (chx + x_start)) * 4;
676 float *fbuf = buf_info->fbuf + buf_ofs;
677 for (int x = x_start; x < width_clip; x++, a_ptr++, fbuf += 4) {
678 const char a_byte = *a_ptr;
679 if (a_byte) {
680 const float a = (a_byte / 255.0f) * b_col_float[3];
681
682 float font_pixel[4];
683 font_pixel[0] = b_col_float[0] * a;
684 font_pixel[1] = b_col_float[1] * a;
685 font_pixel[2] = b_col_float[2] * a;
686 font_pixel[3] = a;
687 blend_color_mix_float(fbuf, fbuf, font_pixel);
688 }
689 }
690
691 if (g->pitch < 0) {
692 yb++;
693 }
694 else {
695 yb--;
696 }
697 }
698 }
699
700 if (buf_info->cbuf) {
701 int yb = yb_start;
702 for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
703 const int x_start = (chx >= 0) ? 0 : -chx;
704 const uchar *a_ptr = g->bitmap + x_start + (yb * g->pitch);
705 const int64_t buf_ofs = (int64_t(buf_info->dims[0]) * (pen_y_px + y) + (chx + x_start)) * 4;
706 uchar *cbuf = buf_info->cbuf + buf_ofs;
707 for (int x = x_start; x < width_clip; x++, a_ptr++, cbuf += 4) {
708 const char a_byte = *a_ptr;
709
710 if (a_byte) {
711 const float a = (a_byte / 255.0f) * b_col_float[3];
712
713 uchar font_pixel[4];
714 font_pixel[0] = b_col_char[0];
715 font_pixel[1] = b_col_char[1];
716 font_pixel[2] = b_col_char[2];
717 font_pixel[3] = unit_float_to_uchar_clamp(a);
718 blend_color_mix_byte(cbuf, cbuf, font_pixel);
719 }
720 }
721
722 if (g->pitch < 0) {
723 yb++;
724 }
725 else {
726 yb--;
727 }
728 }
729 }
730}
731
732/* Sanity checks are done by BLF_draw_buffer() */
734 GlyphCacheBLF *gc,
735 const char *str,
736 const size_t str_len,
737 ResultBLF *r_info,
738 ft_pix pen_y)
739{
740 GlyphBLF *g = nullptr;
741 ft_pix pen_x = ft_pix_from_int(font->pos[0]);
742 ft_pix pen_y_basis = ft_pix_from_int(font->pos[1]) + pen_y;
743 size_t i = 0;
744
745 /* Buffer specific variables. */
746 FontBufInfoBLF *buf_info = &font->buf_info;
747
748 /* Another buffer specific call for color conversion. */
749
750 while ((i < str_len) && str[i]) {
751 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
752
753 if (UNLIKELY(g == nullptr)) {
754 continue;
755 }
756 blf_glyph_draw_buffer(buf_info, g, pen_x, pen_y_basis);
757 pen_x += g->advance_x;
758 }
759
760 if (r_info) {
761 r_info->lines = 1;
762 r_info->width = ft_pix_to_int(pen_x);
763 }
764}
765
766void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
767{
769 blf_font_draw_buffer_ex(font, gc, str, str_len, r_info, 0);
771}
772
775/* -------------------------------------------------------------------- */
784 GlyphCacheBLF *gc,
785 const GlyphBLF *g_prev,
786 GlyphBLF *g,
787 ft_pix *pen_x,
788 const int width_i)
789{
790 if (UNLIKELY(g == nullptr)) {
791 /* Continue the calling loop. */
792 return false;
793 }
794
795 if (!(font->flags & BLF_MONOSPACED)) {
796 *pen_x += blf_kerning(font, g_prev, g);
797
798#ifdef BLF_SUBPIXEL_POSITION
799 if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
800 *pen_x = FT_PIX_ROUND(*pen_x);
801 }
802#else
803 *pen_x = FT_PIX_ROUND(*pen_x);
804#endif
805
806#ifdef BLF_SUBPIXEL_AA
807 g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
808#endif
809 }
810
811 *pen_x += g->advance_x;
812
813 /* When true, break the calling loop. */
814 return (ft_pix_to_int(*pen_x) >= width_i);
815}
816
818 FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
819{
820 GlyphBLF *g;
821 const GlyphBLF *g_prev;
822 ft_pix pen_x;
823 ft_pix width_new;
824 size_t i, i_prev;
825
827 const int width_i = int(width);
828
829 for (i_prev = i = 0, width_new = pen_x = 0, g_prev = nullptr; (i < str_len) && str[i];
830 i_prev = i, width_new = pen_x, g_prev = g)
831 {
832 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i, nullptr);
833 if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width_i)) {
834 break;
835 }
836 }
837
838 if (r_width) {
839 *r_width = ft_pix_to_int(width_new);
840 }
841
843 return i_prev;
844}
845
847 FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
848{
849 GlyphBLF *g, *g_prev;
850 ft_pix pen_x, width_new;
851 size_t i, i_prev, i_tmp;
852 const char *s, *s_prev;
853
855
856 i = BLI_strnlen(str, str_len);
858 i = size_t(s - str);
859 s_prev = BLI_str_find_prev_char_utf8(s, str);
860 i_prev = size_t(s_prev - str);
861
862 i_tmp = i;
863 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i_tmp, nullptr);
864 for (width_new = pen_x = 0; (s != nullptr && i > 0);
865 i = i_prev, s = s_prev, g = g_prev, g_prev = nullptr, width_new = pen_x)
866 {
867 s_prev = BLI_str_find_prev_char_utf8(s, str);
868 i_prev = size_t(s_prev - str);
869
870 i_tmp = i_prev;
871 g_prev = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i_tmp, nullptr);
872 BLI_assert(i_tmp == i);
873
874 if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width)) {
875 break;
876 }
877 }
878
879 if (r_width) {
880 *r_width = ft_pix_to_int(width_new);
881 }
882
884 return i;
885}
886
889/* -------------------------------------------------------------------- */
894 GlyphCacheBLF *gc,
895 const char *str,
896 const size_t str_len,
897 rcti *r_box,
898 ResultBLF *r_info,
899 ft_pix pen_y)
900{
901 const GlyphBLF *g = nullptr;
902 ft_pix pen_x = 0;
903 size_t i = 0;
904
905 ft_pix box_xmin = ft_pix_from_int(32000);
906 ft_pix box_xmax = ft_pix_from_int(-32000);
907 ft_pix box_ymin = ft_pix_from_int(32000);
908 ft_pix box_ymax = ft_pix_from_int(-32000);
909
910 while ((i < str_len) && str[i]) {
911 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
912
913 if (UNLIKELY(g == nullptr)) {
914 continue;
915 }
916 const ft_pix pen_x_next = pen_x + g->advance_x;
917
918 const ft_pix gbox_xmin = std::min(pen_x, pen_x + g->box_xmin);
919 const ft_pix gbox_xmax = std::max(pen_x_next, pen_x + g->box_xmax);
920 const ft_pix gbox_ymin = g->box_ymin + pen_y;
921 const ft_pix gbox_ymax = g->box_ymax + pen_y;
922
923 if (gbox_xmin < box_xmin) {
924 box_xmin = gbox_xmin;
925 }
926 if (gbox_ymin < box_ymin) {
927 box_ymin = gbox_ymin;
928 }
929
930 if (gbox_xmax > box_xmax) {
931 box_xmax = gbox_xmax;
932 }
933 if (gbox_ymax > box_ymax) {
934 box_ymax = gbox_ymax;
935 }
936
937 pen_x = pen_x_next;
938 }
939
940 if (box_xmin > box_xmax) {
941 box_xmin = 0;
942 box_ymin = 0;
943 box_xmax = 0;
944 box_ymax = 0;
945 }
946
947 r_box->xmin = ft_pix_to_int_floor(box_xmin);
948 r_box->xmax = ft_pix_to_int_ceil(box_xmax);
949 r_box->ymin = ft_pix_to_int_floor(box_ymin);
950 r_box->ymax = ft_pix_to_int_ceil(box_ymax);
951
952 if (r_info) {
953 r_info->lines = 1;
954 r_info->width = ft_pix_to_int(pen_x);
955 }
956}
958 FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
959{
961 blf_font_boundbox_ex(font, gc, str, str_len, r_box, r_info, 0);
963}
964
966 const char *str,
967 const size_t str_len,
968 float *r_width,
969 float *r_height,
970 ResultBLF *r_info)
971{
972 float xa, ya;
973 rcti box;
974
975 if (font->flags & BLF_ASPECT) {
976 xa = font->aspect[0];
977 ya = font->aspect[1];
978 }
979 else {
980 xa = 1.0f;
981 ya = 1.0f;
982 }
983
984 if (font->flags & BLF_WORD_WRAP) {
985 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
986 }
987 else {
988 blf_font_boundbox(font, str, str_len, &box, r_info);
989 }
990 *r_width = (float(BLI_rcti_size_x(&box)) * xa);
991 *r_height = (float(BLI_rcti_size_y(&box)) * ya);
992}
993
994float blf_font_width(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
995{
996 float xa;
997 rcti box;
998
999 if (font->flags & BLF_ASPECT) {
1000 xa = font->aspect[0];
1001 }
1002 else {
1003 xa = 1.0f;
1004 }
1005
1006 if (font->flags & BLF_WORD_WRAP) {
1007 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
1008 }
1009 else {
1010 blf_font_boundbox(font, str, str_len, &box, r_info);
1011 }
1012 return float(BLI_rcti_size_x(&box)) * xa;
1013}
1014
1015float blf_font_height(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
1016{
1017 float ya;
1018 rcti box;
1019
1020 if (font->flags & BLF_ASPECT) {
1021 ya = font->aspect[1];
1022 }
1023 else {
1024 ya = 1.0f;
1025 }
1026
1027 if (font->flags & BLF_WORD_WRAP) {
1028 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
1029 }
1030 else {
1031 blf_font_boundbox(font, str, str_len, &box, r_info);
1032 }
1033 return float(BLI_rcti_size_y(&box)) * ya;
1034}
1035
1037{
1038 const GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1039 float width = (gc) ? float(gc->fixed_width) : font->size / 2.0f;
1041 return width;
1042}
1043
1045 const char *str,
1046 const size_t str_len,
1047 BLF_GlyphBoundsFn user_fn,
1048 void *user_data)
1049{
1050 if (str_len == 0 || str[0] == 0) {
1051 /* Early exit. */
1052 return;
1053 }
1054
1055 const GlyphBLF *g = nullptr;
1056 ft_pix pen_x = 0;
1057 size_t i = 0;
1058
1060
1061 while ((i < str_len) && str[i]) {
1062 const size_t i_curr = i;
1063 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
1064
1065 if (UNLIKELY(g == nullptr || g->advance_x == 0)) {
1066 /* Ignore combining characters like diacritical marks. */
1067 continue;
1068 }
1069 rcti bounds;
1074
1075 if (user_fn(str, i_curr, &bounds, user_data) == false) {
1076 break;
1077 }
1078 pen_x += g->advance_x;
1079 }
1080
1082}
1083
1090
1091static bool blf_cursor_position_foreach_glyph(const char * /*str*/,
1092 const size_t str_step_ofs,
1093 const rcti *bounds,
1094 void *user_data)
1095{
1097 user_data);
1098 if (data->location_x < (bounds->xmin + bounds->xmax) / 2) {
1099 data->r_offset = str_step_ofs;
1100 return false;
1101 }
1102 return true;
1103}
1104
1106 const char *str,
1107 size_t str_len,
1108 int location_x)
1109{
1110 /* Do not early exit if location_x <= 0, as this can result in an incorrect
1111 * offset for RTL text. Instead of offset of character responsible for first
1112 * glyph you'd get offset of first character, which could be the last glyph. */
1113 if (!str || !str[0] || !str_len) {
1114 return 0;
1115 }
1116
1118 data.location_x = location_x;
1119 data.r_offset = size_t(-1);
1120
1122
1123 if (data.r_offset == size_t(-1)) {
1124 /* We are to the right of the string, so return position of null terminator. */
1125 data.r_offset = BLI_strnlen(str, str_len);
1126 }
1127 else if (BLI_str_utf8_char_width_or_error(&str[data.r_offset]) == 0) {
1128 /* This is a combining character, so move to previous visible valid char. */
1129 int offset = int(data.r_offset);
1130 BLI_str_cursor_step_prev_utf8(str, int(str_len), &offset);
1131 data.r_offset = size_t(offset);
1132 }
1133
1134 return data.r_offset;
1135}
1136
1141
1142static bool blf_str_offset_foreach_glyph(const char * /*str*/,
1143 const size_t str_step_ofs,
1144 const rcti *bounds,
1145 void *user_data)
1146{
1147 StrOffsetToGlyphBounds_Data *data = static_cast<StrOffsetToGlyphBounds_Data *>(user_data);
1148 if (data->str_offset == str_step_ofs) {
1149 data->bounds = *bounds;
1150 return false;
1151 }
1152 return true;
1153}
1154
1156 const char *str,
1157 size_t str_offset,
1158 rcti *r_glyph_bounds)
1159{
1161 data.str_offset = str_offset;
1162 data.bounds = {0};
1163
1165 *r_glyph_bounds = data.bounds;
1166}
1167
1169 const char *str,
1170 const size_t str_len,
1171 const size_t str_offset,
1172 const int cursor_width)
1173{
1174 if (!str || !str[0]) {
1175 return 0;
1176 }
1177
1178 /* Right edge of the previous character, if available. */
1179 rcti prev = {0};
1180 if (str_offset > 0) {
1181 blf_str_offset_to_glyph_bounds(font, str, str_offset - 1, &prev);
1182 }
1183
1184 /* Left edge of the next character, if available. */
1185 rcti next = {0};
1186 if (str_offset < strlen(str)) {
1187 blf_str_offset_to_glyph_bounds(font, str, str_offset, &next);
1188 }
1189
1190 if ((prev.xmax == prev.xmin) && next.xmax) {
1191 /* Nothing (or a space) to the left, so align to right character. */
1192 return next.xmin - (cursor_width / 2);
1193 }
1194 if ((prev.xmax != prev.xmin) && !next.xmax) {
1195 /* End of string, so align to last character. */
1196 return prev.xmax - (cursor_width / 2);
1197 }
1198 if (prev.xmax && next.xmax) {
1199 /* Between two characters, so use the center. */
1200 if (next.xmin >= prev.xmax || next.xmin == next.xmax) {
1201 return ((prev.xmax + next.xmin) - cursor_width) / 2;
1202 }
1203 /* A nicer center if reversed order - RTL. */
1204 return ((next.xmax + prev.xmin) - cursor_width) / 2;
1205 }
1206 if (!str_offset) {
1207 /* Start of string. */
1208 return 0 - cursor_width;
1209 }
1210 return int(blf_font_width(font, str, str_len, nullptr));
1211}
1212
1214 FontBLF *font, const char *str, size_t str_len, size_t sel_start, size_t sel_length)
1215{
1217 const int start = blf_str_offset_to_cursor(font, str, str_len, sel_start, 0);
1218 const int end = blf_str_offset_to_cursor(font, str, str_len, sel_start + sel_length, 0);
1219 boxes.append(blender::Bounds(start, end));
1220 return boxes;
1221}
1222
1225/* -------------------------------------------------------------------- */
1239 const char *str,
1240 const size_t str_len,
1241 const int max_pixel_width,
1242 ResultBLF *r_info,
1243 void (*callback)(FontBLF *font,
1244 GlyphCacheBLF *gc,
1245 const char *str,
1246 const size_t str_len,
1247 ft_pix pen_y,
1248 void *userdata),
1249 void *userdata)
1250{
1251 GlyphBLF *g = nullptr;
1252 const GlyphBLF *g_prev = nullptr;
1253 ft_pix pen_x = 0;
1254 ft_pix pen_y = 0;
1255 size_t i = 0;
1256 int lines = 0;
1257 ft_pix pen_x_next = 0;
1258
1259 ft_pix line_height = blf_font_height_max_ft_pix(font);
1260
1262
1263 struct WordWrapVars {
1264 ft_pix wrap_width;
1265 size_t start, last[2];
1266 } wrap = {max_pixel_width != -1 ? ft_pix_from_int(max_pixel_width) : INT_MAX, 0, {0, 0}};
1267
1268 // printf("%s wrapping (%d, %d) `%s`:\n", __func__, str_len, strlen(str), str);
1269 while ((i < str_len) && str[i]) {
1270
1271 /* Wrap variables. */
1272 const size_t i_curr = i;
1273 bool do_draw = false;
1274
1275 g = blf_glyph_from_utf8_and_step(font, gc, g_prev, str, str_len, &i, &pen_x);
1276
1277 if (UNLIKELY(g == nullptr)) {
1278 continue;
1279 }
1280
1289 pen_x_next = pen_x + g->advance_x;
1290 if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) {
1291 do_draw = true;
1292 }
1293 else if (UNLIKELY(((i < str_len) && str[i]) == 0)) {
1294 /* Need check here for trailing newline, else we draw it. */
1295 wrap.last[0] = i + ((g->c != '\n') ? 1 : 0);
1296 wrap.last[1] = i;
1297 do_draw = true;
1298 }
1299 else if (UNLIKELY(g->c == '\n')) {
1300 wrap.last[0] = i_curr + 1;
1301 wrap.last[1] = i;
1302 do_draw = true;
1303 }
1304 else if (UNLIKELY(g->c != ' ' && (g_prev ? g_prev->c == ' ' : false))) {
1305 wrap.last[0] = i_curr;
1306 wrap.last[1] = i_curr;
1307 }
1308
1309 if (UNLIKELY(do_draw)) {
1310#if 0
1311 printf("(%03d..%03d) `%.*s`\n",
1312 wrap.start,
1313 wrap.last[0],
1314 (wrap.last[0] - wrap.start) - 1,
1315 &str[wrap.start]);
1316#endif
1317
1318 callback(font, gc, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata);
1319 wrap.start = wrap.last[0];
1320 i = wrap.last[1];
1321 pen_x = 0;
1322 pen_y -= line_height;
1323 g_prev = nullptr;
1324 lines += 1;
1325 continue;
1326 }
1327
1328 pen_x = pen_x_next;
1329 g_prev = g;
1330 }
1331
1332 // printf("done! lines: %d, width, %d\n", lines, pen_x_next);
1333
1334 if (r_info) {
1335 r_info->lines = lines;
1336 /* Width of last line only (with wrapped lines). */
1337 r_info->width = ft_pix_to_int(pen_x_next);
1338 }
1339
1341}
1342
1345 GlyphCacheBLF *gc,
1346 const char *str,
1347 const size_t str_len,
1348 ft_pix pen_y,
1349 void * /*userdata*/)
1350{
1351 blf_font_draw_ex(font, gc, str, str_len, nullptr, pen_y);
1352}
1353void blf_font_draw__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
1354{
1356 font, str, str_len, font->wrap_width, r_info, blf_font_draw__wrap_cb, nullptr);
1357}
1358
1361 GlyphCacheBLF *gc,
1362 const char *str,
1363 const size_t str_len,
1364 ft_pix pen_y,
1365 void *userdata)
1366{
1367 rcti *box = static_cast<rcti *>(userdata);
1368 rcti box_single;
1369
1370 blf_font_boundbox_ex(font, gc, str, str_len, &box_single, nullptr, pen_y);
1371 BLI_rcti_union(box, &box_single);
1372}
1374 FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
1375{
1376 r_box->xmin = 32000;
1377 r_box->xmax = -32000;
1378 r_box->ymin = 32000;
1379 r_box->ymax = -32000;
1380
1382 font, str, str_len, font->wrap_width, r_info, blf_font_boundbox_wrap_cb, r_box);
1383}
1384
1387 GlyphCacheBLF *gc,
1388 const char *str,
1389 const size_t str_len,
1390 ft_pix pen_y,
1391 void * /*userdata*/)
1392{
1393 blf_font_draw_buffer_ex(font, gc, str, str_len, nullptr, pen_y);
1394}
1396 const char *str,
1397 const size_t str_len,
1398 ResultBLF *r_info)
1399{
1401 font, str, str_len, font->wrap_width, r_info, blf_font_draw_buffer__wrap_cb, nullptr);
1402}
1403
1405static void blf_font_string_wrap_cb(FontBLF * /*font*/,
1406 GlyphCacheBLF * /*gc*/,
1407 const char *str,
1408 const size_t str_len,
1409 ft_pix /*pen_y*/,
1410 void *str_list_ptr)
1411{
1413 str_list_ptr);
1414 blender::StringRef line(str, str + str_len);
1415 list->append(line);
1416}
1417
1420 int max_pixel_width)
1421{
1424 str.data(),
1425 size_t(str.size()),
1426 max_pixel_width,
1427 nullptr,
1429 &list);
1430 return list;
1431}
1432
1435/* -------------------------------------------------------------------- */
1440{
1441 blf_ensure_size(font);
1442 /* #Metrics::height is rounded to pixel. Force minimum of one pixel. */
1443 return std::max((ft_pix)font->ft_size->metrics.height, ft_pix_from_int(1));
1444}
1445
1447{
1449}
1450
1452{
1453 blf_ensure_size(font);
1454 /* #Metrics::max_advance is rounded to pixel. Force minimum of one pixel. */
1455 return std::max((ft_pix)font->ft_size->metrics.max_advance, ft_pix_from_int(1));
1456}
1457
1459{
1461}
1462
1464{
1465 blf_ensure_size(font);
1466 return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender);
1467}
1468
1470{
1471 blf_ensure_size(font);
1472 return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender);
1473}
1474
1476{
1477 if (!blf_ensure_face(font) || !font->face->family_name) {
1478 return nullptr;
1479 }
1480 return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name);
1481}
1482
1485/* -------------------------------------------------------------------- */
1490{
1491 memset(&g_batch, 0, sizeof(g_batch));
1493 int err = FT_Init_FreeType(&ft_lib);
1494 if (err == FT_Err_Ok) {
1495 /* Create a FreeType cache manager. */
1496 err = FTC_Manager_New(ft_lib,
1501 nullptr,
1502 &ftc_manager);
1503 if (err == FT_Err_Ok) {
1504 /* Create a character-map cache to speed up glyph index lookups. */
1505 err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache);
1506 }
1507 }
1508 return err;
1509}
1510
1512{
1514 if (ftc_manager) {
1515 FTC_Manager_Done(ftc_manager);
1516 }
1517 if (ft_lib) {
1518 FT_Done_FreeType(ft_lib);
1519 }
1521}
1522
1523void BLF_cache_flush_set_fn(void (*cache_flush_fn)())
1524{
1525 blf_draw_cache_flush = cache_flush_fn;
1526}
1527
1530/* -------------------------------------------------------------------- */
1534static void blf_font_fill(FontBLF *font)
1535{
1536 font->aspect[0] = 1.0f;
1537 font->aspect[1] = 1.0f;
1538 font->aspect[2] = 1.0f;
1539 font->pos[0] = 0;
1540 font->pos[1] = 0;
1541 font->angle = 0.0f;
1542
1543 /* Use an easily identifiable bright color (yellow)
1544 * so its clear when #BLF_color calls are missing. */
1545 font->color[0] = 255;
1546 font->color[1] = 255;
1547 font->color[2] = 0;
1548 font->color[3] = 255;
1549
1550 font->clip_rec.xmin = 0;
1551 font->clip_rec.xmax = 0;
1552 font->clip_rec.ymin = 0;
1553 font->clip_rec.ymax = 0;
1554 font->flags = 0;
1555 font->size = 0;
1556 font->char_weight = 400;
1557 font->char_slant = 0.0f;
1558 font->char_width = 1.0f;
1559 font->char_spacing = 0.0f;
1560
1561 font->kerning_cache = nullptr;
1562 font->tex_size_max = -1;
1563
1564 font->buf_info.fbuf = nullptr;
1565 font->buf_info.cbuf = nullptr;
1566 font->buf_info.dims[0] = 0;
1567 font->buf_info.dims[1] = 0;
1568 font->buf_info.col_init[0] = 0;
1569 font->buf_info.col_init[1] = 0;
1570 font->buf_info.col_init[2] = 0;
1571 font->buf_info.col_init[3] = 0;
1572}
1573
1578static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
1579{
1580 /* Members with non-zero defaults. */
1581 metrics->weight = 400;
1582 metrics->width = 1.0f;
1583
1584 const TT_OS2 *os2_table = (const TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
1585 if (os2_table) {
1586 /* The default (resting) font weight. */
1587 if (os2_table->usWeightClass >= 1 && os2_table->usWeightClass <= 1000) {
1588 metrics->weight = short(os2_table->usWeightClass);
1589 }
1590
1591 /* Width value is one of integers 1-9 with known values. */
1592 if (os2_table->usWidthClass >= 1 && os2_table->usWidthClass <= 9) {
1593 switch (os2_table->usWidthClass) {
1594 case 1:
1595 metrics->width = 0.5f;
1596 break;
1597 case 2:
1598 metrics->width = 0.625f;
1599 break;
1600 case 3:
1601 metrics->width = 0.75f;
1602 break;
1603 case 4:
1604 metrics->width = 0.875f;
1605 break;
1606 case 5:
1607 metrics->width = 1.0f;
1608 break;
1609 case 6:
1610 metrics->width = 1.125f;
1611 break;
1612 case 7:
1613 metrics->width = 1.25f;
1614 break;
1615 case 8:
1616 metrics->width = 1.5f;
1617 break;
1618 case 9:
1619 metrics->width = 2.0f;
1620 break;
1621 }
1622 }
1623
1624 metrics->strikeout_position = short(os2_table->yStrikeoutPosition);
1625 metrics->strikeout_thickness = short(os2_table->yStrikeoutSize);
1626 metrics->subscript_size = short(os2_table->ySubscriptYSize);
1627 metrics->subscript_xoffset = short(os2_table->ySubscriptXOffset);
1628 metrics->subscript_yoffset = short(os2_table->ySubscriptYOffset);
1629 metrics->superscript_size = short(os2_table->ySuperscriptYSize);
1630 metrics->superscript_xoffset = short(os2_table->ySuperscriptXOffset);
1631 metrics->superscript_yoffset = short(os2_table->ySuperscriptYOffset);
1632 metrics->family_class = short(os2_table->sFamilyClass);
1633 metrics->selection_flags = short(os2_table->fsSelection);
1634 metrics->first_charindex = short(os2_table->usFirstCharIndex);
1635 metrics->last_charindex = short(os2_table->usLastCharIndex);
1636 if (os2_table->version > 1) {
1637 metrics->cap_height = short(os2_table->sCapHeight);
1638 metrics->x_height = short(os2_table->sxHeight);
1639 }
1640 }
1641
1642 /* The Post table usually contains a slant value, but in counter-clockwise degrees. */
1643 const TT_Postscript *post_table = (const TT_Postscript *)FT_Get_Sfnt_Table(face, FT_SFNT_POST);
1644 if (post_table) {
1645 if (post_table->italicAngle != 0) {
1646 metrics->slant = float(post_table->italicAngle) / -65536.0f;
1647 }
1648 }
1649
1650 /* Metrics copied from those gathered by FreeType. */
1651 metrics->units_per_EM = short(face->units_per_EM);
1652 metrics->ascender = short(face->ascender);
1653 metrics->descender = short(face->descender);
1654 metrics->line_height = short(face->height);
1655 metrics->max_advance_width = short(face->max_advance_width);
1656 metrics->max_advance_height = short(face->max_advance_height);
1657 metrics->underline_position = short(face->underline_position);
1658 metrics->underline_thickness = short(face->underline_thickness);
1659 metrics->num_glyphs = int(face->num_glyphs);
1660
1661 if (metrics->cap_height == 0) {
1662 /* Calculate or guess cap height if it is not set in the font. */
1663 FT_UInt gi = FT_Get_Char_Index(face, uint('H'));
1664 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1665 metrics->cap_height = short(face->glyph->metrics.height);
1666 }
1667 else {
1668 metrics->cap_height = short(float(metrics->units_per_EM) * 0.7f);
1669 }
1670 }
1671
1672 if (metrics->x_height == 0) {
1673 /* Calculate or guess x-height if it is not set in the font. */
1674 FT_UInt gi = FT_Get_Char_Index(face, uint('x'));
1675 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1676 metrics->x_height = short(face->glyph->metrics.height);
1677 }
1678 else {
1679 metrics->x_height = short(float(metrics->units_per_EM) * 0.5f);
1680 }
1681 }
1682
1683 FT_UInt gi = FT_Get_Char_Index(face, uint('o'));
1684 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1685 metrics->o_proportion = float(face->glyph->metrics.width) / float(face->glyph->metrics.height);
1686 }
1687
1688 if (metrics->ascender == 0) {
1689 /* Set a sane value for ascender if not set in the font. */
1690 metrics->ascender = short(float(metrics->units_per_EM) * 0.8f);
1691 }
1692
1693 if (metrics->descender == 0) {
1694 /* Set a sane value for descender if not set in the font. */
1695 metrics->descender = metrics->ascender - metrics->units_per_EM;
1696 }
1697
1698 if (metrics->weight == 400 && face->style_flags & FT_STYLE_FLAG_BOLD) {
1699 /* Normal weight yet this is an bold font, so set a sane weight value. */
1700 metrics->weight = 700;
1701 }
1702
1703 if (metrics->slant == 0.0f && face->style_flags & FT_STYLE_FLAG_ITALIC) {
1704 /* No slant yet this is an italic font, so set a sane slant value. */
1705 metrics->slant = 8.0f;
1706 }
1707
1708 if (metrics->underline_position == 0) {
1709 metrics->underline_position = short(float(metrics->units_per_EM) * -0.2f);
1710 }
1711
1712 if (metrics->underline_thickness == 0) {
1713 metrics->underline_thickness = short(float(metrics->units_per_EM) * 0.07f);
1714 }
1715
1716 if (metrics->strikeout_position == 0) {
1717 metrics->strikeout_position = short(float(metrics->x_height) * 0.6f);
1718 }
1719
1720 if (metrics->strikeout_thickness == 0) {
1721 metrics->strikeout_thickness = metrics->underline_thickness;
1722 }
1723
1724 if (metrics->subscript_size == 0) {
1725 metrics->subscript_size = short(float(metrics->units_per_EM) * 0.6f);
1726 }
1727
1728 if (metrics->subscript_yoffset == 0) {
1729 metrics->subscript_yoffset = short(float(metrics->units_per_EM) * 0.075f);
1730 }
1731
1732 if (metrics->superscript_size == 0) {
1733 metrics->superscript_size = short(float(metrics->units_per_EM) * 0.6f);
1734 }
1735
1736 if (metrics->superscript_yoffset == 0) {
1737 metrics->superscript_yoffset = short(float(metrics->units_per_EM) * 0.35f);
1738 }
1739
1740 metrics->valid = true;
1741}
1742
1747static bool blf_setup_face(FontBLF *font)
1748{
1749 font->face_flags = font->face->face_flags;
1750
1751 if (FT_HAS_MULTIPLE_MASTERS(font) && !font->variations) {
1752 FT_Get_MM_Var(font->face, &(font->variations));
1753 }
1754
1755 if (!font->metrics.valid) {
1756 blf_font_metrics(font->face, &font->metrics);
1757 font->char_weight = font->metrics.weight;
1758 font->char_slant = font->metrics.slant;
1759 font->char_width = font->metrics.width;
1760 font->char_spacing = font->metrics.spacing;
1761 }
1762
1763 if (FT_IS_FIXED_WIDTH(font)) {
1764 font->flags |= BLF_MONOSPACED;
1765 }
1766
1767 if (FT_HAS_KERNING(font) && !font->kerning_cache) {
1768 /* Create kerning cache table and fill with value indicating "unset". */
1769 font->kerning_cache = static_cast<KerningCacheBLF *>(
1770 MEM_mallocN(sizeof(KerningCacheBLF), __func__));
1771 for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
1772 for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) {
1773 font->kerning_cache->ascii_table[i][j] = KERNING_ENTRY_UNSET;
1774 }
1775 }
1776 }
1777
1778 return true;
1779}
1780
1782{
1783 if (font->face) {
1784 return true;
1785 }
1786
1787 if (font->flags & BLF_BAD_FONT) {
1788 return false;
1789 }
1790
1791 FT_Error err;
1792
1793 if (font->flags & BLF_CACHED) {
1794 err = FTC_Manager_LookupFace(ftc_manager, font, &font->face);
1795 }
1796 else {
1798 if (font->filepath) {
1799 err = FT_New_Face(font->ft_lib, font->filepath, 0, &font->face);
1800 }
1801 if (font->mem) {
1802 err = FT_New_Memory_Face(font->ft_lib,
1803 static_cast<const FT_Byte *>(font->mem),
1804 (FT_Long)font->mem_size,
1805 0,
1806 &font->face);
1807 }
1808 if (!err) {
1809 font->face->generic.data = font;
1810 }
1812 }
1813
1814 if (err) {
1815 if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) {
1816 printf("Format of this font file is not supported\n");
1817 }
1818 else {
1819 printf("Error encountered while opening font file\n");
1820 }
1821 font->flags |= BLF_BAD_FONT;
1822 return false;
1823 }
1824
1825 if (font->face && !(font->face->face_flags & FT_FACE_FLAG_SCALABLE)) {
1826 printf("Font is not scalable\n");
1827 return false;
1828 }
1829
1830 err = FT_Select_Charmap(font->face, FT_ENCODING_UNICODE);
1831 if (err) {
1832 err = FT_Select_Charmap(font->face, FT_ENCODING_APPLE_ROMAN);
1833 }
1834 if (err && font->face->num_charmaps > 0) {
1835 err = FT_Select_Charmap(font->face, font->face->charmaps[0]->encoding);
1836 }
1837 if (err) {
1838 printf("Can't set a character map!\n");
1839 font->flags |= BLF_BAD_FONT;
1840 return false;
1841 }
1842
1843 if (font->filepath) {
1844 char *mfile = blf_dir_metrics_search(font->filepath);
1845 if (mfile) {
1846 err = FT_Attach_File(font->face, mfile);
1847 if (err) {
1848 fprintf(stderr,
1849 "FT_Attach_File failed to load '%s' with error %d\n",
1850 font->filepath,
1851 int(err));
1852 }
1853 MEM_freeN(mfile);
1854 }
1855 }
1856
1857 if (!(font->flags & BLF_CACHED)) {
1858 /* Not cached so point at the face's size for convenience. */
1859 font->ft_size = font->face->size;
1860 }
1861
1862 /* Setup Font details that require having a Face. */
1863 return blf_setup_face(font);
1864}
1865
1873
1874/* Details about the fallback fonts we ship, so that we can load only when needed. */
1876 {"lastresort.woff2", UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX},
1877 {"Noto Sans CJK Regular.woff2",
1878 0,
1879 TT_UCR_CJK_SYMBOLS | TT_UCR_HIRAGANA | TT_UCR_KATAKANA | TT_UCR_BOPOMOFO | TT_UCR_CJK_MISC |
1880 TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS | TT_UCR_CJK_COMPATIBILITY |
1881 TT_UCR_CJK_UNIFIED_IDEOGRAPHS | TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS,
1882 TT_UCR_CJK_COMPATIBILITY_FORMS,
1883 0},
1884 {"NotoEmoji-VariableFont_wght.woff2", 0x80000003L, 0x241E4ACL, 0x14000000L, 0x4000000L},
1885 {"NotoSansArabic-VariableFont_wdth,wght.woff2",
1886 TT_UCR_ARABIC,
1887 uint(TT_UCR_ARABIC_PRESENTATION_FORMS_A),
1888 TT_UCR_ARABIC_PRESENTATION_FORMS_B,
1889 0},
1890 {"NotoSansArmenian-VariableFont_wdth,wght.woff2", TT_UCR_ARMENIAN, 0, 0, 0},
1891 {"NotoSansBengali-VariableFont_wdth,wght.woff2", TT_UCR_BENGALI, 0, 0, 0},
1892 {"NotoSansDevanagari-Regular.woff2", TT_UCR_DEVANAGARI, 0, 0, 0},
1893 {"NotoSansEthiopic-Regular.woff2", 0, 0, TT_UCR_ETHIOPIC, 0},
1894 {"NotoSansGeorgian-VariableFont_wdth,wght.woff2", TT_UCR_GEORGIAN, 0, 0, 0},
1895 {"NotoSansGujarati-Regular.woff2", TT_UCR_GUJARATI, 0, 0, 0},
1896 {"NotoSansGurmukhi-VariableFont_wdth,wght.woff2", TT_UCR_GURMUKHI, 0, 0, 0},
1897 {"NotoSansHebrew-Regular.woff2", TT_UCR_HEBREW, 0, 0, 0},
1898 {"NotoSansJavanese-Regular.woff2", 0x80000003L, 0x2000L, 0, 0},
1899 {"NotoSansKannada-VariableFont_wdth,wght.woff2", TT_UCR_KANNADA, 0, 0, 0},
1900 {"NotoSansKhmer-VariableFont_wdth,wght.woff2", 0, 0, TT_UCR_KHMER, 0},
1901 {"NotoSansMalayalam-VariableFont_wdth,wght.woff2", TT_UCR_MALAYALAM, 0, 0, 0},
1902 {"NotoSansMath-Regular.woff2", 0, TT_UCR_MATHEMATICAL_OPERATORS, 0, 0},
1903 {"NotoSansMyanmar-Regular.woff2", 0, 0, TT_UCR_MYANMAR, 0},
1904 {"NotoSansSymbols-VariableFont_wght.woff2", 0x3L, 0x200E4B4L, 0, 0},
1905 {"NotoSansSymbols2-Regular.woff2", 0x80000003L, 0x200E3E4L, 0x40020L, 0x580A048L},
1906 {"NotoSansTamil-VariableFont_wdth,wght.woff2", TT_UCR_TAMIL, 0, 0, 0},
1907 {"NotoSansTelugu-VariableFont_wdth,wght.woff2", TT_UCR_TELUGU, 0, 0, 0},
1908 {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0},
1909};
1910
1916static FontBLF *blf_font_new_impl(const char *filepath,
1917 const char *mem_name,
1918 const uchar *mem,
1919 const size_t mem_size,
1920 void *ft_library)
1921{
1922 FontBLF *font = MEM_new<FontBLF>(__func__);
1923
1924 font->mem_name = mem_name ? BLI_strdup(mem_name) : nullptr;
1925 font->filepath = filepath ? BLI_strdup(filepath) : nullptr;
1926 if (mem) {
1927 font->mem = (void *)mem;
1928 font->mem_size = mem_size;
1929 }
1930 blf_font_fill(font);
1931
1932 if (ft_library && ((FT_Library)ft_library != ft_lib)) {
1933 /* Pass. */
1934 }
1935 else {
1936 font->flags |= BLF_CACHED;
1937 }
1938
1939 font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib;
1940
1941 /* If we have static details about this font file, we don't have to load the Face yet. */
1942 bool face_needed = true;
1943
1944 if (font->filepath) {
1945 const char *filename = BLI_path_basename(font->filepath);
1946 for (int i = 0; i < int(ARRAY_SIZE(static_face_details)); i++) {
1947 if (BLI_path_cmp(static_face_details[i].filename, filename) == 0) {
1948 const FaceDetails *static_details = &static_face_details[i];
1949 font->unicode_ranges[0] = static_details->coverage1;
1950 font->unicode_ranges[1] = static_details->coverage2;
1951 font->unicode_ranges[2] = static_details->coverage3;
1952 font->unicode_ranges[3] = static_details->coverage4;
1953 face_needed = false;
1954 break;
1955 }
1956 }
1957 }
1958
1959 if (face_needed) {
1960 if (!blf_ensure_face(font)) {
1961 blf_font_free(font);
1962 return nullptr;
1963 }
1964
1965 /* Save TrueType table with bits to quickly test most unicode block coverage. */
1966 const TT_OS2 *os2_table = (const TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
1967 if (os2_table) {
1968 font->unicode_ranges[0] = uint(os2_table->ulUnicodeRange1);
1969 font->unicode_ranges[1] = uint(os2_table->ulUnicodeRange2);
1970 font->unicode_ranges[2] = uint(os2_table->ulUnicodeRange3);
1971 font->unicode_ranges[3] = uint(os2_table->ulUnicodeRange4);
1972 }
1973 }
1974
1975 /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
1976 if (font->unicode_ranges[0] == 0xffffffffU && font->unicode_ranges[1] == 0xffffffffU &&
1977 font->unicode_ranges[2] == 0xffffffffU && font->unicode_ranges[3] >= 0x7FFFFFFU)
1978 {
1979 font->flags |= BLF_LAST_RESORT;
1980 }
1981
1982 return font;
1983}
1984
1986{
1987 return blf_font_new_impl(filepath, nullptr, nullptr, 0, nullptr);
1988}
1989
1990FontBLF *blf_font_new_from_mem(const char *mem_name, const uchar *mem, const size_t mem_size)
1991{
1992 return blf_font_new_impl(nullptr, mem_name, mem, mem_size, nullptr);
1993}
1994
1995void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_size)
1996{
1997 FT_Open_Args open;
1998
1999 open.flags = FT_OPEN_MEMORY;
2000 open.memory_base = (const FT_Byte *)mem;
2001 open.memory_size = (FT_Long)mem_size;
2002 if (blf_ensure_face(font)) {
2003 FT_Attach_Stream(font->face, &open);
2004 }
2005}
2006
2008{
2010
2011 if (font->kerning_cache) {
2012 MEM_freeN(font->kerning_cache);
2013 }
2014
2015 if (font->variations) {
2016 FT_Done_MM_Var(font->ft_lib, font->variations);
2017 }
2018
2019 if (font->face) {
2021 if (font->flags & BLF_CACHED) {
2022 FTC_Manager_RemoveFaceID(ftc_manager, font);
2023 }
2024 else {
2025 FT_Done_Face(font->face);
2026 }
2028 font->face = nullptr;
2029 }
2030 if (font->filepath) {
2031 MEM_freeN(font->filepath);
2032 }
2033 if (font->mem_name) {
2034 MEM_freeN(font->mem_name);
2035 }
2036
2037 MEM_delete(font);
2038}
2039
2042/* -------------------------------------------------------------------- */
2047{
2048 if (font->ft_size || !(font->flags & BLF_CACHED)) {
2049 return;
2050 }
2051
2052 FTC_ScalerRec scaler = {nullptr};
2053 scaler.face_id = font;
2054 scaler.width = 0;
2055 scaler.height = round_fl_to_uint(font->size * 64.0f);
2056 scaler.pixel = 0;
2057 scaler.x_res = BLF_DPI;
2058 scaler.y_res = BLF_DPI;
2059 if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) == FT_Err_Ok) {
2060 font->ft_size->generic.data = (void *)font;
2061 font->ft_size->generic.finalizer = blf_size_finalizer;
2062 return;
2063 }
2064
2066}
2067
2068bool blf_font_size(FontBLF *font, float size)
2069{
2070 if (!blf_ensure_face(font)) {
2071 return false;
2072 }
2073
2074 /* FreeType uses fixed-point integers in 64ths. */
2075 FT_UInt ft_size = round_fl_to_uint(size * 64.0f);
2076 /* Adjust our new size to be on even 64ths. */
2077 size = float(ft_size) / 64.0f;
2078
2079 if (font->size != size) {
2080 if (font->flags & BLF_CACHED) {
2081 FTC_ScalerRec scaler = {nullptr};
2082 scaler.face_id = font;
2083 scaler.width = 0;
2084 scaler.height = ft_size;
2085 scaler.pixel = 0;
2086 scaler.x_res = BLF_DPI;
2087 scaler.y_res = BLF_DPI;
2088 if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) != FT_Err_Ok) {
2089 return false;
2090 }
2091 font->ft_size->generic.data = (void *)font;
2092 font->ft_size->generic.finalizer = blf_size_finalizer;
2093 }
2094 else {
2095 if (FT_Set_Char_Size(font->face, 0, ft_size, BLF_DPI, BLF_DPI) != FT_Err_Ok) {
2096 return false;
2097 }
2098 font->ft_size = font->face->size;
2099 }
2100 }
2101
2102 font->size = size;
2103 return true;
2104}
2105
bool(* BLF_GlyphBoundsFn)(const char *str, size_t str_step_ofs, const rcti *bounds, void *user_data)
Definition BLF_api.hh:167
@ BLF_RENDER_SUBPIXELAA
Definition BLF_api.hh:390
@ BLF_ROTATION
Definition BLF_api.hh:361
@ BLF_LAST_RESORT
Definition BLF_api.hh:380
@ BLF_MONOSPACED
Definition BLF_api.hh:376
@ BLF_CACHED
Definition BLF_api.hh:384
@ BLF_WORD_WRAP
Definition BLF_api.hh:367
@ BLF_BAD_FONT
Definition BLF_api.hh:382
@ BLF_ASPECT
Definition BLF_api.hh:366
@ BLF_SHADOW
Definition BLF_api.hh:363
#define BLI_assert_unreachable()
Definition BLI_assert.h:97
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
#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)
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 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:193
BLI_INLINE int BLI_rcti_size_x(const struct rcti *rct)
Definition BLI_rect.h:189
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.c:40
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.c:909
bool BLI_str_cursor_step_prev_utf8(const char *str, int str_maxlen, int *pos)
int BLI_str_utf8_char_width_or_error(const char *p) ATTR_WARN_UNUSED_RESULT 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
int BLI_wcwidth_safe(char32_t ucs) ATTR_WARN_UNUSED_RESULT
unsigned char uchar
unsigned int uint
void BLI_mutex_end(ThreadMutex *mutex)
Definition threads.cc:360
void BLI_mutex_init(ThreadMutex *mutex)
Definition threads.cc:340
void BLI_mutex_lock(ThreadMutex *mutex)
Definition threads.cc:345
void BLI_mutex_unlock(ThreadMutex *mutex)
Definition threads.cc:350
pthread_mutex_t ThreadMutex
Definition BLI_threads.h:83
#define ARRAY_SIZE(arr)
#define UNLIKELY(x)
#define ELEM(...)
blender::gpu::Batch * GPU_batch_create_ex(GPUPrimType primitive_type, blender::gpu::VertBuf *vertex_buf, blender::gpu::IndexBuf *index_buf, eGPUBatchFlag owns_flag)
Definition gpu_batch.cc:56
void GPU_batch_instbuf_set(blender::gpu::Batch *batch, blender::gpu::VertBuf *vertex_buf, bool own_vbo)
#define GPU_batch_texture_bind(batch, name, tex)
Definition GPU_batch.hh:316
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:205
void GPU_batch_program_set_builtin(blender::gpu::Batch *batch, eGPUBuiltinShader shader_id)
void GPU_batch_draw(blender::gpu::Batch *batch)
@ GPU_BATCH_OWNS_VBO
Definition GPU_batch.hh:42
#define GPU_batch_uniform_1i(batch, name, x)
Definition GPU_batch.hh:297
#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(eGPUBlend blend)
Definition gpu_state.cc:42
int GPU_texture_width(const GPUTexture *texture)
void GPU_texture_unbind(GPUTexture *texture)
@ GPU_DATA_UBYTE
void GPU_texture_update_sub(GPUTexture *texture, eGPUDataFormat data_format, const void *pixels, int offset_x, int offset_y, int offset_z, int width, int height, int depth)
void GPU_vertbuf_attr_get_raw_data(blender::gpu::VertBuf *, uint a_idx, GPUVertBufRaw *access)
#define GPU_vertbuf_create_with_format(format)
void GPU_vertbuf_use(blender::gpu::VertBuf *)
blender::gpu::VertBuf * GPU_vertbuf_create_with_format_ex(const GPUVertFormat &format, GPUUsageType usage)
void GPU_vertbuf_data_len_set(blender::gpu::VertBuf &verts, uint v_len)
void GPU_vertbuf_data_alloc(blender::gpu::VertBuf &verts, uint v_len)
@ GPU_USAGE_STREAM
@ GPU_FETCH_FLOAT
@ GPU_FETCH_INT_TO_FLOAT_UNIT
@ GPU_FETCH_INT
uint GPU_vertformat_attr_add(GPUVertFormat *, const char *name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_U32
@ GPU_COMP_U8
Read Guarded memory(de)allocation.
char * blf_dir_metrics_search(const char *filepath)
Definition blf_dir.cc:30
static void blf_font_draw_buffer__wrap_cb(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, ft_pix pen_y, void *)
Definition blf_font.cc:1386
static ft_pix blf_font_width_max_ft_pix(FontBLF *font)
Definition blf_font.cc:1451
size_t blf_str_offset_from_cursor_position(FontBLF *font, const char *str, size_t str_len, int location_x)
Definition blf_font.cc:1105
static const FaceDetails static_face_details[]
Definition blf_font.cc:1875
void blf_str_offset_to_glyph_bounds(FontBLF *font, const char *str, size_t str_offset, rcti *r_glyph_bounds)
Definition blf_font.cc:1155
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:846
static void blf_font_fill(FontBLF *font)
Definition blf_font.cc:1534
int blf_font_ascender(FontBLF *font)
Definition blf_font.cc:1469
static void(* blf_draw_cache_flush)()
Definition blf_font.cc:70
void blf_draw_svg_icon(FontBLF *font, uint icon_id, float x, float y, float size, const float color[4], float outline_alpha, bool multicolor, blender::FunctionRef< void(std::string &)> edit_source_cb)
Definition blf_font.cc:528
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:1142
float blf_font_width(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:994
bool blf_ensure_face(FontBLF *font)
Definition blf_font.cc:1781
static FTC_Manager ftc_manager
Definition blf_font.cc:63
static GPUTexture * blf_batch_cache_texture_load()
Definition blf_font.cc:285
blender::Vector< blender::StringRef > blf_font_string_wrap(FontBLF *font, blender::StringRef str, int max_pixel_width)
Definition blf_font.cc:1418
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:1439
static void blf_batch_draw_end()
Definition blf_font.cc:365
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:1344
void blf_ensure_size(FontBLF *font)
Definition blf_font.cc:2046
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:893
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:625
void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:766
void BLF_cache_flush_set_fn(void(*cache_flush_fn)())
Definition blf_font.cc:1523
int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth, int tab_columns)
Definition blf_font.cc:492
blender::Array< uchar > blf_svg_icon_bitmap(FontBLF *font, uint icon_id, float size, int *r_width, int *r_height, bool multicolor, blender::FunctionRef< void(std::string &)> edit_source_cb)
Definition blf_font.cc:574
static void blf_font_string_wrap_cb(FontBLF *, GlyphCacheBLF *, const char *str, const size_t str_len, ft_pix, void *str_list_ptr)
Definition blf_font.cc:1405
static void blf_batch_draw_exit()
Definition blf_font.cc:220
static void blf_font_wrap_apply(FontBLF *font, const char *str, const size_t str_len, const int max_pixel_width, 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:1238
void blf_font_free(FontBLF *font)
Definition blf_font.cc:2007
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:1044
static FT_Library ft_lib
Definition blf_font.cc:62
BLI_INLINE GlyphBLF * blf_glyph_from_utf8_and_step(FontBLF *font, GlyphCacheBLF *gc, const GlyphBLF *g_prev, const char *str, size_t str_len, size_t *i_p, int32_t *pen_x)
Definition blf_font.cc:413
bool blf_font_size(FontBLF *font, float size)
Definition blf_font.cc:2068
float blf_font_fixed_width(FontBLF *font)
Definition blf_font.cc:1036
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:1360
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:1015
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:783
int blf_font_init()
Definition blf_font.cc:1489
int blf_font_width_max(FontBLF *font)
Definition blf_font.cc:1458
void blf_batch_draw()
Definition blf_font.cc:325
void blf_batch_draw_begin(FontBLF *font)
Definition blf_font.cc:225
static void blf_size_finalizer(void *object)
Definition blf_font.cc:136
static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
Definition blf_font.cc:160
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:1373
void blf_font_exit()
Definition blf_font.cc:1511
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:1091
void blf_font_boundbox(FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
Definition blf_font.cc:957
uint blf_get_char_index(FontBLF *font, uint charcode)
Definition blf_font.cc:149
char * blf_display_name(FontBLF *font)
Definition blf_font.cc:1475
FontBLF * blf_font_new_from_mem(const char *mem_name, const uchar *mem, const size_t mem_size)
Definition blf_font.cc:1990
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:1168
static bool blf_setup_face(FontBLF *font)
Definition blf_font.cc:1747
void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_size)
Definition blf_font.cc:1995
static void blf_font_draw_buffer_ex(FontBLF *font, GlyphCacheBLF *gc, const char *str, const size_t str_len, ResultBLF *r_info, ft_pix pen_y)
Definition blf_font.cc:733
static void blf_batch_draw_init()
Definition blf_font.cc:189
BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
Definition blf_font.cc:378
static ThreadMutex ft_lib_mutex
Definition blf_font.cc:67
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:817
int blf_font_descender(FontBLF *font)
Definition blf_font.cc:1463
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:965
void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:485
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:450
FontBLF * blf_font_new_from_filepath(const char *filepath)
Definition blf_font.cc:1985
void blf_font_draw_buffer__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1395
int blf_font_height_max(FontBLF *font)
Definition blf_font.cc:1446
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:1213
static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
Definition blf_font.cc:1578
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:1916
void blf_font_draw__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1353
void blf_glyph_cache_clear(FontBLF *font)
Definition blf_glyph.cc:164
GlyphCacheBLF * blf_glyph_cache_acquire(FontBLF *font)
Definition blf_glyph.cc:135
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:148
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
int32_t ft_pix
ft_pix ft_pix_from_int(int v)
#define FT_PIX_ROUND(x)
#define BLF_BATCH_DRAW_LEN_MAX
#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)
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:245
const T * data() const
Definition BLI_array.hh:301
void append(const T &value)
#define printf
DEGForeachIDComponentCallback callback
draw_view in_light_buf[] float
draw_view push_constant(Type::INT, "radiance_src") .push_constant(Type capture_info_buf storage_buf(1, Qualifier::READ, "ObjectBounds", "bounds_buf[]") .push_constant(Type draw_view int
#define str(s)
uint col
format
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
#define unit_float_to_uchar_clamp(val)
MINLINE void zero_v2_int(int r[2])
static ulong * next
float wrap(float value, float max, float min)
Definition node_math.h:71
__int64 int64_t
Definition stdint.h:89
signed int int32_t
Definition stdint.h:77
#define UINT32_MAX
Definition stdint.h:142
unsigned int pos_loc
unsigned int glyph_flags_loc
blender::gpu::Batch * batch
unsigned int col_loc
unsigned int offset_loc
float mat[4][4]
GlyphCacheBLF * glyph_cache
unsigned int glyph_len
GPUVertBufRaw pos_step
GPUVertBufRaw offset_step
unsigned int glyph_size_loc
GPUVertBufRaw glyph_flags_step
GPUVertBufRaw col_step
GPUVertBufRaw glyph_size_step
blender::gpu::VertBuf * verts
char filename[50]
Definition blf_font.cc:1867
unsigned char col_char[4]
unsigned char * cbuf
unsigned char * bitmap
unsigned int c
int ascii_table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE]
int lines
Definition BLF_api.hh:406
int width
Definition BLF_api.hh:410
int ymin
int ymax
int xmin
int xmax
static DynamicLibrary lib