1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2009 Blender Foundation.
17  * All rights reserved.
18  */
19 
20 /** \file
21  * \ingroup blf
22  *
23  * Deals with drawing text to OpenGL or bitmap buffers.
24  *
25  * Also low level functions for managing \a FontBLF.
26  */
27 
28 #include <math.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 #include <ft2build.h>
34 
35 #include FT_FREETYPE_H
36 #include FT_GLYPH_H
37 
38 #include "MEM_guardedalloc.h"
39 
40 #include "DNA_vec_types.h"
41 
42 #include "BLI_listbase.h"
43 #include "BLI_math.h"
44 #include "BLI_rect.h"
45 #include "BLI_string.h"
46 #include "BLI_string_utf8.h"
47 #include "BLI_threads.h"
48 
49 #include "BLF_api.h"
50 
51 #include "UI_interface.h"
52 
53 #include "GPU_batch.h"
54 #include "GPU_matrix.h"
55 
56 #include "blf_internal.h"
57 #include "blf_internal_types.h"
58 
59 #include "BLI_strict_flags.h"
60 
61 #ifdef WIN32
62 #  define FT_New_Face FT_New_Face__win32_compat
63 #endif
64 
65 /* Batching buffer for drawing. */
66 BatchBLF g_batch;
67 
68 /* freetype2 handle ONLY for this file!. */
69 static FT_Library ft_lib;
70 static SpinLock ft_lib_mutex;
71 static SpinLock blf_glyph_cache_mutex;
72 
73 /* -------------------------------------------------------------------- */
74 /** \name Glyph Batching
75  * \{ */
76 
77 /**
78  * Drawcalls are precious! make them count!
79  * Since most of the Text elems are not covered by other UI elements, we can
80  * group some strings together and render them in one drawcall. This behavior
81  * is on demand only, between #BLF_batch_draw_begin() and #BLF_batch_draw_end().
82  */
blf_batch_draw_init(void)83 static void blf_batch_draw_init(void)
84 {
85   GPUVertFormat format = {0};
86   g_batch.pos_loc = GPU_vertformat_attr_add(&format, "pos", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
87   g_batch.col_loc = GPU_vertformat_attr_add(
88       &format, "col", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
89   g_batch.offset_loc = GPU_vertformat_attr_add(&format, "offset", GPU_COMP_I32, 1, GPU_FETCH_INT);
90   g_batch.glyph_size_loc = GPU_vertformat_attr_add(
91       &format, "glyph_size", GPU_COMP_I32, 2, GPU_FETCH_INT);
92 
93   g_batch.verts = GPU_vertbuf_create_with_format_ex(&format, GPU_USAGE_STREAM);
94   GPU_vertbuf_data_alloc(g_batch.verts, BLF_BATCH_DRAW_LEN_MAX);
95 
96   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
97   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
98   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
99   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
100   g_batch.glyph_len = 0;
101 
102   /* A dummy VBO containing 4 points, attributes are not used. */
103   GPUVertBuf *vbo = GPU_vertbuf_create_with_format(&format);
104   GPU_vertbuf_data_alloc(vbo, 4);
105 
106   /* We render a quad as a triangle strip and instance it for each glyph. */
107   g_batch.batch = GPU_batch_create_ex(GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
108   GPU_batch_instbuf_set(g_batch.batch, g_batch.verts, true);
109 }
110 
blf_batch_draw_exit(void)111 static void blf_batch_draw_exit(void)
112 {
113   GPU_BATCH_DISCARD_SAFE(g_batch.batch);
114 }
115 
blf_batch_draw_begin(FontBLF * font)116 void blf_batch_draw_begin(FontBLF *font)
117 {
118   if (g_batch.batch == NULL) {
119     blf_batch_draw_init();
120   }
121 
122   const bool font_changed = (g_batch.font != font);
123   const bool simple_shader = ((font->flags & (BLF_ROTATION | BLF_MATRIX | BLF_ASPECT)) == 0);
124   const bool shader_changed = (simple_shader != g_batch.simple_shader);
125 
126   g_batch.active = g_batch.enabled && simple_shader;
127 
128   if (simple_shader) {
129     /* Offset is applied to each glyph. */
130     g_batch.ofs[0] = floorf(font->pos[0]);
131     g_batch.ofs[1] = floorf(font->pos[1]);
132   }
133   else {
134     /* Offset is baked in modelview mat. */
135     zero_v2(g_batch.ofs);
136   }
137 
138   if (g_batch.active) {
139     float gpumat[4][4];
140     GPU_matrix_model_view_get(gpumat);
141 
142     bool mat_changed = (memcmp(gpumat, g_batch.mat, sizeof(g_batch.mat)) != 0);
143 
144     if (mat_changed) {
145       /* Modelviewmat is no longer the same.
146        * Flush cache but with the previous mat. */
147       GPU_matrix_push();
148       GPU_matrix_set(g_batch.mat);
149     }
150 
151     /* flush cache if config is not the same. */
152     if (mat_changed || font_changed || shader_changed) {
153       blf_batch_draw();
154       g_batch.simple_shader = simple_shader;
155       g_batch.font = font;
156     }
157     else {
158       /* Nothing changed continue batching. */
159       return;
160     }
161 
162     if (mat_changed) {
163       GPU_matrix_pop();
164       /* Save for next memcmp. */
165       memcpy(g_batch.mat, gpumat, sizeof(g_batch.mat));
166     }
167   }
168   else {
169     /* flush cache */
170     blf_batch_draw();
171     g_batch.font = font;
172     g_batch.simple_shader = simple_shader;
173   }
174 }
175 
blf_batch_cache_texture_load(void)176 static GPUTexture *blf_batch_cache_texture_load(void)
177 {
178   GlyphCacheBLF *gc = g_batch.glyph_cache;
179   BLI_assert(gc);
180   BLI_assert(gc->bitmap_len > 0);
181 
182   if (gc->bitmap_len > gc->bitmap_len_landed) {
183     const int tex_width = GPU_texture_width(gc->texture);
184 
185     int bitmap_len_landed = gc->bitmap_len_landed;
186     int remain = gc->bitmap_len - bitmap_len_landed;
187     int offset_x = bitmap_len_landed % tex_width;
188     int offset_y = bitmap_len_landed / tex_width;
189 
190     /* TODO(germano): Update more than one row in a single call. */
191     while (remain) {
192       int remain_row = tex_width - offset_x;
193       int width = remain > remain_row ? remain_row : remain;
194       GPU_texture_update_sub(gc->texture,
195                              GPU_DATA_UNSIGNED_BYTE,
196                              &gc->bitmap_result[bitmap_len_landed],
197                              offset_x,
198                              offset_y,
199                              0,
200                              width,
201                              1,
202                              0);
203 
204       bitmap_len_landed += width;
205       remain -= width;
206       offset_x = 0;
207       offset_y += 1;
208     }
209 
210     gc->bitmap_len_landed = bitmap_len_landed;
211   }
212 
213   return gc->texture;
214 }
215 
blf_batch_draw(void)216 void blf_batch_draw(void)
217 {
218   if (g_batch.glyph_len == 0) {
219     return;
220   }
221 
222   GPU_blend(GPU_BLEND_ALPHA);
223 
224 #ifndef BLF_STANDALONE
225   /* We need to flush widget base first to ensure correct ordering. */
226   UI_widgetbase_draw_cache_flush();
227 #endif
228 
229   GPUTexture *texture = blf_batch_cache_texture_load();
230   GPU_vertbuf_data_len_set(g_batch.verts, g_batch.glyph_len);
231   GPU_vertbuf_use(g_batch.verts); /* send data */
232 
233   GPU_batch_program_set_builtin(g_batch.batch, GPU_SHADER_TEXT);
234   GPU_batch_texture_bind(g_batch.batch, "glyph", texture);
235   GPU_batch_draw(g_batch.batch);
236 
237   GPU_blend(GPU_BLEND_NONE);
238 
239   GPU_texture_unbind(texture);
240 
241   /* restart to 1st vertex data pointers */
242   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.pos_loc, &g_batch.pos_step);
243   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.col_loc, &g_batch.col_step);
244   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.offset_loc, &g_batch.offset_step);
245   GPU_vertbuf_attr_get_raw_data(g_batch.verts, g_batch.glyph_size_loc, &g_batch.glyph_size_step);
246   g_batch.glyph_len = 0;
247 }
248 
blf_batch_draw_end(void)249 static void blf_batch_draw_end(void)
250 {
251   if (!g_batch.active) {
252     blf_batch_draw();
253   }
254 }
255 
256 /** \} */
257 
258 /* -------------------------------------------------------------------- */
259 
blf_font_init(void)260 int blf_font_init(void)
261 {
262   memset(&g_batch, 0, sizeof(g_batch));
263   BLI_spin_init(&ft_lib_mutex);
264   BLI_spin_init(&blf_glyph_cache_mutex);
265   return FT_Init_FreeType(&ft_lib);
266 }
267 
blf_font_exit(void)268 void blf_font_exit(void)
269 {
270   FT_Done_FreeType(ft_lib);
271   BLI_spin_end(&ft_lib_mutex);
272   BLI_spin_end(&blf_glyph_cache_mutex);
273   blf_batch_draw_exit();
274 }
275 
blf_font_size(FontBLF * font,unsigned int size,unsigned int dpi)276 void blf_font_size(FontBLF *font, unsigned int size, unsigned int dpi)
277 {
278   GlyphCacheBLF *gc;
279   FT_Error err;
280 
281   blf_glyph_cache_acquire(font);
282 
283   gc = blf_glyph_cache_find(font, size, dpi);
284   if (gc) {
285     /* Optimization: do not call FT_Set_Char_Size if size did not change. */
286     if (font->size == size && font->dpi == dpi) {
287       blf_glyph_cache_release(font);
288       return;
289     }
290   }
291 
292   err = FT_Set_Char_Size(font->face, 0, ((FT_F26Dot6)(size)) * 64, dpi, dpi);
293   if (err) {
294     /* FIXME: here we can go through the fixed size and choice a close one */
295     printf("The current font don't support the size, %u and dpi, %u\n", size, dpi);
296 
297     blf_glyph_cache_release(font);
298     return;
299   }
300 
301   font->size = size;
302   font->dpi = dpi;
303 
304   if (!gc) {
305     blf_glyph_cache_new(font);
306   }
307   blf_glyph_cache_release(font);
308 }
309 
blf_font_ensure_ascii_table(FontBLF * font,GlyphCacheBLF * gc)310 static GlyphBLF **blf_font_ensure_ascii_table(FontBLF *font, GlyphCacheBLF *gc)
311 {
312   GlyphBLF **glyph_ascii_table;
313 
314   glyph_ascii_table = gc->glyph_ascii_table;
315 
316   /* build ascii on demand */
317   if (glyph_ascii_table['0'] == NULL) {
318     GlyphBLF *g;
319     for (uint i = 0; i < 256; i++) {
320       g = blf_glyph_search(gc, i);
321       if (!g) {
322         FT_UInt glyph_index = FT_Get_Char_Index(font->face, i);
323         g = blf_glyph_add(font, gc, glyph_index, i);
324       }
325       glyph_ascii_table[i] = g;
326     }
327   }
328 
329   return glyph_ascii_table;
330 }
331 
blf_font_ensure_ascii_kerning(FontBLF * font,GlyphCacheBLF * gc,const FT_UInt kern_mode)332 static void blf_font_ensure_ascii_kerning(FontBLF *font,
333                                           GlyphCacheBLF *gc,
334                                           const FT_UInt kern_mode)
335 {
336   KerningCacheBLF *kc = font->kerning_cache;
337 
338   font->kerning_mode = kern_mode;
339 
340   if (!kc || kc->mode != kern_mode) {
341     font->kerning_cache = kc = blf_kerning_cache_find(font);
342     if (!kc) {
343       font->kerning_cache = kc = blf_kerning_cache_new(font, gc);
344     }
345   }
346 }
347 
348 /* Fast path for runs of ASCII characters. Given that common UTF-8
349  * input will consist of an overwhelming majority of ASCII
350  * characters.
351  */
352 
353 /* Note,
354  * blf_font_ensure_ascii_table(font, gc); must be called before this macro */
355 
356 #define BLF_UTF8_NEXT_FAST(_font, _gc, _g, _str, _i, _c, _glyph_ascii_table) \
357   if (((_c) = (_str)[_i]) < 0x80) { \
358     _g = (_glyph_ascii_table)[_c]; \
359     _i++; \
360   } \
361   else if ((_c = BLI_str_utf8_as_unicode_step(_str, &(_i))) != BLI_UTF8_ERR) { \
362     if ((_g = blf_glyph_search(_gc, _c)) == NULL) { \
363       _g = blf_glyph_add(_font, _gc, FT_Get_Char_Index((_font)->face, _c), _c); \
364     } \
365   } \
366   else { \
367     _g = NULL; \
368   } \
369   (void)0
370 
371 #define BLF_KERNING_VARS(_font, _has_kerning, _kern_mode) \
372   const bool _has_kerning = FT_HAS_KERNING((_font)->face) != 0; \
373   const FT_UInt _kern_mode = (_has_kerning == 0) ? 0 : \
374                                                    (((_font)->flags & BLF_KERNING_DEFAULT) ? \
375                                                         ft_kerning_default : \
376                                                         (FT_UInt)FT_KERNING_UNFITTED)
377 
378 /* Note,
379  * blf_font_ensure_ascii_kerning(font, gc, kern_mode); must be called before this macro */
380 
381 #define BLF_KERNING_STEP_FAST(_font, _kern_mode, _g_prev, _g, _c_prev, _c, _pen_x) \
382   { \
383     if (_g_prev) { \
384       FT_Vector _delta; \
385       if (_c_prev < 0x80 && _c < 0x80) { \
386         _pen_x += (_font)->kerning_cache->table[_c][_c_prev]; \
387       } \
388       else if (FT_Get_Kerning((_font)->face, (_g_prev)->idx, (_g)->idx, _kern_mode, &(_delta)) == \
389                0) { \
390         _pen_x += (int)_delta.x >> 6; \
391       } \
392     } \
393   } \
394   (void)0
395 
396 #define BLF_KERNING_STEP(_font, _kern_mode, _g_prev, _g, _delta, _pen_x) \
397   { \
398     if (_g_prev) { \
399       _delta.x = _delta.y = 0; \
400       if (FT_Get_Kerning((_font)->face, (_g_prev)->idx, (_g)->idx, _kern_mode, &(_delta)) == 0) { \
401         _pen_x += (int)_delta.x >> 6; \
402       } \
403     } \
404   } \
405   (void)0
406 
blf_font_draw_ex(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,struct ResultBLF * r_info,int pen_y)407 static void blf_font_draw_ex(FontBLF *font,
408                              GlyphCacheBLF *gc,
409                              const char *str,
410                              size_t len,
411                              struct ResultBLF *r_info,
412                              int pen_y)
413 {
414   unsigned int c, c_prev = BLI_UTF8_ERR;
415   GlyphBLF *g, *g_prev = NULL;
416   int pen_x = 0;
417   size_t i = 0;
418 
419   if (len == 0) {
420     /* early output, don't do any IMM OpenGL. */
421     return;
422   }
423 
424   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
425 
426   BLF_KERNING_VARS(font, has_kerning, kern_mode);
427 
428   blf_font_ensure_ascii_kerning(font, gc, kern_mode);
429 
430   blf_batch_draw_begin(font);
431 
432   while ((i < len) && str[i]) {
433     BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
434 
435     if (UNLIKELY(c == BLI_UTF8_ERR)) {
436       break;
437     }
438     if (UNLIKELY(g == NULL)) {
439       continue;
440     }
441     if (has_kerning) {
442       BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
443     }
444 
445     /* do not return this loop if clipped, we want every character tested */
446     blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
447 
448     pen_x += g->advance_i;
449     g_prev = g;
450     c_prev = c;
451   }
452 
453   blf_batch_draw_end();
454 
455   if (r_info) {
456     r_info->lines = 1;
457     r_info->width = pen_x;
458   }
459 }
blf_font_draw(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info)460 void blf_font_draw(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
461 {
462   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
463   blf_font_draw_ex(font, gc, str, len, r_info, 0);
464   blf_glyph_cache_release(font);
465 }
466 
467 /* faster version of blf_font_draw, ascii only for view dimensions */
blf_font_draw_ascii_ex(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info,int pen_y)468 static void blf_font_draw_ascii_ex(
469     FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info, int pen_y)
470 {
471   unsigned int c, c_prev = BLI_UTF8_ERR;
472   GlyphBLF *g, *g_prev = NULL;
473   int pen_x = 0;
474 
475   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
476   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
477 
478   BLF_KERNING_VARS(font, has_kerning, kern_mode);
479 
480   blf_font_ensure_ascii_kerning(font, gc, kern_mode);
481 
482   blf_batch_draw_begin(font);
483 
484   while ((c = *(str++)) && len--) {
485     BLI_assert(c < 128);
486     if ((g = glyph_ascii_table[c]) == NULL) {
487       continue;
488     }
489     if (has_kerning) {
490       BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
491     }
492 
493     /* do not return this loop if clipped, we want every character tested */
494     blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
495 
496     pen_x += g->advance_i;
497     g_prev = g;
498     c_prev = c;
499   }
500 
501   blf_batch_draw_end();
502 
503   if (r_info) {
504     r_info->lines = 1;
505     r_info->width = pen_x;
506   }
507 
508   blf_glyph_cache_release(font);
509 }
510 
blf_font_draw_ascii(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info)511 void blf_font_draw_ascii(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
512 {
513   blf_font_draw_ascii_ex(font, str, len, r_info, 0);
514 }
515 
516 /* use fixed column width, but an utf8 character may occupy multiple columns */
blf_font_draw_mono(FontBLF * font,const char * str,size_t len,int cwidth)517 int blf_font_draw_mono(FontBLF *font, const char *str, size_t len, int cwidth)
518 {
519   unsigned int c;
520   GlyphBLF *g;
521   int col, columns = 0;
522   int pen_x = 0, pen_y = 0;
523   size_t i = 0;
524 
525   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
526   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
527 
528   blf_batch_draw_begin(font);
529 
530   while ((i < len) && str[i]) {
531     BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
532 
533     if (UNLIKELY(c == BLI_UTF8_ERR)) {
534       break;
535     }
536     if (UNLIKELY(g == NULL)) {
537       continue;
538     }
539 
540     /* do not return this loop if clipped, we want every character tested */
541     blf_glyph_render(font, gc, g, (float)pen_x, (float)pen_y);
542 
543     col = BLI_wcwidth((char32_t)c);
544     if (col < 0) {
545       col = 1;
546     }
547 
548     columns += col;
549     pen_x += cwidth * col;
550   }
551 
552   blf_batch_draw_end();
553 
554   blf_glyph_cache_release(font);
555   return columns;
556 }
557 
558 /* Sanity checks are done by BLF_draw_buffer() */
blf_font_draw_buffer_ex(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,struct ResultBLF * r_info,int pen_y)559 static void blf_font_draw_buffer_ex(FontBLF *font,
560                                     GlyphCacheBLF *gc,
561                                     const char *str,
562                                     size_t len,
563                                     struct ResultBLF *r_info,
564                                     int pen_y)
565 {
566   unsigned int c, c_prev = BLI_UTF8_ERR;
567   GlyphBLF *g, *g_prev = NULL;
568   int pen_x = (int)font->pos[0];
569   int pen_y_basis = (int)font->pos[1] + pen_y;
570   size_t i = 0;
571 
572   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
573 
574   /* buffer specific vars */
575   FontBufInfoBLF *buf_info = &font->buf_info;
576   const float *b_col_float = buf_info->col_float;
577   const unsigned char *b_col_char = buf_info->col_char;
578   int chx, chy;
579   int y, x;
580 
581   BLF_KERNING_VARS(font, has_kerning, kern_mode);
582 
583   blf_font_ensure_ascii_kerning(font, gc, kern_mode);
584 
585   /* another buffer specific call for color conversion */
586 
587   while ((i < len) && str[i]) {
588     BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
589 
590     if (UNLIKELY(c == BLI_UTF8_ERR)) {
591       break;
592     }
593     if (UNLIKELY(g == NULL)) {
594       continue;
595     }
596     if (has_kerning) {
597       BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
598     }
599 
600     chx = pen_x + ((int)g->pos[0]);
601     chy = pen_y_basis + g->dims[1];
602 
603     if (g->pitch < 0) {
604       pen_y = pen_y_basis + (g->dims[1] - g->pos[1]);
605     }
606     else {
607       pen_y = pen_y_basis - (g->dims[1] - g->pos[1]);
608     }
609 
610     if ((chx + g->dims[0]) >= 0 && chx < buf_info->dims[0] && (pen_y + g->dims[1]) >= 0 &&
611         pen_y < buf_info->dims[1]) {
612       /* don't draw beyond the buffer bounds */
613       int width_clip = g->dims[0];
614       int height_clip = g->dims[1];
615       int yb_start = g->pitch < 0 ? 0 : g->dims[1] - 1;
616 
617       if (width_clip + chx > buf_info->dims[0]) {
618         width_clip -= chx + width_clip - buf_info->dims[0];
619       }
620       if (height_clip + pen_y > buf_info->dims[1]) {
621         height_clip -= pen_y + height_clip - buf_info->dims[1];
622       }
623 
624       /* drawing below the image? */
625       if (pen_y < 0) {
626         yb_start += (g->pitch < 0) ? -pen_y : pen_y;
627         height_clip += pen_y;
628         pen_y = 0;
629       }
630 
631       if (buf_info->fbuf) {
632         int yb = yb_start;
633         for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
634           for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
635             const char a_byte = *(g->bitmap + x + (yb * g->pitch));
636             if (a_byte) {
637               const float a = (a_byte / 255.0f) * b_col_float[3];
638               const size_t buf_ofs = (((size_t)(chx + x) +
639                                        ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
640                                       (size_t)buf_info->ch);
641               float *fbuf = buf_info->fbuf + buf_ofs;
642 
643               if (a >= 1.0f) {
644                 fbuf[0] = b_col_float[0];
645                 fbuf[1] = b_col_float[1];
646                 fbuf[2] = b_col_float[2];
647                 fbuf[3] = 1.0f;
648               }
649               else {
650                 fbuf[0] = (b_col_float[0] * a) + (fbuf[0] * (1.0f - a));
651                 fbuf[1] = (b_col_float[1] * a) + (fbuf[1] * (1.0f - a));
652                 fbuf[2] = (b_col_float[2] * a) + (fbuf[2] * (1.0f - a));
653                 fbuf[3] = MIN2(fbuf[3] + a, 1.0f); /* clamp to 1.0 */
654               }
655             }
656           }
657 
658           if (g->pitch < 0) {
659             yb++;
660           }
661           else {
662             yb--;
663           }
664         }
665       }
666 
667       if (buf_info->cbuf) {
668         int yb = yb_start;
669         for (y = ((chy >= 0) ? 0 : -chy); y < height_clip; y++) {
670           for (x = ((chx >= 0) ? 0 : -chx); x < width_clip; x++) {
671             const char a_byte = *(g->bitmap + x + (yb * g->pitch));
672 
673             if (a_byte) {
674               const float a = (a_byte / 255.0f) * b_col_float[3];
675               const size_t buf_ofs = (((size_t)(chx + x) +
676                                        ((size_t)(pen_y + y) * (size_t)buf_info->dims[0])) *
677                                       (size_t)buf_info->ch);
678               unsigned char *cbuf = buf_info->cbuf + buf_ofs;
679 
680               if (a >= 1.0f) {
681                 cbuf[0] = b_col_char[0];
682                 cbuf[1] = b_col_char[1];
683                 cbuf[2] = b_col_char[2];
684                 cbuf[3] = 255;
685               }
686               else {
687                 cbuf[0] = (unsigned char)((b_col_char[0] * a) + (cbuf[0] * (1.0f - a)));
688                 cbuf[1] = (unsigned char)((b_col_char[1] * a) + (cbuf[1] * (1.0f - a)));
689                 cbuf[2] = (unsigned char)((b_col_char[2] * a) + (cbuf[2] * (1.0f - a)));
690                 /* clamp to 255 */
691                 cbuf[3] = (unsigned char)MIN2((int)cbuf[3] + (int)(a * 255), 255);
692               }
693             }
694           }
695 
696           if (g->pitch < 0) {
697             yb++;
698           }
699           else {
700             yb--;
701           }
702         }
703       }
704     }
705 
706     pen_x += g->advance_i;
707     g_prev = g;
708     c_prev = c;
709   }
710 
711   if (r_info) {
712     r_info->lines = 1;
713     r_info->width = pen_x;
714   }
715 }
716 
blf_font_draw_buffer(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info)717 void blf_font_draw_buffer(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
718 {
719   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
720   blf_font_draw_buffer_ex(font, gc, str, len, r_info, 0);
721   blf_glyph_cache_release(font);
722 }
723 
blf_font_width_to_strlen_glyph_process(FontBLF * font,const bool has_kerning,const FT_UInt kern_mode,const uint c_prev,const uint c,GlyphBLF * g_prev,GlyphBLF * g,int * pen_x,const int width_i)724 static bool blf_font_width_to_strlen_glyph_process(FontBLF *font,
725                                                    const bool has_kerning,
726                                                    const FT_UInt kern_mode,
727                                                    const uint c_prev,
728                                                    const uint c,
729                                                    GlyphBLF *g_prev,
730                                                    GlyphBLF *g,
731                                                    int *pen_x,
732                                                    const int width_i)
733 {
734   if (UNLIKELY(c == BLI_UTF8_ERR)) {
735     return true; /* break the calling loop. */
736   }
737   if (UNLIKELY(g == NULL)) {
738     return false; /* continue the calling loop. */
739   }
740   if (has_kerning) {
741     BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, *pen_x);
742   }
743 
744   *pen_x += g->advance_i;
745 
746   return (*pen_x >= width_i);
747 }
748 
blf_font_width_to_strlen(FontBLF * font,const char * str,size_t len,float width,float * r_width)749 size_t blf_font_width_to_strlen(
750     FontBLF *font, const char *str, size_t len, float width, float *r_width)
751 {
752   unsigned int c, c_prev = BLI_UTF8_ERR;
753   GlyphBLF *g, *g_prev;
754   int pen_x, width_new;
755   size_t i, i_prev;
756 
757   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
758   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
759   const int width_i = (int)width;
760 
761   BLF_KERNING_VARS(font, has_kerning, kern_mode);
762 
763   if (has_kerning) {
764     blf_font_ensure_ascii_kerning(font, gc, kern_mode);
765   }
766 
767   for (i_prev = i = 0, width_new = pen_x = 0, g_prev = NULL, c_prev = 0; (i < len) && str[i];
768        i_prev = i, width_new = pen_x, c_prev = c, g_prev = g) {
769     BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
770 
771     if (blf_font_width_to_strlen_glyph_process(
772             font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) {
773       break;
774     }
775   }
776 
777   if (r_width) {
778     *r_width = (float)width_new;
779   }
780 
781   blf_glyph_cache_release(font);
782   return i_prev;
783 }
784 
blf_font_width_to_rstrlen(FontBLF * font,const char * str,size_t len,float width,float * r_width)785 size_t blf_font_width_to_rstrlen(
786     FontBLF *font, const char *str, size_t len, float width, float *r_width)
787 {
788   unsigned int c, c_prev = BLI_UTF8_ERR;
789   GlyphBLF *g, *g_prev;
790   int pen_x, width_new;
791   size_t i, i_prev, i_tmp;
792   char *s, *s_prev;
793 
794   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
795   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
796   const int width_i = (int)width;
797 
798   BLF_KERNING_VARS(font, has_kerning, kern_mode);
799 
800   if (has_kerning) {
801     blf_font_ensure_ascii_kerning(font, gc, kern_mode);
802   }
803 
804   i = BLI_strnlen(str, len);
805   s = BLI_str_find_prev_char_utf8(str, &str[i]);
806   i = (size_t)((s != NULL) ? s - str : 0);
807   s_prev = BLI_str_find_prev_char_utf8(str, s);
808   i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0);
809 
810   i_tmp = i;
811   BLF_UTF8_NEXT_FAST(font, gc, g, str, i_tmp, c, glyph_ascii_table);
812   for (width_new = pen_x = 0; (s != NULL);
813        i = i_prev, s = s_prev, c = c_prev, g = g_prev, g_prev = NULL, width_new = pen_x) {
814     s_prev = BLI_str_find_prev_char_utf8(str, s);
815     i_prev = (size_t)((s_prev != NULL) ? s_prev - str : 0);
816 
817     if (s_prev != NULL) {
818       i_tmp = i_prev;
819       BLF_UTF8_NEXT_FAST(font, gc, g_prev, str, i_tmp, c_prev, glyph_ascii_table);
820       BLI_assert(i_tmp == i);
821     }
822 
823     if (blf_font_width_to_strlen_glyph_process(
824             font, has_kerning, kern_mode, c_prev, c, g_prev, g, &pen_x, width_i)) {
825       break;
826     }
827   }
828 
829   if (r_width) {
830     *r_width = (float)width_new;
831   }
832 
833   blf_glyph_cache_release(font);
834   return i;
835 }
836 
blf_font_boundbox_ex(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,rctf * box,struct ResultBLF * r_info,int pen_y)837 static void blf_font_boundbox_ex(FontBLF *font,
838                                  GlyphCacheBLF *gc,
839                                  const char *str,
840                                  size_t len,
841                                  rctf *box,
842                                  struct ResultBLF *r_info,
843                                  int pen_y)
844 {
845   unsigned int c, c_prev = BLI_UTF8_ERR;
846   GlyphBLF *g, *g_prev = NULL;
847   int pen_x = 0;
848   size_t i = 0;
849 
850   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
851 
852   rctf gbox;
853 
854   BLF_KERNING_VARS(font, has_kerning, kern_mode);
855 
856   box->xmin = 32000.0f;
857   box->xmax = -32000.0f;
858   box->ymin = 32000.0f;
859   box->ymax = -32000.0f;
860 
861   blf_font_ensure_ascii_kerning(font, gc, kern_mode);
862 
863   while ((i < len) && str[i]) {
864     BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
865 
866     if (UNLIKELY(c == BLI_UTF8_ERR)) {
867       break;
868     }
869     if (UNLIKELY(g == NULL)) {
870       continue;
871     }
872     if (has_kerning) {
873       BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
874     }
875 
876     gbox.xmin = (float)pen_x;
877     gbox.xmax = (float)pen_x + g->advance;
878     gbox.ymin = g->box.ymin + (float)pen_y;
879     gbox.ymax = g->box.ymax + (float)pen_y;
880 
881     if (gbox.xmin < box->xmin) {
882       box->xmin = gbox.xmin;
883     }
884     if (gbox.ymin < box->ymin) {
885       box->ymin = gbox.ymin;
886     }
887 
888     if (gbox.xmax > box->xmax) {
889       box->xmax = gbox.xmax;
890     }
891     if (gbox.ymax > box->ymax) {
892       box->ymax = gbox.ymax;
893     }
894 
895     pen_x += g->advance_i;
896     g_prev = g;
897     c_prev = c;
898   }
899 
900   if (box->xmin > box->xmax) {
901     box->xmin = 0.0f;
902     box->ymin = 0.0f;
903     box->xmax = 0.0f;
904     box->ymax = 0.0f;
905   }
906 
907   if (r_info) {
908     r_info->lines = 1;
909     r_info->width = pen_x;
910   }
911 }
blf_font_boundbox(FontBLF * font,const char * str,size_t len,rctf * r_box,struct ResultBLF * r_info)912 void blf_font_boundbox(
913     FontBLF *font, const char *str, size_t len, rctf *r_box, struct ResultBLF *r_info)
914 {
915   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
916   blf_font_boundbox_ex(font, gc, str, len, r_box, r_info, 0);
917   blf_glyph_cache_release(font);
918 }
919 
920 /* -------------------------------------------------------------------- */
921 /** \name Word-Wrap Support
922  * \{ */
923 
924 /**
925  * Generic function to add word-wrap support for other existing functions.
926  *
927  * Wraps on spaces and respects newlines.
928  * Intentionally ignores non-unix newlines, tabs and more advanced text formatting.
929  *
930  * \note If we want rich text - we better have a higher level API to handle that
931  * (color, bold, switching fonts... etc).
932  */
blf_font_wrap_apply(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info,void (* callback)(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,int pen_y,void * userdata),void * userdata)933 static void blf_font_wrap_apply(FontBLF *font,
934                                 const char *str,
935                                 size_t len,
936                                 struct ResultBLF *r_info,
937                                 void (*callback)(FontBLF *font,
938                                                  GlyphCacheBLF *gc,
939                                                  const char *str,
940                                                  size_t len,
941                                                  int pen_y,
942                                                  void *userdata),
943                                 void *userdata)
944 {
945   unsigned int c;
946   GlyphBLF *g, *g_prev = NULL;
947   FT_Vector delta;
948   int pen_x = 0, pen_y = 0;
949   size_t i = 0;
950   int lines = 0;
951   int pen_x_next = 0;
952 
953   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
954   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
955 
956   BLF_KERNING_VARS(font, has_kerning, kern_mode);
957 
958   struct WordWrapVars {
959     int wrap_width;
960     size_t start, last[2];
961   } wrap = {font->wrap_width != -1 ? font->wrap_width : INT_MAX, 0, {0, 0}};
962 
963   // printf("%s wrapping (%d, %d) `%s`:\n", __func__, len, strlen(str), str);
964   while ((i < len) && str[i]) {
965 
966     /* wrap vars */
967     size_t i_curr = i;
968     bool do_draw = false;
969 
970     BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
971 
972     if (UNLIKELY(c == BLI_UTF8_ERR)) {
973       break;
974     }
975     if (UNLIKELY(g == NULL)) {
976       continue;
977     }
978     if (has_kerning) {
979       BLF_KERNING_STEP(font, kern_mode, g_prev, g, delta, pen_x);
980     }
981 
982     /**
983      * Implementation Detail (utf8).
984      *
985      * Take care with single byte offsets here,
986      * since this is utf8 we can't be sure a single byte is a single character.
987      *
988      * This is _only_ done when we know for sure the character is ascii (newline or a space).
989      */
990     pen_x_next = pen_x + g->advance_i;
991     if (UNLIKELY((pen_x_next >= wrap.wrap_width) && (wrap.start != wrap.last[0]))) {
992       do_draw = true;
993     }
994     else if (UNLIKELY(((i < len) && str[i]) == 0)) {
995       /* need check here for trailing newline, else we draw it */
996       wrap.last[0] = i + ((g->c != '\n') ? 1 : 0);
997       wrap.last[1] = i;
998       do_draw = true;
999     }
1000     else if (UNLIKELY(g->c == '\n')) {
1001       wrap.last[0] = i_curr + 1;
1002       wrap.last[1] = i;
1003       do_draw = true;
1004     }
1005     else if (UNLIKELY(g->c != ' ' && (g_prev ? g_prev->c == ' ' : false))) {
1006       wrap.last[0] = i_curr;
1007       wrap.last[1] = i_curr;
1008     }
1009 
1010     if (UNLIKELY(do_draw)) {
1011       // printf("(%03d..%03d)  `%.*s`\n",
1012       //        wrap.start, wrap.last[0], (wrap.last[0] - wrap.start) - 1, &str[wrap.start]);
1013 
1014       callback(font, gc, &str[wrap.start], (wrap.last[0] - wrap.start) - 1, pen_y, userdata);
1015       wrap.start = wrap.last[0];
1016       i = wrap.last[1];
1017       pen_x = 0;
1018       pen_y -= gc->glyph_height_max;
1019       g_prev = NULL;
1020       lines += 1;
1021       continue;
1022     }
1023 
1024     pen_x = pen_x_next;
1025     g_prev = g;
1026   }
1027 
1028   // printf("done! lines: %d, width, %d\n", lines, pen_x_next);
1029 
1030   if (r_info) {
1031     r_info->lines = lines;
1032     /* width of last line only (with wrapped lines) */
1033     r_info->width = pen_x_next;
1034   }
1035 
1036   blf_glyph_cache_release(font);
1037 }
1038 
1039 /* blf_font_draw__wrap */
blf_font_draw__wrap_cb(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,int pen_y,void * UNUSED (userdata))1040 static void blf_font_draw__wrap_cb(FontBLF *font,
1041                                    GlyphCacheBLF *gc,
1042                                    const char *str,
1043                                    size_t len,
1044                                    int pen_y,
1045                                    void *UNUSED(userdata))
1046 {
1047   blf_font_draw_ex(font, gc, str, len, NULL, pen_y);
1048 }
blf_font_draw__wrap(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info)1049 void blf_font_draw__wrap(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
1050 {
1051   blf_font_wrap_apply(font, str, len, r_info, blf_font_draw__wrap_cb, NULL);
1052 }
1053 
1054 /* blf_font_boundbox__wrap */
blf_font_boundbox_wrap_cb(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,int pen_y,void * userdata)1055 static void blf_font_boundbox_wrap_cb(
1056     FontBLF *font, GlyphCacheBLF *gc, const char *str, size_t len, int pen_y, void *userdata)
1057 {
1058   rctf *box = userdata;
1059   rctf box_single;
1060 
1061   blf_font_boundbox_ex(font, gc, str, len, &box_single, NULL, pen_y);
1062   BLI_rctf_union(box, &box_single);
1063 }
blf_font_boundbox__wrap(FontBLF * font,const char * str,size_t len,rctf * box,struct ResultBLF * r_info)1064 void blf_font_boundbox__wrap(
1065     FontBLF *font, const char *str, size_t len, rctf *box, struct ResultBLF *r_info)
1066 {
1067   box->xmin = 32000.0f;
1068   box->xmax = -32000.0f;
1069   box->ymin = 32000.0f;
1070   box->ymax = -32000.0f;
1071 
1072   blf_font_wrap_apply(font, str, len, r_info, blf_font_boundbox_wrap_cb, box);
1073 }
1074 
1075 /* blf_font_draw_buffer__wrap */
blf_font_draw_buffer__wrap_cb(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,int pen_y,void * UNUSED (userdata))1076 static void blf_font_draw_buffer__wrap_cb(FontBLF *font,
1077                                           GlyphCacheBLF *gc,
1078                                           const char *str,
1079                                           size_t len,
1080                                           int pen_y,
1081                                           void *UNUSED(userdata))
1082 {
1083   blf_font_draw_buffer_ex(font, gc, str, len, NULL, pen_y);
1084 }
blf_font_draw_buffer__wrap(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info)1085 void blf_font_draw_buffer__wrap(FontBLF *font,
1086                                 const char *str,
1087                                 size_t len,
1088                                 struct ResultBLF *r_info)
1089 {
1090   blf_font_wrap_apply(font, str, len, r_info, blf_font_draw_buffer__wrap_cb, NULL);
1091 }
1092 
1093 /** \} */
1094 
blf_font_width_and_height(FontBLF * font,const char * str,size_t len,float * r_width,float * r_height,struct ResultBLF * r_info)1095 void blf_font_width_and_height(FontBLF *font,
1096                                const char *str,
1097                                size_t len,
1098                                float *r_width,
1099                                float *r_height,
1100                                struct ResultBLF *r_info)
1101 {
1102   float xa, ya;
1103   rctf box;
1104 
1105   if (font->flags & BLF_ASPECT) {
1106     xa = font->aspect[0];
1107     ya = font->aspect[1];
1108   }
1109   else {
1110     xa = 1.0f;
1111     ya = 1.0f;
1112   }
1113 
1114   if (font->flags & BLF_WORD_WRAP) {
1115     blf_font_boundbox__wrap(font, str, len, &box, r_info);
1116   }
1117   else {
1118     blf_font_boundbox(font, str, len, &box, r_info);
1119   }
1120   *r_width = (BLI_rctf_size_x(&box) * xa);
1121   *r_height = (BLI_rctf_size_y(&box) * ya);
1122 }
1123 
blf_font_width(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info)1124 float blf_font_width(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
1125 {
1126   float xa;
1127   rctf box;
1128 
1129   if (font->flags & BLF_ASPECT) {
1130     xa = font->aspect[0];
1131   }
1132   else {
1133     xa = 1.0f;
1134   }
1135 
1136   if (font->flags & BLF_WORD_WRAP) {
1137     blf_font_boundbox__wrap(font, str, len, &box, r_info);
1138   }
1139   else {
1140     blf_font_boundbox(font, str, len, &box, r_info);
1141   }
1142   return BLI_rctf_size_x(&box) * xa;
1143 }
1144 
blf_font_height(FontBLF * font,const char * str,size_t len,struct ResultBLF * r_info)1145 float blf_font_height(FontBLF *font, const char *str, size_t len, struct ResultBLF *r_info)
1146 {
1147   float ya;
1148   rctf box;
1149 
1150   if (font->flags & BLF_ASPECT) {
1151     ya = font->aspect[1];
1152   }
1153   else {
1154     ya = 1.0f;
1155   }
1156 
1157   if (font->flags & BLF_WORD_WRAP) {
1158     blf_font_boundbox__wrap(font, str, len, &box, r_info);
1159   }
1160   else {
1161     blf_font_boundbox(font, str, len, &box, r_info);
1162   }
1163   return BLI_rctf_size_y(&box) * ya;
1164 }
1165 
blf_font_fixed_width(FontBLF * font)1166 float blf_font_fixed_width(FontBLF *font)
1167 {
1168   const unsigned int c = ' ';
1169 
1170   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1171   blf_font_ensure_ascii_table(font, gc);
1172 
1173   GlyphBLF *g = blf_glyph_search(gc, c);
1174   if (!g) {
1175     g = blf_glyph_add(font, gc, FT_Get_Char_Index(font->face, c), c);
1176 
1177     /* if we don't find the glyph. */
1178     if (!g) {
1179       blf_glyph_cache_release(font);
1180       return 0.0f;
1181     }
1182   }
1183 
1184   blf_glyph_cache_release(font);
1185   return g->advance;
1186 }
1187 
1188 /* -------------------------------------------------------------------- */
1189 /** \name Glyph Bound Box with Callback
1190  * \{ */
1191 
blf_font_boundbox_foreach_glyph_ex(FontBLF * font,GlyphCacheBLF * gc,const char * str,size_t len,BLF_GlyphBoundsFn user_fn,void * user_data,struct ResultBLF * r_info,int pen_y)1192 static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
1193                                                GlyphCacheBLF *gc,
1194                                                const char *str,
1195                                                size_t len,
1196                                                BLF_GlyphBoundsFn user_fn,
1197                                                void *user_data,
1198                                                struct ResultBLF *r_info,
1199                                                int pen_y)
1200 {
1201   unsigned int c, c_prev = BLI_UTF8_ERR;
1202   GlyphBLF *g, *g_prev = NULL;
1203   int pen_x = 0;
1204   size_t i = 0, i_curr;
1205   rcti gbox;
1206 
1207   if (len == 0) {
1208     /* early output. */
1209     return;
1210   }
1211 
1212   GlyphBLF **glyph_ascii_table = blf_font_ensure_ascii_table(font, gc);
1213 
1214   BLF_KERNING_VARS(font, has_kerning, kern_mode);
1215 
1216   blf_font_ensure_ascii_kerning(font, gc, kern_mode);
1217 
1218   while ((i < len) && str[i]) {
1219     i_curr = i;
1220     BLF_UTF8_NEXT_FAST(font, gc, g, str, i, c, glyph_ascii_table);
1221 
1222     if (UNLIKELY(c == BLI_UTF8_ERR)) {
1223       break;
1224     }
1225     if (UNLIKELY(g == NULL)) {
1226       continue;
1227     }
1228     if (has_kerning) {
1229       BLF_KERNING_STEP_FAST(font, kern_mode, g_prev, g, c_prev, c, pen_x);
1230     }
1231 
1232     gbox.xmin = pen_x;
1233     gbox.xmax = gbox.xmin + MIN2(g->advance_i, g->dims[0]);
1234     gbox.ymin = pen_y;
1235     gbox.ymax = gbox.ymin - g->dims[1];
1236 
1237     pen_x += g->advance_i;
1238 
1239     if (user_fn(str, i_curr, &gbox, g->advance_i, &g->box, g->pos, user_data) == false) {
1240       break;
1241     }
1242 
1243     g_prev = g;
1244     c_prev = c;
1245   }
1246 
1247   if (r_info) {
1248     r_info->lines = 1;
1249     r_info->width = pen_x;
1250   }
1251 }
blf_font_boundbox_foreach_glyph(FontBLF * font,const char * str,size_t len,BLF_GlyphBoundsFn user_fn,void * user_data,struct ResultBLF * r_info)1252 void blf_font_boundbox_foreach_glyph(FontBLF *font,
1253                                      const char *str,
1254                                      size_t len,
1255                                      BLF_GlyphBoundsFn user_fn,
1256                                      void *user_data,
1257                                      struct ResultBLF *r_info)
1258 {
1259   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1260   blf_font_boundbox_foreach_glyph_ex(font, gc, str, len, user_fn, user_data, r_info, 0);
1261   blf_glyph_cache_release(font);
1262 }
1263 
1264 /** \} */
1265 
blf_font_count_missing_chars(FontBLF * font,const char * str,const size_t len,int * r_tot_chars)1266 int blf_font_count_missing_chars(FontBLF *font,
1267                                  const char *str,
1268                                  const size_t len,
1269                                  int *r_tot_chars)
1270 {
1271   int missing = 0;
1272   size_t i = 0;
1273 
1274   *r_tot_chars = 0;
1275   while (i < len) {
1276     unsigned int c;
1277 
1278     if ((c = str[i]) < 0x80) {
1279       i++;
1280     }
1281     else if ((c = BLI_str_utf8_as_unicode_step(str, &i)) != BLI_UTF8_ERR) {
1282       if (FT_Get_Char_Index((font)->face, c) == 0) {
1283         missing++;
1284       }
1285     }
1286     (*r_tot_chars)++;
1287   }
1288   return missing;
1289 }
1290 
blf_font_free(FontBLF * font)1291 void blf_font_free(FontBLF *font)
1292 {
1293   BLI_spin_lock(&blf_glyph_cache_mutex);
1294   GlyphCacheBLF *gc;
1295 
1296   while ((gc = BLI_pophead(&font->cache))) {
1297     blf_glyph_cache_free(gc);
1298   }
1299 
1300   blf_kerning_cache_clear(font);
1301 
1302   FT_Done_Face(font->face);
1303   if (font->filename) {
1304     MEM_freeN(font->filename);
1305   }
1306   if (font->name) {
1307     MEM_freeN(font->name);
1308   }
1309   MEM_freeN(font);
1310 
1311   BLI_spin_unlock(&blf_glyph_cache_mutex);
1312 }
1313 
blf_font_fill(FontBLF * font)1314 static void blf_font_fill(FontBLF *font)
1315 {
1316   font->aspect[0] = 1.0f;
1317   font->aspect[1] = 1.0f;
1318   font->aspect[2] = 1.0f;
1319   font->pos[0] = 0.0f;
1320   font->pos[1] = 0.0f;
1321   font->angle = 0.0f;
1322 
1323   for (int i = 0; i < 16; i++) {
1324     font->m[i] = 0;
1325   }
1326 
1327   /* annoying bright color so we can see where to add BLF_color calls */
1328   font->color[0] = 255;
1329   font->color[1] = 255;
1330   font->color[2] = 0;
1331   font->color[3] = 255;
1332 
1333   font->clip_rec.xmin = 0.0f;
1334   font->clip_rec.xmax = 0.0f;
1335   font->clip_rec.ymin = 0.0f;
1336   font->clip_rec.ymax = 0.0f;
1337   font->flags = 0;
1338   font->dpi = 0;
1339   font->size = 0;
1340   BLI_listbase_clear(&font->cache);
1341   BLI_listbase_clear(&font->kerning_caches);
1342   font->kerning_cache = NULL;
1343 #if BLF_BLUR_ENABLE
1344   font->blur = 0;
1345 #endif
1346   font->tex_size_max = -1;
1347 
1348   font->buf_info.fbuf = NULL;
1349   font->buf_info.cbuf = NULL;
1350   font->buf_info.dims[0] = 0;
1351   font->buf_info.dims[1] = 0;
1352   font->buf_info.ch = 0;
1353   font->buf_info.col_init[0] = 0;
1354   font->buf_info.col_init[1] = 0;
1355   font->buf_info.col_init[2] = 0;
1356   font->buf_info.col_init[3] = 0;
1357 
1358   font->ft_lib = ft_lib;
1359   font->ft_lib_mutex = &ft_lib_mutex;
1360   font->glyph_cache_mutex = &blf_glyph_cache_mutex;
1361 }
1362 
blf_font_new(const char * name,const char * filename)1363 FontBLF *blf_font_new(const char *name, const char *filename)
1364 {
1365   FontBLF *font;
1366   FT_Error err;
1367   char *mfile;
1368 
1369   font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new");
1370   err = FT_New_Face(ft_lib, filename, 0, &font->face);
1371   if (err) {
1372     MEM_freeN(font);
1373     return NULL;
1374   }
1375 
1376   err = FT_Select_Charmap(font->face, ft_encoding_unicode);
1377   if (err) {
1378     printf("Can't set the unicode character map!\n");
1379     FT_Done_Face(font->face);
1380     MEM_freeN(font);
1381     return NULL;
1382   }
1383 
1384   mfile = blf_dir_metrics_search(filename);
1385   if (mfile) {
1386     err = FT_Attach_File(font->face, mfile);
1387     if (err) {
1388       fprintf(stderr, "FT_Attach_File failed to load '%s' with error %d\n", filename, (int)err);
1389     }
1390     MEM_freeN(mfile);
1391   }
1392 
1393   font->name = BLI_strdup(name);
1394   font->filename = BLI_strdup(filename);
1395   blf_font_fill(font);
1396   return font;
1397 }
1398 
blf_font_attach_from_mem(FontBLF * font,const unsigned char * mem,int mem_size)1399 void blf_font_attach_from_mem(FontBLF *font, const unsigned char *mem, int mem_size)
1400 {
1401   FT_Open_Args open;
1402 
1403   open.flags = FT_OPEN_MEMORY;
1404   open.memory_base = (const FT_Byte *)mem;
1405   open.memory_size = mem_size;
1406   FT_Attach_Stream(font->face, &open);
1407 }
1408 
blf_font_new_from_mem(const char * name,const unsigned char * mem,int mem_size)1409 FontBLF *blf_font_new_from_mem(const char *name, const unsigned char *mem, int mem_size)
1410 {
1411   FontBLF *font;
1412   FT_Error err;
1413 
1414   font = (FontBLF *)MEM_callocN(sizeof(FontBLF), "blf_font_new_from_mem");
1415   err = FT_New_Memory_Face(ft_lib, mem, mem_size, 0, &font->face);
1416   if (err) {
1417     MEM_freeN(font);
1418     return NULL;
1419   }
1420 
1421   err = FT_Select_Charmap(font->face, ft_encoding_unicode);
1422   if (err) {
1423     printf("Can't set the unicode character map!\n");
1424     FT_Done_Face(font->face);
1425     MEM_freeN(font);
1426     return NULL;
1427   }
1428 
1429   font->name = BLI_strdup(name);
1430   font->filename = NULL;
1431   blf_font_fill(font);
1432   return font;
1433 }
1434 
blf_font_height_max(FontBLF * font)1435 int blf_font_height_max(FontBLF *font)
1436 {
1437   int height_max;
1438 
1439   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1440   blf_font_ensure_ascii_table(font, gc);
1441   height_max = gc->glyph_height_max;
1442 
1443   blf_glyph_cache_release(font);
1444   return height_max;
1445 }
1446 
blf_font_width_max(FontBLF * font)1447 int blf_font_width_max(FontBLF *font)
1448 {
1449   int width_max;
1450 
1451   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1452   blf_font_ensure_ascii_table(font, gc);
1453   width_max = gc->glyph_width_max;
1454 
1455   blf_glyph_cache_release(font);
1456   return width_max;
1457 }
1458 
blf_font_descender(FontBLF * font)1459 float blf_font_descender(FontBLF *font)
1460 {
1461   float descender;
1462 
1463   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1464   blf_font_ensure_ascii_table(font, gc);
1465   descender = gc->descender;
1466 
1467   blf_glyph_cache_release(font);
1468   return descender;
1469 }
1470 
blf_font_ascender(FontBLF * font)1471 float blf_font_ascender(FontBLF *font)
1472 {
1473   float ascender;
1474 
1475   GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
1476   blf_font_ensure_ascii_table(font, gc);
1477   ascender = gc->ascender;
1478 
1479   blf_glyph_cache_release(font);
1480   return ascender;
1481 }
1482