Blender V4.3
vfont.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
8
9#include <algorithm>
10#include <cmath>
11#include <cstdio>
12#include <cstdlib>
13#include <cstring>
14#include <cwctype>
15#include <optional>
16
17#include "CLG_log.h"
18
19#include "MEM_guardedalloc.h"
20
21#include "BLI_ghash.h"
22#include "BLI_listbase.h"
23#include "BLI_math_base_safe.h"
24#include "BLI_math_matrix.h"
25#include "BLI_math_vector.h"
26#include "BLI_path_utils.hh"
27#include "BLI_rect.h"
28#include "BLI_string.h"
29#include "BLI_string_utf8.h"
30#include "BLI_threads.h"
31#include "BLI_utildefines.h"
32
33#include "BLT_translation.hh"
34
35#include "DNA_curve_types.h"
36#include "DNA_object_types.h"
38#include "DNA_vfont_types.h"
39
40#include "BKE_anim_path.h"
41#include "BKE_bpath.hh"
42#include "BKE_curve.hh"
43#include "BKE_global.hh"
44#include "BKE_idtype.hh"
45#include "BKE_lib_id.hh"
46#include "BKE_main.hh"
47#include "BKE_object_types.hh"
48#include "BKE_packedFile.hh"
49#include "BKE_vfont.hh"
50#include "BKE_vfontdata.hh"
51
52#include "BLO_read_write.hh"
53
54static CLG_LogRef LOG = {"bke.data_transfer"};
56
57/**************************** Prototypes **************************/
58
60
61/****************************** VFont Datablock ************************/
62
63const void *builtin_font_data = nullptr;
65
66static void vfont_init_data(ID *id)
67{
68 VFont *vfont = (VFont *)id;
70
71 if (pf) {
72 VFontData *vfd;
73
75 if (vfd) {
76 vfont->data = vfd;
77
79 }
80
81 /* Free the packed file */
83 }
84}
85
86static void vfont_copy_data(Main * /*bmain*/,
87 std::optional<Library *> /*owner_library*/,
88 ID *id_dst,
89 const ID * /*id_src*/,
90 const int flag)
91{
92 VFont *vfont_dst = (VFont *)id_dst;
93
94 /* We never handle user-count here for own data. */
95 const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
96
97 /* Just to be sure, should not have any value actually after reading time. */
98 vfont_dst->temp_pf = nullptr;
99
100 if (vfont_dst->packedfile) {
101 vfont_dst->packedfile = BKE_packedfile_duplicate(vfont_dst->packedfile);
102 }
103
104 if (vfont_dst->data) {
105 vfont_dst->data = BKE_vfontdata_copy(vfont_dst->data, flag_subdata);
106 }
107}
108
110static void vfont_free_data(ID *id)
111{
112 VFont *vfont = (VFont *)id;
113 BKE_vfont_free_data(vfont);
114
115 if (vfont->packedfile) {
117 vfont->packedfile = nullptr;
118 }
119}
120
121static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
122{
123 VFont *vfont = (VFont *)id;
124
125 if ((vfont->packedfile != nullptr) &&
126 (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0)
127 {
128 return;
129 }
130
131 if (BKE_vfont_is_builtin(vfont)) {
132 return;
133 }
134
135 BKE_bpath_foreach_path_fixed_process(bpath_data, vfont->filepath, sizeof(vfont->filepath));
136}
137
138static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
139{
140 VFont *vf = (VFont *)id;
141 const bool is_undo = BLO_write_is_undo(writer);
142
143 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
144 vf->data = nullptr;
145 vf->temp_pf = nullptr;
146
147 /* Do not store packed files in case this is a library override ID. */
148 if (ID_IS_OVERRIDE_LIBRARY(vf) && !is_undo) {
149 vf->packedfile = nullptr;
150 }
151
152 /* write LibData */
153 BLO_write_id_struct(writer, VFont, id_address, &vf->id);
154 BKE_id_blend_write(writer, &vf->id);
155
156 /* direct data */
158}
159
160static void vfont_blend_read_data(BlendDataReader *reader, ID *id)
161{
162 VFont *vf = (VFont *)id;
163 vf->data = nullptr;
164 vf->temp_pf = nullptr;
166}
167
169 /*id_code*/ ID_VF,
170 /*id_filter*/ FILTER_ID_VF,
171 /*dependencies_id_types*/ 0,
172 /*main_listbase_index*/ INDEX_ID_VF,
173 /*struct_size*/ sizeof(VFont),
174 /*name*/ "Font",
175 /*name_plural*/ N_("fonts"),
176 /*translation_context*/ BLT_I18NCONTEXT_ID_VFONT,
178 /*asset_type_info*/ nullptr,
179
180 /*init_data*/ vfont_init_data,
181 /*copy_data*/ vfont_copy_data,
182 /*free_data*/ vfont_free_data,
183 /*make_local*/ nullptr,
184 /*foreach_id*/ nullptr,
185 /*foreach_cache*/ nullptr,
186 /*foreach_path*/ vfont_foreach_path,
187 /*owner_pointer_get*/ nullptr,
188
189 /*blend_write*/ vfont_blend_write,
190 /*blend_read_data*/ vfont_blend_read_data,
191 /*blend_read_after_liblink*/ nullptr,
192
193 /*blend_read_undo_preserve*/ nullptr,
194
195 /*lib_override_apply_post*/ nullptr,
196};
197
198/***************************** VFont *******************************/
199
201{
202 if (vfont->data) {
203 if (vfont->data->characters) {
204 GHashIterator gh_iter;
205 GHASH_ITER (gh_iter, vfont->data->characters) {
206 VChar *che = static_cast<VChar *>(BLI_ghashIterator_getValue(&gh_iter));
207
208 while (che->nurbsbase.first) {
209 Nurb *nu = static_cast<Nurb *>(che->nurbsbase.first);
210 if (nu->bezt) {
211 MEM_freeN(nu->bezt);
212 }
213 BLI_freelinkN(&che->nurbsbase, nu);
214 }
215
216 MEM_freeN(che);
217 }
218
219 BLI_ghash_free(vfont->data->characters, nullptr, nullptr);
220 }
221
222 MEM_freeN(vfont->data);
223 vfont->data = nullptr;
224 }
225
226 if (vfont->temp_pf) {
227 BKE_packedfile_free(vfont->temp_pf); /* Null when the font file can't be found on disk. */
228 vfont->temp_pf = nullptr;
229 }
230}
231
232bool BKE_vfont_is_builtin(const VFont *vfont)
233{
234 return STREQ(vfont->filepath, FO_BUILTIN_NAME);
235}
236
237void BKE_vfont_builtin_register(const void *mem, int size)
238{
239 builtin_font_data = mem;
241}
242
244{
245 if (!builtin_font_data) {
246 CLOG_ERROR(&LOG, "Internal error, builtin font not loaded");
247
248 return nullptr;
249 }
250
251 void *mem = MEM_mallocN(builtin_font_size, "vfd_builtin");
252
254
256}
257
259{
260 if (vfont == nullptr) {
261 return nullptr;
262 }
263
264 /* And then set the data */
265 if (!vfont->data) {
266 PackedFile *pf;
267
269
270 if (vfont->data) {
271 /* Check data again, since it might have been already
272 * initialized from other thread (previous check is
273 * not accurate or threading, just prevents unneeded
274 * lock if all the data is here for sure).
275 */
277 return vfont->data;
278 }
279
280 if (BKE_vfont_is_builtin(vfont)) {
282 }
283 else {
284 if (vfont->packedfile) {
285 pf = vfont->packedfile;
286
287 /* We need to copy a tmp font to memory unless it is already there */
288 if (vfont->temp_pf == nullptr) {
290 }
291 }
292 else {
293 pf = BKE_packedfile_new(nullptr, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
294
295 if (vfont->temp_pf == nullptr) {
297 nullptr, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
298 }
299 }
300 if (!pf) {
301 CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->filepath);
302
303 /* DON'T DO THIS
304 * missing file shouldn't modify path! - campbell */
305#if 0
307#endif
309 }
310 }
311
312 if (pf) {
314 if (pf != vfont->packedfile) {
316 }
317 }
318
320 }
321
322 return vfont->data;
323}
324
325VFont *BKE_vfont_load(Main *bmain, const char *filepath)
326{
327 char filename[FILE_MAXFILE];
328 VFont *vfont = nullptr;
329 PackedFile *pf;
330 bool is_builtin;
331
332 if (STREQ(filepath, FO_BUILTIN_NAME)) {
333 STRNCPY(filename, filepath);
334
336 is_builtin = true;
337 }
338 else {
339 BLI_path_split_file_part(filepath, filename, sizeof(filename));
340 pf = BKE_packedfile_new(nullptr, filepath, BKE_main_blendfile_path(bmain));
341
342 is_builtin = false;
343 }
344
345 if (pf) {
346 VFontData *vfd;
347
349 if (vfd) {
350 /* If there's a font name, use it for the ID name. */
351 vfont = static_cast<VFont *>(
352 BKE_libblock_alloc(bmain, ID_VF, vfd->name[0] ? vfd->name : filename, 0));
353 vfont->data = vfd;
354 STRNCPY(vfont->filepath, filepath);
355
356 /* if auto-pack is on store the packed-file in de font structure */
357 if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) {
358 vfont->packedfile = pf;
359 }
360
361 /* Do not add #FO_BUILTIN_NAME to temporary list-base. */
362 if (!STREQ(filename, FO_BUILTIN_NAME)) {
363 vfont->temp_pf = BKE_packedfile_new(nullptr, filepath, BKE_main_blendfile_path(bmain));
364 }
365 }
366
367 /* Free the packed file */
368 if (!vfont || vfont->packedfile != pf) {
370 }
371 }
372
373 return vfont;
374}
375
376VFont *BKE_vfont_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
377{
378 char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
379
380 STRNCPY(filepath_abs, filepath);
381 BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
382
383 /* first search an identical filepath */
384 LISTBASE_FOREACH (VFont *, vfont, &bmain->fonts) {
385 STRNCPY(filepath_test, vfont->filepath);
386 BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &vfont->id));
387
388 if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
389 id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */
390 if (r_exists) {
391 *r_exists = true;
392 }
393 return vfont;
394 }
395 }
396
397 if (r_exists) {
398 *r_exists = false;
399 }
400 return BKE_vfont_load(bmain, filepath);
401}
402
403VFont *BKE_vfont_load_exists(Main *bmain, const char *filepath)
404{
405 return BKE_vfont_load_exists_ex(bmain, filepath, nullptr);
406}
407
408static VFont *which_vfont(Curve *cu, const CharInfo *info)
409{
410 switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) {
411 case CU_CHINFO_BOLD:
412 return cu->vfontb ? cu->vfontb : cu->vfont;
413 case CU_CHINFO_ITALIC:
414 return cu->vfonti ? cu->vfonti : cu->vfont;
416 return cu->vfontbi ? cu->vfontbi : cu->vfont;
417 default:
418 return cu->vfont;
419 }
420}
421
423{
424 LISTBASE_FOREACH (VFont *, vfont, &G_MAIN->fonts) {
425 if (BKE_vfont_is_builtin(vfont)) {
426 return vfont;
427 }
428 }
429
430 /* Newly loaded ID's have a user by default, in this case the caller is responsible
431 * for assigning a user, otherwise an additional user would be added, see: #100819. */
433 id_us_min(&vfont->id);
434 BLI_assert(vfont->id.us == 0);
435 return vfont;
436}
437
438static VChar *find_vfont_char(const VFontData *vfd, uint character)
439{
440 return static_cast<VChar *>(BLI_ghash_lookup(vfd->characters, POINTER_FROM_UINT(character)));
441}
442
443static void build_underline(Curve *cu,
444 ListBase *nubase,
445 const rctf *rect,
446 float yofs,
447 float rot,
448 int charidx,
449 short mat_nr,
450 const float font_size)
451{
452 Nurb *nu2;
453 BPoint *bp;
454
455 nu2 = (Nurb *)MEM_callocN(sizeof(Nurb), "underline_nurb");
456 nu2->resolu = cu->resolu;
457 nu2->bezt = nullptr;
458 nu2->knotsu = nu2->knotsv = nullptr;
459 nu2->charidx = charidx + 1000;
460 if (mat_nr >= 0) {
461 nu2->mat_nr = mat_nr;
462 }
463 nu2->pntsu = 4;
464 nu2->pntsv = 1;
465 nu2->orderu = 4;
466 nu2->orderv = 1;
467 nu2->flagu = CU_NURB_CYCLIC;
468
469 bp = (BPoint *)MEM_calloc_arrayN(4, sizeof(BPoint), "underline_bp");
470
471 copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f);
472 copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f);
473 copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f);
474 copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f);
475
476 /* Used by curve extrusion. */
477 bp[0].radius = bp[1].radius = bp[2].radius = bp[3].radius = 1.0f;
478
479 nu2->bp = bp;
480 BLI_addtail(nubase, nu2);
481
482 if (rot != 0.0f) {
483 float si = sinf(rot);
484 float co = cosf(rot);
485
486 for (int i = nu2->pntsu; i > 0; i--) {
487 float *fp = bp->vec;
488
489 float x = fp[0] - rect->xmin;
490 float y = fp[1] - rect->ymin;
491
492 fp[0] = (+co * x + si * y) + rect->xmin;
493 fp[1] = (-si * x + co * y) + rect->ymin;
494
495 bp++;
496 }
497
498 bp = nu2->bp;
499 }
500
501 mul_v2_fl(bp[0].vec, font_size);
502 mul_v2_fl(bp[1].vec, font_size);
503 mul_v2_fl(bp[2].vec, font_size);
504 mul_v2_fl(bp[3].vec, font_size);
505}
506
508 ListBase *nubase,
509 uint character,
510 const CharInfo *info,
511 float ofsx,
512 float ofsy,
513 float rot,
514 int charidx,
515 const float fsize)
516{
517 VFontData *vfd = vfont_get_data(which_vfont(cu, info));
518 if (!vfd) {
519 return;
520 }
521
522 /* make a copy at distance ofsx, ofsy with shear */
523 float shear = cu->shear;
524 float si = sinf(rot);
525 float co = cosf(rot);
526
527 VChar *che = find_vfont_char(vfd, character);
528
529 /* Select the glyph data */
530 Nurb *nu1 = nullptr;
531 if (che) {
532 nu1 = static_cast<Nurb *>(che->nurbsbase.first);
533 }
534
535 /* Create the character */
536 while (nu1) {
537 BezTriple *bezt1 = nu1->bezt;
538 if (bezt1) {
539 Nurb *nu2 = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplichar_nurb");
540 if (nu2 == nullptr) {
541 break;
542 }
543 *nu2 = blender::dna::shallow_copy(*nu1);
544 nu2->resolu = cu->resolu;
545 nu2->bp = nullptr;
546 nu2->knotsu = nu2->knotsv = nullptr;
547 nu2->flag = CU_SMOOTH;
548 nu2->charidx = charidx;
549 if (info->mat_nr > 0) {
550 nu2->mat_nr = info->mat_nr;
551 }
552 else {
553 nu2->mat_nr = 0;
554 }
555 // nu2->trim.first = 0;
556 // nu2->trim.last = 0;
557 int u = nu2->pntsu;
558
559 BezTriple *bezt2 = (BezTriple *)MEM_malloc_arrayN(u, sizeof(BezTriple), "duplichar_bezt2");
560 if (bezt2 == nullptr) {
561 MEM_freeN(nu2);
562 break;
563 }
564 memcpy(bezt2, bezt1, u * sizeof(BezTriple));
565 nu2->bezt = bezt2;
566
567 if (shear != 0.0f) {
568 bezt2 = nu2->bezt;
569
570 for (int i = nu2->pntsu; i > 0; i--) {
571 bezt2->vec[0][0] += shear * bezt2->vec[0][1];
572 bezt2->vec[1][0] += shear * bezt2->vec[1][1];
573 bezt2->vec[2][0] += shear * bezt2->vec[2][1];
574 bezt2++;
575 }
576 }
577 if (rot != 0.0f) {
578 bezt2 = nu2->bezt;
579 for (int i = nu2->pntsu; i > 0; i--) {
580 float *fp = bezt2->vec[0];
581
582 float x = fp[0];
583 fp[0] = co * x + si * fp[1];
584 fp[1] = -si * x + co * fp[1];
585 x = fp[3];
586 fp[3] = co * x + si * fp[4];
587 fp[4] = -si * x + co * fp[4];
588 x = fp[6];
589 fp[6] = co * x + si * fp[7];
590 fp[7] = -si * x + co * fp[7];
591
592 bezt2++;
593 }
594 }
595 bezt2 = nu2->bezt;
596
597 if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
598 const float sca = cu->smallcaps_scale;
599 for (int i = nu2->pntsu; i > 0; i--) {
600 float *fp = bezt2->vec[0];
601 fp[0] *= sca;
602 fp[1] *= sca;
603 fp[3] *= sca;
604 fp[4] *= sca;
605 fp[6] *= sca;
606 fp[7] *= sca;
607 bezt2++;
608 }
609 }
610 bezt2 = nu2->bezt;
611
612 for (int i = nu2->pntsu; i > 0; i--) {
613 float *fp = bezt2->vec[0];
614 fp[0] = (fp[0] + ofsx) * fsize;
615 fp[1] = (fp[1] + ofsy) * fsize;
616 fp[3] = (fp[3] + ofsx) * fsize;
617 fp[4] = (fp[4] + ofsy) * fsize;
618 fp[6] = (fp[6] + ofsx) * fsize;
619 fp[7] = (fp[7] + ofsy) * fsize;
620 bezt2++;
621 }
622
623 BLI_addtail(nubase, nu2);
624 }
625
626 nu1 = nu1->next;
627 }
628}
629
630int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end)
631{
632 Curve *cu = static_cast<Curve *>(ob->data);
633 EditFont *ef = cu->editfont;
634 int start, end, direction;
635
636 if ((ob->type != OB_FONT) || (ef == nullptr)) {
637 return 0;
638 }
639
640 BLI_assert(ef->len >= 0);
641 BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
642 BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1);
643 BLI_assert(ef->pos >= 0 && ef->pos <= ef->len);
644
645 if (ef->selstart == 0) {
646 return 0;
647 }
648
649 if (ef->selstart <= ef->selend) {
650 start = ef->selstart - 1;
651 end = ef->selend - 1;
652 direction = 1;
653 }
654 else {
655 start = ef->selend;
656 end = ef->selstart - 2;
657 direction = -1;
658 }
659
660 if (start == end + 1) {
661 return 0;
662 }
663
664 BLI_assert(start < end + 1);
665 *r_start = start;
666 *r_end = end;
667 return direction;
668}
669
671{
672 Curve *cu = static_cast<Curve *>(ob->data);
673 EditFont *ef = cu->editfont;
674
675 BLI_assert((ob->type == OB_FONT) && ef);
676
677 CLAMP_MAX(ef->pos, ef->len);
678 CLAMP_MAX(ef->selstart, ef->len + 1);
679 CLAMP_MAX(ef->selend, ef->len);
680}
681
682static float char_width(Curve *cu, VChar *che, const CharInfo *info)
683{
684 /* The character wasn't found, probably ascii = 0, then the width shall be 0 as well */
685 if (che == nullptr) {
686 return 0.0f;
687 }
688 if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
689 return che->width * cu->smallcaps_scale;
690 }
691
692 return che->width;
693}
694
695static void textbox_scale(TextBox *tb_dst, const TextBox *tb_src, float scale)
696{
697 tb_dst->x = tb_src->x * scale;
698 tb_dst->y = tb_src->y * scale;
699 tb_dst->w = tb_src->w * scale;
700 tb_dst->h = tb_src->h * scale;
701}
702
707 float x_min; /* left margin */
708 float x_max; /* right margin */
709 int char_nr; /* number of characters */
710 int wspace_nr; /* number of white-spaces of line */
711};
712
713/* -------------------------------------------------------------------- */
722
726 struct {
727 float min;
728 float max;
730 bool ok;
742};
743
745
746/* -------------------------------------------------------------------- */
753/* Used when translating a mouse cursor location to a position within the string. */
755 /* Mouse cursor location in Object coordinate space as input. */
757 /* Character position within EditFont::textbuf as output. */
759};
760
761enum {
766};
767
768#define FONT_TO_CURVE_SCALE_ITERATIONS 20
769#define FONT_TO_CURVE_SCALE_THRESHOLD 0.0001f
770
772
787
788static float vfont_ascent(const VFontData *vfd)
789{
790 return vfd->ascender * vfd->em_height;
791}
792static float vfont_descent(const VFontData *vfd)
793{
794 return vfd->em_height - vfont_ascent(vfd);
795}
796
812
813static bool vfont_to_curve(Object *ob,
814 Curve *cu,
815 const eEditFontMode mode,
816 VFontToCurveIter *iter_data,
817 VFontCursor_Params *cursor_params,
818 ListBase *r_nubase,
819 const char32_t **r_text,
820 int *r_text_len,
821 bool *r_text_free,
822 CharTrans **r_chartransdata)
823{
824 EditFont *ef = cu->editfont;
825 EditFontSelBox *selboxes = nullptr;
826 VFont *vfont, *oldvfont;
827 VFontData *vfd = nullptr;
828 CharInfo *info = nullptr, *custrinfo;
829 TextBox tb_scale;
830 bool use_textbox;
831 VChar *che;
832 CharTrans *chartransdata = nullptr, *ct;
833 TempLineInfo *lineinfo;
834 float xof, yof, xtrax, linedist;
835 float twidth = 0, maxlen = 0;
836 int i, slen, j;
837 int curbox;
838 /* These values are only set to the selection range when `selboxes` is non-null. */
839 int selstart = 0, selend = 0;
840 int cnr = 0, lnr = 0, wsnr = 0;
841 const char32_t *mem = nullptr;
842 char32_t ascii;
843 bool ok = false;
844 const float font_size = cu->fsize * iter_data->scale_to_fit;
845 /* Shift down vertically to be 25% below & 75% above baseline (before font scale is applied). */
846 const float font_select_y_offset = 0.25;
847 const bool word_wrap = iter_data->word_wrap;
848 const float xof_scale = safe_divide(cu->xof, font_size);
849 const float yof_scale = safe_divide(cu->yof, font_size);
850 int last_line = -1;
851 /* Length of the text disregarding \n breaks. */
852 float current_line_length = 0.0f;
853 float longest_line_length = 0.0f;
854
855 /* Text at the beginning of the last used text-box (use for y-axis alignment).
856 * We over-allocate by one to simplify logic of getting last char. */
857 blender::Array<int> i_textbox_array(cu->totbox + 1, 0);
858
859#define MARGIN_X_MIN (xof_scale + tb_scale.x)
860#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
861
862 /* NOTE: do calculations including the trailing '\0' of a string
863 * because the cursor can be at that location. */
864
865 BLI_assert(ob == nullptr || ob->type == OB_FONT);
866
867 /* Set font data */
868 vfont = cu->vfont;
869
870 if (cu->str == nullptr) {
871 return ok;
872 }
873 if (vfont == nullptr) {
874 return ok;
875 }
876
877 vfd = vfont_get_data(vfont);
878
879 /* The VFont Data can not be found */
880 if (!vfd) {
881 return ok;
882 }
883
884 if (ef) {
885 slen = ef->len;
886 mem = ef->textbuf;
887 custrinfo = ef->textbufinfo;
888 }
889 else {
890 char32_t *mem_tmp;
891 slen = cu->len_char32;
892
893 /* Create unicode string */
894 mem_tmp = static_cast<char32_t *>(
895 MEM_malloc_arrayN((slen + 1), sizeof(*mem_tmp), "convertedmem"));
896 if (!mem_tmp) {
897 return ok;
898 }
899
900 BLI_str_utf8_as_utf32(mem_tmp, cu->str, slen + 1);
901
902 if (cu->strinfo == nullptr) { /* old file */
903 cu->strinfo = static_cast<CharInfo *>(
904 MEM_calloc_arrayN((slen + 4), sizeof(CharInfo), "strinfo compat"));
905 }
906 custrinfo = cu->strinfo;
907 if (!custrinfo) {
908 return ok;
909 }
910
911 mem = mem_tmp;
912 }
913
914 if (cu->tb == nullptr) {
915 cu->tb = static_cast<TextBox *>(
916 MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBox compat"));
917 }
918
919 if (ef != nullptr && ob != nullptr) {
920 if (ef->selboxes) {
921 MEM_freeN(ef->selboxes);
922 }
923
924 if (BKE_vfont_select_get(ob, &selstart, &selend)) {
925 ef->selboxes_len = (selend - selstart) + 1;
926 ef->selboxes = static_cast<EditFontSelBox *>(
927 MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes"));
928 }
929 else {
930 ef->selboxes_len = 0;
931 ef->selboxes = nullptr;
932 }
933
934 selboxes = ef->selboxes;
935 }
936
937 /* calc offset and rotation of each char */
938 ct = chartransdata = static_cast<CharTrans *>(
939 MEM_calloc_arrayN((slen + 1), sizeof(CharTrans), "buildtext"));
940
941 /* We assume the worst case: 1 character per line (is freed at end anyway) */
942 lineinfo = static_cast<TempLineInfo *>(
943 MEM_malloc_arrayN((slen * 2 + 1), sizeof(*lineinfo), "lineinfo"));
944
945 linedist = cu->linedist;
946
947 curbox = 0;
948 textbox_scale(&tb_scale, &cu->tb[curbox], safe_divide(1.0f, font_size));
949 use_textbox = (tb_scale.w != 0.0f);
950
951 xof = MARGIN_X_MIN;
952 yof = MARGIN_Y_MIN;
953
954 xtrax = 0.5f * cu->spacing - 0.5f;
955
956 oldvfont = nullptr;
957
958 for (i = 0; i < slen; i++) {
960 }
961
962 TextBoxBounds_ForCursor *tb_bounds_for_cursor = nullptr;
963 if (cursor_params != nullptr) {
964 if (cu->textoncurve == nullptr && (cu->totbox > 1) && (slen > 0)) {
965 tb_bounds_for_cursor = static_cast<TextBoxBounds_ForCursor *>(
966 MEM_malloc_arrayN(cu->totbox, sizeof(TextBoxBounds_ForCursor), "TextboxBounds_Cursor"));
967 for (curbox = 0; curbox < cu->totbox; curbox++) {
968 TextBoxBounds_ForCursor *tb_bounds = &tb_bounds_for_cursor[curbox];
969 tb_bounds->char_index_last = -1;
970 tb_bounds->bounds.xmin = FLT_MAX;
971 tb_bounds->bounds.xmax = -FLT_MAX;
972 tb_bounds->bounds.ymin = FLT_MAX;
973 tb_bounds->bounds.ymax = -FLT_MAX;
974 }
975 }
976 curbox = 0;
977 }
978
979 i = 0;
980 while (i <= slen) {
981 /* Characters in the list */
982 info = &custrinfo[i];
983 ascii = mem[i];
984 if (info->flag & CU_CHINFO_SMALLCAPS) {
985 ascii = towupper(ascii);
986 if (mem[i] != ascii) {
988 }
989 }
990
991 vfont = which_vfont(cu, info);
992
993 if (vfont == nullptr) {
994 break;
995 }
996
997 if (vfont != oldvfont) {
998 vfd = vfont_get_data(vfont);
999 oldvfont = vfont;
1000 }
1001
1002 /* VFont Data for VFont couldn't be found */
1003 if (!vfd) {
1004 MEM_freeN(chartransdata);
1005 chartransdata = nullptr;
1006 MEM_freeN(lineinfo);
1007 goto finally;
1008 }
1009
1010 if (!ELEM(ascii, '\n', '\0')) {
1012 che = find_vfont_char(vfd, ascii);
1014
1015 /* The character wasn't in the current curve base so load it. */
1016 if (che == nullptr) {
1018 /* Check it once again, char might have been already load
1019 * between previous #BLI_rw_mutex_unlock() and this #BLI_rw_mutex_lock().
1020 *
1021 * Such a check should not be a bottleneck since it wouldn't
1022 * happen often once all the chars are load. */
1023 if ((che = find_vfont_char(vfd, ascii)) == nullptr) {
1024 che = BKE_vfontdata_char_from_freetypefont(vfont, ascii);
1025 }
1027 }
1028 }
1029 else {
1030 che = nullptr;
1031 }
1032
1033 twidth = char_width(cu, che, info);
1034
1035 /* Calculate positions. */
1036
1037 if ((tb_scale.w != 0.0f) && (ct->dobreak == 0)) { /* May need wrapping. */
1038 const float x_available = xof_scale + tb_scale.w;
1039 const float x_used = (xof - tb_scale.x) + twidth;
1040
1041 if (word_wrap == false) {
1042 /* When scale to fit is used, don't do any wrapping.
1043 *
1044 * Floating precision error can cause the text to be slightly larger.
1045 * Assert this is a small value as large values indicate incorrect
1046 * calculations with scale-to-fit which shouldn't be ignored. See #89241. */
1047 if (x_used > x_available) {
1048 BLI_assert_msg(compare_ff_relative(x_used, x_available, FLT_EPSILON, 64),
1049 "VFontToCurveIter.scale_to_fit not set correctly!");
1050 }
1051 }
1052 else if (x_used > x_available) {
1053 // CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]);
1054 bool dobreak = false;
1055 for (j = i; (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
1056
1057 /* Special case when there are no breaks possible. */
1058 if (UNLIKELY(j == 0)) {
1059 if (i == slen) {
1060 /* Use the behavior of zero a height text-box when a break cannot be inserted.
1061 *
1062 * Typically when a text-box has any height and overflow is set to scale
1063 * the text will wrap to fit the width as necessary. When wrapping isn't
1064 * possible it's important to use the same code-path as zero-height lines.
1065 * Without this exception a single word will not scale-to-fit (see: #95116). */
1066 tb_scale.h = 0.0f;
1067 }
1068 break;
1069 }
1070
1071 if (ELEM(mem[j], ' ', '-')) {
1072 ct -= (i - (j - 1));
1073 cnr -= (i - (j - 1));
1074 if (mem[j] == ' ') {
1075 wsnr--;
1076 }
1077 if (mem[j] == '-') {
1078 wsnr++;
1079 }
1080 i = j - 1;
1081 xof = ct->xof;
1082 ct[1].dobreak = 1;
1083 custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
1084 dobreak = true;
1085 break;
1086 }
1087 BLI_assert(chartransdata[j].dobreak == 0);
1088 }
1089
1090 if (dobreak) {
1091 if (tb_scale.h == 0.0f) {
1092 /* NOTE: If underlined text is truncated away, the extra space is also truncated. */
1093 custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
1094 }
1095 /* Since a break was added, re-run this loop with `i` at it's new value. */
1096 continue;
1097 }
1098 }
1099 }
1100
1101 if (ascii == '\n' || ascii == 0 || ct->dobreak) {
1102 ct->xof = xof;
1103 ct->yof = yof;
1104 ct->linenr = lnr;
1105 ct->charnr = cnr;
1106
1107 yof -= linedist;
1108
1109 lineinfo[lnr].x_min = (xof - xtrax) - tb_scale.x;
1110 lineinfo[lnr].x_max = tb_scale.w;
1111 lineinfo[lnr].char_nr = cnr;
1112 lineinfo[lnr].wspace_nr = wsnr;
1113
1114 CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
1115
1116 if (tb_bounds_for_cursor != nullptr) {
1117 tb_bounds_for_cursor[curbox].char_index_last = i;
1118 }
1119
1120 if ((tb_scale.h != 0.0f) && (-(yof - tb_scale.y) > (tb_scale.h - linedist) - yof_scale)) {
1121 if (cu->totbox > (curbox + 1)) {
1122 maxlen = 0;
1123 curbox++;
1124 i_textbox_array[curbox] = i + 1;
1125
1126 textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
1127
1128 yof = MARGIN_Y_MIN;
1129 }
1130 else if (last_line == -1) {
1131 last_line = lnr + 1;
1132 info->flag |= CU_CHINFO_OVERFLOW;
1133 }
1134 }
1135
1136 current_line_length += xof - MARGIN_X_MIN;
1137 if (ct->dobreak) {
1138 current_line_length += twidth;
1139 }
1140 else {
1141 longest_line_length = std::max(current_line_length, longest_line_length);
1142 current_line_length = 0.0f;
1143 }
1144
1145 xof = MARGIN_X_MIN;
1146 lnr++;
1147 cnr = 0;
1148 wsnr = 0;
1149 }
1150 else if (ascii == '\t') { /* Tab character. */
1151 float tabfac;
1152
1153 ct->xof = xof;
1154 ct->yof = yof;
1155 ct->linenr = lnr;
1156 ct->charnr = cnr++;
1157
1158 tabfac = (xof - MARGIN_X_MIN + 0.01f);
1159 tabfac = 2.0f * ceilf(tabfac / 2.0f);
1160 xof = MARGIN_X_MIN + tabfac;
1161 }
1162 else {
1163 EditFontSelBox *sb = nullptr;
1164 float wsfac;
1165
1166 ct->xof = xof;
1167 ct->yof = yof;
1168 ct->linenr = lnr;
1169 ct->charnr = cnr++;
1170
1171 if (selboxes && (i >= selstart) && (i <= selend)) {
1172 sb = &selboxes[i - selstart];
1173 sb->y = (yof - font_select_y_offset) * font_size - linedist * font_size * 0.1f;
1174 sb->h = linedist * font_size;
1175 sb->w = xof * font_size;
1176 }
1177
1178 if (ascii == ' ') { /* Space character. */
1179 wsfac = cu->wordspace;
1180 wsnr++;
1181 }
1182 else {
1183 wsfac = 1.0f;
1184 }
1185
1186 /* Set the width of the character. */
1187 twidth = char_width(cu, che, info);
1188
1189 xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f))) + xtrax;
1190
1191 if (sb) {
1192 sb->w = (xof * font_size) - sb->w;
1193 }
1194 }
1195 ct++;
1196 i++;
1197 }
1198
1199 current_line_length += xof + twidth - MARGIN_X_MIN;
1200 longest_line_length = std::max(current_line_length, longest_line_length);
1201
1202 cu->lines = 1;
1203 for (i = 0; i <= slen; i++) {
1204 ascii = mem[i];
1205 ct = &chartransdata[i];
1206 if (ascii == '\n' || ct->dobreak) {
1207 cu->lines++;
1208 }
1209 }
1210
1211 if (ef && selboxes) {
1212 /* Set combined style flags for the selected string. Start with all styles then
1213 * remove one if ANY characters do not have it. Break out if we've removed them all. */
1215 for (int k = selstart; k <= selend && ef->select_char_info_flag; k++) {
1216 info = &custrinfo[k];
1217 ef->select_char_info_flag &= info->flag;
1218 }
1219 }
1220
1221 if (cu->spacemode != CU_ALIGN_X_LEFT) {
1222 ct = chartransdata;
1223
1224 if (cu->spacemode == CU_ALIGN_X_RIGHT) {
1225 TempLineInfo *li;
1226
1227 for (i = 0, li = lineinfo; i < lnr; i++, li++) {
1228 li->x_min = (li->x_max - li->x_min) + xof_scale;
1229 }
1230
1231 for (i = 0; i <= slen; i++) {
1232 ct->xof += lineinfo[ct->linenr].x_min;
1233 ct++;
1234 }
1235 }
1236 else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
1237 TempLineInfo *li;
1238
1239 for (i = 0, li = lineinfo; i < lnr; i++, li++) {
1240 li->x_min = ((li->x_max - li->x_min) + xof_scale) / 2.0f;
1241 }
1242
1243 for (i = 0; i <= slen; i++) {
1244 ct->xof += lineinfo[ct->linenr].x_min;
1245 ct++;
1246 }
1247 }
1248 else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) {
1249 TempLineInfo *li;
1250
1251 for (i = 0, li = lineinfo; i < lnr; i++, li++) {
1252 li->x_min = ((li->x_max - li->x_min) + xof_scale);
1253
1254 if (li->char_nr > 1) {
1255 li->x_min /= float(li->char_nr - 1);
1256 }
1257 }
1258 for (i = 0; i <= slen; i++) {
1259 for (j = i; !ELEM(mem[j], '\0', '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
1260 j++)
1261 {
1262 /* do nothing */
1263 }
1264
1265 // if ((mem[j] != '\n') && (mem[j])) {
1266 ct->xof += ct->charnr * lineinfo[ct->linenr].x_min;
1267 // }
1268 ct++;
1269 }
1270 }
1271 else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) {
1272 float curofs = 0.0f;
1273 for (i = 0; i <= slen; i++) {
1274 for (j = i; (mem[j]) && (mem[j] != '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
1275 j++)
1276 {
1277 /* pass */
1278 }
1279
1280 if ((mem[j] != '\n') && (chartransdata[j].dobreak != 0)) {
1281 if (mem[i] == ' ') {
1282 TempLineInfo *li;
1283
1284 li = &lineinfo[ct->linenr];
1285 curofs += ((li->x_max - li->x_min) + xof_scale) / float(li->wspace_nr);
1286 }
1287 ct->xof += curofs;
1288 }
1289 if (mem[i] == '\n' || chartransdata[i].dobreak) {
1290 curofs = 0;
1291 }
1292 ct++;
1293 }
1294 }
1295 }
1296
1297 /* Top-baseline is default, in this case, do nothing. */
1298 if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
1299 if (tb_scale.h != 0.0f) {
1300 /* We need to loop all the text-boxes even the "full" ones.
1301 * This way they all get the same vertical padding. */
1302 for (int tb_index = 0; tb_index < cu->totbox; tb_index++) {
1303 CharTrans *ct_first, *ct_last;
1304 const int i_textbox = i_textbox_array[tb_index];
1305 const int i_textbox_next = i_textbox_array[tb_index + 1];
1306 const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1);
1307 int lines;
1308
1309 ct_first = chartransdata + i_textbox;
1310 ct_last = chartransdata + (is_last_filled_textbox ? slen : i_textbox_next - 1);
1311 lines = ct_last->linenr - ct_first->linenr + 1;
1312
1313 if (cu->overflow == CU_OVERFLOW_TRUNCATE) {
1314 /* Ensure overflow doesn't truncate text, before centering vertically
1315 * giving odd/buggy results, see: #66614. */
1316 if ((tb_index == cu->totbox - 1) && (last_line != -1)) {
1317 lines = last_line - ct_first->linenr;
1318 }
1319 }
1320
1321 textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / font_size);
1322 /* The initial Y origin of the text-box is hard-coded to 1.0f * text scale. */
1323 const float textbox_y_origin = 1.0f;
1324 float yoff = 0.0f;
1325
1326 switch (cu->align_y) {
1328 break;
1329 case CU_ALIGN_Y_TOP:
1330 yoff = textbox_y_origin - vfont_ascent(vfd);
1331 break;
1332 case CU_ALIGN_Y_CENTER:
1333 yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - vfont_ascent(vfd)) -
1334 (tb_scale.h * 0.5f) + textbox_y_origin);
1335 break;
1337 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h;
1338 break;
1339 case CU_ALIGN_Y_BOTTOM:
1340 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + vfont_descent(vfd);
1341 break;
1342 }
1343
1344 for (ct = ct_first; ct <= ct_last; ct++) {
1345 ct->yof += yoff;
1346 }
1347
1348 if (is_last_filled_textbox) {
1349 break;
1350 }
1351 }
1352 }
1353 else {
1354 /* Non text-box case handled separately. */
1355 float yoff = 0.0f;
1356
1357 switch (cu->align_y) {
1359 break;
1360 case CU_ALIGN_Y_TOP:
1361 yoff = -vfont_ascent(vfd);
1362 break;
1363 case CU_ALIGN_Y_CENTER:
1364 yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - vfont_ascent(vfd);
1365 break;
1367 yoff = (lnr - 1) * linedist;
1368 break;
1369 case CU_ALIGN_Y_BOTTOM:
1370 yoff = (lnr - 1) * linedist + vfont_descent(vfd);
1371 break;
1372 }
1373
1374 ct = chartransdata;
1375 for (i = 0; i <= slen; i++) {
1376 ct->yof += yoff;
1377 ct++;
1378 }
1379 }
1380 }
1381 if (tb_bounds_for_cursor != nullptr) {
1382 int char_beg_next = 0;
1383 for (curbox = 0; curbox < cu->totbox; curbox++) {
1384 TextBoxBounds_ForCursor *tb_bounds = &tb_bounds_for_cursor[curbox];
1385 if (tb_bounds->char_index_last == -1) {
1386 continue;
1387 }
1388 const int char_beg = char_beg_next;
1389 const int char_end = tb_bounds->char_index_last;
1390
1391 TempLineInfo *line_beg = &lineinfo[chartransdata[char_beg].linenr];
1392 TempLineInfo *line_end = &lineinfo[chartransdata[char_end].linenr];
1393
1394 int char_idx_offset = char_beg;
1395
1396 rctf *bounds = &tb_bounds->bounds;
1397 /* In a text-box with no curves, 'yof' only decrements over lines, 'ymax' and 'ymin'
1398 * can be obtained from any character in the first and last line of the text-box. */
1399 bounds->ymax = chartransdata[char_beg].yof;
1400 bounds->ymin = chartransdata[char_end].yof;
1401
1402 for (TempLineInfo *line = line_beg; line <= line_end; line++) {
1403 const CharTrans *first_char_line = &chartransdata[char_idx_offset];
1404 const CharTrans *last_char_line = &chartransdata[char_idx_offset + line->char_nr];
1405
1406 bounds->xmin = min_ff(bounds->xmin, first_char_line->xof);
1407 bounds->xmax = max_ff(bounds->xmax, last_char_line->xof);
1408 char_idx_offset += line->char_nr + 1;
1409 }
1410 /* Move the bounds into a space compatible with `cursor_location`. */
1411 BLI_rctf_mul(bounds, font_size);
1412
1413 char_beg_next = tb_bounds->char_index_last + 1;
1414 }
1415 }
1416
1417 MEM_freeN(lineinfo);
1418
1419 /* TEXT ON CURVE */
1420 /* NOTE: Only #OB_CURVES_LEGACY objects could have a path. */
1421 if (cu->textoncurve && cu->textoncurve->type == OB_CURVES_LEGACY) {
1422 BLI_assert(cu->textoncurve->runtime->curve_cache != nullptr);
1423 if (cu->textoncurve->runtime->curve_cache != nullptr &&
1424 cu->textoncurve->runtime->curve_cache->anim_path_accum_length != nullptr)
1425 {
1426 float distfac, imat[4][4], imat3[3][3], cmat[3][3];
1427 float minx, maxx;
1428 float timeofs, sizefac;
1429
1430 if (ob != nullptr) {
1431 invert_m4_m4(imat, ob->object_to_world().ptr());
1432 }
1433 else {
1434 unit_m4(imat);
1435 }
1436 copy_m3_m4(imat3, imat);
1437
1438 copy_m3_m4(cmat, cu->textoncurve->object_to_world().ptr());
1439 mul_m3_m3m3(cmat, cmat, imat3);
1440 sizefac = normalize_v3(cmat[0]) / font_size;
1441
1442 ct = chartransdata;
1443 minx = maxx = ct->xof;
1444 ct++;
1445 for (i = 1; i <= slen; i++, ct++) {
1446 if (minx > ct->xof) {
1447 minx = ct->xof;
1448 }
1449 if (maxx < ct->xof) {
1450 maxx = ct->xof;
1451 }
1452 }
1453
1454 /* We put the x-coordinate exact at the curve, the y is rotated. */
1455
1456 /* length correction */
1457 const float chartrans_size_x = maxx - minx;
1458 if (chartrans_size_x != 0.0f) {
1459 const CurveCache *cc = cu->textoncurve->runtime->curve_cache;
1460 const float totdist = BKE_anim_path_get_length(cc);
1461 distfac = (sizefac * totdist) / chartrans_size_x;
1462 distfac = (distfac > 1.0f) ? (1.0f / distfac) : 1.0f;
1463 }
1464 else {
1465 /* Happens when there are no characters, set this value to place the text cursor. */
1466 distfac = 0.0f;
1467 }
1468
1469 timeofs = 0.0f;
1470
1471 if (distfac < 1.0f) {
1472 /* Path longer than text: space-mode is involved. */
1473
1474 if (cu->spacemode == CU_ALIGN_X_RIGHT) {
1475 timeofs = 1.0f - distfac;
1476 }
1477 else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
1478 timeofs = (1.0f - distfac) / 2.0f;
1479 }
1480 else if (cu->spacemode == CU_ALIGN_X_FLUSH) {
1481 distfac = 1.0f;
1482 }
1483 }
1484
1485 if (chartrans_size_x != 0.0f) {
1486 distfac /= chartrans_size_x;
1487 }
1488
1489 timeofs += distfac * cu->xof; /* not cyclic */
1490
1491 ct = chartransdata;
1492 for (i = 0; i <= slen; i++, ct++) {
1493 float ctime, dtime, vec[4], rotvec[3];
1494 float si, co;
1495
1496 /* Rotate around center character. */
1497 info = &custrinfo[i];
1498 ascii = mem[i];
1499 if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
1500 ascii = towupper(ascii);
1501 }
1502
1503 che = find_vfont_char(vfd, ascii);
1504
1505 twidth = char_width(cu, che, info);
1506
1507 dtime = distfac * 0.5f * twidth;
1508
1509 ctime = timeofs + distfac * (ct->xof - minx);
1510 CLAMP(ctime, 0.0f, 1.0f);
1511
1512 /* Calculate the right loc AND the right rot separately. */
1513 /* `vec` needs 4 items. */
1514 BKE_where_on_path(cu->textoncurve, ctime, vec, nullptr, nullptr, nullptr, nullptr);
1516 cu->textoncurve, ctime + dtime, nullptr, rotvec, nullptr, nullptr, nullptr);
1517
1518 mul_v3_fl(vec, sizefac);
1519
1520 ct->rot = float(M_PI) - atan2f(rotvec[1], rotvec[0]);
1521
1522 si = sinf(ct->rot);
1523 co = cosf(ct->rot);
1524
1525 yof = ct->yof;
1526
1527 ct->xof = vec[0] + si * yof;
1528 ct->yof = vec[1] + co * yof;
1529
1530 if (selboxes && (i >= selstart) && (i <= selend)) {
1531 EditFontSelBox *sb;
1532 sb = &selboxes[i - selstart];
1533 sb->rot = -ct->rot;
1534 }
1535 }
1536 }
1537 }
1538
1539 if (selboxes) {
1540 ct = chartransdata;
1541 for (i = 0; i <= selend; i++, ct++) {
1542 if (i >= selstart) {
1543 EditFontSelBox *sb = &selboxes[i - selstart];
1544 sb->x = ct->xof;
1545 sb->y = ct->yof;
1546 if (ct->rot != 0.0f) {
1547 sb->x -= sinf(ct->rot) * font_select_y_offset;
1548 sb->y -= cosf(ct->rot) * font_select_y_offset;
1549 }
1550 else {
1551 /* Simple downward shift below baseline when not rotated. */
1552 sb->y -= font_select_y_offset;
1553 }
1554 sb->x *= font_size;
1555 sb->y *= font_size;
1556 selboxes[i - selstart].h = font_size;
1557 }
1558 }
1559 }
1560
1562 iter_data->status == VFONT_TO_CURVE_INIT)
1563 {
1564 ct = &chartransdata[ef->pos];
1565
1566 if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
1567 /* pass */
1568 }
1569 else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
1570 /* pass */
1571 }
1572 else {
1573 switch (mode) {
1574 case FO_CURSUP:
1575 lnr = ct->linenr - 1;
1576 break;
1577 case FO_CURSDOWN:
1578 lnr = ct->linenr + 1;
1579 break;
1580 case FO_PAGEUP:
1581 lnr = ct->linenr - 10;
1582 break;
1583 case FO_PAGEDOWN:
1584 lnr = ct->linenr + 10;
1585 break;
1586 /* Ignored. */
1587 case FO_EDIT:
1588 case FO_CURS:
1589 case FO_DUPLI:
1590 case FO_SELCHANGE:
1591 break;
1592 }
1593 cnr = ct->charnr;
1594 /* Seek for char with `lnr` & `cnr`. */
1595 ef->pos = 0;
1596 ct = chartransdata;
1597 for (i = 0; i < slen; i++) {
1598 if (ct->linenr == lnr) {
1599 if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) {
1600 break;
1601 }
1602 }
1603 else if (ct->linenr > lnr) {
1604 break;
1605 }
1606 ef->pos++;
1607 ct++;
1608 }
1609 }
1610 }
1611
1612 /* Cursor first. */
1613 if (ef) {
1614 ct = &chartransdata[ef->pos];
1615 const float cursor_width = 0.04f;
1616 const float cursor_half = 0.02f;
1617 const float xoffset = ct->xof;
1618 const float yoffset = ct->yof;
1619
1620 /* By default the cursor is exactly between the characters
1621 * and matches the rotation of the character to the right. */
1622 float cursor_left = 0.0f - cursor_half;
1623 float rotation = ct->rot;
1624
1625 if (ef->selboxes) {
1626 if (ef->selend >= ef->selstart) {
1627 /* Cursor at right edge of a text selection. Match rotation to the character at the
1628 * end of selection. Cursor is further right to show the selected characters better. */
1629 rotation = chartransdata[max_ii(0, ef->selend - 1)].rot;
1630 cursor_left = 0.0f;
1631 }
1632 else {
1633 /* Cursor at the left edge of a text selection. Cursor
1634 * is further left to show the selected characters better. */
1635 cursor_left = 0.0f - cursor_width;
1636 }
1637 }
1638 else if ((ef->pos == ef->len) && (ef->len > 0)) {
1639 /* Nothing selected, but at the end of the string. Match rotation to previous character. */
1640 rotation = chartransdata[ef->len - 1].rot;
1641 }
1642
1643 /* We need the rotation to be around the bottom-left corner. So we make
1644 * that the zero point before rotation, rotate, then apply offsets afterward. */
1645
1646 /* Bottom left. */
1647 ef->textcurs[0][0] = cursor_left;
1648 ef->textcurs[0][1] = 0.0f - font_select_y_offset;
1649 /* Bottom right. */
1650 ef->textcurs[1][0] = cursor_left + cursor_width;
1651 ef->textcurs[1][1] = 0.0f - font_select_y_offset;
1652 /* Top left. */
1653 ef->textcurs[3][0] = cursor_left;
1654 ef->textcurs[3][1] = 1.0f - font_select_y_offset;
1655 /* Top right. */
1656 ef->textcurs[2][0] = cursor_left + cursor_width;
1657 ef->textcurs[2][1] = 1.0f - font_select_y_offset;
1658
1659 for (int vert = 0; vert < 4; vert++) {
1660 float temp_fl[2];
1661 /* Rotate around the cursor's bottom-left corner. */
1662 rotate_v2_v2fl(temp_fl, &ef->textcurs[vert][0], -rotation);
1663 ef->textcurs[vert][0] = font_size * (xoffset + temp_fl[0]);
1664 ef->textcurs[vert][1] = font_size * (yoffset + temp_fl[1]);
1665 }
1666 }
1667
1668 if (mode == FO_SELCHANGE) {
1669 MEM_freeN(chartransdata);
1670 chartransdata = nullptr;
1671 }
1672 else if (mode == FO_EDIT) {
1673 /* Make NURBS-data. */
1674 BKE_nurbList_free(r_nubase);
1675
1676 ct = chartransdata;
1677 for (i = 0; i < slen; i++) {
1678 uint cha = uint(mem[i]);
1679 info = &(custrinfo[i]);
1680
1681 if ((cu->overflow == CU_OVERFLOW_TRUNCATE) && (ob && ob->mode != OB_MODE_EDIT) &&
1682 (info->flag & CU_CHINFO_OVERFLOW))
1683 {
1684 break;
1685 }
1686
1687 if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
1688 cha = towupper(cha);
1689 }
1690
1691 /* Only do that check in case we do have an object, otherwise all materials get erased every
1692 * time that code is called without an object. */
1693 if (ob != nullptr && (info->mat_nr > (ob->totcol))) {
1694 // CLOG_ERROR(
1695 // &LOG, "Illegal material index (%d) in text object, setting to 0", info->mat_nr);
1696 info->mat_nr = 0;
1697 }
1698 /* We don't want to see any character for '\n'. */
1699 if (cha != '\n') {
1700 BKE_vfont_build_char(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i, font_size);
1701 }
1702
1703 if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
1704 float ulwidth, uloverlap = 0.0f;
1705 rctf rect;
1706
1707 if ((i < (slen - 1)) && (mem[i + 1] != '\n') &&
1708 ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) &&
1709 ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0))
1710 {
1711 uloverlap = xtrax + 0.1f;
1712 }
1713 /* Find the character, the characters has to be in the memory already
1714 * since character checking has been done earlier already. */
1715 che = find_vfont_char(vfd, cha);
1716
1717 twidth = char_width(cu, che, info);
1718 ulwidth = (twidth * (1.0f + (info->kern / 40.0f))) + uloverlap;
1719
1720 rect.xmin = ct->xof;
1721 rect.xmax = rect.xmin + ulwidth;
1722
1723 rect.ymin = ct->yof;
1724 rect.ymax = rect.ymin - cu->ulheight;
1725
1727 cu, r_nubase, &rect, cu->ulpos - 0.05f, ct->rot, i, info->mat_nr, font_size);
1728 }
1729 ct++;
1730 }
1731 }
1732
1733 if (iter_data->status == VFONT_TO_CURVE_SCALE_ONCE) {
1734 /* That means we were in a final run, just exit. */
1736 iter_data->status = VFONT_TO_CURVE_DONE;
1737 }
1738 else if (cu->overflow == CU_OVERFLOW_NONE) {
1739 /* Do nothing. */
1740 }
1741 else if ((tb_scale.h == 0.0f) && (tb_scale.w == 0.0f)) {
1742 /* Do nothing. */
1743 }
1744 else if (cu->overflow == CU_OVERFLOW_SCALE) {
1745 if ((cu->totbox == 1) && ((tb_scale.w == 0.0f) || (tb_scale.h == 0.0f))) {
1746 /* These are special cases, simpler to deal with. */
1747 if (tb_scale.w == 0.0f) {
1748 /* This is a potential vertical overflow.
1749 * Since there is no width limit, all the new lines are from line breaks. */
1750 if ((last_line != -1) && (lnr > last_line)) {
1751 const float total_text_height = lnr * linedist;
1752 iter_data->scale_to_fit = tb_scale.h / total_text_height;
1753 iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
1754 iter_data->word_wrap = false;
1755 }
1756 }
1757 else if (tb_scale.h == 0.0f) {
1758 /* This is a horizontal overflow. */
1759 if (longest_line_length > tb_scale.w) {
1760 /* We make sure longest line before it broke can fit here. */
1761 float scale_to_fit = tb_scale.w / longest_line_length;
1762
1763 iter_data->scale_to_fit = scale_to_fit;
1764 iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
1765 iter_data->word_wrap = false;
1766 }
1767 }
1768 }
1769 else {
1770 /* This is the really complicated case, the best we can do is to iterate over
1771 * this function a few times until we get an acceptable result.
1772 *
1773 * Keep in mind that there is no single number that will make all fit to the end.
1774 * In a way, our ultimate goal is to get the highest scale that still leads to the
1775 * number of extra lines to zero. */
1776 if (iter_data->status == VFONT_TO_CURVE_INIT) {
1777 bool valid = true;
1778
1779 for (int tb_index = 0; tb_index <= curbox; tb_index++) {
1780 TextBox *tb = &cu->tb[tb_index];
1781 if ((tb->w == 0.0f) || (tb->h == 0.0f)) {
1782 valid = false;
1783 break;
1784 }
1785 }
1786
1787 if (valid && (last_line != -1) && (lnr > last_line)) {
1788 const float total_text_height = lnr * linedist;
1789 float scale_to_fit = tb_scale.h / total_text_height;
1790
1791 iter_data->bisect.max = 1.0f;
1792 iter_data->bisect.min = scale_to_fit;
1793
1794 iter_data->status = VFONT_TO_CURVE_BISECT;
1795 }
1796 }
1797 else {
1799 /* Try to get the highest scale that gives us the exactly
1800 * number of lines we need. */
1801 bool valid = false;
1802
1803 if ((last_line != -1) && (lnr > last_line)) {
1804 /* It is overflowing, scale it down. */
1805 iter_data->bisect.max = iter_data->scale_to_fit;
1806 }
1807 else {
1808 /* It fits inside the text-box, scale it up. */
1809 iter_data->bisect.min = iter_data->scale_to_fit;
1810 valid = true;
1811 }
1812
1813 /* Bisecting to try to find the best fit. */
1814 iter_data->scale_to_fit = (iter_data->bisect.max + iter_data->bisect.min) * 0.5f;
1815
1816 /* We iterated enough or got a good enough result. */
1817 if ((!iter_data->iteraction--) || ((iter_data->bisect.max - iter_data->bisect.min) <
1819 {
1820 if (valid) {
1821 iter_data->status = VFONT_TO_CURVE_DONE;
1822 }
1823 else {
1824 iter_data->scale_to_fit = iter_data->bisect.min;
1825 iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
1826 }
1827 }
1828 }
1829 }
1830 }
1831
1832 if (cursor_params) {
1833 const float *cursor_location = cursor_params->cursor_location;
1834 /* Erasing all text could give slen = 0 */
1835 if (slen == 0) {
1836 cursor_params->r_string_offset = -1;
1837 }
1838 else if (cu->textoncurve != nullptr) {
1839
1840 int closest_char = -1;
1841 float closest_dist_sq = FLT_MAX;
1842
1843 for (i = 0; i <= slen; i++) {
1844 const float char_location[2] = {
1845 chartransdata[i].xof * font_size,
1846 chartransdata[i].yof * font_size,
1847 };
1848 const float test_dist_sq = len_squared_v2v2(cursor_location, char_location);
1849 if (closest_dist_sq > test_dist_sq) {
1850 closest_char = i;
1851 closest_dist_sq = test_dist_sq;
1852 }
1853 }
1854
1855 cursor_params->r_string_offset = closest_char;
1856 }
1857 else {
1858 /* Find the first box closest to `cursor_location`. */
1859 int char_beg = 0;
1860 int char_end = slen;
1861
1862 if (tb_bounds_for_cursor != nullptr) {
1863 /* Search for the closest box. */
1864 int closest_box = -1;
1865 float closest_dist_sq = FLT_MAX;
1866 for (curbox = 0; curbox < cu->totbox; curbox++) {
1867 const TextBoxBounds_ForCursor *tb_bounds = &tb_bounds_for_cursor[curbox];
1868 if (tb_bounds->char_index_last == -1) {
1869 continue;
1870 }
1871 /* The closest point in the box to the `cursor_location`
1872 * by clamping it to the bounding box. */
1873 const float cursor_location_clamped[2] = {
1874 clamp_f(cursor_location[0], tb_bounds->bounds.xmin, tb_bounds->bounds.xmax),
1875 clamp_f(cursor_location[1], tb_bounds->bounds.ymin, tb_bounds->bounds.ymax),
1876 };
1877
1878 const float test_dist_sq = len_squared_v2v2(cursor_location, cursor_location_clamped);
1879 if (test_dist_sq < closest_dist_sq) {
1880 closest_dist_sq = test_dist_sq;
1881 closest_box = curbox;
1882 }
1883 }
1884 if (closest_box != -1) {
1885 if (closest_box != 0) {
1886 char_beg = tb_bounds_for_cursor[closest_box - 1].char_index_last + 1;
1887 }
1888 char_end = tb_bounds_for_cursor[closest_box].char_index_last;
1889 }
1890 MEM_freeN(tb_bounds_for_cursor);
1891 tb_bounds_for_cursor = nullptr; /* Safety only. */
1892 }
1893 const float interline_offset = ((linedist - 0.5f) / 2.0f) * font_size;
1894 /* Loop until find the line where `cursor_location` is over. */
1895 for (i = char_beg; i <= char_end; i++) {
1896 if (cursor_location[1] >= ((chartransdata[i].yof * font_size) - interline_offset)) {
1897 break;
1898 }
1899 }
1900
1901 i = min_ii(i, char_end);
1902 const float char_yof = chartransdata[i].yof;
1903
1904 /* Loop back until find the first character of the line, this because `cursor_location` can
1905 * be positioned further below the text, so #i can be the last character of the last line. */
1906 for (; i >= char_beg + 1 && chartransdata[i - 1].yof == char_yof; i--) {
1907 }
1908 /* Loop until find the first character to the right of `cursor_location`
1909 * (using the character midpoint on the x-axis as a reference). */
1910 for (; i <= char_end && char_yof == chartransdata[i].yof; i++) {
1911 info = &custrinfo[i];
1912 ascii = info->flag & CU_CHINFO_SMALLCAPS_CHECK ? towupper(mem[i]) : mem[i];
1913 che = find_vfont_char(vfd, ascii);
1914 const float charwidth = char_width(cu, che, info);
1915 const float charhalf = (charwidth / 2.0f);
1916 if (cursor_location[0] <= ((chartransdata[i].xof + charhalf) * font_size)) {
1917 break;
1918 }
1919 }
1920 i = min_ii(i, char_end);
1921
1922 /* If there is no character to the right of the cursor we are on the next line, go back to
1923 * the last character of the previous line. */
1924 if (i > char_beg && chartransdata[i].yof != char_yof) {
1925 i -= 1;
1926 }
1927 cursor_params->r_string_offset = i;
1928 }
1929 /* Must be cleared & freed. */
1930 BLI_assert(tb_bounds_for_cursor == nullptr);
1931 }
1932
1933 /* Scale to fit only works for single text box layouts. */
1935 /* Always cleanup before going to the scale-to-fit repetition. */
1936 if (r_nubase != nullptr) {
1937 BKE_nurbList_free(r_nubase);
1938 }
1939
1940 if (chartransdata != nullptr) {
1941 MEM_freeN(chartransdata);
1942 }
1943
1944 if (ef == nullptr) {
1945 MEM_freeN((void *)mem);
1946 }
1947 return true;
1948 }
1949
1950 ok = true;
1951finally:
1952 if (r_text) {
1953 *r_text = mem;
1954 *r_text_len = slen;
1955 *r_text_free = (ef == nullptr);
1956 }
1957 else {
1958 if (ef == nullptr) {
1959 MEM_freeN((void *)mem);
1960 }
1961 }
1962
1963 if (chartransdata) {
1964 if (ok && r_chartransdata) {
1965 *r_chartransdata = chartransdata;
1966 }
1967 else {
1968 MEM_freeN(chartransdata);
1969 }
1970 }
1971
1972 /* Store the effective scale, to use for the text-box lines. */
1973 cu->fsize_realtime = font_size;
1974
1975 return ok;
1976
1977#undef MARGIN_X_MIN
1978#undef MARGIN_Y_MIN
1979}
1980
1981#undef DESCENT
1982#undef ASCENT
1983
1985 Curve *cu,
1986 const eEditFontMode mode,
1987 ListBase *r_nubase,
1988 const char32_t **r_text,
1989 int *r_text_len,
1990 bool *r_text_free,
1991 CharTrans **r_chartransdata)
1992{
1994 data.iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS;
1995 data.scale_to_fit = 1.0f;
1996 data.word_wrap = true;
1997 data.ok = true;
1998 data.status = VFONT_TO_CURVE_INIT;
1999
2000 do {
2001 data.ok &= vfont_to_curve(
2002 ob, cu, mode, &data, nullptr, r_nubase, r_text, r_text_len, r_text_free, r_chartransdata);
2004
2005 return data.ok;
2006}
2007
2008int BKE_vfont_cursor_to_text_index(Object *ob, const float cursor_location[2])
2009{
2010 Curve *cu = (Curve *)ob->data;
2011 ListBase *r_nubase = &cu->nurb;
2012
2013 /* TODO: iterating to calculate the scale can be avoided. */
2015 data.iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS;
2016 data.scale_to_fit = 1.0f;
2017 data.word_wrap = true;
2018 data.ok = true;
2019 data.status = VFONT_TO_CURVE_INIT;
2020
2021 VFontCursor_Params cursor_params = {};
2022 cursor_params.cursor_location[0] = cursor_location[0];
2023 cursor_params.cursor_location[1] = cursor_location[1];
2024 cursor_params.r_string_offset = -1;
2025
2026 do {
2027 data.ok &= vfont_to_curve(
2028 ob, cu, FO_CURS, &data, &cursor_params, r_nubase, nullptr, nullptr, nullptr, nullptr);
2030
2031 return cursor_params.r_string_offset;
2032}
2033
2034#undef FONT_TO_CURVE_SCALE_ITERATIONS
2035#undef FONT_TO_CURVE_SCALE_THRESHOLD
2036
2038{
2039 BLI_assert(ob->type == OB_FONT);
2040
2041 return BKE_vfont_to_curve_ex(
2042 ob, static_cast<Curve *>(ob->data), mode, r_nubase, nullptr, nullptr, nullptr, nullptr);
2043}
2044
2046{
2047 Curve *cu = static_cast<Curve *>(ob->data);
2048
2049 return BKE_vfont_to_curve_ex(
2050 ob, static_cast<Curve *>(ob->data), mode, &cu->nurb, nullptr, nullptr, nullptr, nullptr);
2051}
2052
2053/* -------------------------------------------------------------------- */
2056
2057static struct {
2058 char32_t *text_buffer;
2061 size_t len_utf8;
2062} g_vfont_clipboard = {nullptr};
2063
2065{
2066 MEM_SAFE_FREE(g_vfont_clipboard.text_buffer);
2067 MEM_SAFE_FREE(g_vfont_clipboard.info_buffer);
2068 g_vfont_clipboard.len_utf32 = 0;
2069 g_vfont_clipboard.len_utf8 = 0;
2070}
2071
2072void BKE_vfont_clipboard_set(const char32_t *text_buf, const CharInfo *info_buf, const size_t len)
2073{
2074 char32_t *text;
2075 CharInfo *info;
2076
2077 /* Clean previous buffers. */
2079
2080 text = static_cast<char32_t *>(MEM_malloc_arrayN((len + 1), sizeof(*text), __func__));
2081 if (text == nullptr) {
2082 return;
2083 }
2084
2085 info = static_cast<CharInfo *>(MEM_malloc_arrayN(len, sizeof(CharInfo), __func__));
2086 if (info == nullptr) {
2087 MEM_freeN(text);
2088 return;
2089 }
2090
2091 memcpy(text, text_buf, len * sizeof(*text));
2092 text[len] = '\0';
2093 memcpy(info, info_buf, len * sizeof(CharInfo));
2094
2095 /* store new buffers */
2096 g_vfont_clipboard.text_buffer = text;
2097 g_vfont_clipboard.info_buffer = info;
2099 g_vfont_clipboard.len_utf32 = len;
2100}
2101
2102void BKE_vfont_clipboard_get(char32_t **r_text_buf,
2103 CharInfo **r_info_buf,
2104 size_t *r_len_utf8,
2105 size_t *r_len_utf32)
2106{
2107 if (r_text_buf) {
2108 *r_text_buf = g_vfont_clipboard.text_buffer;
2109 }
2110
2111 if (r_info_buf) {
2112 *r_info_buf = g_vfont_clipboard.info_buffer;
2113 }
2114
2115 if (r_len_utf32) {
2116 *r_len_utf32 = g_vfont_clipboard.len_utf32;
2117 }
2118
2119 if (r_len_utf8) {
2120 *r_len_utf8 = g_vfont_clipboard.len_utf8;
2121 }
2122}
2123
bool BKE_where_on_path(const struct Object *ob, float ctime, float r_vec[4], float r_dir[3], float r_quat[4], float *r_radius, float *r_weight)
float BKE_anim_path_get_length(const struct CurveCache *curve_cache)
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:123
@ BKE_BPATH_FOREACH_PATH_SKIP_PACKED
Definition BKE_bpath.hh:37
void BKE_nurbList_free(ListBase *lb)
Definition curve.cc:596
@ G_FILE_AUTOPACK
#define G_MAIN
IDTypeInfo IDType_ID_VF
Definition vfont.cc:168
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:39
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:41
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1415
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
@ LIB_ID_CREATE_NO_USER_REFCOUNT
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2560
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:832
PackedFile * BKE_packedfile_duplicate(const PackedFile *pf_src)
void BKE_packedfile_free(PackedFile *pf)
PackedFile * BKE_packedfile_new_from_memory(const void *mem, int memlen, const blender::ImplicitSharingInfo *sharing_info=nullptr)
void BKE_packedfile_blend_write(BlendWriter *writer, const PackedFile *pf)
void BKE_packedfile_blend_read(BlendDataReader *reader, PackedFile **pf_p, blender::StringRefNull filepath)
PackedFile * BKE_packedfile_new(ReportList *reports, const char *filepath_rel, const char *basepath)
eEditFontMode
Definition BKE_vfont.hh:68
@ FO_PAGEUP
Definition BKE_vfont.hh:74
@ FO_EDIT
Definition BKE_vfont.hh:69
@ FO_CURSUP
Definition BKE_vfont.hh:71
@ FO_SELCHANGE
Definition BKE_vfont.hh:76
@ FO_CURS
Definition BKE_vfont.hh:70
@ FO_CURSDOWN
Definition BKE_vfont.hh:72
@ FO_PAGEDOWN
Definition BKE_vfont.hh:75
@ FO_DUPLI
Definition BKE_vfont.hh:73
A structure to represent vector fonts, and to load them from PostScript fonts.
VFontData * BKE_vfontdata_copy(const VFontData *vfont_src, int flag)
VChar * BKE_vfontdata_char_from_freetypefont(VFont *vfont, unsigned long character)
VFontData * BKE_vfontdata_from_freetypefont(PackedFile *pf)
#define BLI_assert(a)
Definition BLI_assert.h:50
#define BLI_assert_msg(a, msg)
Definition BLI_assert.h:57
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:303
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:322
void * BLI_ghash_lookup(const GHash *gh, const void *key) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.c:731
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.c:860
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:269
void BLI_addtail(struct ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:110
MINLINE float max_ff(float a, float b)
MINLINE int min_ii(int a, int b)
MINLINE float clamp_f(float value, float min, float max)
MINLINE float min_ff(float a, float b)
MINLINE int max_ii(int a, int b)
#define M_PI
MINLINE int compare_ff_relative(float a, float b, float max_diff, int max_ulps)
MINLINE float safe_divide(float a, float b)
void copy_m3_m4(float m1[3][3], const float m2[4][4])
void unit_m4(float m[4][4])
Definition rct.c:1127
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void mul_m3_m3m3(float R[3][3], const float A[3][3], const float B[3][3])
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 mul_v2_fl(float r[2], float f)
MINLINE void mul_v3_fl(float r[3], float f)
void rotate_v2_v2fl(float r[2], const float p[2], float angle)
MINLINE float normalize_v3(float n[3])
bool BLI_path_abs(char path[FILE_MAX], const char *basepath) ATTR_NONNULL(1
#define FILE_MAXFILE
#define FILE_MAX
void void void BLI_path_split_file_part(const char *filepath, char *file, size_t file_maxncpy) ATTR_NONNULL(1
#define BLI_path_cmp
void BLI_rctf_mul(struct rctf *rect, float factor)
Definition rct.c:582
#define STRNCPY(dst, src)
Definition BLI_string.h:593
size_t BLI_str_utf32_as_utf8_len(const char32_t *src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
size_t BLI_str_utf8_as_utf32(char32_t *__restrict dst_w, const char *__restrict src_c, size_t dst_w_maxncpy) ATTR_NONNULL(1
unsigned int uint
pthread_rwlock_t ThreadRWMutex
#define THREAD_LOCK_READ
#define THREAD_LOCK_WRITE
#define BLI_RWLOCK_INITIALIZER
void BLI_rw_mutex_lock(ThreadRWMutex *mutex, int mode)
Definition threads.cc:467
void BLI_rw_mutex_unlock(ThreadRWMutex *mutex)
Definition threads.cc:477
#define CLAMP(a, b, c)
#define CLAMP_MAX(a, c)
#define UNLIKELY(x)
#define ELEM(...)
#define POINTER_FROM_UINT(i)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
#define BLO_write_id_struct(writer, struct_name, id_address, id)
bool BLO_write_is_undo(BlendWriter *writer)
#define BLT_I18NCONTEXT_ID_VFONT
#define CLOG_ERROR(clg_ref,...)
Definition CLG_log.h:182
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:181
#define FILTER_ID_VF
Definition DNA_ID.h:1189
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:649
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:647
@ INDEX_ID_VF
Definition DNA_ID.h:1268
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:683
@ ID_VF
#define MAXTEXTBOX
@ CU_CHINFO_WRAP
@ CU_CHINFO_UNDERLINE
@ CU_CHINFO_BOLD
@ CU_CHINFO_ITALIC
@ CU_CHINFO_SMALLCAPS_CHECK
@ CU_CHINFO_SMALLCAPS
@ CU_CHINFO_OVERFLOW
#define CU_CHINFO_STYLE_ALL
@ CU_ALIGN_X_FLUSH
@ CU_ALIGN_X_MIDDLE
@ CU_ALIGN_X_LEFT
@ CU_ALIGN_X_JUSTIFY
@ CU_ALIGN_X_RIGHT
@ CU_ALIGN_Y_TOP
@ CU_ALIGN_Y_BOTTOM_BASELINE
@ CU_ALIGN_Y_CENTER
@ CU_ALIGN_Y_BOTTOM
@ CU_ALIGN_Y_TOP_BASELINE
@ CU_SMOOTH
@ CU_OVERFLOW_SCALE
@ CU_OVERFLOW_TRUNCATE
@ CU_OVERFLOW_NONE
@ CU_NURB_CYCLIC
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ OB_FONT
@ OB_CURVES_LEGACY
#define FO_BUILTIN_NAME
Read Guarded memory(de)allocation.
#define MEM_SAFE_FREE(v)
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition btDbvt.cpp:52
static btDbvtVolume bounds(btDbvtNode **leaves, int count)
Definition btDbvt.cpp:299
#define sinf(x)
#define cosf(x)
#define atan2f(x, y)
#define ceilf(x)
int len
draw_view in_light_buf[] float
#define rot(x, k)
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
#define LOG(severity)
Definition log.h:33
void *(* MEM_mallocN)(size_t len, const char *str)
Definition mallocn.cc:44
void *(* MEM_malloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:45
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition mallocn.cc:43
void MEM_freeN(void *vmemh)
Definition mallocn.cc:105
void *(* MEM_callocN)(size_t len, const char *str)
Definition mallocn.cc:42
#define G(x, y, z)
#define FLT_MAX
Definition stdcycles.h:14
eBPathForeachFlag flag
Definition BKE_bpath.hh:88
float vec[4]
float vec[3][3]
short linenr
Definition BKE_vfont.hh:21
float yof
Definition BKE_vfont.hh:19
float xof
Definition BKE_vfont.hh:19
float rot
Definition BKE_vfont.hh:20
char dobreak
Definition BKE_vfont.hh:22
char overflow
float spacing
struct VFont * vfont
struct TextBox * tb
float ulheight
float ulpos
struct EditFont * editfont
short resolu
short lines
float fsize_realtime
char spacemode
float wordspace
struct CharInfo * strinfo
struct VFont * vfontb
struct Object * textoncurve
float shear
char * str
struct VFont * vfonti
float smallcaps_scale
ListBase nurb
float linedist
float fsize
struct VFont * vfontbi
float textcurs[4][2]
Definition BKE_vfont.hh:40
CharInfo * textbufinfo
Definition BKE_vfont.hh:37
int selend
Definition BKE_vfont.hh:52
EditFontSelBox * selboxes
Definition BKE_vfont.hh:41
int select_char_info_flag
Definition BKE_vfont.hh:59
int selboxes_len
Definition BKE_vfont.hh:42
char32_t * textbuf
Definition BKE_vfont.hh:35
int selstart
Definition BKE_vfont.hh:52
Definition DNA_ID.h:413
int us
Definition DNA_ID.h:435
void * first
ListBase fonts
Definition BKE_main.hh:226
short flagu
short orderu
struct Nurb * next
short orderv
float * knotsu
short flag
float * knotsv
BezTriple * bezt
BPoint * bp
short resolu
short mat_nr
ObjectRuntimeHandle * runtime
int char_nr
Definition vfont.cc:709
int wspace_nr
Definition vfont.cc:710
float x_min
Definition vfont.cc:707
float x_max
Definition vfont.cc:708
float width
ListBase nurbsbase
float cursor_location[2]
Definition vfont.cc:756
GHash * characters
char name[128]
float em_height
float scale_to_fit
Definition vfont.cc:725
struct VFontToCurveIter::@000013273122051275230224374026362160273263254370 bisect
struct VFontData * data
char filepath[1024]
struct PackedFile * temp_pf
struct PackedFile * packedfile
float xmax
float xmin
float ymax
float ymin
#define N_(msgid)
static struct @142203217214037347132233362236020073047017327341 g_vfont_clipboard
static PackedFile * get_builtin_packedfile(void)
Definition vfont.cc:243
static void vfont_init_data(ID *id)
Definition vfont.cc:66
CharInfo * info_buffer
Definition vfont.cc:2059
void BKE_vfont_select_clamp(Object *ob)
Definition vfont.cc:670
static float vfont_descent(const VFontData *vfd)
Definition vfont.cc:792
int builtin_font_size
Definition vfont.cc:64
VFont * BKE_vfont_load(Main *bmain, const char *filepath)
Definition vfont.cc:325
bool BKE_vfont_to_curve(Object *ob, const eEditFontMode mode)
Definition vfont.cc:2045
static bool vfont_to_curve(Object *ob, Curve *cu, const eEditFontMode mode, VFontToCurveIter *iter_data, VFontCursor_Params *cursor_params, ListBase *r_nubase, const char32_t **r_text, int *r_text_len, bool *r_text_free, CharTrans **r_chartransdata)
Definition vfont.cc:813
static void vfont_blend_read_data(BlendDataReader *reader, ID *id)
Definition vfont.cc:160
@ VFONT_TO_CURVE_BISECT
Definition vfont.cc:763
@ VFONT_TO_CURVE_SCALE_ONCE
Definition vfont.cc:764
@ VFONT_TO_CURVE_INIT
Definition vfont.cc:762
@ VFONT_TO_CURVE_DONE
Definition vfont.cc:765
bool BKE_vfont_is_builtin(const VFont *vfont)
Definition vfont.cc:232
const void * builtin_font_data
Definition vfont.cc:63
int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end)
Definition vfont.cc:630
static void vfont_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *, const int flag)
Definition vfont.cc:86
bool BKE_vfont_to_curve_nubase(Object *ob, const eEditFontMode mode, ListBase *r_nubase)
Definition vfont.cc:2037
static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Definition vfont.cc:121
static ThreadRWMutex vfont_rwlock
Definition vfont.cc:55
static float vfont_ascent(const VFontData *vfd)
Definition vfont.cc:788
VFont * BKE_vfont_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
Definition vfont.cc:376
static VFontData * vfont_get_data(VFont *vfont)
Definition vfont.cc:258
char32_t * text_buffer
Definition vfont.cc:2058
static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect, float yofs, float rot, int charidx, short mat_nr, const float font_size)
Definition vfont.cc:443
static VFont * which_vfont(Curve *cu, const CharInfo *info)
Definition vfont.cc:408
void BKE_vfont_clipboard_set(const char32_t *text_buf, const CharInfo *info_buf, const size_t len)
Definition vfont.cc:2072
static VChar * find_vfont_char(const VFontData *vfd, uint character)
Definition vfont.cc:438
#define FONT_TO_CURVE_SCALE_THRESHOLD
Definition vfont.cc:769
static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition vfont.cc:138
VFont * BKE_vfont_load_exists(Main *bmain, const char *filepath)
Definition vfont.cc:403
void BKE_vfont_builtin_register(const void *mem, int size)
Definition vfont.cc:237
static float char_width(Curve *cu, VChar *che, const CharInfo *info)
Definition vfont.cc:682
void BKE_vfont_clipboard_get(char32_t **r_text_buf, CharInfo **r_info_buf, size_t *r_len_utf8, size_t *r_len_utf32)
Definition vfont.cc:2102
bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, const eEditFontMode mode, ListBase *r_nubase, const char32_t **r_text, int *r_text_len, bool *r_text_free, CharTrans **r_chartransdata)
Definition vfont.cc:1984
VFont * BKE_vfont_builtin_get()
Definition vfont.cc:422
#define MARGIN_Y_MIN
#define FONT_TO_CURVE_SCALE_ITERATIONS
Definition vfont.cc:768
size_t len_utf32
Definition vfont.cc:2060
#define MARGIN_X_MIN
int BKE_vfont_cursor_to_text_index(Object *ob, const float cursor_location[2])
Definition vfont.cc:2008
static void textbox_scale(TextBox *tb_dst, const TextBox *tb_src, float scale)
Definition vfont.cc:695
static void vfont_free_data(ID *id)
Definition vfont.cc:110
void BKE_vfont_build_char(Curve *cu, ListBase *nubase, uint character, const CharInfo *info, float ofsx, float ofsy, float rot, int charidx, const float fsize)
Definition vfont.cc:507
size_t len_utf8
Definition vfont.cc:2061
void BKE_vfont_free_data(VFont *vfont)
Definition vfont.cc:200
void BKE_vfont_clipboard_free()
Definition vfont.cc:2064
uint8_t flag
Definition wm_window.cc:138