Blender V4.5
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
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. */
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{
190 GPUVertFormat format = {0};
195 g_batch.glyph_size_loc = GPU_vertformat_attr_add(
196 &format, "glyph_size", GPU_COMP_I32, 2, GPU_FETCH_INT);
197 g_batch.glyph_flags_loc = GPU_vertformat_attr_add(
198 &format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
199
202
203 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
204 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
205 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
206 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
207 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_flags_loc, &g_batch.glyph_flags_step);
208 g_batch.glyph_len = 0;
209
210 /* A dummy VBO containing 4 points, attributes are not used. */
212 GPU_vertbuf_data_alloc(*vbo, 4);
213
214 /* We render a quad as a triangle strip and instance it for each glyph. */
216 GPU_batch_instbuf_set(g_batch.batch, g_batch.verts, true);
217}
218
220{
222}
223
225{
226 if (g_batch.batch == nullptr) {
228 }
229
230 const bool font_changed = (g_batch.font != font);
231 const bool simple_shader = ((font->flags & (BLF_ROTATION | BLF_ASPECT)) == 0);
232 const bool shader_changed = (simple_shader != g_batch.simple_shader);
233
234 g_batch.active = g_batch.enabled && simple_shader;
235
236 if (simple_shader) {
237 /* Offset is applied to each glyph. */
238 g_batch.ofs[0] = font->pos[0];
239 g_batch.ofs[1] = font->pos[1];
240 }
241 else {
242 /* Offset is baked in model-view matrix. */
243 zero_v2_int(g_batch.ofs);
244 }
245
246 if (g_batch.active) {
247 float gpumat[4][4];
249
250 bool mat_changed = equals_m4m4(gpumat, g_batch.mat) == false;
251
252 if (mat_changed) {
253 /* Model view matrix is no longer the same.
254 * Flush cache but with the previous matrix. */
257 }
258
259 /* Flush cache if configuration is not the same. */
260 if (mat_changed || font_changed || shader_changed) {
262 g_batch.simple_shader = simple_shader;
263 g_batch.font = font;
264 }
265 else {
266 /* Nothing changed continue batching. */
267 return;
268 }
269
270 if (mat_changed) {
272 /* Save for next `memcmp`. */
273 memcpy(g_batch.mat, gpumat, sizeof(g_batch.mat));
274 }
275 }
276 else {
277 /* Flush cache. */
279 g_batch.font = font;
280 g_batch.simple_shader = simple_shader;
281 }
282}
283
285{
286 GlyphCacheBLF *gc = g_batch.glyph_cache;
287 BLI_assert(gc);
288 BLI_assert(gc->bitmap_len > 0);
289
290 if (gc->bitmap_len > gc->bitmap_len_landed) {
291 const int tex_width = GPU_texture_width(gc->texture);
292
293 int bitmap_len_landed = gc->bitmap_len_landed;
294 int remain = gc->bitmap_len - bitmap_len_landed;
295 int offset_x = bitmap_len_landed % tex_width;
296 int offset_y = bitmap_len_landed / tex_width;
297
298 /* TODO(@germano): Update more than one row in a single call. */
299 while (remain) {
300 int remain_row = tex_width - offset_x;
301 int width = remain > remain_row ? remain_row : remain;
304 &gc->bitmap_result[bitmap_len_landed],
305 offset_x,
306 offset_y,
307 0,
308 width,
309 1,
310 0);
311
312 bitmap_len_landed += width;
313 remain -= width;
314 offset_x = 0;
315 offset_y += 1;
316 }
317
318 gc->bitmap_len_landed = bitmap_len_landed;
319 }
320
321 return gc->texture;
322}
323
325{
326 if (g_batch.glyph_len == 0) {
327 return;
328 }
329
331
332 /* We need to flush widget base first to ensure correct ordering. */
333 if (blf_draw_cache_flush != nullptr) {
335 }
336
338 GPU_vertbuf_data_len_set(*g_batch.verts, g_batch.glyph_len);
339 GPU_vertbuf_use(g_batch.verts); /* Send data. */
340
342 GPU_batch_texture_bind(g_batch.batch, "glyph", texture);
343 /* Setup texture width mask and shift, so that shader can avoid costly divisions. */
344 int tex_width = GPU_texture_width(texture);
345 BLI_assert_msg(is_power_of_2_i(tex_width), "Font texture width must be power of two");
346 int width_shift = 31 - bitscan_reverse_i(tex_width);
347 GPU_batch_uniform_1i(g_batch.batch, "glyph_tex_width_mask", tex_width - 1);
348 GPU_batch_uniform_1i(g_batch.batch, "glyph_tex_width_shift", width_shift);
349 GPU_batch_draw(g_batch.batch);
350
352
354
355 /* Restart to 1st vertex data pointers. */
356 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
357 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
358 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
359 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
360 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_flags_loc, &g_batch.glyph_flags_step);
361 g_batch.glyph_len = 0;
362}
363
365{
366 if (!g_batch.active) {
368 }
369}
370
372
373/* -------------------------------------------------------------------- */
376
377BLI_INLINE ft_pix blf_kerning(FontBLF *font, const GlyphBLF *g_prev, const GlyphBLF *g)
378{
379 ft_pix adjustment = 0;
380
381 /* Small adjust if there is hinting. */
382 adjustment += g->lsb_delta - ((g_prev) ? g_prev->rsb_delta : 0);
383
384 if (FT_HAS_KERNING(font) && g_prev) {
385 FT_Vector delta = {KERNING_ENTRY_UNSET};
386
387 /* Get unscaled kerning value from our cache if ASCII. */
388 if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
389 delta.x = font->kerning_cache->ascii_table[g->c][g_prev->c];
390 }
391
392 /* If not ASCII or not found in cache, ask FreeType for kerning. */
393 if (UNLIKELY(font->face && delta.x == KERNING_ENTRY_UNSET)) {
394 /* Note that this function sets delta values to zero on any error. */
395 FT_Get_Kerning(font->face, g_prev->idx, g->idx, FT_KERNING_UNSCALED, &delta);
396 }
397
398 /* If ASCII we save this value to our cache for quicker access next time. */
399 if ((g_prev->c < KERNING_CACHE_TABLE_SIZE) && (g->c < KERNING_CACHE_TABLE_SIZE)) {
400 font->kerning_cache->ascii_table[g->c][g_prev->c] = int(delta.x);
401 }
402
403 if (delta.x != 0) {
404 /* Convert unscaled design units to pixels and move pen. */
405 adjustment += blf_unscaled_F26Dot6_to_pixels(font, delta.x);
406 }
407 }
408
409 return adjustment;
410}
411
413 GlyphCacheBLF *gc,
414 const GlyphBLF *g_prev,
415 const char *str,
416 size_t str_len,
417 size_t *i_p,
418 int32_t *pen_x)
419{
420 uint charcode = BLI_str_utf8_as_unicode_step_safe(str, str_len, i_p);
421 /* Invalid unicode sequences return the byte value, stepping forward one.
422 * This allows `latin1` to display (which is sometimes used for file-paths). */
423 BLI_assert(charcode != BLI_UTF8_ERR);
424 GlyphBLF *g = blf_glyph_ensure(font, gc, charcode);
425 if (g && pen_x && !(font->flags & BLF_MONOSPACED)) {
426 *pen_x += blf_kerning(font, g_prev, g);
427
428#ifdef BLF_SUBPIXEL_POSITION
429 if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
430 *pen_x = FT_PIX_ROUND(*pen_x);
431 }
432#else
433 *pen_x = FT_PIX_ROUND(*pen_x);
434#endif
435
436#ifdef BLF_SUBPIXEL_AA
437 g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
438#endif
439 }
440 return g;
441}
442
444
445/* -------------------------------------------------------------------- */
448
452[[maybe_unused]] static int blf_str_is_utf8_valid_lazy_init(const char *str,
453 const size_t str_len,
454 int &is_utf8_valid)
455{
456 if (is_utf8_valid == -1) {
457 is_utf8_valid = BLI_str_utf8_invalid_byte(str, str_len) == -1;
458 }
459 return is_utf8_valid;
460}
461
463
464/* -------------------------------------------------------------------- */
467
468static void blf_font_draw_ex(FontBLF *font,
469 GlyphCacheBLF *gc,
470 const char *str,
471 const size_t str_len,
472 ResultBLF *r_info,
473 const ft_pix pen_y)
474{
475 if (str_len == 0) {
476 /* Early exit, don't do any immediate-mode GPU operations. */
477 return;
478 }
479
480 GlyphBLF *g = nullptr;
481 ft_pix pen_x = 0;
482 size_t i = 0;
483
485
486 while ((i < str_len) && str[i]) {
487 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
488 if (UNLIKELY(g == nullptr)) {
489 continue;
490 }
491 /* Do not return this loop if clipped, we want every character tested. */
492 blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
493 pen_x += g->advance_x;
494 }
495
497
498 if (r_info) {
499 r_info->lines = 1;
500 r_info->width = ft_pix_to_int(pen_x);
501 }
502}
503void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
504{
506 blf_font_draw_ex(font, gc, str, str_len, r_info, 0);
508}
509
511 FontBLF *font, const char *str, const size_t str_len, int cwidth, int tab_columns)
512{
513 GlyphBLF *g;
514 int columns = 0;
515 ft_pix pen_x = 0, pen_y = 0;
516 ft_pix cwidth_fpx = ft_pix_from_int(cwidth);
517
518 size_t i = 0;
519
521
523
524 while ((i < str_len) && str[i]) {
525 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i, nullptr);
526
527 if (UNLIKELY(g == nullptr)) {
528 continue;
529 }
530 /* Do not return this loop if clipped, we want every character tested. */
531 blf_glyph_draw(font, gc, g, ft_pix_to_int_floor(pen_x), ft_pix_to_int_floor(pen_y));
532
533 const int col = UNLIKELY(g->c == '\t') ? (tab_columns - (columns % tab_columns)) :
534 BLI_wcwidth_safe(char32_t(g->c));
535 columns += col;
536 pen_x += cwidth_fpx * col;
537 }
538
540
542 return columns;
543}
544
545#ifndef WITH_HEADLESS
547 uint icon_id,
548 float x,
549 float y,
550 float size,
551 const float color[4],
552 float outline_alpha,
553 bool multicolor,
554 blender::FunctionRef<void(std::string &)> edit_source_cb)
555{
556 blf_font_size(font, size);
557 font->pos[0] = int(x);
558 font->pos[1] = int(y);
559 font->pos[2] = 0;
560
561 if (color != nullptr) {
562 rgba_float_to_uchar(font->color, color);
563 }
564
565 if (outline_alpha > 0.0f) {
566 font->flags |= BLF_SHADOW;
568 font->shadow_x = 0;
569 font->shadow_y = 0;
570 font->shadow_color[0] = 0;
571 font->shadow_color[1] = 0;
572 font->shadow_color[2] = 0;
573 font->shadow_color[3] = char(outline_alpha * 255.0f);
574 }
575
578
579 GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor, edit_source_cb);
580 if (g) {
581 blf_glyph_draw(font, gc, g, 0, 0);
582 }
583
584 if (outline_alpha > 0) {
585 font->flags &= ~BLF_SHADOW;
586 }
587
590}
591
593 uint icon_id,
594 float size,
595 int *r_width,
596 int *r_height,
597 bool multicolor,
598 blender::FunctionRef<void(std::string &)> edit_source_cb)
599{
600 blf_font_size(font, size);
602 GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor, edit_source_cb);
603
604 if (!g) {
606 *r_width = 0;
607 *r_height = 0;
608 return {};
609 }
610
611 *r_width = g->dims[0];
612 *r_height = g->dims[1];
613 blender::Array<uchar> bitmap(g->dims[0] * g->dims[1] * 4);
614
615 if (g->num_channels == 4) {
616 memcpy(bitmap.data(), g->bitmap, size_t(bitmap.size()));
617 }
618 else if (g->num_channels == 1) {
619 for (int64_t y = 0; y < int64_t(g->dims[1]); y++) {
620 for (int64_t x = 0; x < int64_t(g->dims[0]); x++) {
621 int64_t offs_in = (y * int64_t(g->pitch)) + x;
622 bitmap[int64_t(offs_in * 4)] = g->bitmap[offs_in];
623 bitmap[int64_t(offs_in * 4 + 1)] = g->bitmap[offs_in];
624 bitmap[int64_t(offs_in * 4 + 2)] = g->bitmap[offs_in];
625 bitmap[int64_t(offs_in * 4 + 3)] = g->bitmap[offs_in];
626 }
627 }
628 }
630 return bitmap;
631}
632#endif /* WITH_HEADLESS */
633
635
636/* -------------------------------------------------------------------- */
639
644 GlyphBLF *g,
645 const ft_pix pen_x,
646 const ft_pix pen_y_basis)
647{
648 const int chx = ft_pix_to_int(pen_x + ft_pix_from_int(g->pos[0]));
649 const int chy = ft_pix_to_int(pen_y_basis + ft_pix_from_int(g->dims[1]));
650
651 ft_pix pen_y = (g->pitch < 0) ? (pen_y_basis + ft_pix_from_int(g->dims[1] - g->pos[1])) :
652 (pen_y_basis - ft_pix_from_int(g->dims[1] - g->pos[1]));
653
654 if ((chx + g->dims[0]) < 0 || /* Out of bounds: left. */
655 chx >= buf_info->dims[0] || /* Out of bounds: right. */
656 (ft_pix_to_int(pen_y) + g->dims[1]) < 0 || /* Out of bounds: bottom. */
657 ft_pix_to_int(pen_y) >= buf_info->dims[1] /* Out of bounds: top. */
658 )
659 {
660 return;
661 }
662
663 /* Don't draw beyond the buffer bounds. */
664 int width_clip = g->dims[0];
665 int height_clip = g->dims[1];
666 int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
667
668 if (width_clip + chx > buf_info->dims[0]) {
669 width_clip -= chx + width_clip - buf_info->dims[0];
670 }
671 if (height_clip + ft_pix_to_int(pen_y) > buf_info->dims[1]) {
672 height_clip -= ft_pix_to_int(pen_y) + height_clip - buf_info->dims[1];
673 }
674
675 /* Clip drawing below the image. */
676 if (pen_y < 0) {
677 yb_start += (g->pitch < 0) ? -ft_pix_to_int(pen_y) : ft_pix_to_int(pen_y);
678 height_clip += ft_pix_to_int(pen_y);
679 pen_y = 0;
680 }
681
682 /* Avoid conversions in the pixel writing loop. */
683 const int pen_y_px = ft_pix_to_int(pen_y);
684
685 const float *b_col_float = buf_info->col_float;
686 const uchar *b_col_char = buf_info->col_char;
687
688 if (buf_info->fbuf) {
689 int yb = yb_start;
690 for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
691 const int x_start = (chx >= 0) ? 0 : -chx;
692 const uchar *a_ptr = g->bitmap + x_start + (yb * g->pitch);
693 const int64_t buf_ofs = (int64_t(buf_info->dims[0]) * (pen_y_px + y) + (chx + x_start)) * 4;
694 float *fbuf = buf_info->fbuf + buf_ofs;
695 for (int x = x_start; x < width_clip; x++, a_ptr++, fbuf += 4) {
696 const char a_byte = *a_ptr;
697 if (a_byte) {
698 const float a = (a_byte / 255.0f) * b_col_float[3];
699
700 float font_pixel[4];
701 font_pixel[0] = b_col_float[0] * a;
702 font_pixel[1] = b_col_float[1] * a;
703 font_pixel[2] = b_col_float[2] * a;
704 font_pixel[3] = a;
705 blend_color_mix_float(fbuf, fbuf, font_pixel);
706 }
707 }
708
709 if (g->pitch < 0) {
710 yb++;
711 }
712 else {
713 yb--;
714 }
715 }
716 }
717
718 if (buf_info->cbuf) {
719 int yb = yb_start;
720 for (int y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
721 const int x_start = (chx >= 0) ? 0 : -chx;
722 const uchar *a_ptr = g->bitmap + x_start + (yb * g->pitch);
723 const int64_t buf_ofs = (int64_t(buf_info->dims[0]) * (pen_y_px + y) + (chx + x_start)) * 4;
724 uchar *cbuf = buf_info->cbuf + buf_ofs;
725 for (int x = x_start; x < width_clip; x++, a_ptr++, cbuf += 4) {
726 const char a_byte = *a_ptr;
727
728 if (a_byte) {
729 const float a = (a_byte / 255.0f) * b_col_float[3];
730
731 uchar font_pixel[4];
732 font_pixel[0] = b_col_char[0];
733 font_pixel[1] = b_col_char[1];
734 font_pixel[2] = b_col_char[2];
735 font_pixel[3] = unit_float_to_uchar_clamp(a);
736 blend_color_mix_byte(cbuf, cbuf, font_pixel);
737 }
738 }
739
740 if (g->pitch < 0) {
741 yb++;
742 }
743 else {
744 yb--;
745 }
746 }
747 }
748}
749
750/* Sanity checks are done by BLF_draw_buffer() */
752 GlyphCacheBLF *gc,
753 const char *str,
754 const size_t str_len,
755 ResultBLF *r_info,
756 ft_pix pen_y)
757{
758 GlyphBLF *g = nullptr;
759 ft_pix pen_x = ft_pix_from_int(font->pos[0]);
760 ft_pix pen_y_basis = ft_pix_from_int(font->pos[1]) + pen_y;
761 size_t i = 0;
762
763 /* Buffer specific variables. */
764 FontBufInfoBLF *buf_info = &font->buf_info;
765
766 /* Another buffer specific call for color conversion. */
767
768 while ((i < str_len) && str[i]) {
769 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
770
771 if (UNLIKELY(g == nullptr)) {
772 continue;
773 }
774 blf_glyph_draw_buffer(buf_info, g, pen_x, pen_y_basis);
775 pen_x += g->advance_x;
776 }
777
778 if (r_info) {
779 r_info->lines = 1;
780 r_info->width = ft_pix_to_int(pen_x);
781 }
782}
783
784void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
785{
787 blf_font_draw_buffer_ex(font, gc, str, str_len, r_info, 0);
789}
790
792
793/* -------------------------------------------------------------------- */
800
802 GlyphCacheBLF *gc,
803 const GlyphBLF *g_prev,
804 GlyphBLF *g,
805 ft_pix *pen_x,
806 const int width_i)
807{
808 if (UNLIKELY(g == nullptr)) {
809 /* Continue the calling loop. */
810 return false;
811 }
812
813 if (!(font->flags & BLF_MONOSPACED)) {
814 *pen_x += blf_kerning(font, g_prev, g);
815
816#ifdef BLF_SUBPIXEL_POSITION
817 if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
818 *pen_x = FT_PIX_ROUND(*pen_x);
819 }
820#else
821 *pen_x = FT_PIX_ROUND(*pen_x);
822#endif
823
824#ifdef BLF_SUBPIXEL_AA
825 g = blf_glyph_ensure_subpixel(font, gc, g, *pen_x);
826#endif
827 }
828
829 *pen_x += g->advance_x;
830
831 /* When true, break the calling loop. */
832 return (ft_pix_to_int(*pen_x) >= width_i);
833}
834
836 FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
837{
838 GlyphBLF *g;
839 const GlyphBLF *g_prev;
840 ft_pix pen_x;
841 ft_pix width_new;
842 size_t i, i_prev;
843
845 const int width_i = width;
846
847 for (i_prev = i = 0, width_new = pen_x = 0, g_prev = nullptr; (i < str_len) && str[i];
848 i_prev = i, width_new = pen_x, g_prev = g)
849 {
850 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i, nullptr);
851 if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width_i)) {
852 break;
853 }
854 }
855
856 if (r_width) {
857 *r_width = ft_pix_to_int(width_new);
858 }
859
861 return i_prev;
862}
863
865 FontBLF *font, const char *str, const size_t str_len, int width, int *r_width)
866{
867 GlyphBLF *g, *g_prev;
868 ft_pix pen_x, width_new;
869 size_t i, i_prev, i_tmp;
870 std::optional<size_t> i_next = {};
871 const char *s, *s_prev;
872
874#ifndef NDEBUG
875 int is_utf8_valid = -1;
876#endif
877
878 i = BLI_strnlen(str, str_len);
880 i = size_t(s - str);
881 s_prev = BLI_str_find_prev_char_utf8(s, str);
882 i_prev = size_t(s_prev - str);
883
884 i_tmp = i;
885 g = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i_tmp, nullptr);
886 for (width_new = pen_x = 0; (s != nullptr && i > 0);
887 i_next = i, i = i_prev, s = s_prev, g = g_prev, g_prev = nullptr, width_new = pen_x)
888 {
889 s_prev = BLI_str_find_prev_char_utf8(s, str);
890 i_prev = size_t(s_prev - str);
891
892 i_tmp = i_prev;
893 g_prev = blf_glyph_from_utf8_and_step(font, gc, nullptr, str, str_len, &i_tmp, nullptr);
894 BLI_assert(i_tmp == i ||
895 /* TODO: proper handling of non UTF8 strings. */
896 (blf_str_is_utf8_valid_lazy_init(str, str_len, is_utf8_valid) == 0));
897
898 if (blf_font_width_to_strlen_glyph_process(font, gc, g_prev, g, &pen_x, width)) {
899 break;
900 }
901 }
902
903 if (r_width) {
904 *r_width = ft_pix_to_int(width_new);
905 }
906
908 return i_next ? *i_next : i;
909}
910
912
913/* -------------------------------------------------------------------- */
916
918 GlyphCacheBLF *gc,
919 const char *str,
920 const size_t str_len,
921 rcti *r_box,
922 ResultBLF *r_info,
923 ft_pix pen_y)
924{
925 const GlyphBLF *g = nullptr;
926 ft_pix pen_x = 0;
927 size_t i = 0;
928
929 ft_pix box_xmin = ft_pix_from_int(32000);
930 ft_pix box_xmax = ft_pix_from_int(-32000);
931 ft_pix box_ymin = ft_pix_from_int(32000);
932 ft_pix box_ymax = ft_pix_from_int(-32000);
933
934 while ((i < str_len) && str[i]) {
935 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
936
937 if (UNLIKELY(g == nullptr)) {
938 continue;
939 }
940 const ft_pix pen_x_next = pen_x + g->advance_x;
941
942 const ft_pix gbox_xmin = std::min(pen_x, pen_x + g->box_xmin);
943 /* Mono-spaced characters should only use advance. See #130385. */
944 const ft_pix gbox_xmax = (font->flags & BLF_MONOSPACED) ?
945 pen_x_next :
946 std::max(pen_x_next, pen_x + g->box_xmax);
947 const ft_pix gbox_ymin = g->box_ymin + pen_y;
948 const ft_pix gbox_ymax = g->box_ymax + pen_y;
949
950 box_xmin = std::min(gbox_xmin, box_xmin);
951 box_ymin = std::min(gbox_ymin, box_ymin);
952
953 box_xmax = std::max(gbox_xmax, box_xmax);
954 box_ymax = std::max(gbox_ymax, box_ymax);
955
956 pen_x = pen_x_next;
957 }
958
959 if (box_xmin > box_xmax) {
960 box_xmin = 0;
961 box_ymin = 0;
962 box_xmax = 0;
963 box_ymax = 0;
964 }
965
966 r_box->xmin = ft_pix_to_int_floor(box_xmin);
967 r_box->xmax = ft_pix_to_int_ceil(box_xmax);
968 r_box->ymin = ft_pix_to_int_floor(box_ymin);
969 r_box->ymax = ft_pix_to_int_ceil(box_ymax);
970
971 if (r_info) {
972 r_info->lines = 1;
973 r_info->width = ft_pix_to_int(pen_x);
974 }
975}
977 FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
978{
980 blf_font_boundbox_ex(font, gc, str, str_len, r_box, r_info, 0);
982}
983
985 const char *str,
986 const size_t str_len,
987 float *r_width,
988 float *r_height,
989 ResultBLF *r_info)
990{
991 float xa, ya;
992 rcti box;
993
994 if (font->flags & BLF_ASPECT) {
995 xa = font->aspect[0];
996 ya = font->aspect[1];
997 }
998 else {
999 xa = 1.0f;
1000 ya = 1.0f;
1001 }
1002
1003 if (font->flags & BLF_WORD_WRAP) {
1004 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
1005 }
1006 else {
1007 blf_font_boundbox(font, str, str_len, &box, r_info);
1008 }
1009 *r_width = (float(BLI_rcti_size_x(&box)) * xa);
1010 *r_height = (float(BLI_rcti_size_y(&box)) * ya);
1011}
1012
1013float blf_font_width(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
1014{
1015 float xa;
1016 rcti box;
1017
1018 if (font->flags & BLF_ASPECT) {
1019 xa = font->aspect[0];
1020 }
1021 else {
1022 xa = 1.0f;
1023 }
1024
1025 if (font->flags & BLF_WORD_WRAP) {
1026 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
1027 }
1028 else {
1029 blf_font_boundbox(font, str, str_len, &box, r_info);
1030 }
1031 return float(BLI_rcti_size_x(&box)) * xa;
1032}
1033
1034float blf_font_height(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
1035{
1036 float ya;
1037 rcti box;
1038
1039 if (font->flags & BLF_ASPECT) {
1040 ya = font->aspect[1];
1041 }
1042 else {
1043 ya = 1.0f;
1044 }
1045
1046 if (font->flags & BLF_WORD_WRAP) {
1047 blf_font_boundbox__wrap(font, str, str_len, &box, r_info);
1048 }
1049 else {
1050 blf_font_boundbox(font, str, str_len, &box, r_info);
1051 }
1052 return float(BLI_rcti_size_y(&box)) * ya;
1053}
1054
1056{
1057 const GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1058 float width = (gc) ? float(gc->fixed_width) : font->size / 2.0f;
1060 return width;
1061}
1062
1063int blf_font_glyph_advance(FontBLF *font, const char *str)
1064{
1066 const uint charcode = BLI_str_utf8_as_unicode_safe(str);
1067 const GlyphBLF *g = blf_glyph_ensure(font, gc, charcode);
1068
1069 if (UNLIKELY(g == nullptr)) {
1071 return 0;
1072 }
1073
1074 const int glyph_advance = ft_pix_to_int(g->advance_x);
1075
1077 return glyph_advance;
1078}
1079
1081 const char *str,
1082 const size_t str_len,
1083 BLF_GlyphBoundsFn user_fn,
1084 void *user_data)
1085{
1086 if (str_len == 0 || str[0] == 0) {
1087 /* Early exit. */
1088 return;
1089 }
1090
1091 const GlyphBLF *g = nullptr;
1092 ft_pix pen_x = 0;
1093 size_t i = 0;
1094
1096
1097 while ((i < str_len) && str[i]) {
1098 const size_t i_curr = i;
1099 g = blf_glyph_from_utf8_and_step(font, gc, g, str, str_len, &i, &pen_x);
1100
1101 if (UNLIKELY(g == nullptr || g->advance_x == 0)) {
1102 /* Ignore combining characters like diacritical marks. */
1103 continue;
1104 }
1105 rcti bounds;
1110
1111 if (user_fn(str, i_curr, &bounds, user_data) == false) {
1112 break;
1113 }
1114 pen_x += g->advance_x;
1115 }
1116
1118}
1119
1126
1127static bool blf_cursor_position_foreach_glyph(const char * /*str*/,
1128 const size_t str_step_ofs,
1129 const rcti *bounds,
1130 void *user_data)
1131{
1133 user_data);
1134 if (data->location_x < (bounds->xmin + bounds->xmax) / 2) {
1135 data->r_offset = str_step_ofs;
1136 return false;
1137 }
1138 return true;
1139}
1140
1142 const char *str,
1143 size_t str_len,
1144 int location_x)
1145{
1146 /* Do not early exit if location_x <= 0, as this can result in an incorrect
1147 * offset for RTL text. Instead of offset of character responsible for first
1148 * glyph you'd get offset of first character, which could be the last glyph. */
1149 if (!str || !str[0] || !str_len) {
1150 return 0;
1151 }
1152
1154 data.location_x = location_x;
1155 data.r_offset = size_t(-1);
1156
1158
1159 if (data.r_offset == size_t(-1)) {
1160 /* We are to the right of the string, so return position of null terminator. */
1161 data.r_offset = BLI_strnlen(str, str_len);
1162 }
1163 else if (BLI_str_utf8_char_width_or_error(&str[data.r_offset]) == 0) {
1164 /* This is a combining character, so move to previous visible valid char. */
1165 int offset = int(data.r_offset);
1166 BLI_str_cursor_step_prev_utf8(str, int(str_len), &offset);
1167 data.r_offset = size_t(offset);
1168 }
1169
1170 return data.r_offset;
1171}
1172
1177
1178static bool blf_str_offset_foreach_glyph(const char * /*str*/,
1179 const size_t str_step_ofs,
1180 const rcti *bounds,
1181 void *user_data)
1182{
1184 if (data->str_offset == str_step_ofs) {
1185 data->bounds = *bounds;
1186 return false;
1187 }
1188 return true;
1189}
1190
1192 const char *str,
1193 size_t str_offset,
1194 rcti *r_glyph_bounds)
1195{
1197 data.str_offset = str_offset;
1198 data.bounds = {0};
1199
1201 *r_glyph_bounds = data.bounds;
1202}
1203
1205 const char *str,
1206 const size_t str_len,
1207 const size_t str_offset,
1208 const int cursor_width)
1209{
1210 if (!str || !str[0]) {
1211 return 0;
1212 }
1213
1214 /* Right edge of the previous character, if available. */
1215 rcti prev = {0};
1216 if (str_offset > 0) {
1217 blf_str_offset_to_glyph_bounds(font, str, str_offset - 1, &prev);
1218 }
1219
1220 /* Left edge of the next character, if available. */
1221 rcti next = {0};
1222 if (str_offset < strlen(str)) {
1223 blf_str_offset_to_glyph_bounds(font, str, str_offset, &next);
1224 }
1225
1226 if ((prev.xmax == prev.xmin) && next.xmax) {
1227 /* Nothing (or a space) to the left, so align to right character. */
1228 return next.xmin - (cursor_width / 2);
1229 }
1230 if ((prev.xmax != prev.xmin) && !next.xmax) {
1231 /* End of string, so align to last character. */
1232 return prev.xmax - (cursor_width / 2);
1233 }
1234 if (prev.xmax && next.xmax) {
1235 /* Between two characters, so use the center. */
1236 if (next.xmin >= prev.xmax || next.xmin == next.xmax) {
1237 return ((prev.xmax + next.xmin) - cursor_width) / 2;
1238 }
1239 /* A nicer center if reversed order - RTL. */
1240 return ((next.xmax + prev.xmin) - cursor_width) / 2;
1241 }
1242 if (!str_offset) {
1243 /* Start of string. */
1244 return 0 - cursor_width;
1245 }
1246 return int(blf_font_width(font, str, str_len, nullptr));
1247}
1248
1250 FontBLF *font, const char *str, size_t str_len, size_t sel_start, size_t sel_length)
1251{
1253 const int start = blf_str_offset_to_cursor(font, str, str_len, sel_start, 0);
1254 const int end = blf_str_offset_to_cursor(font, str, str_len, sel_start + sel_length, 0);
1255 boxes.append(blender::Bounds(start, end));
1256 return boxes;
1257}
1258
1260
1261/* -------------------------------------------------------------------- */
1264
1275 const char *str,
1276 const size_t str_len,
1277 const int max_pixel_width,
1278 BLFWrapMode mode,
1279 ResultBLF *r_info,
1280 void (*callback)(FontBLF *font,
1281 GlyphCacheBLF *gc,
1282 const char *str,
1283 const size_t str_len,
1284 ft_pix pen_y,
1285 void *userdata),
1286 void *userdata)
1287{
1288 GlyphBLF *g = nullptr;
1289 const GlyphBLF *g_prev = nullptr;
1290 ft_pix pen_x = 0;
1291 ft_pix pen_y = 0;
1292 size_t i = 0;
1293 int lines = 0;
1294 ft_pix pen_x_next = 0;
1295
1296 /* Size of characters not shown at the end of the wrapped line. */
1297 size_t clip_bytes = 0;
1298
1299 ft_pix line_height = blf_font_height_max_ft_pix(font);
1300
1302
1303 struct WordWrapVars {
1304 ft_pix wrap_width;
1305 size_t start, last[2];
1306 } wrap = {max_pixel_width != -1 ? ft_pix_from_int(max_pixel_width) : INT_MAX, 0, {0, 0}};
1307
1308 // printf("%s wrapping (%d, %d) `%s`:\n", __func__, str_len, strlen(str), str);
1309 while ((i < str_len) && str[i]) {
1310
1311 /* Wrap variables. */
1312 const size_t i_curr = i;
1313 bool do_draw = false;
1314
1315 g = blf_glyph_from_utf8_and_step(font, gc, g_prev, str, str_len, &i, &pen_x);
1316
1317 const ft_pix advance_x = g ? g->advance_x : 0;
1318 const uint codepoint = BLI_str_utf8_as_unicode_safe(&str[i_curr]);
1319 const uint codepoint_prev = g_prev ? g_prev->c : 0;
1320
1329 pen_x_next = pen_x + advance_x;
1330
1331 if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) {
1332 do_draw = true;
1333 }
1334 else if (UNLIKELY((int(mode) & int(BLFWrapMode::HardLimit)) &&
1335 (pen_x_next >= wrap.wrap_width) && (advance_x != 0)))
1336 {
1337 wrap.last[0] = i_curr;
1338 wrap.last[1] = i_curr;
1339 do_draw = true;
1340 clip_bytes = 0;
1341 }
1342 else if (UNLIKELY(((i < str_len) && str[i]) == 0)) {
1343 /* Need check here for trailing newline, else we draw it. */
1344 wrap.last[0] = i + ((codepoint != '\n') ? 1 : 0);
1345 wrap.last[1] = i;
1346 do_draw = true;
1347 clip_bytes = 0;
1348 }
1349 else if (UNLIKELY(codepoint == '\n')) {
1350 wrap.last[0] = i_curr + 1;
1351 wrap.last[1] = i;
1352 do_draw = true;
1353 clip_bytes = 1;
1354 }
1355 else if (UNLIKELY(((int(mode) & int(BLFWrapMode::Minimal)) == int(BLFWrapMode::Minimal)) &&
1356 codepoint != ' ' && (g_prev ? g_prev->c == ' ' : false)))
1357 {
1358 wrap.last[0] = i_curr;
1359 wrap.last[1] = i_curr;
1360 clip_bytes = 1;
1361 }
1362 else if (UNLIKELY(int(mode) & int(BLFWrapMode::Path))) {
1363 if (ELEM(codepoint, SEP, ' ', '?', '&', '=')) {
1364 /* Break and leave at the end of line. */
1365 wrap.last[0] = i;
1366 wrap.last[1] = i;
1367 clip_bytes = 0;
1368 }
1369 else if (ELEM(codepoint, '-', '_', '.', '%')) {
1370 /* Break and move to the next line. */
1371 wrap.last[0] = i_curr;
1372 wrap.last[1] = i_curr;
1373 clip_bytes = 0;
1374 }
1375 }
1376 else if (UNLIKELY((int(mode) & int(BLFWrapMode::Typographical)) &&
1378 BLI_str_utf32_char_is_breaking_space(codepoint_prev)))
1379 {
1380 /* Optional break after space, removing it. */
1381 wrap.last[0] = i_curr;
1382 wrap.last[1] = i_curr;
1383 clip_bytes = BLI_str_utf8_from_unicode_len(codepoint_prev);
1384 }
1385 else if (UNLIKELY((int(mode) & int(BLFWrapMode::Typographical)) &&
1386 BLI_str_utf32_char_is_optional_break_after(codepoint, codepoint_prev)))
1387 {
1388 /* Optional break after various characters, keeping it. */
1389 wrap.last[0] = i;
1390 wrap.last[1] = i;
1391 clip_bytes = 0;
1392 }
1393 else if (UNLIKELY((int(mode) & int(BLFWrapMode::Typographical)) &&
1394 BLI_str_utf32_char_is_optional_break_before(codepoint, codepoint_prev)))
1395 {
1396 /* Optional break before various characters. */
1397 wrap.last[0] = i_curr;
1398 wrap.last[1] = i_curr;
1399 clip_bytes = 0;
1400 }
1401
1402 if (UNLIKELY(do_draw)) {
1403#if 0
1404 printf("(%03d..%03d) `%.*s`\n",
1405 wrap.start,
1406 wrap.last[0],
1407 (wrap.last[0] - wrap.start) - 1,
1408 &str[wrap.start]);
1409#endif
1410
1411 callback(
1412 font, gc, &str[wrap.start], (wrap.last[0] - wrap.start) - clip_bytes, pen_y, userdata);
1413 wrap.start = wrap.last[0];
1414 i = wrap.last[1];
1415 pen_x = 0;
1416 pen_y -= line_height;
1417 g_prev = nullptr;
1418 lines += 1;
1419 continue;
1420 }
1421
1422 pen_x = pen_x_next;
1423 g_prev = g;
1424 }
1425
1426 // printf("done! lines: %d, width, %d\n", lines, pen_x_next);
1427
1428 if (r_info) {
1429 r_info->lines = lines;
1430 /* Width of last line only (with wrapped lines). */
1431 r_info->width = ft_pix_to_int(pen_x_next);
1432 }
1433
1435}
1436
1439 GlyphCacheBLF *gc,
1440 const char *str,
1441 const size_t str_len,
1442 ft_pix pen_y,
1443 void * /*userdata*/)
1444{
1445 blf_font_draw_ex(font, gc, str, str_len, nullptr, pen_y);
1446}
1447void blf_font_draw__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
1448{
1450 str,
1451 str_len,
1452 font->wrap_width,
1453 font->wrap_mode,
1454 r_info,
1456 nullptr);
1457}
1458
1461 GlyphCacheBLF *gc,
1462 const char *str,
1463 const size_t str_len,
1464 ft_pix pen_y,
1465 void *userdata)
1466{
1467 rcti *box = static_cast<rcti *>(userdata);
1468 rcti box_single;
1469
1470 blf_font_boundbox_ex(font, gc, str, str_len, &box_single, nullptr, pen_y);
1471 BLI_rcti_union(box, &box_single);
1472}
1474 FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
1475{
1476 r_box->xmin = 32000;
1477 r_box->xmax = -32000;
1478 r_box->ymin = 32000;
1479 r_box->ymax = -32000;
1480
1482 str,
1483 str_len,
1484 font->wrap_width,
1485 font->wrap_mode,
1486 r_info,
1488 r_box);
1489}
1490
1493 GlyphCacheBLF *gc,
1494 const char *str,
1495 const size_t str_len,
1496 ft_pix pen_y,
1497 void * /*userdata*/)
1498{
1499 blf_font_draw_buffer_ex(font, gc, str, str_len, nullptr, pen_y);
1500}
1502 const char *str,
1503 const size_t str_len,
1504 ResultBLF *r_info)
1505{
1507 str,
1508 str_len,
1509 font->wrap_width,
1510 font->wrap_mode,
1511 r_info,
1513 nullptr);
1514}
1515
1517static void blf_font_string_wrap_cb(FontBLF * /*font*/,
1518 GlyphCacheBLF * /*gc*/,
1519 const char *str,
1520 const size_t str_len,
1521 ft_pix /*pen_y*/,
1522 void *str_list_ptr)
1523{
1525 str_list_ptr);
1526 blender::StringRef line(str, str + str_len);
1527 list->append(line);
1528}
1529
1532 int max_pixel_width,
1533 BLFWrapMode mode)
1534{
1537 str.data(),
1538 size_t(str.size()),
1539 max_pixel_width,
1540 mode,
1541 nullptr,
1543 &list);
1544 return list;
1545}
1546
1548
1549/* -------------------------------------------------------------------- */
1552
1554{
1555 blf_ensure_size(font);
1556 /* #Metrics::height is rounded to pixel. Force minimum of one pixel. */
1557 return std::max((ft_pix)font->ft_size->metrics.height, ft_pix_from_int(1));
1558}
1559
1561{
1563}
1564
1566{
1567 blf_ensure_size(font);
1568 /* #Metrics::max_advance is rounded to pixel. Force minimum of one pixel. */
1569 return std::max((ft_pix)font->ft_size->metrics.max_advance, ft_pix_from_int(1));
1570}
1571
1573{
1575}
1576
1578{
1579 blf_ensure_size(font);
1580 return ft_pix_to_int((ft_pix)font->ft_size->metrics.descender);
1581}
1582
1584{
1585 blf_ensure_size(font);
1586 return ft_pix_to_int((ft_pix)font->ft_size->metrics.ascender);
1587}
1588
1590{
1591 if (!blf_ensure_face(font) || !font->face->family_name) {
1592 return nullptr;
1593 }
1594 return BLI_sprintfN("%s %s", font->face->family_name, font->face->style_name);
1595}
1596
1598
1599/* -------------------------------------------------------------------- */
1602
1604{
1605 memset(&g_batch, 0, sizeof(g_batch));
1606 int err = FT_Init_FreeType(&ft_lib);
1607 if (err == FT_Err_Ok) {
1608 /* Create a FreeType cache manager. */
1609 err = FTC_Manager_New(ft_lib,
1614 nullptr,
1615 &ftc_manager);
1616 if (err == FT_Err_Ok) {
1617 /* Create a character-map cache to speed up glyph index lookups. */
1618 err = FTC_CMapCache_New(ftc_manager, &ftc_charmap_cache);
1619 }
1620 }
1621 return err;
1622}
1623
1625{
1626 if (ftc_manager) {
1627 FTC_Manager_Done(ftc_manager);
1628 }
1629 if (ft_lib) {
1630 FT_Done_FreeType(ft_lib);
1631 }
1633}
1634
1635void BLF_cache_flush_set_fn(void (*cache_flush_fn)())
1636{
1637 blf_draw_cache_flush = cache_flush_fn;
1638}
1639
1641
1642/* -------------------------------------------------------------------- */
1645
1646static void blf_font_fill(FontBLF *font)
1647{
1648 font->aspect[0] = 1.0f;
1649 font->aspect[1] = 1.0f;
1650 font->aspect[2] = 1.0f;
1651 font->pos[0] = 0;
1652 font->pos[1] = 0;
1653 font->angle = 0.0f;
1654
1655 /* Use an easily identifiable bright color (yellow)
1656 * so its clear when #BLF_color calls are missing. */
1657 font->color[0] = 255;
1658 font->color[1] = 255;
1659 font->color[2] = 0;
1660 font->color[3] = 255;
1661
1662 font->clip_rec.xmin = 0;
1663 font->clip_rec.xmax = 0;
1664 font->clip_rec.ymin = 0;
1665 font->clip_rec.ymax = 0;
1666 font->flags = 0;
1667 font->size = 0;
1668 font->char_weight = 400;
1669 font->char_slant = 0.0f;
1670 font->char_width = 1.0f;
1671 font->char_spacing = 0.0f;
1672
1673 font->kerning_cache = nullptr;
1674 font->tex_size_max = -1;
1675
1676 font->buf_info.fbuf = nullptr;
1677 font->buf_info.cbuf = nullptr;
1678 font->buf_info.dims[0] = 0;
1679 font->buf_info.dims[1] = 0;
1680 font->buf_info.col_init[0] = 0;
1681 font->buf_info.col_init[1] = 0;
1682 font->buf_info.col_init[2] = 0;
1683 font->buf_info.col_init[3] = 0;
1684}
1685
1690static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
1691{
1692 /* Members with non-zero defaults. */
1693 metrics->weight = 400;
1694 metrics->width = 1.0f;
1695
1696 const TT_OS2 *os2_table = (const TT_OS2 *)FT_Get_Sfnt_Table(face, FT_SFNT_OS2);
1697 if (os2_table) {
1698 /* The default (resting) font weight. */
1699 if (os2_table->usWeightClass >= 1 && os2_table->usWeightClass <= 1000) {
1700 metrics->weight = short(os2_table->usWeightClass);
1701 }
1702
1703 /* Width value is one of integers 1-9 with known values. */
1704 if (os2_table->usWidthClass >= 1 && os2_table->usWidthClass <= 9) {
1705 switch (os2_table->usWidthClass) {
1706 case 1:
1707 metrics->width = 0.5f;
1708 break;
1709 case 2:
1710 metrics->width = 0.625f;
1711 break;
1712 case 3:
1713 metrics->width = 0.75f;
1714 break;
1715 case 4:
1716 metrics->width = 0.875f;
1717 break;
1718 case 5:
1719 metrics->width = 1.0f;
1720 break;
1721 case 6:
1722 metrics->width = 1.125f;
1723 break;
1724 case 7:
1725 metrics->width = 1.25f;
1726 break;
1727 case 8:
1728 metrics->width = 1.5f;
1729 break;
1730 case 9:
1731 metrics->width = 2.0f;
1732 break;
1733 }
1734 }
1735
1736 metrics->strikeout_position = short(os2_table->yStrikeoutPosition);
1737 metrics->strikeout_thickness = short(os2_table->yStrikeoutSize);
1738 metrics->subscript_size = short(os2_table->ySubscriptYSize);
1739 metrics->subscript_xoffset = short(os2_table->ySubscriptXOffset);
1740 metrics->subscript_yoffset = short(os2_table->ySubscriptYOffset);
1741 metrics->superscript_size = short(os2_table->ySuperscriptYSize);
1742 metrics->superscript_xoffset = short(os2_table->ySuperscriptXOffset);
1743 metrics->superscript_yoffset = short(os2_table->ySuperscriptYOffset);
1744 metrics->family_class = short(os2_table->sFamilyClass);
1745 metrics->selection_flags = short(os2_table->fsSelection);
1746 metrics->first_charindex = short(os2_table->usFirstCharIndex);
1747 metrics->last_charindex = short(os2_table->usLastCharIndex);
1748 if (os2_table->version > 1) {
1749 metrics->cap_height = short(os2_table->sCapHeight);
1750 metrics->x_height = short(os2_table->sxHeight);
1751 }
1752 }
1753
1754 /* The Post table usually contains a slant value, but in counter-clockwise degrees. */
1755 const TT_Postscript *post_table = (const TT_Postscript *)FT_Get_Sfnt_Table(face, FT_SFNT_POST);
1756 if (post_table) {
1757 if (post_table->italicAngle != 0) {
1758 metrics->slant = float(post_table->italicAngle) / -65536.0f;
1759 }
1760 }
1761
1762 /* Metrics copied from those gathered by FreeType. */
1763 metrics->units_per_EM = short(face->units_per_EM);
1764 metrics->ascender = short(face->ascender);
1765 metrics->descender = short(face->descender);
1766 metrics->line_height = short(face->height);
1767 metrics->max_advance_width = short(face->max_advance_width);
1768 metrics->max_advance_height = short(face->max_advance_height);
1769 metrics->underline_position = short(face->underline_position);
1770 metrics->underline_thickness = short(face->underline_thickness);
1771 metrics->num_glyphs = int(face->num_glyphs);
1772
1773 if (metrics->cap_height == 0) {
1774 /* Calculate or guess cap height if it is not set in the font. */
1775 FT_UInt gi = FT_Get_Char_Index(face, uint('H'));
1776 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1777 metrics->cap_height = short(face->glyph->metrics.height);
1778 }
1779 else {
1780 metrics->cap_height = short(float(metrics->units_per_EM) * 0.7f);
1781 }
1782 }
1783
1784 if (metrics->x_height == 0) {
1785 /* Calculate or guess x-height if it is not set in the font. */
1786 FT_UInt gi = FT_Get_Char_Index(face, uint('x'));
1787 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1788 metrics->x_height = short(face->glyph->metrics.height);
1789 }
1790 else {
1791 metrics->x_height = short(float(metrics->units_per_EM) * 0.5f);
1792 }
1793 }
1794
1795 FT_UInt gi = FT_Get_Char_Index(face, uint('o'));
1796 if (gi && FT_Load_Glyph(face, gi, FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP) == FT_Err_Ok) {
1797 metrics->o_proportion = float(face->glyph->metrics.width) / float(face->glyph->metrics.height);
1798 }
1799
1800 if (metrics->ascender == 0) {
1801 /* Set a sane value for ascender if not set in the font. */
1802 metrics->ascender = short(float(metrics->units_per_EM) * 0.8f);
1803 }
1804
1805 if (metrics->descender == 0) {
1806 /* Set a sane value for descender if not set in the font. */
1807 metrics->descender = metrics->ascender - metrics->units_per_EM;
1808 }
1809
1810 if (metrics->weight == 400 && face->style_flags & FT_STYLE_FLAG_BOLD) {
1811 /* Normal weight yet this is an bold font, so set a sane weight value. */
1812 metrics->weight = 700;
1813 }
1814
1815 if (metrics->slant == 0.0f && face->style_flags & FT_STYLE_FLAG_ITALIC) {
1816 /* No slant yet this is an italic font, so set a sane slant value. */
1817 metrics->slant = 8.0f;
1818 }
1819
1820 if (metrics->underline_position == 0) {
1821 metrics->underline_position = short(float(metrics->units_per_EM) * -0.2f);
1822 }
1823
1824 if (metrics->underline_thickness == 0) {
1825 metrics->underline_thickness = short(float(metrics->units_per_EM) * 0.07f);
1826 }
1827
1828 if (metrics->strikeout_position == 0) {
1829 metrics->strikeout_position = short(float(metrics->x_height) * 0.6f);
1830 }
1831
1832 if (metrics->strikeout_thickness == 0) {
1833 metrics->strikeout_thickness = metrics->underline_thickness;
1834 }
1835
1836 if (metrics->subscript_size == 0) {
1837 metrics->subscript_size = short(float(metrics->units_per_EM) * 0.6f);
1838 }
1839
1840 if (metrics->subscript_yoffset == 0) {
1841 metrics->subscript_yoffset = short(float(metrics->units_per_EM) * 0.075f);
1842 }
1843
1844 if (metrics->superscript_size == 0) {
1845 metrics->superscript_size = short(float(metrics->units_per_EM) * 0.6f);
1846 }
1847
1848 if (metrics->superscript_yoffset == 0) {
1849 metrics->superscript_yoffset = short(float(metrics->units_per_EM) * 0.35f);
1850 }
1851
1852 metrics->valid = true;
1853}
1854
1859static bool blf_setup_face(FontBLF *font)
1860{
1861 font->face_flags = font->face->face_flags;
1862
1863 if (FT_HAS_MULTIPLE_MASTERS(font) && !font->variations) {
1864 FT_Get_MM_Var(font->face, &(font->variations));
1865 }
1866
1867 if (!font->metrics.valid) {
1868 blf_font_metrics(font->face, &font->metrics);
1869 font->char_weight = font->metrics.weight;
1870 font->char_slant = font->metrics.slant;
1871 font->char_width = font->metrics.width;
1872 font->char_spacing = font->metrics.spacing;
1873 }
1874
1875 if (FT_IS_FIXED_WIDTH(font)) {
1876 font->flags |= BLF_MONOSPACED;
1877 }
1878
1879 if (FT_HAS_KERNING(font) && !font->kerning_cache) {
1880 /* Create kerning cache table and fill with value indicating "unset". */
1882 for (uint i = 0; i < KERNING_CACHE_TABLE_SIZE; i++) {
1883 for (uint j = 0; j < KERNING_CACHE_TABLE_SIZE; j++) {
1885 }
1886 }
1887 }
1888
1889 return true;
1890}
1891
1893{
1894 if (font->face) {
1895 return true;
1896 }
1897
1898 if (font->flags & BLF_BAD_FONT) {
1899 return false;
1900 }
1901
1902 FT_Error err;
1903
1904 if (font->flags & BLF_CACHED) {
1905 err = FTC_Manager_LookupFace(ftc_manager, font, &font->face);
1906 }
1907 else {
1908 std::scoped_lock lock(ft_lib_mutex);
1909 if (font->filepath) {
1910 err = FT_New_Face(font->ft_lib, font->filepath, 0, &font->face);
1911 }
1912 if (font->mem) {
1913 err = FT_New_Memory_Face(font->ft_lib,
1914 static_cast<const FT_Byte *>(font->mem),
1915 (FT_Long)font->mem_size,
1916 0,
1917 &font->face);
1918 }
1919 if (!err) {
1920 font->face->generic.data = font;
1921 }
1922 }
1923
1924 if (err) {
1925 if (ELEM(err, FT_Err_Unknown_File_Format, FT_Err_Unimplemented_Feature)) {
1926 printf("Format of this font file is not supported\n");
1927 }
1928 else {
1929 printf("Error encountered while opening font file\n");
1930 }
1931 font->flags |= BLF_BAD_FONT;
1932 return false;
1933 }
1934
1935 if (font->face && !(font->face->face_flags & FT_FACE_FLAG_SCALABLE)) {
1936 printf("Font is not scalable\n");
1937 return false;
1938 }
1939
1940 err = FT_Select_Charmap(font->face, FT_ENCODING_UNICODE);
1941 if (err) {
1942 err = FT_Select_Charmap(font->face, FT_ENCODING_APPLE_ROMAN);
1943 }
1944 if (err && font->face->num_charmaps > 0) {
1945 err = FT_Select_Charmap(font->face, font->face->charmaps[0]->encoding);
1946 }
1947 if (err) {
1948 printf("Can't set a character map!\n");
1949 font->flags |= BLF_BAD_FONT;
1950 return false;
1951 }
1952
1953 if (font->filepath) {
1954 char *mfile = blf_dir_metrics_search(font->filepath);
1955 if (mfile) {
1956 err = FT_Attach_File(font->face, mfile);
1957 if (err) {
1958 fprintf(stderr,
1959 "FT_Attach_File failed to load '%s' with error %d\n",
1960 font->filepath,
1961 int(err));
1962 }
1963 MEM_freeN(mfile);
1964 }
1965 }
1966
1967 if (!(font->flags & BLF_CACHED)) {
1968 /* Not cached so point at the face's size for convenience. */
1969 font->ft_size = font->face->size;
1970 }
1971
1972 /* Setup Font details that require having a Face. */
1973 return blf_setup_face(font);
1974}
1975
1983
1984/* Details about the fallback fonts we ship, so that we can load only when needed. */
1986 {"lastresort.woff2", UINT32_MAX, UINT32_MAX, UINT32_MAX, UINT32_MAX},
1987 {"Noto Sans CJK Regular.woff2",
1988 0,
1989 TT_UCR_CJK_SYMBOLS | TT_UCR_HIRAGANA | TT_UCR_KATAKANA | TT_UCR_BOPOMOFO | TT_UCR_CJK_MISC |
1990 TT_UCR_ENCLOSED_CJK_LETTERS_MONTHS | TT_UCR_CJK_COMPATIBILITY |
1991 TT_UCR_CJK_UNIFIED_IDEOGRAPHS | TT_UCR_CJK_COMPATIBILITY_IDEOGRAPHS,
1992 TT_UCR_CJK_COMPATIBILITY_FORMS,
1993 0},
1994 {"NotoEmoji-VariableFont_wght.woff2", 0x80000003L, 0x241E4ACL, 0x14000000L, 0x4000000L},
1995 {"NotoSansArabic-VariableFont_wdth,wght.woff2",
1996 TT_UCR_ARABIC,
1997 uint(TT_UCR_ARABIC_PRESENTATION_FORMS_A),
1998 TT_UCR_ARABIC_PRESENTATION_FORMS_B,
1999 0},
2000 {"NotoSansArmenian-VariableFont_wdth,wght.woff2", TT_UCR_ARMENIAN, 0, 0, 0},
2001 {"NotoSansBengali-VariableFont_wdth,wght.woff2", TT_UCR_BENGALI, 0, 0, 0},
2002 {"NotoSansDevanagari-Regular.woff2", TT_UCR_DEVANAGARI, 0, 0, 0},
2003 {"NotoSansEthiopic-Regular.woff2", 0, 0, TT_UCR_ETHIOPIC, 0},
2004 {"NotoSansGeorgian-VariableFont_wdth,wght.woff2", TT_UCR_GEORGIAN, 0, 0, 0},
2005 {"NotoSansGujarati-Regular.woff2", TT_UCR_GUJARATI, 0, 0, 0},
2006 {"NotoSansGurmukhi-VariableFont_wdth,wght.woff2", TT_UCR_GURMUKHI, 0, 0, 0},
2007 {"NotoSansHebrew-Regular.woff2", TT_UCR_HEBREW, 0, 0, 0},
2008 {"NotoSansJavanese-Regular.woff2", 0x80000003L, 0x2000L, 0, 0},
2009 {"NotoSansKannada-VariableFont_wdth,wght.woff2", TT_UCR_KANNADA, 0, 0, 0},
2010 {"NotoSansKhmer-VariableFont_wdth,wght.woff2", 0, 0, TT_UCR_KHMER, 0},
2011 {"NotoSansMalayalam-VariableFont_wdth,wght.woff2", TT_UCR_MALAYALAM, 0, 0, 0},
2012 {"NotoSansMath-Regular.woff2", 0, TT_UCR_MATHEMATICAL_OPERATORS, 0, 0},
2013 {"NotoSansMyanmar-Regular.woff2", 0, 0, TT_UCR_MYANMAR, 0},
2014 {"NotoSansSymbols-VariableFont_wght.woff2", 0x3L, 0x200E4B4L, 0, 0},
2015 {"NotoSansSymbols2-Regular.woff2", 0x80000003L, 0x200E3E4L, 0x40020L, 0x580A048L},
2016 {"NotoSansTamil-VariableFont_wdth,wght.woff2", TT_UCR_TAMIL, 0, 0, 0},
2017 {"NotoSansTelugu-VariableFont_wdth,wght.woff2", TT_UCR_TELUGU, 0, 0, 0},
2018 {"NotoSansThai-VariableFont_wdth,wght.woff2", TT_UCR_THAI, 0, 0, 0},
2019};
2020
2026static FontBLF *blf_font_new_impl(const char *filepath,
2027 const char *mem_name,
2028 const uchar *mem,
2029 const size_t mem_size,
2030 void *ft_library)
2031{
2032 FontBLF *font = MEM_new<FontBLF>(__func__);
2033
2034 font->mem_name = mem_name ? BLI_strdup(mem_name) : nullptr;
2035 font->filepath = filepath ? BLI_strdup(filepath) : nullptr;
2036 if (mem) {
2037 font->mem = (void *)mem;
2038 font->mem_size = mem_size;
2039 }
2040 blf_font_fill(font);
2041
2042 if (ft_library && ((FT_Library)ft_library != ft_lib)) {
2043 /* Pass. */
2044 }
2045 else {
2046 font->flags |= BLF_CACHED;
2047 }
2048
2049 font->ft_lib = ft_library ? (FT_Library)ft_library : ft_lib;
2050
2051 /* If we have static details about this font file, we don't have to load the Face yet. */
2052 bool face_needed = true;
2053
2054 if (font->filepath) {
2055 const char *filename = BLI_path_basename(font->filepath);
2056 for (int i = 0; i < int(ARRAY_SIZE(static_face_details)); i++) {
2057 if (BLI_path_cmp(static_face_details[i].filename, filename) == 0) {
2058 const FaceDetails *static_details = &static_face_details[i];
2059 font->unicode_ranges[0] = static_details->coverage1;
2060 font->unicode_ranges[1] = static_details->coverage2;
2061 font->unicode_ranges[2] = static_details->coverage3;
2062 font->unicode_ranges[3] = static_details->coverage4;
2063 face_needed = false;
2064 break;
2065 }
2066 }
2067 }
2068
2069 if (face_needed) {
2070 if (!blf_ensure_face(font)) {
2071 blf_font_free(font);
2072 return nullptr;
2073 }
2074
2075 /* Save TrueType table with bits to quickly test most unicode block coverage. */
2076 const TT_OS2 *os2_table = (const TT_OS2 *)FT_Get_Sfnt_Table(font->face, FT_SFNT_OS2);
2077 if (os2_table) {
2078 font->unicode_ranges[0] = uint(os2_table->ulUnicodeRange1);
2079 font->unicode_ranges[1] = uint(os2_table->ulUnicodeRange2);
2080 font->unicode_ranges[2] = uint(os2_table->ulUnicodeRange3);
2081 font->unicode_ranges[3] = uint(os2_table->ulUnicodeRange4);
2082 }
2083 }
2084
2085 /* Detect "Last resort" fonts. They have everything. Usually except last 5 bits. */
2086 if (font->unicode_ranges[0] == 0xffffffffU && font->unicode_ranges[1] == 0xffffffffU &&
2087 font->unicode_ranges[2] == 0xffffffffU && font->unicode_ranges[3] >= 0x7FFFFFFU)
2088 {
2089 font->flags |= BLF_LAST_RESORT;
2090 }
2091
2092 return font;
2093}
2094
2096{
2097 return blf_font_new_impl(filepath, nullptr, nullptr, 0, nullptr);
2098}
2099
2100FontBLF *blf_font_new_from_mem(const char *mem_name, const uchar *mem, const size_t mem_size)
2101{
2102 return blf_font_new_impl(nullptr, mem_name, mem, mem_size, nullptr);
2103}
2104
2105void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_size)
2106{
2107 FT_Open_Args open;
2108
2109 open.flags = FT_OPEN_MEMORY;
2110 open.memory_base = (const FT_Byte *)mem;
2111 open.memory_size = (FT_Long)mem_size;
2112 if (blf_ensure_face(font)) {
2113 FT_Attach_Stream(font->face, &open);
2114 }
2115}
2116
2118{
2120
2121 if (font->kerning_cache) {
2122 MEM_freeN(font->kerning_cache);
2123 }
2124
2125 if (font->variations) {
2126 FT_Done_MM_Var(font->ft_lib, font->variations);
2127 }
2128
2129 if (font->face) {
2130 std::scoped_lock lock(ft_lib_mutex);
2131 if (font->flags & BLF_CACHED) {
2132 FTC_Manager_RemoveFaceID(ftc_manager, font);
2133 }
2134 else {
2135 FT_Done_Face(font->face);
2136 }
2137 font->face = nullptr;
2138 }
2139 if (font->filepath) {
2140 MEM_freeN(font->filepath);
2141 }
2142 if (font->mem_name) {
2143 MEM_freeN(font->mem_name);
2144 }
2145
2146 MEM_delete(font);
2147}
2148
2150
2151/* -------------------------------------------------------------------- */
2154
2156{
2157 if (font->ft_size || !(font->flags & BLF_CACHED)) {
2158 return;
2159 }
2160
2161 FTC_ScalerRec scaler = {nullptr};
2162 scaler.face_id = font;
2163 scaler.width = 0;
2164 scaler.height = round_fl_to_uint(font->size * 64.0f);
2165 scaler.pixel = 0;
2166 scaler.x_res = BLF_DPI;
2167 scaler.y_res = BLF_DPI;
2168 if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) == FT_Err_Ok) {
2169 font->ft_size->generic.data = (void *)font;
2170 font->ft_size->generic.finalizer = blf_size_finalizer;
2171 return;
2172 }
2173
2175}
2176
2177bool blf_font_size(FontBLF *font, float size)
2178{
2179 if (!blf_ensure_face(font)) {
2180 return false;
2181 }
2182
2183 /* FreeType uses fixed-point integers in 64ths. */
2184 FT_UInt ft_size = round_fl_to_uint(size * 64.0f);
2185 /* Adjust our new size to be on even 64ths. */
2186 size = float(ft_size) / 64.0f;
2187
2188 if (font->size != size) {
2189 if (font->flags & BLF_CACHED) {
2190 FTC_ScalerRec scaler = {nullptr};
2191 scaler.face_id = font;
2192 scaler.width = 0;
2193 scaler.height = ft_size;
2194 scaler.pixel = 0;
2195 scaler.x_res = BLF_DPI;
2196 scaler.y_res = BLF_DPI;
2197 if (FTC_Manager_LookupSize(ftc_manager, &scaler, &font->ft_size) != FT_Err_Ok) {
2198 return false;
2199 }
2200 font->ft_size->generic.data = (void *)font;
2201 font->ft_size->generic.finalizer = blf_size_finalizer;
2202 }
2203 else {
2204 if (FT_Set_Char_Size(font->face, 0, ft_size, BLF_DPI, BLF_DPI) != FT_Err_Ok) {
2205 return false;
2206 }
2207 font->ft_size = font->face->size;
2208 }
2209 }
2210
2211 font->size = size;
2212 return true;
2213}
2214
BLFWrapMode
Definition BLF_api.hh:44
@ Typographical
Definition BLF_api.hh:46
bool(*)(const char *str, size_t str_step_ofs, const rcti *bounds, void *user_dataconst) BLF_GlyphBoundsFn
Definition BLF_api.hh:205
@ BLF_RENDER_SUBPIXELAA
Definition BLF_api.hh:462
@ BLF_ROTATION
Definition BLF_api.hh:433
@ BLF_LAST_RESORT
Definition BLF_api.hh:452
@ BLF_MONOSPACED
Definition BLF_api.hh:448
@ BLF_CACHED
Definition BLF_api.hh:456
@ BLF_WORD_WRAP
Definition BLF_api.hh:439
@ BLF_BAD_FONT
Definition BLF_api.hh:454
@ BLF_ASPECT
Definition BLF_api.hh:438
@ BLF_SHADOW
Definition BLF_api.hh:435
#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)
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:923
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(...)
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:51
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:318
#define GPU_BATCH_DISCARD_SAFE(batch)
Definition GPU_batch.hh:204
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:41
#define GPU_batch_uniform_1i(batch, name, x)
Definition GPU_batch.hh:299
#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 *, blender::StringRef name, GPUVertCompType, uint comp_len, GPUVertFetchMode)
@ GPU_COMP_F32
@ GPU_COMP_I32
@ GPU_COMP_U32
@ GPU_COMP_U8
Read Guarded memory(de)allocation.
volatile int lock
char * blf_dir_metrics_search(const char *filepath)
Definition blf_dir.cc:26
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:1492
static ft_pix blf_font_width_max_ft_pix(FontBLF *font)
Definition blf_font.cc:1565
size_t blf_str_offset_from_cursor_position(FontBLF *font, const char *str, size_t str_len, int location_x)
Definition blf_font.cc:1141
static const FaceDetails static_face_details[]
Definition blf_font.cc:1985
void blf_str_offset_to_glyph_bounds(FontBLF *font, const char *str, size_t str_offset, rcti *r_glyph_bounds)
Definition blf_font.cc:1191
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:864
static void blf_font_fill(FontBLF *font)
Definition blf_font.cc:1646
int blf_font_ascender(FontBLF *font)
Definition blf_font.cc:1583
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:546
blender::Vector< blender::StringRef > blf_font_string_wrap(FontBLF *font, blender::StringRef str, int max_pixel_width, BLFWrapMode mode)
Definition blf_font.cc:1530
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:1178
float blf_font_width(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1013
bool blf_ensure_face(FontBLF *font)
Definition blf_font.cc:1892
static FTC_Manager ftc_manager
Definition blf_font.cc:63
static GPUTexture * blf_batch_cache_texture_load()
Definition blf_font.cc:284
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:1553
static void blf_batch_draw_end()
Definition blf_font.cc:364
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:1438
void blf_ensure_size(FontBLF *font)
Definition blf_font.cc:2155
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:917
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:643
void blf_font_draw_buffer(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:784
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:1274
void BLF_cache_flush_set_fn(void(*cache_flush_fn)())
Definition blf_font.cc:1635
int blf_font_draw_mono(FontBLF *font, const char *str, const size_t str_len, int cwidth, int tab_columns)
Definition blf_font.cc:510
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:592
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:1517
static void blf_batch_draw_exit()
Definition blf_font.cc:219
void blf_font_free(FontBLF *font)
Definition blf_font.cc:2117
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:1080
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:412
bool blf_font_size(FontBLF *font, float size)
Definition blf_font.cc:2177
float blf_font_fixed_width(FontBLF *font)
Definition blf_font.cc:1055
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:1460
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:1034
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:801
int blf_font_init()
Definition blf_font.cc:1603
int blf_font_width_max(FontBLF *font)
Definition blf_font.cc:1572
void blf_batch_draw()
Definition blf_font.cc:324
void blf_batch_draw_begin(FontBLF *font)
Definition blf_font.cc:224
static void blf_size_finalizer(void *object)
Definition blf_font.cc:135
static ft_pix blf_unscaled_F26Dot6_to_pixels(FontBLF *font, FT_Pos value)
Definition blf_font.cc:159
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:1473
void blf_font_exit()
Definition blf_font.cc:1624
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:1127
void blf_font_boundbox(FontBLF *font, const char *str, const size_t str_len, rcti *r_box, ResultBLF *r_info)
Definition blf_font.cc:976
int blf_font_glyph_advance(FontBLF *font, const char *str)
Definition blf_font.cc:1063
uint blf_get_char_index(FontBLF *font, uint charcode)
Definition blf_font.cc:148
char * blf_display_name(FontBLF *font)
Definition blf_font.cc:1589
FontBLF * blf_font_new_from_mem(const char *mem_name, const uchar *mem, const size_t mem_size)
Definition blf_font.cc:2100
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:1204
static bool blf_setup_face(FontBLF *font)
Definition blf_font.cc:1859
void blf_font_attach_from_mem(FontBLF *font, const uchar *mem, const size_t mem_size)
Definition blf_font.cc:2105
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:751
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:377
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:835
int blf_font_descender(FontBLF *font)
Definition blf_font.cc:1577
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:984
void blf_font_draw(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:503
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:468
FontBLF * blf_font_new_from_filepath(const char *filepath)
Definition blf_font.cc:2095
void blf_font_draw_buffer__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1501
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:452
int blf_font_height_max(FontBLF *font)
Definition blf_font.cc:1560
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:1249
static void blf_font_metrics(FT_Face face, FontMetrics *metrics)
Definition blf_font.cc:1690
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:2026
void blf_font_draw__wrap(FontBLF *font, const char *str, const size_t str_len, ResultBLF *r_info)
Definition blf_font.cc:1447
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 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)
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:245
const T * data() const
Definition BLI_array.hh:301
void append(const T &value)
#define str(s)
#define UINT32_MAX
uint col
TEX_TEMPLATE DataVec texture(T, FltCoord, float=0.0f) RET
#define printf(...)
format
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:71
char filename[50]
Definition blf_font.cc:1977
KerningCacheBLF * kerning_cache
uint unicode_ranges[4]
unsigned char color[4]
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
int ascii_table[KERNING_CACHE_TABLE_SIZE][KERNING_CACHE_TABLE_SIZE]
int lines
Definition BLF_api.hh:481
int width
Definition BLF_api.hh:485
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230
static DynamicLibrary lib