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