Blender V5.0
blf_glyph.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
10
11#include <algorithm>
12#include <cmath>
13#include <cstdio>
14#include <cstdlib>
15#include <cstring>
16
17#include <ft2build.h>
18
19#include FT_FREETYPE_H
20#include FT_GLYPH_H
21#include FT_OUTLINE_H
22#include FT_BITMAP_H
23#include FT_ADVANCES_H /* For FT_Get_Advance. */
24#include FT_MULTIPLE_MASTERS_H /* Variable font support. */
25
26#include "MEM_guardedalloc.h"
27
28#include "BLI_listbase.h"
29#include "BLI_math_color.h"
30#include "BLI_math_geom.h"
31#include "BLI_rect.h"
32
33#include "BLF_api.hh"
34
35#include "DNA_curve_types.h"
36
37#include "GPU_capabilities.hh"
38
39#include "blf_internal.hh"
40#include "blf_internal_types.hh"
41
42#include "BLI_math_vector.h"
43#include "BLI_string_utf8.h"
44
45#ifndef WITH_HEADLESS
46# include "nanosvgrast.h"
47
48# include "svg_icons.h"
49#endif /* WITH_HEADLESS */
50
51#include "BLI_strict_flags.h" /* IWYU pragma: keep. Keep last. */
52
58#define BLF_GAMMA_CORRECT_GLYPHS
59
60/* -------------------------------------------------------------------- */
63
67static FT_Fixed to_16dot16(const double val)
68{
69 return (FT_Fixed)lround(val * 65536.0);
70}
71
75static float from_16dot16(const FT_Fixed value)
76{
77 return float(value) / 65536.0f;
78}
79
81
82/* -------------------------------------------------------------------- */
85
87{
88 for (const std::unique_ptr<GlyphCacheBLF> &gc : font->cache) {
89 if (gc->size == font->size && (gc->bold == ((font->flags & BLF_BOLD) != 0)) &&
90 (gc->italic == ((font->flags & BLF_ITALIC) != 0)) &&
91 (gc->char_weight == font->char_weight) && (gc->char_slant == font->char_slant) &&
92 (gc->char_width == font->char_width) && (gc->char_spacing == font->char_spacing))
93 {
94 return gc.get();
95 }
96 }
97 return nullptr;
98}
99
101{
102 std::unique_ptr<GlyphCacheBLF> gc = std::make_unique<GlyphCacheBLF>();
103
104 gc->size = font->size;
105 gc->bold = ((font->flags & BLF_BOLD) != 0);
106 gc->italic = ((font->flags & BLF_ITALIC) != 0);
107 gc->char_weight = font->char_weight;
108 gc->char_slant = font->char_slant;
109 gc->char_width = font->char_width;
110 gc->char_spacing = font->char_spacing;
111
112 blf_ensure_size(font);
113
114 /* Determine ideal fixed-width size for monospaced output. */
115 FT_UInt gindex = blf_get_char_index(font, U'0');
116 if (gindex && font->face) {
117 FT_Fixed advance = 0;
118 FT_Get_Advance(font->face, gindex, FT_LOAD_NO_HINTING, &advance);
119 /* Use CSS 'ch unit' width, advance of zero character. */
120 gc->fixed_width = int(advance >> 16);
121 }
122 else {
123 /* Font does not have a face or does not contain "0" so use CSS fallback of 1/2 of em. */
124 gc->fixed_width = int((font->ft_size->metrics.height / 2) >> 6);
125 }
126 gc->fixed_width = std::max(gc->fixed_width, 1);
127
128 font->cache.append(std::move(gc));
129
130 return font->cache.last().get();
131}
132
134{
135 font->glyph_cache_mutex.lock();
136
138
139 if (!gc) {
140 gc = blf_glyph_cache_new(font);
141 }
142
143 return gc;
144}
145
147{
148 font->glyph_cache_mutex.unlock();
149}
150
152{
153 this->glyphs.clear();
154 if (this->texture) {
156 }
157 if (this->bitmap_result) {
159 }
160}
161
163{
164 std::lock_guard lock{font->glyph_cache_mutex};
165 font->cache.clear_and_shrink();
166}
167
174 const uint charcode,
175 const uint8_t subpixel)
176{
177 const std::unique_ptr<GlyphBLF> *ptr = gc->glyphs.lookup_ptr_as(
178 GlyphCacheKey{charcode, subpixel});
179 if (ptr != nullptr) {
180 return ptr->get();
181 }
182 return nullptr;
183}
184
185#ifdef BLF_GAMMA_CORRECT_GLYPHS
186
199{
200 /* The following is `char(powf(c / 256.0f, 1.0f / 1.43f) * 256.0f)`. */
201 static const uchar gamma[256] = {
202 0, 5, 9, 11, 14, 16, 19, 21, 23, 25, 26, 28, 30, 32, 34, 35, 37, 38,
203 40, 41, 43, 44, 46, 47, 49, 50, 52, 53, 54, 56, 57, 58, 60, 61, 62, 64,
204 65, 66, 67, 69, 70, 71, 72, 73, 75, 76, 77, 78, 79, 80, 82, 83, 84, 85,
205 86, 87, 88, 89, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104,
206 105, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122,
207 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 133, 134, 135, 136, 137, 138, 139,
208 140, 141, 142, 143, 143, 144, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155,
209 156, 157, 157, 158, 159, 160, 161, 162, 163, 163, 164, 165, 166, 167, 168, 168, 169, 170,
210 171, 172, 173, 173, 174, 175, 176, 177, 178, 178, 179, 180, 181, 182, 182, 183, 184, 185,
211 186, 186, 187, 188, 189, 190, 190, 191, 192, 193, 194, 194, 195, 196, 197, 198, 198, 199,
212 200, 201, 201, 202, 203, 204, 205, 205, 206, 207, 208, 208, 209, 210, 211, 211, 212, 213,
213 214, 214, 215, 216, 217, 217, 218, 219, 220, 220, 221, 222, 223, 223, 224, 225, 226, 226,
214 227, 228, 229, 229, 230, 231, 231, 232, 233, 234, 234, 235, 236, 237, 237, 238, 239, 239,
215 240, 241, 242, 242, 243, 244, 244, 245, 246, 247, 247, 248, 249, 249, 250, 251, 251, 252,
216 253, 254, 254, 255};
217 return gamma[c];
218}
219
220#endif /* BLF_GAMMA_CORRECT_GLYPHS */
221
226 const FT_GlyphSlot glyph,
227 const uint charcode,
228 const FT_UInt glyph_index,
229 const uint8_t subpixel)
230{
231 std::unique_ptr<GlyphBLF> g = std::make_unique<GlyphBLF>();
232 g->c = charcode;
233 g->idx = glyph_index;
234 g->advance_x = (ft_pix)glyph->advance.x;
235 g->subpixel = subpixel;
236
237 FT_BBox bbox;
238 FT_Outline_Get_CBox(&(glyph->outline), &bbox);
239 g->box_xmin = (ft_pix)bbox.xMin;
240 g->box_xmax = (ft_pix)bbox.xMax;
241 g->box_ymin = (ft_pix)bbox.yMin;
242 g->box_ymax = (ft_pix)bbox.yMax;
243
244 /* Used to improve advance when hinting is enabled. */
245 g->lsb_delta = (ft_pix)glyph->lsb_delta;
246 g->rsb_delta = (ft_pix)glyph->rsb_delta;
247
248 if (glyph->format == FT_GLYPH_FORMAT_BITMAP) {
249 /* This has been rendered and we have a bitmap. */
250 g->pos[0] = glyph->bitmap_left;
251 g->pos[1] = glyph->bitmap_top;
252 g->dims[0] = int(glyph->bitmap.width);
253 g->dims[1] = int(glyph->bitmap.rows);
254 g->pitch = glyph->bitmap.pitch;
255 g->num_channels = 1;
256
257 switch (glyph->bitmap.pixel_mode) {
258 case FT_PIXEL_MODE_LCD:
259 g->num_channels = 3;
260 g->dims[0] /= 3;
261 break;
262 case FT_PIXEL_MODE_LCD_V:
263 g->num_channels = 3;
264 g->dims[1] /= 3;
265 g->pitch *= 3;
266 break;
267 case FT_PIXEL_MODE_BGRA:
268 g->num_channels = 4;
269 break;
270 }
271
272 const int buffer_size = g->dims[0] * g->dims[1] * g->num_channels;
273 g->bitmap = MEM_malloc_arrayN<uchar>(size_t(buffer_size), "glyph bitmap");
274
275 if (ELEM(glyph->bitmap.pixel_mode,
276 FT_PIXEL_MODE_GRAY,
277 FT_PIXEL_MODE_GRAY2,
278 FT_PIXEL_MODE_GRAY4))
279 {
280 /* Scale 1, 2, 4-bit gray to 8-bit. */
281 const char scale = char(255 / (glyph->bitmap.num_grays - 1));
282 for (int i = 0; i < buffer_size; i++) {
283#ifdef BLF_GAMMA_CORRECT_GLYPHS
284 /* Convert coverage amounts to perceptually-improved lightness values. */
285 g->bitmap[i] = blf_glyph_gamma(glyph->bitmap.buffer[i] * scale);
286#else
287 g->bitmap[i] = glyph->bitmap.buffer[i] * scale;
288#endif /* BLF_GAMMA_CORRECT_GLYPHS */
289 }
290 }
291 else if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
292 /* RGB (BGR) in successive columns. */
293 for (size_t y = 0; y < size_t(g->dims[1]); y++) {
294 for (size_t x = 0; x < size_t(g->dims[0]); x++) {
295 size_t offs_in = (y * size_t(glyph->bitmap.pitch)) + (x * size_t(g->num_channels));
296 size_t offs_out = (y * size_t(g->dims[0]) * size_t(g->num_channels)) +
297 (x * size_t(g->num_channels));
298 g->bitmap[offs_out + 0] = glyph->bitmap.buffer[offs_in + 2];
299 g->bitmap[offs_out + 1] = glyph->bitmap.buffer[offs_in + 1];
300 g->bitmap[offs_out + 2] = glyph->bitmap.buffer[offs_in + 0];
301 }
302 }
303 }
304 else if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
305 /* RGB (BGR) in successive ROWS. */
306 for (size_t y = 0; y < size_t(g->dims[1]); y++) {
307 for (size_t x = 0; x < size_t(g->dims[0]); x++) {
308 size_t offs_in = (y * size_t(glyph->bitmap.pitch) * size_t(g->num_channels)) + x;
309 size_t offs_out = (y * size_t(g->dims[0]) * size_t(g->num_channels)) +
310 (x * size_t(g->num_channels));
311 g->bitmap[offs_out + 2] = glyph->bitmap.buffer[offs_in];
312 g->bitmap[offs_out + 1] = glyph->bitmap.buffer[offs_in + size_t(glyph->bitmap.pitch)];
313 g->bitmap[offs_out + 0] = glyph->bitmap.buffer[offs_in + size_t(glyph->bitmap.pitch) +
314 size_t(glyph->bitmap.pitch)];
315 }
316 }
317 }
318 else if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
319 /* Convert from BGRA to RGBA. */
320 for (size_t y = 0; y < size_t(g->dims[1]); y++) {
321 for (size_t x = 0; x < size_t(g->dims[0]); x++) {
322 size_t offs_in = (y * size_t(g->pitch)) + (x * size_t(g->num_channels));
323 size_t offs_out = (y * size_t(g->dims[0]) * size_t(g->num_channels)) +
324 (x * size_t(g->num_channels));
325 g->bitmap[offs_out + 0] = glyph->bitmap.buffer[offs_in + 2];
326 g->bitmap[offs_out + 1] = glyph->bitmap.buffer[offs_in + 1];
327 g->bitmap[offs_out + 2] = glyph->bitmap.buffer[offs_in + 0];
328 g->bitmap[offs_out + 3] = glyph->bitmap.buffer[offs_in + 3];
329 }
330 }
331 }
332 else {
333 memcpy(g->bitmap, glyph->bitmap.buffer, size_t(buffer_size));
334 }
335 }
336
337 GlyphBLF *result = g.get();
338 GlyphCacheKey key = {charcode, subpixel};
339 gc->glyphs.add(key, std::move(g));
340 return result;
341}
342
343#ifndef WITH_HEADLESS
345{
346 /* Add an empty GlyphBLF to the cache and return it. With
347 * zero dimensions it will be skipped by blf_glyph_draw. */
348 std::unique_ptr<GlyphBLF> g = std::make_unique<GlyphBLF>();
349 g->c = charcode;
350 GlyphBLF *result = g.get();
351 GlyphCacheKey key = {charcode, 0};
352 gc->glyphs.add(key, std::move(g));
353 return result;
354}
355
357 GlyphCacheBLF *gc,
358 const uint charcode,
359 const bool color,
360 blender::FunctionRef<void(std::string &)> edit_source_cb = nullptr)
361{
362 std::string svg_source = blf_get_icon_svg(int(charcode) - BLF_ICON_OFFSET);
363 if (edit_source_cb) {
364 edit_source_cb(svg_source);
365 }
366
367 NSVGimage *image = nsvgParse(svg_source.data(), "px", 96.0f);
368
369 if (image == nullptr) {
370 return blf_glyph_cache_add_blank(gc, charcode);
371 }
372
373 if (image->width == 0 || image->height == 0) {
374 nsvgDelete(image);
375 return blf_glyph_cache_add_blank(gc, charcode);
376 }
377
378 NSVGrasterizer *rast = nsvgCreateRasterizer();
379 if (rast == nullptr) {
380 nsvgDelete(image);
381 return blf_glyph_cache_add_blank(gc, charcode);
382 }
383
384 float scale = (gc->size / 1600.0f);
385 const int dest_w = int(ceil(image->width * scale));
386 const int dest_h = int(ceil(image->height * scale));
387 scale = float(dest_w) / image->width;
388
389 blender::Array<uchar> render_bmp(dest_w * dest_h * 4);
390
391 nsvgRasterize(rast, image, 0.0f, 0.0f, scale, render_bmp.data(), dest_w, dest_h, dest_w * 4);
392 nsvgDeleteRasterizer(rast);
393
394 /* Bitmaps vary in size, so calculate the offsets needed when drawn. */
395 const int offset_x = std::max(int(round((gc->size - (image->width * scale)) / 2.0f)),
396 int(-100.0f * scale));
397
398 const int offset_y = std::max(int(ceil((gc->size + float(dest_h)) / 2.0f)),
399 dest_h - int(100.0f * scale));
400
401 nsvgDelete(image);
402
403 std::unique_ptr<GlyphBLF> g = std::make_unique<GlyphBLF>();
404 g->c = charcode;
405 g->idx = 0;
406 g->advance_x = dest_w * 64;
407 g->subpixel = 0;
408 g->box_xmin = 0;
409 g->box_xmax = dest_w * 64;
410 g->box_ymin = 0;
411 g->box_ymax = dest_h * 64;
412 g->lsb_delta = 0;
413 g->rsb_delta = 0;
414 g->pos[0] = offset_x;
415 g->pos[1] = offset_y;
416 g->dims[0] = dest_w;
417 g->dims[1] = dest_h;
418 g->pitch = dest_w;
419 g->num_channels = color ? 4 : 1;
420
421 const int buffer_size = g->dims[0] * g->dims[1] * g->num_channels;
422 g->bitmap = MEM_malloc_arrayN<uchar>(size_t(buffer_size), "glyph bitmap");
423
424 if (color) {
425 memcpy(g->bitmap, render_bmp.data(), size_t(buffer_size));
426 }
427 else {
428 /* Convert from RGBA to coverage map. */
429 for (int64_t y = 0; y < int64_t(g->dims[1]); y++) {
430 for (int64_t x = 0; x < int64_t(g->dims[0]); x++) {
431 int64_t offs_in = (y * int64_t(dest_w) * 4) + (x * 4);
432 int64_t offs_out = (y * int64_t(g->dims[0]) + x);
433 g->bitmap[offs_out] = uchar(float(srgb_to_grayscale_byte(&render_bmp[offs_in])) *
434 (float(render_bmp[int64_t(offs_in + 3)]) / 255.0f));
435 }
436 }
437 }
438
439 GlyphBLF *result = g.get();
440 GlyphCacheKey key = {charcode, 0};
441 gc->glyphs.add(key, std::move(g));
442 return result;
443}
444#endif /* WITH_HEADLESS */
445
447
448/* -------------------------------------------------------------------- */
454
458 int coverage_bit; /* 0-122. -1 is N/A. */
459 /* Later we add primary script and language for Harfbuzz, data from
460 * https://en.wikipedia.org/wiki/Unicode_block */
461};
462
463static const UnicodeBlock unicode_blocks[] = {
464 /* Must be in ascending order by start of range. */
465 {0x0, 0x7F, 0}, /* Basic Latin. */
466 {0x80, 0xFF, 1}, /* Latin-1 Supplement. */
467 {0x100, 0x17F, 2}, /* Latin Extended-A. */
468 {0x180, 0x24F, 3}, /* Latin Extended-B. */
469 {0x250, 0x2AF, 4}, /* IPA Extensions. */
470 {0x2B0, 0x2FF, 5}, /* Spacing Modifier Letters. */
471 {0x300, 0x36F, 6}, /* Combining Diacritical Marks. */
472 {0x370, 0x3FF, 7}, /* Greek. */
473 {0x400, 0x52F, 9}, /* Cyrillic. */
474 {0x530, 0x58F, 10}, /* Armenian. */
475 {0x590, 0x5FF, 11}, /* Hebrew. */
476 {0x600, 0x6FF, 13}, /* Arabic. */
477 {0x700, 0x74F, 71}, /* Syriac. */
478 {0x750, 0x77F, 13}, /* Arabic Supplement. */
479 {0x780, 0x7BF, 72}, /* Thaana. */
480 {0x7C0, 0x7FF, 14}, /* NKo. */
481 {0x800, 0x83F, -1}, /* Samaritan. */
482 {0x840, 0x85F, -1}, /* Mandaic. */
483 {0x900, 0x97F, 15}, /* Devanagari. */
484 {0x980, 0x9FF, 16}, /* Bengali. */
485 {0xA00, 0xA7F, 17}, /* Gurmukhi. */
486 {0xA80, 0xAFF, 18}, /* Gujarati. */
487 {0xB00, 0xB7F, 19}, /* Oriya. */
488 {0xB80, 0xBFF, 20}, /* Tamil. */
489 {0xC00, 0xC7F, 21}, /* Telugu. */
490 {0xC80, 0xCFF, 22}, /* Kannada. */
491 {0xD00, 0xD7F, 23}, /* Malayalam. */
492 {0xD80, 0xDFF, 73}, /* Sinhala. */
493 {0xE00, 0xE7F, 24}, /* Thai. */
494 {0xE80, 0xEFF, 25}, /* Lao. */
495 {0xF00, 0xFFF, 70}, /* Tibetan. */
496 {0x1000, 0x109F, 74}, /* Myanmar. */
497 {0x10A0, 0x10FF, 26}, /* Georgian. */
498 {0x1100, 0x11FF, 28}, /* Hangul Jamo. */
499 {0x1200, 0x139F, 75}, /* Ethiopic. */
500 {0x13A0, 0x13FF, 76}, /* Cherokee. */
501 {0x1400, 0x167F, 77}, /* Canadian Aboriginal. */
502 {0x1680, 0x169F, 78}, /* Ogham. */
503 {0x16A0, 0x16FF, 79}, /* unic. */
504 {0x1700, 0x171F, 84}, /* Tagalog. */
505 {0x1720, 0x173F, 84}, /* Hanunoo. */
506 {0x1740, 0x175F, 84}, /* Buhid. */
507 {0x1760, 0x177F, 84}, /* Tagbanwa. */
508 {0x1780, 0x17FF, 80}, /* Khmer. */
509 {0x1800, 0x18AF, 81}, /* Mongolian. */
510 {0x1900, 0x194F, 93}, /* Limbu. */
511 {0x1950, 0x197F, 94}, /* Tai Le. */
512 {0x1980, 0x19DF, 95}, /* New Tai Lue". */
513 {0x19E0, 0x19FF, 80}, /* Khmer. */
514 {0x1A00, 0x1A1F, 96}, /* Buginese. */
515 {0x1A20, 0x1AAF, -1}, /* Tai Tham. */
516 {0x1B00, 0x1B7F, 27}, /* Balinese. */
517 {0x1B80, 0x1BBF, 112}, /* Sundanese. */
518 {0x1BC0, 0x1BFF, -1}, /* Batak. */
519 {0x1C00, 0x1C4F, 113}, /* Lepcha. */
520 {0x1C50, 0x1C7F, 114}, /* Ol Chiki. */
521 {0x1D00, 0x1DBF, 4}, /* IPA Extensions. */
522 {0x1DC0, 0x1DFF, 6}, /* Combining Diacritical Marks. */
523 {0x1E00, 0x1EFF, 29}, /* Latin Extended Additional. */
524 {0x1F00, 0x1FFF, 30}, /* Greek Extended. */
525 {0x2000, 0x206F, 31}, /* General Punctuation. */
526 {0x2070, 0x209F, 32}, /* Superscripts And Subscripts. */
527 {0x20A0, 0x20CF, 33}, /* Currency Symbols. */
528 {0x20D0, 0x20FF, 34}, /* Combining Diacritical Marks For Symbols. */
529 {0x2100, 0x214F, 35}, /* Letterlike Symbols. */
530 {0x2150, 0x218F, 36}, /* Number Forms. */
531 {0x2190, 0x21FF, 37}, /* Arrows. */
532 {0x2200, 0x22FF, 38}, /* Mathematical Operators. */
533 {0x2300, 0x23FF, 39}, /* Miscellaneous Technical. */
534 {0x2400, 0x243F, 40}, /* Control Pictures. */
535 {0x2440, 0x245F, 41}, /* Optical Character Recognition. */
536 {0x2460, 0x24FF, 42}, /* Enclosed Alphanumerics. */
537 {0x2500, 0x257F, 43}, /* Box Drawing. */
538 {0x2580, 0x259F, 44}, /* Block Elements. */
539 {0x25A0, 0x25FF, 45}, /* Geometric Shapes. */
540 {0x2600, 0x26FF, 46}, /* Miscellaneous Symbols. */
541 {0x2700, 0x27BF, 47}, /* Dingbats. */
542 {0x27C0, 0x27EF, 38}, /* Mathematical Operators. */
543 {0x27F0, 0x27FF, 37}, /* Arrows. */
544 {0x2800, 0x28FF, 82}, /* Braille. */
545 {0x2900, 0x297F, 37}, /* Arrows. */
546 {0x2980, 0x2AFF, 38}, /* Mathematical Operators. */
547 {0x2B00, 0x2BFF, 37}, /* Arrows. */
548 {0x2C00, 0x2C5F, 97}, /* Glagolitic. */
549 {0x2C60, 0x2C7F, 29}, /* Latin Extended Additional. */
550 {0x2C80, 0x2CFF, 8}, /* Coptic. */
551 {0x2D00, 0x2D2F, 26}, /* Georgian. */
552 {0x2D30, 0x2D7F, 98}, /* Tifinagh. */
553 {0x2D80, 0x2DDF, 75}, /* Ethiopic. */
554 {0x2DE0, 0x2DFF, 9}, /* Cyrillic. */
555 {0x2E00, 0x2E7F, 31}, /* General Punctuation. */
556 {0x2E80, 0x2FFF, 59}, /* CJK Unified Ideographs. */
557 {0x3000, 0x303F, 48}, /* CJK Symbols And Punctuation. */
558 {0x3040, 0x309F, 49}, /* Hiragana. */
559 {0x30A0, 0x30FF, 50}, /* Katakana. */
560 {0x3100, 0x312F, 51}, /* Bopomofo. */
561 {0x3130, 0x318F, 52}, /* Hangul Compatibility Jamo. */
562 {0x3190, 0x319F, 59}, /* CJK Unified Ideographs. */
563 {0x31A0, 0x31BF, 51}, /* Bopomofo. */
564 {0x31C0, 0x31EF, 59}, /* CJK Unified Ideographs. */
565 {0x31F0, 0x31FF, 50}, /* Katakana. */
566 {0x3200, 0x32FF, 54}, /* Enclosed CJK Letters And Months. */
567 {0x3300, 0x33FF, 55}, /* CJK Compatibility. */
568 {0x3400, 0x4DBF, 59}, /* CJK Unified Ideographs. */
569 {0x4DC0, 0x4DFF, 99}, /* Yijing. */
570 {0x4E00, 0x9FFF, 59}, /* CJK Unified Ideographs. */
571 {0xA000, 0xA4CF, 83}, /* Yi. */
572 {0xA4D0, 0xA4FF, -1}, /* Lisu. */
573 {0xA500, 0xA63F, 12}, /* Vai. */
574 {0xA640, 0xA69F, 9}, /* Cyrillic. */
575 {0xA6A0, 0xA6FF, -1}, /* Bamum. */
576 {0xA700, 0xA71F, 5}, /* Spacing Modifier Letters. */
577 {0xA720, 0xA7FF, 29}, /* Latin Extended Additional. */
578 {0xA800, 0xA82F, 100}, /* Syloti Nagri. */
579 {0xA840, 0xA87F, 53}, /* Phags-pa. */
580 {0xA880, 0xA8DF, 115}, /* Saurashtra. */
581 {0xA900, 0xA92F, 116}, /* Kayah Li. */
582 {0xA930, 0xA95F, 117}, /* Rejang. */
583 {0xA960, 0xA97F, 56}, /* Hangul Syllables. */
584 {0xA980, 0xA9DF, -1}, /* Javanese. */
585 {0xA9E0, 0xA9FF, 74}, /* Myanmar. */
586 {0xAA00, 0xAA5F, 118}, /* Cham. */
587 {0xAA60, 0xAA7F, 74}, /* Myanmar. */
588 {0xAA80, 0xAADF, -1}, /* Tai Viet. */
589 {0xAAE0, 0xAAFF, -1}, /* Meetei Mayek. */
590 {0xAB00, 0xAB2F, 75}, /* Ethiopic. */
591 {0xAB70, 0xABBF, 76}, /* Cherokee. */
592 {0xABC0, 0xABFF, -1}, /* Meetei Mayek. */
593 {0xAC00, 0xD7AF, 56}, /* Hangul Syllables. */
594 {0xD800, 0xDFFF, 57}, /* Non-Plane 0. */
595 {0xE000, 0xF6FF, 60}, /* Private Use Area. */
596 {0xE700, 0xEFFF, -1}, /* MS Wingdings. */
597 {0xF000, 0xF8FF, -1}, /* MS Symbols. */
598 {0xF900, 0xFAFF, 61}, /* CJK Compatibility Ideographs. */
599 {0xFB00, 0xFB4F, 62}, /* Alphabetic Presentation Forms. */
600 {0xFB50, 0xFDFF, 63}, /* Arabic Presentation Forms-A. */
601 {0xFE00, 0xFE0F, 91}, /* Variation Selectors. */
602 {0xFE10, 0xFE1F, 65}, /* CJK Compatibility Forms. */
603 {0xFE20, 0xFE2F, 64}, /* Combining Half Marks. */
604 {0xFE30, 0xFE4F, 65}, /* CJK Compatibility Forms. */
605 {0xFE50, 0xFE6F, 66}, /* Small Form Variants. */
606 {0xFE70, 0xFEFF, 67}, /* Arabic Presentation Forms-B. */
607 {0xFF00, 0xFFEF, 68}, /* Half-width And Full-width Forms. */
608 {0xFFF0, 0xFFFF, 69}, /* Specials. */
609 {0x10000, 0x1013F, 101}, /* Linear B. */
610 {0x10140, 0x1018F, 102}, /* Ancient Greek Numbers. */
611 {0x10190, 0x101CF, 119}, /* Ancient Symbols. */
612 {0x101D0, 0x101FF, 120}, /* Phaistos Disc. */
613 {0x10280, 0x1029F, 121}, /* Lycian. */
614 {0x102A0, 0x102DF, 121}, /* Carian. */
615 {0x10300, 0x1032F, 85}, /* Old Italic. */
616 {0x10330, 0x1034F, 86}, /* Gothic. */
617 {0x10350, 0x1037F, -1}, /* Old Permic. */
618 {0x10380, 0x1039F, 103}, /* Ugaritic. */
619 {0x103A0, 0x103DF, 104}, /* Old Persian. */
620 {0x10400, 0x1044F, 87}, /* Deseret. */
621 {0x10450, 0x1047F, 105}, /* Shavian. */
622 {0x10480, 0x104AF, 106}, /* Osmanya. */
623 {0x104B0, 0x104FF, -1}, /* Osage. */
624 {0x10500, 0x1052F, -1}, /* Elbasan. */
625 {0x10530, 0x1056F, -1}, /* Caucasian Albanian. */
626 {0x10570, 0x105BF, -1}, /* Vithkuqi. */
627 {0x10600, 0x1077F, -1}, /* Linear A. */
628 {0x10780, 0x107BF, 3}, /* Latin Extended-B. */
629 {0x10800, 0x1083F, 107}, /* Cypriot Syllabary. */
630 {0x10840, 0x1085F, -1}, /* Imperial Aramaic. */
631 {0x10860, 0x1087F, -1}, /* Palmyrene. */
632 {0x10880, 0x108AF, -1}, /* Nabataean. */
633 {0x108E0, 0x108FF, -1}, /* Hatran. */
634 {0x10900, 0x1091F, 58}, /* Phoenician. */
635 {0x10920, 0x1093F, 121}, /* Lydian. */
636 {0x10980, 0x1099F, -1}, /* Meroitic Hieroglyphs. */
637 {0x109A0, 0x109FF, -1}, /* Meroitic Cursive. */
638 {0x10A00, 0x10A5F, 108}, /* Kharoshthi. */
639 {0x10A60, 0x10A7F, -1}, /* Old South Arabian. */
640 {0x10A80, 0x10A9F, -1}, /* Old North Arabian. */
641 {0x10AC0, 0x10AFF, -1}, /* Manichaean. */
642 {0x10B00, 0x10B3F, -1}, /* Avestan. */
643 {0x10B40, 0x10B5F, -1}, /* Inscriptional Parthian. */
644 {0x10B60, 0x10B7F, -1}, /* Inscriptional Pahlavi. */
645 {0x10B80, 0x10BAF, -1}, /* Psalter Pahlavi. */
646 {0x10C00, 0x10C4F, -1}, /* Old Turkic. */
647 {0x10C80, 0x10CFF, -1}, /* Old Hungarian. */
648 {0x10D00, 0x10D3F, -1}, /* Hanifi Rohingya. */
649 {0x108E0, 0x10E7F, -1}, /* Rumi Numeral Symbols. */
650 {0x10E80, 0x10EBF, -1}, /* Yezidi. */
651 {0x10F00, 0x10F2F, -1}, /* Old Sogdian. */
652 {0x10F30, 0x10F6F, -1}, /* Sogdian. */
653 {0x10F70, 0x10FAF, -1}, /* Old Uyghur. */
654 {0x10FB0, 0x10FDF, -1}, /* Chorasmian. */
655 {0x10FE0, 0x10FFF, -1}, /* Elymaic. */
656 {0x11000, 0x1107F, -1}, /* Brahmi. */
657 {0x11080, 0x110CF, -1}, /* Kaithi. */
658 {0x110D0, 0x110FF, -1}, /* Sora Sompeng. */
659 {0x11100, 0x1114F, -1}, /* Chakma. */
660 {0x11150, 0x1117F, -1}, /* Mahajani. */
661 {0x11180, 0x111DF, -1}, /* Sharada. */
662 {0x111E0, 0x111FF, -1}, /* Sinhala Archaic Numbers. */
663 {0x11200, 0x1124F, -1}, /* Khojki. */
664 {0x11280, 0x112AF, -1}, /* Multani. */
665 {0x112B0, 0x112FF, -1}, /* Khudawadi. */
666 {0x11300, 0x1137F, -1}, /* Grantha. */
667 {0x11400, 0x1147F, -1}, /* Newa. */
668 {0x11480, 0x114DF, -1}, /* Tirhuta. */
669 {0x11580, 0x115FF, -1}, /* Siddham. */
670 {0x11600, 0x1165F, -1}, /* Modi. */
671 {0x11660, 0x1167F, 81}, /* Mongolian. */
672 {0x11680, 0x116CF, -1}, /* Takri. */
673 {0x11700, 0x1174F, -1}, /* Ahom. */
674 {0x11800, 0x1184F, -1}, /* Dogra. */
675 {0x118A0, 0x118FF, -1}, /* Warang Citi. */
676 {0x11900, 0x1195F, -1}, /* Dives Akuru. */
677 {0x119A0, 0x119FF, -1}, /* Nandinagari. */
678 {0x11A00, 0x11A4F, -1}, /* Zanabazar Square. */
679 {0x11A50, 0x11AAF, -1}, /* Soyombo. */
680 {0x11AB0, 0x11ABF, 77}, /* Canadian Aboriginal Syllabics. */
681 {0x11AC0, 0x11AFF, -1}, /* Pau Cin Hau. */
682 {0x11C00, 0x11C6F, -1}, /* Bhaiksuki. */
683 {0x11C70, 0x11CBF, -1}, /* Marchen. */
684 {0x11D00, 0x11D5F, -1}, /* Masaram Gondi. */
685 {0x11D60, 0x11DAF, -1}, /* Gunjala Gondi. */
686 {0x11EE0, 0x11EFF, -1}, /* Makasar. */
687 {0x11FB0, 0x11FBF, -1}, /* Lisu. */
688 {0x11FC0, 0x11FFF, 20}, /* Tamil. */
689 {0x12000, 0x1254F, 110}, /* Cuneiform. */
690 {0x12F90, 0x12FFF, -1}, /* Cypro-Minoan. */
691 {0x13000, 0x1343F, -1}, /* Egyptian Hieroglyphs. */
692 {0x14400, 0x1467F, -1}, /* Anatolian Hieroglyphs. */
693 {0x16800, 0x16A3F, -1}, /* Bamum. */
694 {0x16A40, 0x16A6F, -1}, /* Mro. */
695 {0x16A70, 0x16ACF, -1}, /* Tangsa. */
696 {0x16AD0, 0x16AFF, -1}, /* Bassa Vah. */
697 {0x16B00, 0x16B8F, -1}, /* Pahawh Hmong. */
698 {0x16E40, 0x16E9F, -1}, /* Medefaidrin. */
699 {0x16F00, 0x16F9F, -1}, /* Miao. */
700 {0x16FE0, 0x16FFF, -1}, /* Ideographic Symbols. */
701 {0x17000, 0x18AFF, -1}, /* Tangut. */
702 {0x1B170, 0x1B2FF, -1}, /* Nushu. */
703 {0x1BC00, 0x1BC9F, -1}, /* Duployan. */
704 {0x1D000, 0x1D24F, 88}, /* Musical Symbols. */
705 {0x1D2E0, 0x1D2FF, -1}, /* Mayan Numerals. */
706 {0x1D300, 0x1D35F, 109}, /* Tai Xuan Jing. */
707 {0x1D360, 0x1D37F, 111}, /* Counting Rod Numerals. */
708 {0x1D400, 0x1D7FF, 89}, /* Mathematical Alphanumeric Symbols. */
709 {0x1E2C0, 0x1E2FF, -1}, /* Wancho. */
710 {0x1E800, 0x1E8DF, -1}, /* Mende Kikakui. */
711 {0x1E900, 0x1E95F, -1}, /* Adlam. */
712 {0x1EC70, 0x1ECBF, -1}, /* Indic Siyaq Numbers. */
713 {0x1F000, 0x1F02F, 122}, /* Mahjong Tiles. */
714 {0x1F030, 0x1F09F, 122}, /* Domino Tiles. */
715 {0x1F600, 0x1F64F, -1}, /* Emoticons. */
716 {0x20000, 0x2A6DF, 59}, /* CJK Unified Ideographs. */
717 {0x2F800, 0x2FA1F, 61}, /* CJK Compatibility Ideographs. */
718 {0xE0000, 0xE007F, 92}, /* Tags. */
719 {0xE0100, 0xE01EF, 91}, /* Variation Selectors. */
720 {0xF0000, 0x10FFFD, 90}}; /* Private Use Supplementary. */
721
726{
727 if (charcode < 0x80) {
728 /* Shortcut to Basic Latin. */
729 return &unicode_blocks[0];
730 }
731
732 /* Binary search for other blocks. */
733
734 int min = 0;
735 int max = int(ARRAY_SIZE(unicode_blocks)) - 1;
736
737 if (charcode < unicode_blocks[0].first || charcode > unicode_blocks[max].last) {
738 return nullptr;
739 }
740
741 while (max >= min) {
742 const int mid = (min + max) / 2;
743 if (charcode > unicode_blocks[mid].last) {
744 min = mid + 1;
745 }
746 else if (charcode < unicode_blocks[mid].first) {
747 max = mid - 1;
748 }
749 else {
750 return &unicode_blocks[mid];
751 }
752 }
753
754 return nullptr;
755}
756
757static int blf_charcode_to_coverage_bit(const uint charcode)
758{
759 int coverage_bit = -1;
760 const UnicodeBlock *block = blf_charcode_to_unicode_block(charcode);
761 if (block) {
762 coverage_bit = block->coverage_bit;
763 }
764
765 if (coverage_bit < 0 && charcode > 0xFFFF) {
766 /* No coverage bit, but OpenType specs v.1.3+ says bit 57 implies that there
767 * are code-points supported beyond the BMP, so only check fonts with this set. */
768 coverage_bit = 57;
769 }
770
771 return coverage_bit;
772}
773
774static bool blf_font_has_coverage_bit(const FontBLF *font, const int coverage_bit)
775{
776 if (coverage_bit < 0) {
777 return false;
778 }
779 return (font->unicode_ranges[uint(coverage_bit) >> 5] & (1u << (uint(coverage_bit) % 32)));
780}
781
786static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode)
787{
788 FT_UInt glyph_index = blf_get_char_index(*font, charcode);
789 if (glyph_index) {
790 return glyph_index;
791 }
792
793 /* Fonts managed by the cache can fallback. Unless specifically forbidden. */
794 if (!((*font)->flags & BLF_CACHED) || ((*font)->flags & BLF_NO_FALLBACK)) {
795 return 0;
796 }
797
798 /* First look in fonts that match the coverage bit. */
799 int coverage_bit = blf_charcode_to_coverage_bit(charcode);
800 for (int i = 0; i < BLF_MAX_FONT; i++) {
801 FontBLF *f = global_font[i];
802 if (!f || f == *font || !(f->flags & BLF_DEFAULT) ||
803 (!((*font)->flags & BLF_MONOSPACED) && (f->flags & BLF_MONOSPACED)) ||
805 {
806 continue;
807 }
808 if (coverage_bit < 0 || blf_font_has_coverage_bit(f, coverage_bit)) {
809 glyph_index = blf_get_char_index(f, charcode);
810 if (glyph_index) {
811 *font = f;
812 return glyph_index;
813 }
814 }
815 }
816
817 /* Next look in the rest. */
818 for (int i = 0; i < BLF_MAX_FONT; i++) {
819 FontBLF *f = global_font[i];
820 if (!f || f == *font || !(f->flags & BLF_DEFAULT)) {
821 continue;
822 }
823 if (coverage_bit >= 0 && !blf_font_has_coverage_bit(f, coverage_bit)) {
824 glyph_index = blf_get_char_index(f, charcode);
825 if (glyph_index) {
826 *font = f;
827 return glyph_index;
828 }
829 }
830 }
831
832#ifndef NDEBUG
833 /* Disable this print even in debug mode as it floods the console
834 * when browsing a file-system containing unknown characters. */
835 // printf("Unicode character U+%04X not found in loaded fonts. \n", charcode);
836#endif
837
838 return 0;
839}
840
842
843/* -------------------------------------------------------------------- */
846
850static FT_GlyphSlot blf_glyph_load(FontBLF *font,
851 const FT_UInt glyph_index,
852 const bool outline_only)
853{
854 int load_flags;
855
856 if (outline_only) {
857 load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP;
858 }
859 else if (font->flags & BLF_MONOCHROME) {
860 load_flags = FT_LOAD_TARGET_MONO;
861 }
862 else {
863 load_flags = FT_LOAD_NO_BITMAP;
864 if (font->flags & BLF_HINTING_NONE) {
865 load_flags |= FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING;
866 }
867 else if (font->flags & BLF_HINTING_SLIGHT) {
868 load_flags |= FT_LOAD_TARGET_LIGHT;
869 }
870 else if (font->flags & BLF_HINTING_FULL) {
871 load_flags |= FT_LOAD_TARGET_NORMAL;
872 }
873 else {
874 /* Default "Auto" is Slight (vertical only) hinting. */
875 load_flags |= FT_LOAD_TARGET_LIGHT;
876 }
877 }
878
879 if (!outline_only && FT_HAS_COLOR(font->face)) {
880 load_flags |= FT_LOAD_COLOR;
881 }
882
883 if (FT_Load_Glyph(font->face, glyph_index, load_flags) == FT_Err_Ok) {
884 return font->face->glyph;
885 }
886 return nullptr;
887}
888
890
891/* -------------------------------------------------------------------- */
894
898static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph)
899{
900 int render_mode;
901
902 if (font->flags & BLF_MONOCHROME) {
903 render_mode = FT_RENDER_MODE_MONO;
904 }
905 else if (font->flags & BLF_HINTING_SLIGHT) {
906 render_mode = FT_RENDER_MODE_LIGHT;
907 }
908 else {
909 render_mode = FT_RENDER_MODE_NORMAL;
910 }
911
912 /* Render the glyph curves to a bitmap. */
913 FT_Error err = FT_Render_Glyph(glyph, FT_Render_Mode(render_mode));
914 if (err != FT_Err_Ok) {
915 return false;
916 }
917
918 if (ELEM(glyph->bitmap.pixel_mode, FT_PIXEL_MODE_MONO, FT_PIXEL_MODE_GRAY2, FT_PIXEL_MODE_GRAY4))
919 {
920 /* Convert to 8 bit per pixel */
921 FT_Bitmap tempbitmap;
922 FT_Bitmap_New(&tempbitmap);
923
924 /* Does Blender use Pitch 1 always? It works so far */
925 err += FT_Bitmap_Convert(font->ft_lib, &glyph->bitmap, &tempbitmap, 1);
926 err += FT_Bitmap_Copy(font->ft_lib, &tempbitmap, &glyph->bitmap);
927 err += FT_Bitmap_Done(font->ft_lib, &tempbitmap);
928 }
929
930 return (err == FT_Err_Ok);
931}
932
934
935/* -------------------------------------------------------------------- */
938
946static const FT_Var_Axis *blf_var_axis_by_tag(const FT_MM_Var *variations,
947 const uint32_t tag,
948 int *r_axis_index)
949{
950 *r_axis_index = -1;
951 if (!variations) {
952 return nullptr;
953 }
954 for (int i = 0; i < int(variations->num_axis); i++) {
955 if (variations->axis[i].tag == tag) {
956 *r_axis_index = i;
957 return &(variations->axis)[i];
958 }
959 }
960 return nullptr;
961}
962
972[[maybe_unused]] static FT_Fixed blf_factor_to_coordinate(const FT_Var_Axis *axis,
973 const float factor)
974{
975 FT_Fixed value = axis->def;
976 if (factor > 0) {
977 /* Map 0-1 to axis->def - axis->maximum */
978 value += (FT_Fixed)(double(axis->maximum - axis->def) * factor);
979 }
980 else if (factor < 0) {
981 /* Map -1-0 to axis->minimum - axis->def */
982 value += (FT_Fixed)(double(axis->def - axis->minimum) * factor);
983 }
984 return value;
985}
986
998[[maybe_unused]] static bool blf_glyph_set_variation_normalized(const FontBLF *font,
999 FT_Fixed coords[],
1000 const uint32_t tag,
1001 const float factor)
1002{
1003 int axis_index;
1004 const FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index);
1005 if (axis && (axis_index < BLF_VARIATIONS_MAX)) {
1006 coords[axis_index] = blf_factor_to_coordinate(axis, factor);
1007 return true;
1008 }
1009 return false;
1010}
1011
1021 FT_Fixed coords[],
1022 uint32_t tag,
1023 float *value)
1024{
1025 int axis_index;
1026 const FT_Var_Axis *axis = blf_var_axis_by_tag(font->variations, tag, &axis_index);
1027 if (axis && (axis_index < BLF_VARIATIONS_MAX)) {
1028 FT_Fixed int_value = to_16dot16(*value);
1029 CLAMP(int_value, axis->minimum, axis->maximum);
1030 coords[axis_index] = int_value;
1031 *value = from_16dot16(int_value);
1032 return true;
1033 }
1034 return false;
1035}
1036
1045 FT_Fixed coords[],
1046 float current_weight,
1047 float target_weight)
1048{
1049 float value = target_weight;
1050 if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_WEIGHT, &value)) {
1051 return value;
1052 }
1053 return current_weight;
1054}
1055
1064 FT_Fixed coords[],
1065 float current_degrees,
1066 float target_degrees)
1067{
1068 float value = -target_degrees;
1069 if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_SLANT, &value)) {
1070 return -value;
1071 }
1072 return current_degrees;
1073}
1074
1083 FT_Fixed coords[],
1084 float current_width,
1085 float target_width)
1086{
1087 float value = target_width * 100.0f;
1088 if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_WIDTH, &value)) {
1089 return value / 100.0f;
1090 }
1091 return current_width;
1092}
1093
1102 FT_Fixed coords[],
1103 float current_spacing,
1104 float target_spacing)
1105{
1106 float value = target_spacing;
1107 if (blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_SPACING, &value)) {
1108 return value;
1109 }
1110 return current_spacing;
1111}
1112
1121 FT_Fixed coords[],
1122 const float points)
1123{
1124 float value = points;
1125 return blf_glyph_set_variation_float(font, coords, BLF_VARIATION_AXIS_OPTSIZE, &value);
1126}
1127
1129
1130/* -------------------------------------------------------------------- */
1133
1140static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float width, bool monospaced)
1141{
1142 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1143 const FontBLF *font = (FontBLF *)glyph->face->generic.data;
1144 const FT_Pos average_width = font->ft_size->metrics.height;
1145 float factor = width * 0.000225f;
1146 FT_Pos change = (FT_Pos)(float(average_width) * factor);
1147 FT_Outline_EmboldenXY(&glyph->outline, change, 0);
1148 if (monospaced) {
1149 /* Widened fixed-pitch font needs a nudge left. */
1150 FT_Outline_Translate(&glyph->outline, change / -2, 0);
1151 }
1152 else {
1153 /* Need to increase horizontal advance. */
1154 glyph->advance.x += change / 2;
1155 }
1156 return true;
1157 }
1158 return false;
1159}
1160
1167static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float degrees)
1168{
1169 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1170 FT_Matrix transform = {to_16dot16(1), to_16dot16(degrees * 0.0225f), 0, to_16dot16(1)};
1171 FT_Outline_Transform(&glyph->outline, &transform);
1172 if (degrees < 0.0f) {
1173 /* Leftward slant could interfere with prior characters to nudge right. */
1174 const FontBLF *font = (FontBLF *)glyph->face->generic.data;
1175 const FT_Pos average_width = font->ft_size->metrics.height;
1176 FT_Pos change = (FT_Pos)(float(average_width) * degrees * -0.01f);
1177 FT_Outline_Translate(&glyph->outline, change, 0);
1178 }
1179 return true;
1180 }
1181 return false;
1182}
1183
1190static bool blf_glyph_transform_width(FT_GlyphSlot glyph, float factor)
1191{
1192 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1193 float scale = factor + 1.0f;
1194 FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)};
1195 FT_Outline_Transform(&glyph->outline, &matrix);
1196 glyph->advance.x = (FT_Pos)(double(glyph->advance.x) * scale);
1197 return true;
1198 }
1199 return false;
1200}
1201
1208static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor)
1209{
1210 if (glyph->advance.x > 0) {
1211 const FontBLF *font = (FontBLF *)glyph->face->generic.data;
1212 const long int size = font->ft_size->metrics.height;
1213 glyph->advance.x += (FT_Pos)(factor * float(size) / 6.0f);
1214 return true;
1215 }
1216 return false;
1217}
1218
1224static bool blf_glyph_transform_monospace(FT_GlyphSlot glyph, int width)
1225{
1226 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1227 FT_Fixed current = glyph->linearHoriAdvance;
1228 FT_Fixed target = FT_Fixed(width) << 16; /* Do math in 16.16 values. */
1229 if (target < current) {
1230 const FT_Pos embolden = (FT_Pos)((current - target) >> 13);
1231 /* Horizontally widen strokes to counteract narrowing. */
1232 FT_Outline_EmboldenXY(&glyph->outline, embolden, 0);
1233 const float scale = float(target - (embolden << 9)) / float(current);
1234 FT_Matrix matrix = {to_16dot16(scale), 0, 0, to_16dot16(1)};
1235 FT_Outline_Transform(&glyph->outline, &matrix);
1236 }
1237 else if (target > current) {
1238 /* Center narrow glyphs. */
1239 FT_Outline_Translate(&glyph->outline, (FT_Pos)((target - current) >> 11), 0);
1240 }
1241 glyph->advance.x = width << 6;
1242 return true;
1243 }
1244 return false;
1245}
1246
1248
1249/* -------------------------------------------------------------------- */
1252
1256static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font,
1257 FontBLF *glyph_font,
1258 FT_UInt glyph_index,
1259 uint charcode,
1260 uint8_t subpixel,
1261 int fixed_width,
1262 bool outline_only)
1263{
1264 if (glyph_font != settings_font) {
1265 blf_font_size(glyph_font, settings_font->size);
1266 }
1267
1268 blf_ensure_size(glyph_font);
1269
1270 /* Default style values of the font containing the glyph. */
1271 float weight = glyph_font->metrics.weight;
1272 float slant = glyph_font->metrics.slant;
1273 float width = glyph_font->metrics.width;
1274 float spacing = glyph_font->metrics.spacing;
1275
1276 /* Style targets are on the settings_font. */
1277 float weight_target = float(settings_font->char_weight);
1278 if (settings_font->flags & BLF_BOLD) {
1279 weight_target = std::min(weight_target + 300.0f, 900.0f);
1280 }
1281 float slant_target = settings_font->char_slant;
1282 if (settings_font->flags & BLF_ITALIC) {
1283 slant_target = std::min(slant_target + 8.0f, 15.0f);
1284 }
1285 float width_target = settings_font->char_width;
1286 float spacing_target = settings_font->char_spacing;
1287
1288 /* Font variations need to be set before glyph loading. Even if new value is zero. */
1289
1290 if (glyph_font->variations) {
1291 FT_Fixed coords[BLF_VARIATIONS_MAX];
1292 /* Load current design coordinates. */
1293 FT_Get_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
1294 /* Update design coordinates with new values. */
1295
1296 weight = blf_glyph_set_variation_weight(glyph_font, coords, weight, weight_target);
1297 slant = blf_glyph_set_variation_slant(glyph_font, coords, slant, slant_target);
1298 width = blf_glyph_set_variation_width(glyph_font, coords, width, width_target);
1299 spacing = blf_glyph_set_variation_spacing(glyph_font, coords, spacing, spacing_target);
1300 blf_glyph_set_variation_optical_size(glyph_font, coords, settings_font->size);
1301
1302 /* Save updated design coordinates. */
1303 FT_Set_Var_Design_Coordinates(glyph_font->face, BLF_VARIATIONS_MAX, &coords[0]);
1304 }
1305
1306 FT_GlyphSlot glyph = blf_glyph_load(glyph_font, glyph_index, outline_only);
1307 if (!glyph) {
1308 return nullptr;
1309 }
1310
1311 if ((settings_font->flags & BLF_MONOSPACED) && (settings_font != glyph_font)) {
1312 const int col = BLI_wcwidth_or_error(char32_t(charcode));
1313 if (col > 0) {
1314 blf_glyph_transform_monospace(glyph, col * fixed_width);
1315 }
1316 }
1317
1318 /* Fallback glyph transforms, but only if required and not yet done. */
1319
1320 if (weight != weight_target) {
1321 blf_glyph_transform_weight(glyph, weight_target - weight, FT_IS_FIXED_WIDTH(glyph_font));
1322 }
1323 if (slant != slant_target) {
1324 blf_glyph_transform_slant(glyph, slant_target - slant);
1325 }
1326 if (width != width_target) {
1327 blf_glyph_transform_width(glyph, width_target - width);
1328 }
1329 if (spacing != spacing_target) {
1330 blf_glyph_transform_spacing(glyph, spacing_target - spacing);
1331 }
1332
1333 if (outline_only) {
1334 return glyph;
1335 }
1336
1337 FT_Outline_Translate(&glyph->outline, (FT_Pos)subpixel, 0);
1338
1339 if (blf_glyph_render_bitmap(glyph_font, glyph)) {
1340 return glyph;
1341 }
1342 return nullptr;
1343}
1344
1345GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode, uint8_t subpixel)
1346{
1347 if (charcode < 32) {
1348 if (ELEM(charcode, 0x10, 0x13)) {
1349 /* Do not render line feed or carriage return. #134972. */
1350 return nullptr;
1351 }
1352 /* Other C0 controls (U+0000 - U+001F) can show as space. #135421. */
1353 /* TODO: Return all but TAB as ".notdef" character when we have our own. */
1354 return blf_glyph_cache_find_glyph(gc, ' ', 0);
1355 }
1356
1357 GlyphBLF *g = blf_glyph_cache_find_glyph(gc, charcode, subpixel);
1358 if (g) {
1359 return g;
1360 }
1361
1362 /* Glyph might not come from the initial font. */
1363 FontBLF *font_with_glyph = font;
1364 FT_UInt glyph_index = blf_glyph_index_from_charcode(&font_with_glyph, charcode);
1365
1366 if (!glyph_index) {
1367 /* 1 = id of ICON_CHAR_NOTDEF */
1368 return blf_glyph_ensure_icon(gc, 1, false, nullptr);
1369 }
1370
1371 if (!blf_ensure_face(font_with_glyph)) {
1372 return nullptr;
1373 }
1374
1375 FT_GlyphSlot glyph = blf_glyph_render(
1376 font, font_with_glyph, glyph_index, charcode, subpixel, gc->fixed_width, false);
1377
1378 if (glyph) {
1379 /* Save this glyph in the initial font's cache. */
1380 g = blf_glyph_cache_add_glyph(gc, glyph, charcode, glyph_index, subpixel);
1381 }
1382
1383 return g;
1384}
1385
1386#ifndef WITH_HEADLESS
1388 const uint icon_id,
1389 bool color,
1390 blender::FunctionRef<void(std::string &)> edit_source_cb)
1391{
1393 if (g) {
1394 return g;
1395 }
1396 return blf_glyph_cache_add_svg(gc, icon_id + BLF_ICON_OFFSET, color, edit_source_cb);
1397}
1398#endif /* WITH_HEADLESS */
1399
1400#ifdef BLF_SUBPIXEL_AA
1402{
1403 if (!(font->flags & BLF_RENDER_SUBPIXELAA)) {
1404 /* Not if we are in mono mode (aliased) or the feature is turned off. */
1405 return g;
1406 }
1407
1408 if (font->size > 35.0f || g->dims[0] == 0 || g->advance_x < 0) {
1409 /* Single position for large sizes, spaces, and combining characters. */
1410 return g;
1411 }
1412
1413 /* Four sub-pixel positions up to 16 point, 2 until 35 points. */
1414 const uint8_t subpixel = uint8_t(pen_x & ((font->size > 16.0f) ? 32L : 48L));
1415
1416 if (g->subpixel != subpixel) {
1417 g = blf_glyph_ensure(font, gc, g->c, subpixel);
1418 }
1419 return g;
1420}
1421#endif
1422
1424{
1425 if (this->bitmap) {
1426 MEM_freeN(this->bitmap);
1427 }
1428}
1429
1431
1432/* -------------------------------------------------------------------- */
1435
1436static void blf_glyph_calc_rect(const GlyphBLF *g, const int x, const int y, rcti *r_rect)
1437{
1438 r_rect->xmin = x + g->pos[0];
1439 r_rect->xmax = r_rect->xmin + g->dims[0];
1440 r_rect->ymin = y + g->pos[1];
1441 r_rect->ymax = r_rect->ymin - g->dims[1];
1442}
1443
1444static void blf_glyph_calc_rect_test(const GlyphBLF *g, const int x, const int y, rcti *r_rect)
1445{
1446 /* Intentionally check with `g->advance`, because this is the
1447 * width used by BLF_width. This allows that the text slightly
1448 * overlaps the clipping border to achieve better alignment. */
1449 r_rect->xmin = x + abs(g->pos[0]) + 1;
1450 r_rect->xmax = x + std::min(ft_pix_to_int(g->advance_x), g->dims[0]);
1451 r_rect->ymin = y;
1452 r_rect->ymax = r_rect->ymin - g->dims[1];
1453}
1454
1456 const GlyphBLF *g, const int x, const int y, const FontBLF *font, rcti *r_rect)
1457{
1458 blf_glyph_calc_rect(g, x + font->shadow_x, y + font->shadow_y, r_rect);
1459}
1460
1462
1463/* -------------------------------------------------------------------- */
1466
1467static void blf_texture_draw(const GlyphBLF *g,
1468 const uchar color[4],
1469 const FontShadowType shadow,
1470 const int x1,
1471 const int y1,
1472 const int x2,
1473 const int y2)
1474{
1475 using namespace blender;
1476 BLI_assert(size_t(g_batch.glyph_len) < ARRAY_SIZE(g_batch.glyph_data));
1477 GlyphQuad &glyph_data = g_batch.glyph_data[g_batch.glyph_len++];
1478 /* One vertex per glyph, instancing expands it into a quad. */
1479 glyph_data.position = int4(
1480 x1 + g_batch.ofs[0], y1 + g_batch.ofs[1], x2 + g_batch.ofs[0], y2 + g_batch.ofs[1]);
1481 glyph_data.glyph_color = float4(UNPACK4(color)) / 255.0f;
1482 glyph_data.glyph_size = int2(g->dims);
1483 glyph_data.offset = g->offset;
1484 /* Glyph flags packs color channel count and shadow type. */
1485 glyph_data.flags = uint32_t(shadow) | (uint32_t(g->num_channels) << 4);
1486
1487 /* Flush cache if it's full. */
1488 if (g_batch.glyph_len == BLF_BATCH_DRAW_LEN_MAX) {
1490 }
1491}
1492
1493void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, const int y)
1494{
1495 if ((!g->dims[0]) || (!g->dims[1])) {
1496 return;
1497 }
1498
1499 if (g->glyph_cache == nullptr) {
1500 if (font->tex_size_max == -1) {
1502 }
1503
1504 g->offset = gc->bitmap_len;
1505
1506 int buff_size = g->dims[0] * g->dims[1] * g->num_channels;
1507 int bitmap_len = gc->bitmap_len + buff_size;
1508
1509 if (bitmap_len > gc->bitmap_len_alloc) {
1510 int w = font->tex_size_max;
1511 int h = bitmap_len / w + 1;
1512
1513 gc->bitmap_len_alloc = w * h;
1514 gc->bitmap_result = static_cast<char *>(
1515 MEM_reallocN(gc->bitmap_result, size_t(gc->bitmap_len_alloc)));
1516
1517 /* Keep in sync with the texture. */
1518 if (gc->texture) {
1520 }
1521 gc->texture = GPU_texture_create_2d(__func__,
1522 w,
1523 h,
1524 1,
1525 blender::gpu::TextureFormat::UNORM_8,
1527 nullptr);
1528
1529 gc->bitmap_len_landed = 0;
1530 }
1531
1532 memcpy(&gc->bitmap_result[gc->bitmap_len], g->bitmap, size_t(buff_size));
1533 gc->bitmap_len = bitmap_len;
1534
1535 g->glyph_cache = gc;
1536 }
1537
1538 if (font->flags & BLF_CLIPPING) {
1539 float xa, ya;
1540
1541 if (font->flags & BLF_ASPECT) {
1542 xa = font->aspect[0];
1543 ya = font->aspect[1];
1544 }
1545 else {
1546 xa = 1.0f;
1547 ya = 1.0f;
1548 }
1549
1550 rcti rect_test;
1551 blf_glyph_calc_rect_test(g, int(float(x) * xa), int(float(y) * ya), &rect_test);
1552 BLI_rcti_translate(&rect_test, font->pos[0], font->pos[1]);
1553 if (!BLI_rcti_inside_rcti(&font->clip_rec, &rect_test)) {
1554 return;
1555 }
1556 }
1557
1558 if (g_batch.glyph_cache != g->glyph_cache) {
1560 g_batch.glyph_cache = g->glyph_cache;
1561 }
1562
1563 if (font->flags & BLF_SHADOW) {
1564 rcti rect_ofs;
1565 blf_glyph_calc_rect_shadow(g, x, y, font, &rect_ofs);
1566
1568 font->shadow_color,
1569 font->shadow,
1570 rect_ofs.xmin,
1571 rect_ofs.ymin,
1572 rect_ofs.xmax,
1573 rect_ofs.ymax);
1574 }
1575
1576 rcti rect;
1577 blf_glyph_calc_rect(g, x, y, &rect);
1579 g, font->color, FontShadowType::None, rect.xmin, rect.ymin, rect.xmax, rect.ymax);
1580}
1581
1582/* -------------------------------------------------------------------- */
1585
1666
1667static void blf_glyph_to_curves(const FT_Outline &ftoutline,
1668 ListBase *nurbsbase,
1669 const float scale)
1670{
1671 const float eps = 0.0001f;
1672 const float eps_sq = eps * eps;
1673 Nurb *nu;
1674 BezTriple *bezt;
1675 float dx, dy;
1676 int j, k, l, l_first = 0;
1677
1678 /* initialize as -1 to add 1 on first loop each time */
1679 int contour_prev;
1680
1681 /* Start converting the FT data */
1682 int *onpoints = MEM_calloc_arrayN<int>(size_t(ftoutline.n_contours), "onpoints");
1683
1684 /* Get number of on-curve points for bezier-triples (including conic virtual on-points). */
1685 for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
1686 const int n = ftoutline.contours[j] - contour_prev;
1687 contour_prev = ftoutline.contours[j];
1688
1689 for (k = 0; k < n; k++) {
1690 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
1691 if (k == 0) {
1692 l_first = l;
1693 }
1694
1695 if (ftoutline.tags[l] == FT_Curve_Tag_On) {
1696 onpoints[j]++;
1697 }
1698
1699 {
1700 const int l_next = (k < n - 1) ? (l + 1) : l_first;
1701 if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
1702 ftoutline.tags[l_next] == FT_Curve_Tag_Conic)
1703 {
1704 onpoints[j]++;
1705 }
1706 }
1707 }
1708 }
1709
1710 /* contour loop, bezier & conic styles merged */
1711 for (j = 0, contour_prev = -1; j < ftoutline.n_contours; j++) {
1712 const int n = ftoutline.contours[j] - contour_prev;
1713 contour_prev = ftoutline.contours[j];
1714
1715 /* add new curve */
1716 nu = MEM_callocN<Nurb>("objfnt_nurb");
1717 bezt = MEM_calloc_arrayN<BezTriple>(size_t(onpoints[j]), "objfnt_bezt");
1718 BLI_addtail(nurbsbase, nu);
1719
1720 nu->type = CU_BEZIER;
1721 nu->pntsu = onpoints[j];
1722 nu->resolu = 8;
1723 nu->flagu = CU_NURB_CYCLIC;
1724 nu->bezt = bezt;
1725
1726 /* individual curve loop, start-end */
1727 for (k = 0; k < n; k++) {
1728 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
1729 if (k == 0) {
1730 l_first = l;
1731 }
1732
1733 /* virtual conic on-curve points */
1734 {
1735 const int l_next = (k < n - 1) ? (l + 1) : l_first;
1736 if (ftoutline.tags[l] == FT_Curve_Tag_Conic &&
1737 ftoutline.tags[l_next] == FT_Curve_Tag_Conic)
1738 {
1739 dx = float(ftoutline.points[l].x + ftoutline.points[l_next].x) * scale / 2.0f;
1740 dy = float(ftoutline.points[l].y + ftoutline.points[l_next].y) * scale / 2.0f;
1741
1742 /* left handle */
1743 bezt->vec[0][0] = (dx + (2.0f * float(ftoutline.points[l].x)) * scale) / 3.0f;
1744 bezt->vec[0][1] = (dy + (2.0f * float(ftoutline.points[l].y)) * scale) / 3.0f;
1745
1746 /* midpoint (virtual on-curve point) */
1747 bezt->vec[1][0] = dx;
1748 bezt->vec[1][1] = dy;
1749
1750 /* right handle */
1751 bezt->vec[2][0] = (dx + (2.0f * float(ftoutline.points[l_next].x)) * scale) / 3.0f;
1752 bezt->vec[2][1] = (dy + (2.0f * float(ftoutline.points[l_next].y)) * scale) / 3.0f;
1753
1754 bezt->h1 = bezt->h2 = HD_ALIGN;
1755 bezt->radius = 1.0f;
1756 bezt++;
1757 }
1758 }
1759
1760 /* on-curve points */
1761 if (ftoutline.tags[l] == FT_Curve_Tag_On) {
1762 const int l_prev = (k > 0) ? (l - 1) : ftoutline.contours[j];
1763 const int l_next = (k < n - 1) ? (l + 1) : l_first;
1764
1765 /* left handle */
1766 if (ftoutline.tags[l_prev] == FT_Curve_Tag_Cubic) {
1767 bezt->vec[0][0] = float(ftoutline.points[l_prev].x) * scale;
1768 bezt->vec[0][1] = float(ftoutline.points[l_prev].y) * scale;
1769 bezt->h1 = HD_FREE;
1770 }
1771 else if (ftoutline.tags[l_prev] == FT_Curve_Tag_Conic) {
1772 bezt->vec[0][0] = (float(ftoutline.points[l].x) +
1773 (2.0f * float(ftoutline.points[l_prev].x))) *
1774 scale / 3.0f;
1775 bezt->vec[0][1] = (float(ftoutline.points[l].y) +
1776 (2.0f * float(ftoutline.points[l_prev].y))) *
1777 scale / 3.0f;
1778 bezt->h1 = HD_FREE;
1779 }
1780 else {
1781 bezt->vec[0][0] = float(ftoutline.points[l].x) * scale -
1782 (float(ftoutline.points[l].x) - float(ftoutline.points[l_prev].x)) *
1783 scale / 3.0f;
1784 bezt->vec[0][1] = float(ftoutline.points[l].y) * scale -
1785 (float(ftoutline.points[l].y) - float(ftoutline.points[l_prev].y)) *
1786 scale / 3.0f;
1787 bezt->h1 = HD_VECT;
1788 }
1789
1790 /* midpoint (on-curve point) */
1791 bezt->vec[1][0] = float(ftoutline.points[l].x) * scale;
1792 bezt->vec[1][1] = float(ftoutline.points[l].y) * scale;
1793
1794 /* right handle */
1795 if (ftoutline.tags[l_next] == FT_Curve_Tag_Cubic) {
1796 bezt->vec[2][0] = float(ftoutline.points[l_next].x) * scale;
1797 bezt->vec[2][1] = float(ftoutline.points[l_next].y) * scale;
1798 bezt->h2 = HD_FREE;
1799 }
1800 else if (ftoutline.tags[l_next] == FT_Curve_Tag_Conic) {
1801 bezt->vec[2][0] = (float(ftoutline.points[l].x) +
1802 (2.0f * float(ftoutline.points[l_next].x))) *
1803 scale / 3.0f;
1804 bezt->vec[2][1] = (float(ftoutline.points[l].y) +
1805 (2.0f * float(ftoutline.points[l_next].y))) *
1806 scale / 3.0f;
1807 bezt->h2 = HD_FREE;
1808 }
1809 else {
1810 bezt->vec[2][0] = float(ftoutline.points[l].x) * scale -
1811 (float(ftoutline.points[l].x) - float(ftoutline.points[l_next].x)) *
1812 scale / 3.0f;
1813 bezt->vec[2][1] = float(ftoutline.points[l].y) * scale -
1814 (float(ftoutline.points[l].y) - float(ftoutline.points[l_next].y)) *
1815 scale / 3.0f;
1816 bezt->h2 = HD_VECT;
1817 }
1818
1819 /* get the handles that are aligned, tricky...
1820 * - check if one of them is a vector handle.
1821 * - dist_squared_to_line_v2, check if the three beztriple points are on one line
1822 * - len_squared_v2v2, see if there's a distance between the three points
1823 * - len_squared_v2v2 again, to check the angle between the handles
1824 */
1825 if ((bezt->h1 != HD_VECT && bezt->h2 != HD_VECT) &&
1826 (dist_squared_to_line_v2(bezt->vec[0], bezt->vec[1], bezt->vec[2]) <
1827 (0.001f * 0.001f)) &&
1828 (len_squared_v2v2(bezt->vec[0], bezt->vec[1]) > eps_sq) &&
1829 (len_squared_v2v2(bezt->vec[1], bezt->vec[2]) > eps_sq) &&
1830 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) > eps_sq) &&
1831 (len_squared_v2v2(bezt->vec[0], bezt->vec[2]) >
1832 max_ff(len_squared_v2v2(bezt->vec[0], bezt->vec[1]),
1833 len_squared_v2v2(bezt->vec[1], bezt->vec[2]))))
1834 {
1835 bezt->h1 = bezt->h2 = HD_ALIGN;
1836 }
1837 bezt->radius = 1.0f;
1838 bezt++;
1839 }
1840 }
1841 }
1842
1843 MEM_freeN(onpoints);
1844}
1845
1846static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, uint charcode, bool use_fallback)
1847{
1848 if (charcode < 32) {
1849 if (ELEM(charcode, 0x10, 0x13)) {
1850 /* Do not render line feed or carriage return. #134972. */
1851 return nullptr;
1852 }
1853 /* Other C0 controls (U+0000 - U+001F) can show as space. #135421. */
1854 /* TODO: Return all but TAB as ".notdef" character when we have our own. */
1855 charcode = ' ';
1856 }
1857
1858 /* Glyph might not come from the initial font. */
1859 FontBLF *font_with_glyph = font;
1860 FT_UInt glyph_index = use_fallback ? blf_glyph_index_from_charcode(&font_with_glyph, charcode) :
1861 blf_get_char_index(font_with_glyph, charcode);
1862
1863 if (!glyph_index) {
1864 return nullptr;
1865 }
1866
1867 if (!blf_ensure_face(font_with_glyph)) {
1868 return nullptr;
1869 }
1870
1871 FT_GlyphSlot glyph = blf_glyph_render(font, font_with_glyph, glyph_index, charcode, 0, 0, true);
1872
1873 if (font != font_with_glyph) {
1874 if (!blf_ensure_face(font)) {
1875 return nullptr;
1876 }
1877 double ratio = float(font->face->units_per_EM) / float(font_with_glyph->face->units_per_EM);
1878 FT_Matrix transform = {to_16dot16(ratio), 0, 0, to_16dot16(ratio)};
1879 FT_Outline_Transform(&glyph->outline, &transform);
1880 glyph->advance.x = int(float(glyph->advance.x) * ratio);
1881 glyph->metrics.horiAdvance = int(float(glyph->metrics.horiAdvance) * ratio);
1882 }
1883
1884 return glyph;
1885}
1886
1888 uint unicode,
1889 ListBase *nurbsbase,
1890 const float scale,
1891 bool use_fallback,
1892 float *r_advance)
1893{
1894 FT_GlyphSlot glyph = blf_glyphslot_ensure_outline(font, unicode, use_fallback);
1895 if (!glyph) {
1896 *r_advance = 0.0f;
1897 return false;
1898 }
1899
1900 blf_glyph_to_curves(glyph->outline, nurbsbase, scale);
1901 *r_advance = float(glyph->advance.x) * scale;
1902 return true;
1903}
1904
@ BLF_RENDER_SUBPIXELAA
Definition BLF_enums.hh:62
@ BLF_ITALIC
Definition BLF_enums.hh:46
@ BLF_HINTING_NONE
Definition BLF_enums.hh:42
@ BLF_LAST_RESORT
Definition BLF_enums.hh:52
@ BLF_MONOSPACED
Definition BLF_enums.hh:48
@ BLF_CACHED
Definition BLF_enums.hh:56
@ BLF_MONOCHROME
Definition BLF_enums.hh:41
@ BLF_BOLD
Definition BLF_enums.hh:45
@ BLF_NO_FALLBACK
Definition BLF_enums.hh:65
@ BLF_HINTING_FULL
Definition BLF_enums.hh:44
@ BLF_HINTING_SLIGHT
Definition BLF_enums.hh:43
@ BLF_ASPECT
Definition BLF_enums.hh:38
@ BLF_SHADOW
Definition BLF_enums.hh:35
@ BLF_CLIPPING
Definition BLF_enums.hh:34
@ BLF_DEFAULT
Definition BLF_enums.hh:50
FontShadowType
Definition BLF_enums.hh:13
#define BLI_assert(a)
Definition BLI_assert.h:46
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:111
MINLINE float max_ff(float a, float b)
MINLINE unsigned char srgb_to_grayscale_byte(const unsigned char rgb[3])
float dist_squared_to_line_v2(const float p[2], const float l1[2], const float l2[2])
Definition math_geom.cc:278
MINLINE float len_squared_v2v2(const float a[2], const float b[2]) ATTR_WARN_UNUSED_RESULT
void BLI_rcti_translate(struct rcti *rect, int x, int y)
Definition rct.cc:566
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b)
Definition rct.cc:198
size_t size_t int BLI_wcwidth_or_error(char32_t ucs) ATTR_WARN_UNUSED_RESULT
unsigned char uchar
unsigned int uint
#define CLAMP(a, b, c)
#define UNPACK4(a)
#define ARRAY_SIZE(arr)
#define ELEM(...)
@ CU_NURB_CYCLIC
@ CU_BEZIER
@ HD_VECT
@ HD_FREE
@ HD_ALIGN
int GPU_max_texture_size()
@ GPU_TEXTURE_USAGE_SHADER_READ
blender::gpu::Texture * GPU_texture_create_2d(const char *name, int width, int height, int mip_len, blender::gpu::TextureFormat format, eGPUTextureUsage usage, const float *data)
void GPU_texture_free(blender::gpu::Texture *texture)
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
volatile int lock
#define U
FontBLF * global_font[BLF_MAX_FONT]
Definition blf.cc:44
BatchBLF g_batch
Definition blf_font.cc:59
bool blf_ensure_face(FontBLF *font)
Definition blf_font.cc:1890
void blf_ensure_size(FontBLF *font)
Definition blf_font.cc:2152
bool blf_font_size(FontBLF *font, float size)
Definition blf_font.cc:2174
uint blf_get_char_index(FontBLF *font, const uint charcode)
Definition blf_font.cc:148
void blf_batch_draw()
Definition blf_font.cc:305
static GlyphBLF * blf_glyph_cache_find_glyph(const GlyphCacheBLF *gc, const uint charcode, const uint8_t subpixel)
Definition blf_glyph.cc:173
static GlyphBLF * blf_glyph_cache_add_svg(GlyphCacheBLF *gc, const uint charcode, const bool color, blender::FunctionRef< void(std::string &)> edit_source_cb=nullptr)
Definition blf_glyph.cc:356
static float blf_glyph_set_variation_spacing(const FontBLF *font, FT_Fixed coords[], float current_spacing, float target_spacing)
static FT_GlyphSlot blf_glyph_render(FontBLF *settings_font, FontBLF *glyph_font, FT_UInt glyph_index, uint charcode, uint8_t subpixel, int fixed_width, bool outline_only)
static GlyphBLF * blf_glyph_cache_add_blank(GlyphCacheBLF *gc, const uint charcode)
Definition blf_glyph.cc:344
static float blf_glyph_set_variation_width(const FontBLF *font, FT_Fixed coords[], float current_width, float target_width)
static bool blf_glyph_set_variation_optical_size(const FontBLF *font, FT_Fixed coords[], const float points)
static float from_16dot16(const FT_Fixed value)
Definition blf_glyph.cc:75
static int blf_charcode_to_coverage_bit(const uint charcode)
Definition blf_glyph.cc:757
bool blf_character_to_curves(FontBLF *font, uint unicode, ListBase *nurbsbase, const float scale, bool use_fallback, float *r_advance)
static float blf_glyph_set_variation_weight(const FontBLF *font, FT_Fixed coords[], float current_weight, float target_weight)
static bool blf_glyph_render_bitmap(FontBLF *font, FT_GlyphSlot glyph)
Definition blf_glyph.cc:898
static GlyphBLF * blf_glyph_cache_add_glyph(GlyphCacheBLF *gc, const FT_GlyphSlot glyph, const uint charcode, const FT_UInt glyph_index, const uint8_t subpixel)
Definition blf_glyph.cc:225
static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor)
void blf_glyph_cache_clear(FontBLF *font)
Definition blf_glyph.cc:162
GlyphCacheBLF * blf_glyph_cache_acquire(FontBLF *font)
Definition blf_glyph.cc:133
static void blf_glyph_calc_rect(const GlyphBLF *g, const int x, const int y, rcti *r_rect)
static const UnicodeBlock * blf_charcode_to_unicode_block(const uint charcode)
Definition blf_glyph.cc:725
static void blf_texture_draw(const GlyphBLF *g, const uchar color[4], const FontShadowType shadow, const int x1, const int y1, const int x2, const int y2)
void blf_glyph_draw(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, const int x, const int y)
static const FT_Var_Axis * blf_var_axis_by_tag(const FT_MM_Var *variations, const uint32_t tag, int *r_axis_index)
Definition blf_glyph.cc:946
static GlyphCacheBLF * blf_glyph_cache_find(const FontBLF *font)
Definition blf_glyph.cc:86
static void blf_glyph_to_curves(const FT_Outline &ftoutline, ListBase *nurbsbase, const float scale)
static void blf_glyph_calc_rect_shadow(const GlyphBLF *g, const int x, const int y, const FontBLF *font, rcti *r_rect)
static FT_Fixed to_16dot16(const double val)
Definition blf_glyph.cc:67
static bool blf_glyph_transform_monospace(FT_GlyphSlot glyph, int width)
static FT_GlyphSlot blf_glyph_load(FontBLF *font, const FT_UInt glyph_index, const bool outline_only)
Definition blf_glyph.cc:850
static const UnicodeBlock unicode_blocks[]
Definition blf_glyph.cc:463
static bool blf_glyph_transform_weight(FT_GlyphSlot glyph, float width, bool monospaced)
GlyphBLF * blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int32_t pen_x)
static GlyphCacheBLF * blf_glyph_cache_new(FontBLF *font)
Definition blf_glyph.cc:100
static void blf_glyph_calc_rect_test(const GlyphBLF *g, const int x, const int y, rcti *r_rect)
static FT_GlyphSlot blf_glyphslot_ensure_outline(FontBLF *font, uint charcode, bool use_fallback)
void blf_glyph_cache_release(FontBLF *font)
Definition blf_glyph.cc:146
static bool blf_glyph_set_variation_float(const FontBLF *font, FT_Fixed coords[], uint32_t tag, float *value)
static bool blf_glyph_transform_slant(FT_GlyphSlot glyph, float degrees)
static float blf_glyph_set_variation_slant(const FontBLF *font, FT_Fixed coords[], float current_degrees, float target_degrees)
GlyphBLF * blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode, uint8_t subpixel)
static bool blf_glyph_transform_width(FT_GlyphSlot glyph, float factor)
static uchar blf_glyph_gamma(const uchar c)
Definition blf_glyph.cc:198
static bool blf_font_has_coverage_bit(const FontBLF *font, const int coverage_bit)
Definition blf_glyph.cc:774
static FT_Fixed blf_factor_to_coordinate(const FT_Var_Axis *axis, const float factor)
Definition blf_glyph.cc:972
static bool blf_glyph_set_variation_normalized(const FontBLF *font, FT_Fixed coords[], const uint32_t tag, const float factor)
Definition blf_glyph.cc:998
GlyphBLF * blf_glyph_ensure_icon(GlyphCacheBLF *gc, const uint icon_id, bool color, blender::FunctionRef< void(std::string &)> edit_source_cb)
static FT_UInt blf_glyph_index_from_charcode(FontBLF **font, const uint charcode)
Definition blf_glyph.cc:786
#define BLF_MAX_FONT
#define BLF_ICON_OFFSET
#define BLF_VARIATIONS_MAX
#define BLF_VARIATION_AXIS_SLANT
#define BLF_VARIATION_AXIS_OPTSIZE
#define BLF_VARIATION_AXIS_WIDTH
#define BLF_VARIATION_AXIS_WEIGHT
#define BLF_VARIATION_AXIS_SPACING
int32_t ft_pix
#define BLF_BATCH_DRAW_LEN_MAX
int ft_pix_to_int(ft_pix v)
ATTR_WARN_UNUSED_RESULT const BMLoop * l
SIMD_FORCE_INLINE btVector3 transform(const btVector3 &point) const
long long int int64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
Definition btQuadWord.h:119
bool add(const Key &key, const Value &value)
Definition BLI_map.hh:295
const Value * lookup_ptr_as(const ForwardKey &key) const
Definition BLI_map.hh:516
void append(const T &value)
const T & last(const int64_t n=0) const
void clear_and_shrink()
const T * data() const
Definition BLI_array.hh:312
nullptr float
uint col
#define round
#define abs
#define ceil
constexpr T degrees(T) RET
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:123
void * MEM_callocN(size_t len, const char *str)
Definition mallocn.cc:118
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
VecBase< int32_t, 4 > int4
VecBase< float, 4 > float4
VecBase< int32_t, 2 > int2
const btScalar eps
Definition poly34.cpp:11
#define min(a, b)
Definition sort.cc:36
float vec[3][3]
uint unicode_ranges[4]
blender::Vector< std::unique_ptr< GlyphCacheBLF > > cache
unsigned char color[4]
FontFlags flags
FT_MM_Var * variations
FontMetrics metrics
FT_Library ft_lib
FontShadowType shadow
blender::Mutex glyph_cache_mutex
unsigned char shadow_color[4]
GlyphCacheBLF * glyph_cache
unsigned char * bitmap
unsigned int c
blender::Map< GlyphCacheKey, std::unique_ptr< GlyphBLF > > glyphs
blender::gpu::Texture * texture
short flagu
short type
BezTriple * bezt
short resolu
int ymin
int ymax
int xmin
int xmax
i
Definition text_draw.cc:230
max
Definition text_draw.cc:251
PointerRNA * ptr
Definition wm_files.cc:4238