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