24#include FT_MULTIPLE_MASTERS_H
46# include "nanosvgrast.h"
48# include "svg_icons.h"
58#define BLF_GAMMA_CORRECT_GLYPHS
69 return (FT_Fixed)lround(val * 65536.0);
77 return float(value) / 65536.0f;
88 for (
const std::unique_ptr<GlyphCacheBLF> &gc : font->
cache) {
102 std::unique_ptr<GlyphCacheBLF> gc = std::make_unique<GlyphCacheBLF>();
104 gc->size = font->
size;
116 if (gindex && font->
face) {
117 FT_Fixed advance = 0;
118 FT_Get_Advance(font->
face, gindex, FT_LOAD_NO_HINTING, &advance);
120 gc->fixed_width = int(advance >> 16);
124 gc->fixed_width = int((font->
ft_size->metrics.height / 2) >> 6);
126 gc->fixed_width = std::max(gc->fixed_width, 1);
179 if (ptr !=
nullptr) {
185#ifdef BLF_GAMMA_CORRECT_GLYPHS
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,
226 GlyphCacheBLF *gc, FT_GlyphSlot glyph,
uint charcode, FT_UInt glyph_index, uint8_t subpixel)
228 std::unique_ptr<GlyphBLF> g = std::make_unique<GlyphBLF>();
230 g->idx = glyph_index;
231 g->advance_x = (
ft_pix)glyph->advance.x;
232 g->subpixel = subpixel;
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;
242 g->lsb_delta = (
ft_pix)glyph->lsb_delta;
243 g->rsb_delta = (
ft_pix)glyph->rsb_delta;
245 if (glyph->format == FT_GLYPH_FORMAT_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;
254 switch (glyph->bitmap.pixel_mode) {
255 case FT_PIXEL_MODE_LCD:
259 case FT_PIXEL_MODE_LCD_V:
264 case FT_PIXEL_MODE_BGRA:
269 const int buffer_size = g->dims[0] * g->dims[1] * g->num_channels;
272 if (
ELEM(glyph->bitmap.pixel_mode,
275 FT_PIXEL_MODE_GRAY4))
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
284 g->bitmap[
i] = glyph->bitmap.buffer[
i] * scale;
288 else if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD) {
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];
301 else if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_LCD_V) {
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)];
315 else if (glyph->bitmap.pixel_mode == FT_PIXEL_MODE_BGRA) {
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];
330 memcpy(g->bitmap, glyph->bitmap.buffer,
size_t(buffer_size));
345 std::unique_ptr<GlyphBLF> g = std::make_unique<GlyphBLF>();
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);
364 NSVGimage *image = nsvgParse(svg_source.data(),
"px", 96.0f);
366 if (image ==
nullptr) {
370 if (image->width == 0 || image->height == 0) {
375 NSVGrasterizer *rast = nsvgCreateRasterizer();
376 if (rast ==
nullptr) {
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;
388 nsvgRasterize(rast, image, 0.0f, 0.0f, scale, render_bmp.
data(), dest_w, dest_h, dest_w * 4);
389 nsvgDeleteRasterizer(rast);
392 const int offset_x = std::max(
int(
round((gc->
size - (image->width * scale)) / 2.0f)),
393 int(-100.0f * scale));
395 const int offset_y = std::max(
int(
ceil((gc->
size +
float(dest_h)) / 2.0f)),
396 dest_h -
int(100.0f * scale));
400 std::unique_ptr<GlyphBLF> g = std::make_unique<GlyphBLF>();
403 g->advance_x = dest_w * 64;
406 g->box_xmax = dest_w * 64;
408 g->box_ymax = dest_h * 64;
411 g->pos[0] = offset_x;
412 g->pos[1] = offset_y;
416 g->num_channels = color ? 4 : 1;
418 const int buffer_size = g->dims[0] * g->dims[1] * g->num_channels;
422 memcpy(g->bitmap, render_bmp.
data(),
size_t(buffer_size));
431 (
float(render_bmp[
int64_t(offs_in + 3)]) / 255.0f));
493 {0x1000, 0x109F, 74},
494 {0x10A0, 0x10FF, 26},
495 {0x1100, 0x11FF, 28},
496 {0x1200, 0x139F, 75},
497 {0x13A0, 0x13FF, 76},
498 {0x1400, 0x167F, 77},
499 {0x1680, 0x169F, 78},
500 {0x16A0, 0x16FF, 79},
501 {0x1700, 0x171F, 84},
502 {0x1720, 0x173F, 84},
503 {0x1740, 0x175F, 84},
504 {0x1760, 0x177F, 84},
505 {0x1780, 0x17FF, 80},
506 {0x1800, 0x18AF, 81},
507 {0x1900, 0x194F, 93},
508 {0x1950, 0x197F, 94},
509 {0x1980, 0x19DF, 95},
510 {0x19E0, 0x19FF, 80},
511 {0x1A00, 0x1A1F, 96},
512 {0x1A20, 0x1AAF, -1},
513 {0x1B00, 0x1B7F, 27},
514 {0x1B80, 0x1BBF, 112},
515 {0x1BC0, 0x1BFF, -1},
516 {0x1C00, 0x1C4F, 113},
517 {0x1C50, 0x1C7F, 114},
520 {0x1E00, 0x1EFF, 29},
521 {0x1F00, 0x1FFF, 30},
522 {0x2000, 0x206F, 31},
523 {0x2070, 0x209F, 32},
524 {0x20A0, 0x20CF, 33},
525 {0x20D0, 0x20FF, 34},
526 {0x2100, 0x214F, 35},
527 {0x2150, 0x218F, 36},
528 {0x2190, 0x21FF, 37},
529 {0x2200, 0x22FF, 38},
530 {0x2300, 0x23FF, 39},
531 {0x2400, 0x243F, 40},
532 {0x2440, 0x245F, 41},
533 {0x2460, 0x24FF, 42},
534 {0x2500, 0x257F, 43},
535 {0x2580, 0x259F, 44},
536 {0x25A0, 0x25FF, 45},
537 {0x2600, 0x26FF, 46},
538 {0x2700, 0x27BF, 47},
539 {0x27C0, 0x27EF, 38},
540 {0x27F0, 0x27FF, 37},
541 {0x2800, 0x28FF, 82},
542 {0x2900, 0x297F, 37},
543 {0x2980, 0x2AFF, 38},
544 {0x2B00, 0x2BFF, 37},
545 {0x2C00, 0x2C5F, 97},
546 {0x2C60, 0x2C7F, 29},
548 {0x2D00, 0x2D2F, 26},
549 {0x2D30, 0x2D7F, 98},
550 {0x2D80, 0x2DDF, 75},
552 {0x2E00, 0x2E7F, 31},
553 {0x2E80, 0x2FFF, 59},
554 {0x3000, 0x303F, 48},
555 {0x3040, 0x309F, 49},
556 {0x30A0, 0x30FF, 50},
557 {0x3100, 0x312F, 51},
558 {0x3130, 0x318F, 52},
559 {0x3190, 0x319F, 59},
560 {0x31A0, 0x31BF, 51},
561 {0x31C0, 0x31EF, 59},
562 {0x31F0, 0x31FF, 50},
563 {0x3200, 0x32FF, 54},
564 {0x3300, 0x33FF, 55},
565 {0x3400, 0x4DBF, 59},
566 {0x4DC0, 0x4DFF, 99},
567 {0x4E00, 0x9FFF, 59},
568 {0xA000, 0xA4CF, 83},
569 {0xA4D0, 0xA4FF, -1},
570 {0xA500, 0xA63F, 12},
572 {0xA6A0, 0xA6FF, -1},
574 {0xA720, 0xA7FF, 29},
575 {0xA800, 0xA82F, 100},
576 {0xA840, 0xA87F, 53},
577 {0xA880, 0xA8DF, 115},
578 {0xA900, 0xA92F, 116},
579 {0xA930, 0xA95F, 117},
580 {0xA960, 0xA97F, 56},
581 {0xA980, 0xA9DF, -1},
582 {0xA9E0, 0xA9FF, 74},
583 {0xAA00, 0xAA5F, 118},
584 {0xAA60, 0xAA7F, 74},
585 {0xAA80, 0xAADF, -1},
586 {0xAAE0, 0xAAFF, -1},
587 {0xAB00, 0xAB2F, 75},
588 {0xAB70, 0xABBF, 76},
589 {0xABC0, 0xABFF, -1},
590 {0xAC00, 0xD7AF, 56},
591 {0xD800, 0xDFFF, 57},
592 {0xE000, 0xF6FF, 60},
593 {0xE700, 0xEFFF, -1},
594 {0xF000, 0xF8FF, -1},
595 {0xF900, 0xFAFF, 61},
596 {0xFB00, 0xFB4F, 62},
597 {0xFB50, 0xFDFF, 63},
598 {0xFE00, 0xFE0F, 91},
599 {0xFE10, 0xFE1F, 65},
600 {0xFE20, 0xFE2F, 64},
601 {0xFE30, 0xFE4F, 65},
602 {0xFE50, 0xFE6F, 66},
603 {0xFE70, 0xFEFF, 67},
604 {0xFF00, 0xFFEF, 68},
605 {0xFFF0, 0xFFFF, 69},
606 {0x10000, 0x1013F, 101},
607 {0x10140, 0x1018F, 102},
608 {0x10190, 0x101CF, 119},
609 {0x101D0, 0x101FF, 120},
610 {0x10280, 0x1029F, 121},
611 {0x102A0, 0x102DF, 121},
612 {0x10300, 0x1032F, 85},
613 {0x10330, 0x1034F, 86},
614 {0x10350, 0x1037F, -1},
615 {0x10380, 0x1039F, 103},
616 {0x103A0, 0x103DF, 104},
617 {0x10400, 0x1044F, 87},
618 {0x10450, 0x1047F, 105},
619 {0x10480, 0x104AF, 106},
620 {0x104B0, 0x104FF, -1},
621 {0x10500, 0x1052F, -1},
622 {0x10530, 0x1056F, -1},
623 {0x10570, 0x105BF, -1},
624 {0x10600, 0x1077F, -1},
625 {0x10780, 0x107BF, 3},
626 {0x10800, 0x1083F, 107},
627 {0x10840, 0x1085F, -1},
628 {0x10860, 0x1087F, -1},
629 {0x10880, 0x108AF, -1},
630 {0x108E0, 0x108FF, -1},
631 {0x10900, 0x1091F, 58},
632 {0x10920, 0x1093F, 121},
633 {0x10980, 0x1099F, -1},
634 {0x109A0, 0x109FF, -1},
635 {0x10A00, 0x10A5F, 108},
636 {0x10A60, 0x10A7F, -1},
637 {0x10A80, 0x10A9F, -1},
638 {0x10AC0, 0x10AFF, -1},
639 {0x10B00, 0x10B3F, -1},
640 {0x10B40, 0x10B5F, -1},
641 {0x10B60, 0x10B7F, -1},
642 {0x10B80, 0x10BAF, -1},
643 {0x10C00, 0x10C4F, -1},
644 {0x10C80, 0x10CFF, -1},
645 {0x10D00, 0x10D3F, -1},
646 {0x108E0, 0x10E7F, -1},
647 {0x10E80, 0x10EBF, -1},
648 {0x10F00, 0x10F2F, -1},
649 {0x10F30, 0x10F6F, -1},
650 {0x10F70, 0x10FAF, -1},
651 {0x10FB0, 0x10FDF, -1},
652 {0x10FE0, 0x10FFF, -1},
653 {0x11000, 0x1107F, -1},
654 {0x11080, 0x110CF, -1},
655 {0x110D0, 0x110FF, -1},
656 {0x11100, 0x1114F, -1},
657 {0x11150, 0x1117F, -1},
658 {0x11180, 0x111DF, -1},
659 {0x111E0, 0x111FF, -1},
660 {0x11200, 0x1124F, -1},
661 {0x11280, 0x112AF, -1},
662 {0x112B0, 0x112FF, -1},
663 {0x11300, 0x1137F, -1},
664 {0x11400, 0x1147F, -1},
665 {0x11480, 0x114DF, -1},
666 {0x11580, 0x115FF, -1},
667 {0x11600, 0x1165F, -1},
668 {0x11660, 0x1167F, 81},
669 {0x11680, 0x116CF, -1},
670 {0x11700, 0x1174F, -1},
671 {0x11800, 0x1184F, -1},
672 {0x118A0, 0x118FF, -1},
673 {0x11900, 0x1195F, -1},
674 {0x119A0, 0x119FF, -1},
675 {0x11A00, 0x11A4F, -1},
676 {0x11A50, 0x11AAF, -1},
677 {0x11AB0, 0x11ABF, 77},
678 {0x11AC0, 0x11AFF, -1},
679 {0x11C00, 0x11C6F, -1},
680 {0x11C70, 0x11CBF, -1},
681 {0x11D00, 0x11D5F, -1},
682 {0x11D60, 0x11DAF, -1},
683 {0x11EE0, 0x11EFF, -1},
684 {0x11FB0, 0x11FBF, -1},
685 {0x11FC0, 0x11FFF, 20},
686 {0x12000, 0x1254F, 110},
687 {0x12F90, 0x12FFF, -1},
688 {0x13000, 0x1343F, -1},
689 {0x14400, 0x1467F, -1},
690 {0x16800, 0x16A3F, -1},
691 {0x16A40, 0x16A6F, -1},
692 {0x16A70, 0x16ACF, -1},
693 {0x16AD0, 0x16AFF, -1},
694 {0x16B00, 0x16B8F, -1},
695 {0x16E40, 0x16E9F, -1},
696 {0x16F00, 0x16F9F, -1},
697 {0x16FE0, 0x16FFF, -1},
698 {0x17000, 0x18AFF, -1},
699 {0x1B170, 0x1B2FF, -1},
700 {0x1BC00, 0x1BC9F, -1},
701 {0x1D000, 0x1D24F, 88},
702 {0x1D2E0, 0x1D2FF, -1},
703 {0x1D300, 0x1D35F, 109},
704 {0x1D360, 0x1D37F, 111},
705 {0x1D400, 0x1D7FF, 89},
706 {0x1E2C0, 0x1E2FF, -1},
707 {0x1E800, 0x1E8DF, -1},
708 {0x1E900, 0x1E95F, -1},
709 {0x1EC70, 0x1ECBF, -1},
710 {0x1F000, 0x1F02F, 122},
711 {0x1F030, 0x1F09F, 122},
712 {0x1F600, 0x1F64F, -1},
713 {0x20000, 0x2A6DF, 59},
714 {0x2F800, 0x2FA1F, 61},
715 {0xE0000, 0xE007F, 92},
716 {0xE0100, 0xE01EF, 91},
717 {0xF0000, 0x10FFFD, 90}};
724 if (charcode < 0x80) {
739 const int mid = (
min +
max) / 2;
756 int coverage_bit = -1;
762 if (coverage_bit < 0 && charcode > 0xFFFF) {
773 if (coverage_bit < 0) {
815 FontBLF *last_resort =
nullptr;
835 printf(
"Unicode character U+%04X not found in loaded fonts. \n", charcode);
864 load_flags = FT_LOAD_NO_SCALE | FT_LOAD_NO_BITMAP;
867 load_flags = FT_LOAD_TARGET_MONO;
870 load_flags = FT_LOAD_NO_BITMAP;
872 load_flags |= FT_LOAD_TARGET_NORMAL | FT_LOAD_NO_HINTING;
875 load_flags |= FT_LOAD_TARGET_LIGHT;
878 load_flags |= FT_LOAD_TARGET_NORMAL;
882 load_flags |= FT_LOAD_TARGET_LIGHT;
886 if (!outline_only && FT_HAS_COLOR(font->
face)) {
887 load_flags |= FT_LOAD_COLOR;
890 if (FT_Load_Glyph(font->
face, glyph_index, load_flags) == FT_Err_Ok) {
891 return font->
face->glyph;
910 render_mode = FT_RENDER_MODE_MONO;
913 render_mode = FT_RENDER_MODE_LIGHT;
916 render_mode = FT_RENDER_MODE_NORMAL;
920 FT_Error err = FT_Render_Glyph(glyph, FT_Render_Mode(render_mode));
921 if (err != FT_Err_Ok) {
925 if (
ELEM(glyph->bitmap.pixel_mode, FT_PIXEL_MODE_MONO, FT_PIXEL_MODE_GRAY2, FT_PIXEL_MODE_GRAY4))
928 FT_Bitmap tempbitmap;
929 FT_Bitmap_New(&tempbitmap);
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);
937 return (err == FT_Err_Ok);
961 for (
int i = 0;
i < int(variations->num_axis);
i++) {
962 if (variations->axis[
i].tag == tag) {
964 return &(variations->axis)[
i];
982 FT_Fixed value = axis->def;
985 value += (FT_Fixed)(
double(axis->maximum - axis->def) * factor);
987 else if (factor < 0) {
989 value += (FT_Fixed)(
double(axis->def - axis->minimum) * factor);
1036 CLAMP(int_value, axis->minimum, axis->maximum);
1037 coords[axis_index] = int_value;
1053 float current_weight,
1054 float target_weight)
1056 float value = target_weight;
1060 return current_weight;
1072 float current_degrees,
1073 float target_degrees)
1075 float value = -target_degrees;
1079 return current_degrees;
1091 float current_width,
1094 float value = target_width * 100.0f;
1096 return value / 100.0f;
1098 return current_width;
1110 float current_spacing,
1111 float target_spacing)
1113 float value = target_spacing;
1117 return current_spacing;
1131 float value = points;
1149 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
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);
1157 FT_Outline_Translate(&glyph->outline, change / -2, 0);
1161 glyph->advance.x += change / 2;
1176 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1178 FT_Outline_Transform(&glyph->outline, &
transform);
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);
1199 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1200 float scale = factor + 1.0f;
1202 FT_Outline_Transform(&glyph->outline, &matrix);
1203 glyph->advance.x = (FT_Pos)(
double(glyph->advance.x) * scale);
1217 if (glyph->advance.x > 0) {
1219 const long int size = font->
ft_size->metrics.height;
1220 glyph->advance.x += (FT_Pos)(factor *
float(
size) / 6.0f);
1233 if (glyph->format == FT_GLYPH_FORMAT_OUTLINE) {
1234 FT_Fixed current = glyph->linearHoriAdvance;
1235 FT_Fixed target = FT_Fixed(width) << 16;
1236 if (target < current) {
1237 const FT_Pos embolden = (FT_Pos)((current - target) >> 13);
1239 FT_Outline_EmboldenXY(&glyph->outline, embolden, 0);
1240 const float scale = float(target - (embolden << 9)) / float(current);
1242 FT_Outline_Transform(&glyph->outline, &matrix);
1244 else if (target > current) {
1246 FT_Outline_Translate(&glyph->outline, (FT_Pos)((target - current) >> 11), 0);
1248 glyph->advance.x = width << 6;
1265 FT_UInt glyph_index,
1271 if (glyph_font != settings_font) {
1284 float weight_target = float(settings_font->
char_weight);
1286 weight_target = std::min(weight_target + 300.0f, 900.0f);
1288 float slant_target = settings_font->
char_slant;
1290 slant_target = std::min(slant_target + 8.0f, 15.0f);
1292 float width_target = settings_font->
char_width;
1313 FT_GlyphSlot glyph =
blf_glyph_load(glyph_font, glyph_index, outline_only);
1327 if (weight != weight_target) {
1330 if (slant != slant_target) {
1333 if (width != width_target) {
1336 if (spacing != spacing_target) {
1344 FT_Outline_Translate(&glyph->outline, (FT_Pos)subpixel, 0);
1354 if (charcode < 32) {
1355 if (
ELEM(charcode, 0x10, 0x13)) {
1370 FontBLF *font_with_glyph = font;
1378 font, font_with_glyph, glyph_index, charcode, subpixel, gc->
fixed_width,
false);
1388#ifndef WITH_HEADLESS
1402#ifdef BLF_SUBPIXEL_AA
1416 const uint8_t subpixel = uint8_t(pen_x & ((font->
size > 16.0f) ? 32L : 48L));
1470 const uchar color[4],
1487 uint32_t flags = uint32_t(shadow) | (uint32_t(g->
num_channels) << 4);
1499 if ((!g->
dims[0]) || (!g->
dims[1])) {
1515 int h = bitmap_len /
w + 1;
1670 const float eps = 0.0001f;
1671 const float eps_sq =
eps *
eps;
1675 int j, k,
l, l_first = 0;
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];
1688 for (k = 0; k < n; k++) {
1689 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
1694 if (ftoutline.tags[
l] == FT_Curve_Tag_On) {
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)
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];
1720 nu->
pntsu = onpoints[j];
1726 for (k = 0; k < n; k++) {
1727 l = (j > 0) ? (k + ftoutline.contours[j - 1] + 1) : k;
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)
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;
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;
1746 bezt->
vec[1][0] = dx;
1747 bezt->
vec[1][1] = dy;
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;
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;
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;
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))) *
1774 bezt->
vec[0][1] = (float(ftoutline.points[
l].y) +
1775 (2.0f * float(ftoutline.points[l_prev].y))) *
1780 bezt->
vec[0][0] = float(ftoutline.points[
l].x) * scale -
1781 (float(ftoutline.points[
l].x) - float(ftoutline.points[l_prev].x)) *
1783 bezt->
vec[0][1] = float(ftoutline.points[
l].y) * scale -
1784 (float(ftoutline.points[
l].y) - float(ftoutline.points[l_prev].y)) *
1790 bezt->
vec[1][0] = float(ftoutline.points[
l].x) * scale;
1791 bezt->
vec[1][1] = float(ftoutline.points[
l].y) * scale;
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;
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))) *
1803 bezt->
vec[2][1] = (float(ftoutline.points[
l].y) +
1804 (2.0f * float(ftoutline.points[l_next].y))) *
1809 bezt->
vec[2][0] = float(ftoutline.points[
l].x) * scale -
1810 (float(ftoutline.points[
l].x) - float(ftoutline.points[l_next].x)) *
1812 bezt->
vec[2][1] = float(ftoutline.points[
l].y) * scale -
1813 (float(ftoutline.points[
l].y) - float(ftoutline.points[l_next].y)) *
1826 (0.001f * 0.001f)) &&
1847 if (charcode < 32) {
1848 if (
ELEM(charcode, 0x10, 0x13)) {
1858 FontBLF *font_with_glyph = font;
1865 FT_GlyphSlot glyph =
blf_glyph_render(font, font_with_glyph, glyph_index, charcode, 0, 0,
true);
1867 if (font != font_with_glyph) {
1871 double ratio = float(font->
face->units_per_EM) / float(font_with_glyph->
face->units_per_EM);
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);
1890 return float(glyph->advance.x) * scale;
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
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])
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)
bool BLI_rcti_inside_rcti(const rcti *rct_a, const rcti *rct_b)
size_t size_t int BLI_wcwidth_or_error(char32_t ucs) ATTR_WARN_UNUSED_RESULT
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_INLINE void * GPU_vertbuf_raw_step(GPUVertBufRaw *a)
Read Guarded memory(de)allocation.
FontBLF * global_font[BLF_MAX_FONT]
bool blf_ensure_face(FontBLF *font)
void blf_ensure_size(FontBLF *font)
bool blf_font_size(FontBLF *font, float size)
uint blf_get_char_index(FontBLF *font, uint charcode)
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)
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)
static bool blf_glyph_transform_spacing(FT_GlyphSlot glyph, float factor)
void blf_glyph_cache_clear(FontBLF *font)
float blf_character_to_curves(FontBLF *font, uint unicode, ListBase *nurbsbase, const float scale, bool use_fallback)
GlyphCacheBLF * blf_glyph_cache_acquire(FontBLF *font)
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)
static FT_GlyphSlot blf_glyph_load(FontBLF *font, FT_UInt glyph_index, bool outline_only)
static const UnicodeBlock * blf_charcode_to_unicode_block(const uint charcode)
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)
static bool blf_font_has_coverage_bit(const FontBLF *font, int coverage_bit)
static int blf_charcode_to_coverage_bit(uint charcode)
static uchar blf_glyph_gamma(uchar c)
static const FT_Var_Axis * blf_var_axis_by_tag(const FT_MM_Var *variations, const uint32_t tag, int *r_axis_index)
static GlyphCacheBLF * blf_glyph_cache_find(const FontBLF *font)
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)
static bool blf_glyph_transform_monospace(FT_GlyphSlot glyph, int width)
static const UnicodeBlock unicode_blocks[]
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)
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)
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)
static GlyphBLF * blf_glyph_cache_add_blank(GlyphCacheBLF *gc, uint charcode)
static FT_Fixed blf_factor_to_coordinate(const FT_Var_Axis *axis, const float factor)
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)
#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
#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
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
bool add(const Key &key, const Value &value)
const Value * lookup_ptr_as(const ForwardKey &key) const
void append(const T &value)
const T & last(const int64_t n=0) const
constexpr T degrees(T) RET
#define MEM_reallocN(vmemh, len)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
GlyphCacheBLF * glyph_cache
GPUVertBufRaw offset_step
GPUVertBufRaw glyph_flags_step
GPUVertBufRaw glyph_size_step
blender::Vector< std::unique_ptr< GlyphCacheBLF > > cache
blender::Mutex glyph_cache_mutex
unsigned char shadow_color[4]
GlyphCacheBLF * glyph_cache
blender::Map< GlyphCacheKey, std::unique_ptr< GlyphBLF > > glyphs