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
12
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
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
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
144
145/* -------------------------------------------------------------------- */
148
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
178
179/* -------------------------------------------------------------------- */
182
190{
191 GPUVertFormat format = {0};
196 g_batch.glyph_size_loc = GPU_vertformat_attr_add(
197 &format, "glyph_size", GPU_COMP_I32, 2, GPU_FETCH_INT);
198 g_batch.glyph_flags_loc = GPU_vertformat_attr_add(
199 &format, "flags", GPU_COMP_U32, 1, GPU_FETCH_INT);
200
203
204 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
205 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
206 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
207 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
208 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_flags_loc, &g_batch.glyph_flags_step);
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. */
217 GPU_batch_instbuf_set(g_batch.batch, g_batch.verts, true);
218}
219
221{
223}
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. */
244 zero_v2_int(g_batch.ofs);
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{
287 GlyphCacheBLF *gc = g_batch.glyph_cache;
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
339 GPU_vertbuf_data_len_set(*g_batch.verts, g_batch.glyph_len);
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);
350 GPU_batch_draw(g_batch.batch);
351
353
355
356 /* Restart to 1st vertex data pointers. */
357 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
358 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
359 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
360 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
361 GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_flags_loc, &g_batch.glyph_flags_step);
362 g_batch.glyph_len = 0;
363}
364
366{
367 if (!g_batch.active) {
369 }
370}
371
373
374/* -------------------------------------------------------------------- */
377
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
445
446/* -------------------------------------------------------------------- */
449
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) {
545 }
546
547 if (outline_alpha > 0.0f) {
548 font->flags |= BLF_SHADOW;
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
617
618/* -------------------------------------------------------------------- */
621
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
774
775/* -------------------------------------------------------------------- */
782
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
888
889/* -------------------------------------------------------------------- */
892
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{
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
1224
1225/* -------------------------------------------------------------------- */
1228
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
1434
1435/* -------------------------------------------------------------------- */
1438
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
1484
1485/* -------------------------------------------------------------------- */
1488
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
1529
1530/* -------------------------------------------------------------------- */
1533
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++) {
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
2041
2042/* -------------------------------------------------------------------- */
2045
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
@ 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
bool(* BLF_GlyphBoundsFn)(const char *str, size_t str_step_ofs, const rcti *bounds, void *user_data)
Definition BLF_api.hh:167
#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.
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Brightness Control the brightness and contrast of the input color Vector Map input vector components with curves Camera Retrieve information about the camera and how it relates to the current shading point s position Clamp a value between a minimum and a maximum Vector Perform vector math operation Invert Invert a color
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)
local_group_size(16, 16) .push_constant(Type texture
#define printf
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
char filename[50]
Definition blf_font.cc:1867
KerningCacheBLF * kerning_cache
uint unicode_ranges[4]
unsigned char color[4]
FT_MM_Var * variations
FontMetrics metrics
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:406
int width
Definition BLF_api.hh:410
int ymin
int ymax
int xmin
int xmax
static DynamicLibrary lib