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
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/* -------------------------------------------------------------------- */
726 struct {
727 float min;
728 float max;
730 bool ok;
742};
743
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
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 int selstart = 0, selend = 0;
839 int cnr = 0, lnr = 0, wsnr = 0;
840 const char32_t *mem = nullptr;
841 char32_t ascii;
842 bool ok = false;
843 const float font_size = cu->fsize * iter_data->scale_to_fit;
844 /* Shift down vertically to be 25% below & 75% above baseline (before font scale is applied). */
845 const float font_select_y_offset = 0.25;
846 const bool word_wrap = iter_data->word_wrap;
847 const float xof_scale = safe_divide(cu->xof, font_size);
848 const float yof_scale = safe_divide(cu->yof, font_size);
849 int last_line = -1;
850 /* Length of the text disregarding \n breaks. */
851 float current_line_length = 0.0f;
852 float longest_line_length = 0.0f;
853
854 /* Text at the beginning of the last used text-box (use for y-axis alignment).
855 * We over-allocate by one to simplify logic of getting last char. */
856 blender::Array<int> i_textbox_array(cu->totbox + 1, 0);
857
858#define MARGIN_X_MIN (xof_scale + tb_scale.x)
859#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
860
861 /* NOTE: do calculations including the trailing '\0' of a string
862 * because the cursor can be at that location. */
863
864 BLI_assert(ob == nullptr || ob->type == OB_FONT);
865
866 /* Set font data */
867 vfont = cu->vfont;
868
869 if (cu->str == nullptr) {
870 return ok;
871 }
872 if (vfont == nullptr) {
873 return ok;
874 }
875
876 vfd = vfont_get_data(vfont);
877
878 /* The VFont Data can not be found */
879 if (!vfd) {
880 return ok;
881 }
882
883 if (ef) {
884 slen = ef->len;
885 mem = ef->textbuf;
886 custrinfo = ef->textbufinfo;
887 }
888 else {
889 char32_t *mem_tmp;
890 slen = cu->len_char32;
891
892 /* Create unicode string */
893 mem_tmp = static_cast<char32_t *>(
894 MEM_malloc_arrayN((slen + 1), sizeof(*mem_tmp), "convertedmem"));
895 if (!mem_tmp) {
896 return ok;
897 }
898
899 BLI_str_utf8_as_utf32(mem_tmp, cu->str, slen + 1);
900
901 if (cu->strinfo == nullptr) { /* old file */
902 cu->strinfo = static_cast<CharInfo *>(
903 MEM_calloc_arrayN((slen + 4), sizeof(CharInfo), "strinfo compat"));
904 }
905 custrinfo = cu->strinfo;
906 if (!custrinfo) {
907 return ok;
908 }
909
910 mem = mem_tmp;
911 }
912
913 if (cu->tb == nullptr) {
914 cu->tb = static_cast<TextBox *>(
915 MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBox compat"));
916 }
917
918 if (ef != nullptr && ob != nullptr) {
919 if (ef->selboxes) {
920 MEM_freeN(ef->selboxes);
921 }
922
923 if (BKE_vfont_select_get(ob, &selstart, &selend)) {
924 ef->selboxes_len = (selend - selstart) + 1;
925 ef->selboxes = static_cast<EditFontSelBox *>(
926 MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes"));
927 }
928 else {
929 ef->selboxes_len = 0;
930 ef->selboxes = nullptr;
931 }
932
933 selboxes = ef->selboxes;
934 }
935
936 /* calc offset and rotation of each char */
937 ct = chartransdata = static_cast<CharTrans *>(
938 MEM_calloc_arrayN((slen + 1), sizeof(CharTrans), "buildtext"));
939
940 /* We assume the worst case: 1 character per line (is freed at end anyway) */
941 lineinfo = static_cast<TempLineInfo *>(
942 MEM_malloc_arrayN((slen * 2 + 1), sizeof(*lineinfo), "lineinfo"));
943
944 linedist = cu->linedist;
945
946 curbox = 0;
947 textbox_scale(&tb_scale, &cu->tb[curbox], safe_divide(1.0f, font_size));
948 use_textbox = (tb_scale.w != 0.0f);
949
950 xof = MARGIN_X_MIN;
951 yof = MARGIN_Y_MIN;
952
953 xtrax = 0.5f * cu->spacing - 0.5f;
954
955 oldvfont = nullptr;
956
957 for (i = 0; i < slen; i++) {
959 }
960
961 TextBoxBounds_ForCursor *tb_bounds_for_cursor = nullptr;
962 if (cursor_params != nullptr) {
963 if (cu->textoncurve == nullptr && (cu->totbox > 1) && (slen > 0)) {
964 tb_bounds_for_cursor = static_cast<TextBoxBounds_ForCursor *>(
965 MEM_malloc_arrayN(cu->totbox, sizeof(TextBoxBounds_ForCursor), "TextboxBounds_Cursor"));
966 for (curbox = 0; curbox < cu->totbox; curbox++) {
967 TextBoxBounds_ForCursor *tb_bounds = &tb_bounds_for_cursor[curbox];
968 tb_bounds->char_index_last = -1;
969 tb_bounds->bounds.xmin = FLT_MAX;
970 tb_bounds->bounds.xmax = -FLT_MAX;
971 tb_bounds->bounds.ymin = FLT_MAX;
972 tb_bounds->bounds.ymax = -FLT_MAX;
973 }
974 }
975 curbox = 0;
976 }
977
978 i = 0;
979 while (i <= slen) {
980 /* Characters in the list */
981 info = &custrinfo[i];
982 ascii = mem[i];
983 if (info->flag & CU_CHINFO_SMALLCAPS) {
984 ascii = towupper(ascii);
985 if (mem[i] != ascii) {
987 }
988 }
989
990 vfont = which_vfont(cu, info);
991
992 if (vfont == nullptr) {
993 break;
994 }
995
996 if (vfont != oldvfont) {
997 vfd = vfont_get_data(vfont);
998 oldvfont = vfont;
999 }
1000
1001 /* VFont Data for VFont couldn't be found */
1002 if (!vfd) {
1003 MEM_freeN(chartransdata);
1004 chartransdata = nullptr;
1005 MEM_freeN(lineinfo);
1006 goto finally;
1007 }
1008
1009 if (!ELEM(ascii, '\n', '\0')) {
1011 che = find_vfont_char(vfd, ascii);
1013
1014 /* The character wasn't in the current curve base so load it. */
1015 if (che == nullptr) {
1017 /* Check it once again, char might have been already load
1018 * between previous #BLI_rw_mutex_unlock() and this #BLI_rw_mutex_lock().
1019 *
1020 * Such a check should not be a bottleneck since it wouldn't
1021 * happen often once all the chars are load. */
1022 if ((che = find_vfont_char(vfd, ascii)) == nullptr) {
1023 che = BKE_vfontdata_char_from_freetypefont(vfont, ascii);
1024 }
1026 }
1027 }
1028 else {
1029 che = nullptr;
1030 }
1031
1032 twidth = char_width(cu, che, info);
1033
1034 /* Calculate positions. */
1035
1036 if ((tb_scale.w != 0.0f) && (ct->dobreak == 0)) { /* May need wrapping. */
1037 const float x_available = xof_scale + tb_scale.w;
1038 const float x_used = (xof - tb_scale.x) + twidth;
1039
1040 if (word_wrap == false) {
1041 /* When scale to fit is used, don't do any wrapping.
1042 *
1043 * Floating precision error can cause the text to be slightly larger.
1044 * Assert this is a small value as large values indicate incorrect
1045 * calculations with scale-to-fit which shouldn't be ignored. See #89241. */
1046 if (x_used > x_available) {
1047 BLI_assert_msg(compare_ff_relative(x_used, x_available, FLT_EPSILON, 64),
1048 "VFontToCurveIter.scale_to_fit not set correctly!");
1049 }
1050 }
1051 else if (x_used > x_available) {
1052 // CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]);
1053 bool dobreak = false;
1054 for (j = i; (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
1055
1056 /* Special case when there are no breaks possible. */
1057 if (UNLIKELY(j == 0)) {
1058 if (i == slen) {
1059 /* Use the behavior of zero a height text-box when a break cannot be inserted.
1060 *
1061 * Typically when a text-box has any height and overflow is set to scale
1062 * the text will wrap to fit the width as necessary. When wrapping isn't
1063 * possible it's important to use the same code-path as zero-height lines.
1064 * Without this exception a single word will not scale-to-fit (see: #95116). */
1065 tb_scale.h = 0.0f;
1066 }
1067 break;
1068 }
1069
1070 if (ELEM(mem[j], ' ', '-')) {
1071 ct -= (i - (j - 1));
1072 cnr -= (i - (j - 1));
1073 if (mem[j] == ' ') {
1074 wsnr--;
1075 }
1076 if (mem[j] == '-') {
1077 wsnr++;
1078 }
1079 i = j - 1;
1080 xof = ct->xof;
1081 ct[1].dobreak = 1;
1082 custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
1083 dobreak = true;
1084 break;
1085 }
1086 BLI_assert(chartransdata[j].dobreak == 0);
1087 }
1088
1089 if (dobreak) {
1090 if (tb_scale.h == 0.0f) {
1091 /* NOTE: If underlined text is truncated away, the extra space is also truncated. */
1092 custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW;
1093 }
1094 /* Since a break was added, re-run this loop with `i` at it's new value. */
1095 continue;
1096 }
1097 }
1098 }
1099
1100 if (ascii == '\n' || ascii == 0 || ct->dobreak) {
1101 ct->xof = xof;
1102 ct->yof = yof;
1103 ct->linenr = lnr;
1104 ct->charnr = cnr;
1105
1106 yof -= linedist;
1107
1108 lineinfo[lnr].x_min = (xof - xtrax) - tb_scale.x;
1109 lineinfo[lnr].x_max = tb_scale.w;
1110 lineinfo[lnr].char_nr = cnr;
1111 lineinfo[lnr].wspace_nr = wsnr;
1112
1113 CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
1114
1115 if (tb_bounds_for_cursor != nullptr) {
1116 tb_bounds_for_cursor[curbox].char_index_last = i;
1117 }
1118
1119 if ((tb_scale.h != 0.0f) && (-(yof - tb_scale.y) > (tb_scale.h - linedist) - yof_scale)) {
1120 if (cu->totbox > (curbox + 1)) {
1121 maxlen = 0;
1122 curbox++;
1123 i_textbox_array[curbox] = i + 1;
1124
1125 textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
1126
1127 yof = MARGIN_Y_MIN;
1128 }
1129 else if (last_line == -1) {
1130 last_line = lnr + 1;
1131 info->flag |= CU_CHINFO_OVERFLOW;
1132 }
1133 }
1134
1135 current_line_length += xof - MARGIN_X_MIN;
1136 if (ct->dobreak) {
1137 current_line_length += twidth;
1138 }
1139 else {
1140 longest_line_length = std::max(current_line_length, longest_line_length);
1141 current_line_length = 0.0f;
1142 }
1143
1144 xof = MARGIN_X_MIN;
1145 lnr++;
1146 cnr = 0;
1147 wsnr = 0;
1148 }
1149 else if (ascii == '\t') { /* Tab character. */
1150 float tabfac;
1151
1152 ct->xof = xof;
1153 ct->yof = yof;
1154 ct->linenr = lnr;
1155 ct->charnr = cnr++;
1156
1157 tabfac = (xof - MARGIN_X_MIN + 0.01f);
1158 tabfac = 2.0f * ceilf(tabfac / 2.0f);
1159 xof = MARGIN_X_MIN + tabfac;
1160 }
1161 else {
1162 EditFontSelBox *sb = nullptr;
1163 float wsfac;
1164
1165 ct->xof = xof;
1166 ct->yof = yof;
1167 ct->linenr = lnr;
1168 ct->charnr = cnr++;
1169
1170 if (selboxes && (i >= selstart) && (i <= selend)) {
1171 sb = &selboxes[i - selstart];
1172 sb->y = (yof - font_select_y_offset) * font_size - linedist * font_size * 0.1f;
1173 sb->h = linedist * font_size;
1174 sb->w = xof * font_size;
1175 }
1176
1177 if (ascii == ' ') { /* Space character. */
1178 wsfac = cu->wordspace;
1179 wsnr++;
1180 }
1181 else {
1182 wsfac = 1.0f;
1183 }
1184
1185 /* Set the width of the character. */
1186 twidth = char_width(cu, che, info);
1187
1188 xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f))) + xtrax;
1189
1190 if (sb) {
1191 sb->w = (xof * font_size) - sb->w;
1192 }
1193 }
1194 ct++;
1195 i++;
1196 }
1197
1198 current_line_length += xof + twidth - MARGIN_X_MIN;
1199 longest_line_length = std::max(current_line_length, longest_line_length);
1200
1201 cu->lines = 1;
1202 for (i = 0; i <= slen; i++) {
1203 ascii = mem[i];
1204 ct = &chartransdata[i];
1205 if (ascii == '\n' || ct->dobreak) {
1206 cu->lines++;
1207 }
1208 }
1209
1210 if (ef && ef->selboxes) {
1211 /* Set combined style flags for the selected string. Start with all styles then
1212 * remove one if ANY characters do not have it. Break out if we've removed them all. */
1214 for (int k = selstart; k <= selend && ef->select_char_info_flag; k++) {
1215 info = &custrinfo[k];
1216 ef->select_char_info_flag &= info->flag;
1217 }
1218 }
1219
1220 if (cu->spacemode != CU_ALIGN_X_LEFT) {
1221 ct = chartransdata;
1222
1223 if (cu->spacemode == CU_ALIGN_X_RIGHT) {
1224 TempLineInfo *li;
1225
1226 for (i = 0, li = lineinfo; i < lnr; i++, li++) {
1227 li->x_min = (li->x_max - li->x_min) + xof_scale;
1228 }
1229
1230 for (i = 0; i <= slen; i++) {
1231 ct->xof += lineinfo[ct->linenr].x_min;
1232 ct++;
1233 }
1234 }
1235 else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
1236 TempLineInfo *li;
1237
1238 for (i = 0, li = lineinfo; i < lnr; i++, li++) {
1239 li->x_min = ((li->x_max - li->x_min) + xof_scale) / 2.0f;
1240 }
1241
1242 for (i = 0; i <= slen; i++) {
1243 ct->xof += lineinfo[ct->linenr].x_min;
1244 ct++;
1245 }
1246 }
1247 else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) {
1248 TempLineInfo *li;
1249
1250 for (i = 0, li = lineinfo; i < lnr; i++, li++) {
1251 li->x_min = ((li->x_max - li->x_min) + xof_scale);
1252
1253 if (li->char_nr > 1) {
1254 li->x_min /= float(li->char_nr - 1);
1255 }
1256 }
1257 for (i = 0; i <= slen; i++) {
1258 for (j = i; !ELEM(mem[j], '\0', '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
1259 j++)
1260 {
1261 /* do nothing */
1262 }
1263
1264 // if ((mem[j] != '\n') && (mem[j])) {
1265 ct->xof += ct->charnr * lineinfo[ct->linenr].x_min;
1266 // }
1267 ct++;
1268 }
1269 }
1270 else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) {
1271 float curofs = 0.0f;
1272 for (i = 0; i <= slen; i++) {
1273 for (j = i; (mem[j]) && (mem[j] != '\n') && (chartransdata[j].dobreak == 0) && (j < slen);
1274 j++)
1275 {
1276 /* pass */
1277 }
1278
1279 if ((mem[j] != '\n') && (chartransdata[j].dobreak != 0)) {
1280 if (mem[i] == ' ') {
1281 TempLineInfo *li;
1282
1283 li = &lineinfo[ct->linenr];
1284 curofs += ((li->x_max - li->x_min) + xof_scale) / float(li->wspace_nr);
1285 }
1286 ct->xof += curofs;
1287 }
1288 if (mem[i] == '\n' || chartransdata[i].dobreak) {
1289 curofs = 0;
1290 }
1291 ct++;
1292 }
1293 }
1294 }
1295
1296 /* Top-baseline is default, in this case, do nothing. */
1297 if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
1298 if (tb_scale.h != 0.0f) {
1299 /* We need to loop all the text-boxes even the "full" ones.
1300 * This way they all get the same vertical padding. */
1301 for (int tb_index = 0; tb_index < cu->totbox; tb_index++) {
1302 CharTrans *ct_first, *ct_last;
1303 const int i_textbox = i_textbox_array[tb_index];
1304 const int i_textbox_next = i_textbox_array[tb_index + 1];
1305 const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1);
1306 int lines;
1307
1308 ct_first = chartransdata + i_textbox;
1309 ct_last = chartransdata + (is_last_filled_textbox ? slen : i_textbox_next - 1);
1310 lines = ct_last->linenr - ct_first->linenr + 1;
1311
1312 if (cu->overflow == CU_OVERFLOW_TRUNCATE) {
1313 /* Ensure overflow doesn't truncate text, before centering vertically
1314 * giving odd/buggy results, see: #66614. */
1315 if ((tb_index == cu->totbox - 1) && (last_line != -1)) {
1316 lines = last_line - ct_first->linenr;
1317 }
1318 }
1319
1320 textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / font_size);
1321 /* The initial Y origin of the text-box is hard-coded to 1.0f * text scale. */
1322 const float textbox_y_origin = 1.0f;
1323 float yoff = 0.0f;
1324
1325 switch (cu->align_y) {
1327 break;
1328 case CU_ALIGN_Y_TOP:
1329 yoff = textbox_y_origin - vfont_ascent(vfd);
1330 break;
1331 case CU_ALIGN_Y_CENTER:
1332 yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - vfont_ascent(vfd)) -
1333 (tb_scale.h * 0.5f) + textbox_y_origin);
1334 break;
1336 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h;
1337 break;
1338 case CU_ALIGN_Y_BOTTOM:
1339 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + vfont_descent(vfd);
1340 break;
1341 }
1342
1343 for (ct = ct_first; ct <= ct_last; ct++) {
1344 ct->yof += yoff;
1345 }
1346
1347 if (is_last_filled_textbox) {
1348 break;
1349 }
1350 }
1351 }
1352 else {
1353 /* Non text-box case handled separately. */
1354 float yoff = 0.0f;
1355
1356 switch (cu->align_y) {
1358 break;
1359 case CU_ALIGN_Y_TOP:
1360 yoff = -vfont_ascent(vfd);
1361 break;
1362 case CU_ALIGN_Y_CENTER:
1363 yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - vfont_ascent(vfd);
1364 break;
1366 yoff = (lnr - 1) * linedist;
1367 break;
1368 case CU_ALIGN_Y_BOTTOM:
1369 yoff = (lnr - 1) * linedist + vfont_descent(vfd);
1370 break;
1371 }
1372
1373 ct = chartransdata;
1374 for (i = 0; i <= slen; i++) {
1375 ct->yof += yoff;
1376 ct++;
1377 }
1378 }
1379 }
1380 if (tb_bounds_for_cursor != nullptr) {
1381 int char_beg_next = 0;
1382 for (curbox = 0; curbox < cu->totbox; curbox++) {
1383 TextBoxBounds_ForCursor *tb_bounds = &tb_bounds_for_cursor[curbox];
1384 if (tb_bounds->char_index_last == -1) {
1385 continue;
1386 }
1387 const int char_beg = char_beg_next;
1388 const int char_end = tb_bounds->char_index_last;
1389
1390 TempLineInfo *line_beg = &lineinfo[chartransdata[char_beg].linenr];
1391 TempLineInfo *line_end = &lineinfo[chartransdata[char_end].linenr];
1392
1393 int char_idx_offset = char_beg;
1394
1395 rctf *bounds = &tb_bounds->bounds;
1396 /* In a text-box with no curves, 'yof' only decrements over lines, 'ymax' and 'ymin'
1397 * can be obtained from any character in the first and last line of the text-box. */
1398 bounds->ymax = chartransdata[char_beg].yof;
1399 bounds->ymin = chartransdata[char_end].yof;
1400
1401 for (TempLineInfo *line = line_beg; line <= line_end; line++) {
1402 const CharTrans *first_char_line = &chartransdata[char_idx_offset];
1403 const CharTrans *last_char_line = &chartransdata[char_idx_offset + line->char_nr];
1404
1405 bounds->xmin = min_ff(bounds->xmin, first_char_line->xof);
1406 bounds->xmax = max_ff(bounds->xmax, last_char_line->xof);
1407 char_idx_offset += line->char_nr + 1;
1408 }
1409 /* Move the bounds into a space compatible with `cursor_location`. */
1410 BLI_rctf_mul(bounds, font_size);
1411
1412 char_beg_next = tb_bounds->char_index_last + 1;
1413 }
1414 }
1415
1416 MEM_freeN(lineinfo);
1417
1418 /* TEXT ON CURVE */
1419 /* NOTE: Only #OB_CURVES_LEGACY objects could have a path. */
1420 if (cu->textoncurve && cu->textoncurve->type == OB_CURVES_LEGACY) {
1421 BLI_assert(cu->textoncurve->runtime->curve_cache != nullptr);
1422 if (cu->textoncurve->runtime->curve_cache != nullptr &&
1423 cu->textoncurve->runtime->curve_cache->anim_path_accum_length != nullptr)
1424 {
1425 float distfac, imat[4][4], imat3[3][3], cmat[3][3];
1426 float minx, maxx;
1427 float timeofs, sizefac;
1428
1429 if (ob != nullptr) {
1430 invert_m4_m4(imat, ob->object_to_world().ptr());
1431 }
1432 else {
1433 unit_m4(imat);
1434 }
1435 copy_m3_m4(imat3, imat);
1436
1437 copy_m3_m4(cmat, cu->textoncurve->object_to_world().ptr());
1438 mul_m3_m3m3(cmat, cmat, imat3);
1439 sizefac = normalize_v3(cmat[0]) / font_size;
1440
1441 ct = chartransdata;
1442 minx = maxx = ct->xof;
1443 ct++;
1444 for (i = 1; i <= slen; i++, ct++) {
1445 if (minx > ct->xof) {
1446 minx = ct->xof;
1447 }
1448 if (maxx < ct->xof) {
1449 maxx = ct->xof;
1450 }
1451 }
1452
1453 /* We put the x-coordinate exact at the curve, the y is rotated. */
1454
1455 /* length correction */
1456 const float chartrans_size_x = maxx - minx;
1457 if (chartrans_size_x != 0.0f) {
1458 const CurveCache *cc = cu->textoncurve->runtime->curve_cache;
1459 const float totdist = BKE_anim_path_get_length(cc);
1460 distfac = (sizefac * totdist) / chartrans_size_x;
1461 distfac = (distfac > 1.0f) ? (1.0f / distfac) : 1.0f;
1462 }
1463 else {
1464 /* Happens when there are no characters, set this value to place the text cursor. */
1465 distfac = 0.0f;
1466 }
1467
1468 timeofs = 0.0f;
1469
1470 if (distfac < 1.0f) {
1471 /* Path longer than text: space-mode is involved. */
1472
1473 if (cu->spacemode == CU_ALIGN_X_RIGHT) {
1474 timeofs = 1.0f - distfac;
1475 }
1476 else if (cu->spacemode == CU_ALIGN_X_MIDDLE) {
1477 timeofs = (1.0f - distfac) / 2.0f;
1478 }
1479 else if (cu->spacemode == CU_ALIGN_X_FLUSH) {
1480 distfac = 1.0f;
1481 }
1482 }
1483
1484 if (chartrans_size_x != 0.0f) {
1485 distfac /= chartrans_size_x;
1486 }
1487
1488 timeofs += distfac * cu->xof; /* not cyclic */
1489
1490 ct = chartransdata;
1491 for (i = 0; i <= slen; i++, ct++) {
1492 float ctime, dtime, vec[4], rotvec[3];
1493 float si, co;
1494
1495 /* Rotate around center character. */
1496 info = &custrinfo[i];
1497 ascii = mem[i];
1498 if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
1499 ascii = towupper(ascii);
1500 }
1501
1502 che = find_vfont_char(vfd, ascii);
1503
1504 twidth = char_width(cu, che, info);
1505
1506 dtime = distfac * 0.5f * twidth;
1507
1508 ctime = timeofs + distfac * (ct->xof - minx);
1509 CLAMP(ctime, 0.0f, 1.0f);
1510
1511 /* Calculate the right loc AND the right rot separately. */
1512 /* `vec` needs 4 items. */
1513 BKE_where_on_path(cu->textoncurve, ctime, vec, nullptr, nullptr, nullptr, nullptr);
1515 cu->textoncurve, ctime + dtime, nullptr, rotvec, nullptr, nullptr, nullptr);
1516
1517 mul_v3_fl(vec, sizefac);
1518
1519 ct->rot = float(M_PI) - atan2f(rotvec[1], rotvec[0]);
1520
1521 si = sinf(ct->rot);
1522 co = cosf(ct->rot);
1523
1524 yof = ct->yof;
1525
1526 ct->xof = vec[0] + si * yof;
1527 ct->yof = vec[1] + co * yof;
1528
1529 if (selboxes && (i >= selstart) && (i <= selend)) {
1530 EditFontSelBox *sb;
1531 sb = &selboxes[i - selstart];
1532 sb->rot = -ct->rot;
1533 }
1534 }
1535 }
1536 }
1537
1538 if (selboxes) {
1539 ct = chartransdata;
1540 for (i = 0; i <= selend; i++, ct++) {
1541 if (i >= selstart) {
1542 EditFontSelBox *sb = &selboxes[i - selstart];
1543 sb->x = ct->xof;
1544 sb->y = ct->yof;
1545 if (ct->rot != 0.0f) {
1546 sb->x -= sinf(ct->rot) * font_select_y_offset;
1547 sb->y -= cosf(ct->rot) * font_select_y_offset;
1548 }
1549 else {
1550 /* Simple downward shift below baseline when not rotated. */
1551 sb->y -= font_select_y_offset;
1552 }
1553 sb->x *= font_size;
1554 sb->y *= font_size;
1555 selboxes[i - selstart].h = font_size;
1556 }
1557 }
1558 }
1559
1561 iter_data->status == VFONT_TO_CURVE_INIT)
1562 {
1563 ct = &chartransdata[ef->pos];
1564
1565 if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
1566 /* pass */
1567 }
1568 else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
1569 /* pass */
1570 }
1571 else {
1572 switch (mode) {
1573 case FO_CURSUP:
1574 lnr = ct->linenr - 1;
1575 break;
1576 case FO_CURSDOWN:
1577 lnr = ct->linenr + 1;
1578 break;
1579 case FO_PAGEUP:
1580 lnr = ct->linenr - 10;
1581 break;
1582 case FO_PAGEDOWN:
1583 lnr = ct->linenr + 10;
1584 break;
1585 /* Ignored. */
1586 case FO_EDIT:
1587 case FO_CURS:
1588 case FO_DUPLI:
1589 case FO_SELCHANGE:
1590 break;
1591 }
1592 cnr = ct->charnr;
1593 /* Seek for char with `lnr` & `cnr`. */
1594 ef->pos = 0;
1595 ct = chartransdata;
1596 for (i = 0; i < slen; i++) {
1597 if (ct->linenr == lnr) {
1598 if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) {
1599 break;
1600 }
1601 }
1602 else if (ct->linenr > lnr) {
1603 break;
1604 }
1605 ef->pos++;
1606 ct++;
1607 }
1608 }
1609 }
1610
1611 /* Cursor first. */
1612 if (ef) {
1613 ct = &chartransdata[ef->pos];
1614 const float cursor_width = 0.04f;
1615 const float cursor_half = 0.02f;
1616 const float xoffset = ct->xof;
1617 const float yoffset = ct->yof;
1618
1619 /* By default the cursor is exactly between the characters
1620 * and matches the rotation of the character to the right. */
1621 float cursor_left = 0.0f - cursor_half;
1622 float rotation = ct->rot;
1623
1624 if (ef->selboxes) {
1625 if (ef->selend >= ef->selstart) {
1626 /* Cursor at right edge of a text selection. Match rotation to the character at the
1627 * end of selection. Cursor is further right to show the selected characters better. */
1628 rotation = chartransdata[max_ii(0, ef->selend - 1)].rot;
1629 cursor_left = 0.0f;
1630 }
1631 else {
1632 /* Cursor at the left edge of a text selection. Cursor
1633 * is further left to show the selected characters better. */
1634 cursor_left = 0.0f - cursor_width;
1635 }
1636 }
1637 else if ((ef->pos == ef->len) && (ef->len > 0)) {
1638 /* Nothing selected, but at the end of the string. Match rotation to previous character. */
1639 rotation = chartransdata[ef->len - 1].rot;
1640 }
1641
1642 /* We need the rotation to be around the bottom-left corner. So we make
1643 * that the zero point before rotation, rotate, then apply offsets afterward. */
1644
1645 /* Bottom left. */
1646 ef->textcurs[0][0] = cursor_left;
1647 ef->textcurs[0][1] = 0.0f - font_select_y_offset;
1648 /* Bottom right. */
1649 ef->textcurs[1][0] = cursor_left + cursor_width;
1650 ef->textcurs[1][1] = 0.0f - font_select_y_offset;
1651 /* Top left. */
1652 ef->textcurs[3][0] = cursor_left;
1653 ef->textcurs[3][1] = 1.0f - font_select_y_offset;
1654 /* Top right. */
1655 ef->textcurs[2][0] = cursor_left + cursor_width;
1656 ef->textcurs[2][1] = 1.0f - font_select_y_offset;
1657
1658 for (int vert = 0; vert < 4; vert++) {
1659 float temp_fl[2];
1660 /* Rotate around the cursor's bottom-left corner. */
1661 rotate_v2_v2fl(temp_fl, &ef->textcurs[vert][0], -rotation);
1662 ef->textcurs[vert][0] = font_size * (xoffset + temp_fl[0]);
1663 ef->textcurs[vert][1] = font_size * (yoffset + temp_fl[1]);
1664 }
1665 }
1666
1667 if (mode == FO_SELCHANGE) {
1668 MEM_freeN(chartransdata);
1669 chartransdata = nullptr;
1670 }
1671 else if (mode == FO_EDIT) {
1672 /* Make NURBS-data. */
1673 BKE_nurbList_free(r_nubase);
1674
1675 ct = chartransdata;
1676 for (i = 0; i < slen; i++) {
1677 uint cha = uint(mem[i]);
1678 info = &(custrinfo[i]);
1679
1680 if ((cu->overflow == CU_OVERFLOW_TRUNCATE) && (ob && ob->mode != OB_MODE_EDIT) &&
1681 (info->flag & CU_CHINFO_OVERFLOW))
1682 {
1683 break;
1684 }
1685
1686 if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
1687 cha = towupper(cha);
1688 }
1689
1690 /* Only do that check in case we do have an object, otherwise all materials get erased every
1691 * time that code is called without an object. */
1692 if (ob != nullptr && (info->mat_nr > (ob->totcol))) {
1693 // CLOG_ERROR(
1694 // &LOG, "Illegal material index (%d) in text object, setting to 0", info->mat_nr);
1695 info->mat_nr = 0;
1696 }
1697 /* We don't want to see any character for '\n'. */
1698 if (cha != '\n') {
1699 BKE_vfont_build_char(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i, font_size);
1700 }
1701
1702 if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) {
1703 float ulwidth, uloverlap = 0.0f;
1704 rctf rect;
1705
1706 if ((i < (slen - 1)) && (mem[i + 1] != '\n') &&
1707 ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) &&
1708 ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0))
1709 {
1710 uloverlap = xtrax + 0.1f;
1711 }
1712 /* Find the character, the characters has to be in the memory already
1713 * since character checking has been done earlier already. */
1714 che = find_vfont_char(vfd, cha);
1715
1716 twidth = char_width(cu, che, info);
1717 ulwidth = (twidth * (1.0f + (info->kern / 40.0f))) + uloverlap;
1718
1719 rect.xmin = ct->xof;
1720 rect.xmax = rect.xmin + ulwidth;
1721
1722 rect.ymin = ct->yof;
1723 rect.ymax = rect.ymin - cu->ulheight;
1724
1726 cu, r_nubase, &rect, cu->ulpos - 0.05f, ct->rot, i, info->mat_nr, font_size);
1727 }
1728 ct++;
1729 }
1730 }
1731
1732 if (iter_data->status == VFONT_TO_CURVE_SCALE_ONCE) {
1733 /* That means we were in a final run, just exit. */
1735 iter_data->status = VFONT_TO_CURVE_DONE;
1736 }
1737 else if (cu->overflow == CU_OVERFLOW_NONE) {
1738 /* Do nothing. */
1739 }
1740 else if ((tb_scale.h == 0.0f) && (tb_scale.w == 0.0f)) {
1741 /* Do nothing. */
1742 }
1743 else if (cu->overflow == CU_OVERFLOW_SCALE) {
1744 if ((cu->totbox == 1) && ((tb_scale.w == 0.0f) || (tb_scale.h == 0.0f))) {
1745 /* These are special cases, simpler to deal with. */
1746 if (tb_scale.w == 0.0f) {
1747 /* This is a potential vertical overflow.
1748 * Since there is no width limit, all the new lines are from line breaks. */
1749 if ((last_line != -1) && (lnr > last_line)) {
1750 const float total_text_height = lnr * linedist;
1751 iter_data->scale_to_fit = tb_scale.h / total_text_height;
1752 iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
1753 iter_data->word_wrap = false;
1754 }
1755 }
1756 else if (tb_scale.h == 0.0f) {
1757 /* This is a horizontal overflow. */
1758 if (longest_line_length > tb_scale.w) {
1759 /* We make sure longest line before it broke can fit here. */
1760 float scale_to_fit = tb_scale.w / longest_line_length;
1761
1762 iter_data->scale_to_fit = scale_to_fit;
1763 iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
1764 iter_data->word_wrap = false;
1765 }
1766 }
1767 }
1768 else {
1769 /* This is the really complicated case, the best we can do is to iterate over
1770 * this function a few times until we get an acceptable result.
1771 *
1772 * Keep in mind that there is no single number that will make all fit to the end.
1773 * In a way, our ultimate goal is to get the highest scale that still leads to the
1774 * number of extra lines to zero. */
1775 if (iter_data->status == VFONT_TO_CURVE_INIT) {
1776 bool valid = true;
1777
1778 for (int tb_index = 0; tb_index <= curbox; tb_index++) {
1779 TextBox *tb = &cu->tb[tb_index];
1780 if ((tb->w == 0.0f) || (tb->h == 0.0f)) {
1781 valid = false;
1782 break;
1783 }
1784 }
1785
1786 if (valid && (last_line != -1) && (lnr > last_line)) {
1787 const float total_text_height = lnr * linedist;
1788 float scale_to_fit = tb_scale.h / total_text_height;
1789
1790 iter_data->bisect.max = 1.0f;
1791 iter_data->bisect.min = scale_to_fit;
1792
1793 iter_data->status = VFONT_TO_CURVE_BISECT;
1794 }
1795 }
1796 else {
1798 /* Try to get the highest scale that gives us the exactly
1799 * number of lines we need. */
1800 bool valid = false;
1801
1802 if ((last_line != -1) && (lnr > last_line)) {
1803 /* It is overflowing, scale it down. */
1804 iter_data->bisect.max = iter_data->scale_to_fit;
1805 }
1806 else {
1807 /* It fits inside the text-box, scale it up. */
1808 iter_data->bisect.min = iter_data->scale_to_fit;
1809 valid = true;
1810 }
1811
1812 /* Bisecting to try to find the best fit. */
1813 iter_data->scale_to_fit = (iter_data->bisect.max + iter_data->bisect.min) * 0.5f;
1814
1815 /* We iterated enough or got a good enough result. */
1816 if ((!iter_data->iteraction--) || ((iter_data->bisect.max - iter_data->bisect.min) <
1818 {
1819 if (valid) {
1820 iter_data->status = VFONT_TO_CURVE_DONE;
1821 }
1822 else {
1823 iter_data->scale_to_fit = iter_data->bisect.min;
1824 iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
1825 }
1826 }
1827 }
1828 }
1829 }
1830
1831 if (cursor_params) {
1832 const float *cursor_location = cursor_params->cursor_location;
1833 /* Erasing all text could give slen = 0 */
1834 if (slen == 0) {
1835 cursor_params->r_string_offset = -1;
1836 }
1837 else if (cu->textoncurve != nullptr) {
1838
1839 int closest_char = -1;
1840 float closest_dist_sq = FLT_MAX;
1841
1842 for (i = 0; i <= slen; i++) {
1843 const float char_location[2] = {
1844 chartransdata[i].xof * font_size,
1845 chartransdata[i].yof * font_size,
1846 };
1847 const float test_dist_sq = len_squared_v2v2(cursor_location, char_location);
1848 if (closest_dist_sq > test_dist_sq) {
1849 closest_char = i;
1850 closest_dist_sq = test_dist_sq;
1851 }
1852 }
1853
1854 cursor_params->r_string_offset = closest_char;
1855 }
1856 else {
1857 /* Find the first box closest to `cursor_location`. */
1858 int char_beg = 0;
1859 int char_end = slen;
1860
1861 if (tb_bounds_for_cursor != nullptr) {
1862 /* Search for the closest box. */
1863 int closest_box = -1;
1864 float closest_dist_sq = FLT_MAX;
1865 for (curbox = 0; curbox < cu->totbox; curbox++) {
1866 const TextBoxBounds_ForCursor *tb_bounds = &tb_bounds_for_cursor[curbox];
1867 if (tb_bounds->char_index_last == -1) {
1868 continue;
1869 }
1870 /* The closest point in the box to the `cursor_location`
1871 * by clamping it to the bounding box. */
1872 const float cursor_location_clamped[2] = {
1873 clamp_f(cursor_location[0], tb_bounds->bounds.xmin, tb_bounds->bounds.xmax),
1874 clamp_f(cursor_location[1], tb_bounds->bounds.ymin, tb_bounds->bounds.ymax),
1875 };
1876
1877 const float test_dist_sq = len_squared_v2v2(cursor_location, cursor_location_clamped);
1878 if (test_dist_sq < closest_dist_sq) {
1879 closest_dist_sq = test_dist_sq;
1880 closest_box = curbox;
1881 }
1882 }
1883 if (closest_box != -1) {
1884 if (closest_box != 0) {
1885 char_beg = tb_bounds_for_cursor[closest_box - 1].char_index_last + 1;
1886 }
1887 char_end = tb_bounds_for_cursor[closest_box].char_index_last;
1888 }
1889 MEM_freeN(tb_bounds_for_cursor);
1890 tb_bounds_for_cursor = nullptr; /* Safety only. */
1891 }
1892 const float interline_offset = ((linedist - 0.5f) / 2.0f) * font_size;
1893 /* Loop until find the line where `cursor_location` is over. */
1894 for (i = char_beg; i <= char_end; i++) {
1895 if (cursor_location[1] >= ((chartransdata[i].yof * font_size) - interline_offset)) {
1896 break;
1897 }
1898 }
1899
1900 i = min_ii(i, char_end);
1901 const float char_yof = chartransdata[i].yof;
1902
1903 /* Loop back until find the first character of the line, this because `cursor_location` can
1904 * be positioned further below the text, so #i can be the last character of the last line. */
1905 for (; i >= char_beg + 1 && chartransdata[i - 1].yof == char_yof; i--) {
1906 }
1907 /* Loop until find the first character to the right of `cursor_location`
1908 * (using the character midpoint on the x-axis as a reference). */
1909 for (; i <= char_end && char_yof == chartransdata[i].yof; i++) {
1910 info = &custrinfo[i];
1911 ascii = info->flag & CU_CHINFO_SMALLCAPS_CHECK ? towupper(mem[i]) : mem[i];
1912 che = find_vfont_char(vfd, ascii);
1913 const float charwidth = char_width(cu, che, info);
1914 const float charhalf = (charwidth / 2.0f);
1915 if (cursor_location[0] <= ((chartransdata[i].xof + charhalf) * font_size)) {
1916 break;
1917 }
1918 }
1919 i = min_ii(i, char_end);
1920
1921 /* If there is no character to the right of the cursor we are on the next line, go back to
1922 * the last character of the previous line. */
1923 if (i > char_beg && chartransdata[i].yof != char_yof) {
1924 i -= 1;
1925 }
1926 cursor_params->r_string_offset = i;
1927 }
1928 /* Must be cleared & freed. */
1929 BLI_assert(tb_bounds_for_cursor == nullptr);
1930 }
1931
1932 /* Scale to fit only works for single text box layouts. */
1934 /* Always cleanup before going to the scale-to-fit repetition. */
1935 if (r_nubase != nullptr) {
1936 BKE_nurbList_free(r_nubase);
1937 }
1938
1939 if (chartransdata != nullptr) {
1940 MEM_freeN(chartransdata);
1941 }
1942
1943 if (ef == nullptr) {
1944 MEM_freeN((void *)mem);
1945 }
1946 return true;
1947 }
1948
1949 ok = true;
1950finally:
1951 if (r_text) {
1952 *r_text = mem;
1953 *r_text_len = slen;
1954 *r_text_free = (ef == nullptr);
1955 }
1956 else {
1957 if (ef == nullptr) {
1958 MEM_freeN((void *)mem);
1959 }
1960 }
1961
1962 if (chartransdata) {
1963 if (ok && r_chartransdata) {
1964 *r_chartransdata = chartransdata;
1965 }
1966 else {
1967 MEM_freeN(chartransdata);
1968 }
1969 }
1970
1971 /* Store the effective scale, to use for the text-box lines. */
1972 cu->fsize_realtime = font_size;
1973
1974 return ok;
1975
1976#undef MARGIN_X_MIN
1977#undef MARGIN_Y_MIN
1978}
1979
1980#undef DESCENT
1981#undef ASCENT
1982
1984 Curve *cu,
1985 const eEditFontMode mode,
1986 ListBase *r_nubase,
1987 const char32_t **r_text,
1988 int *r_text_len,
1989 bool *r_text_free,
1990 CharTrans **r_chartransdata)
1991{
1992 VFontToCurveIter data = {};
1994 data.scale_to_fit = 1.0f;
1995 data.word_wrap = true;
1996 data.ok = true;
1997 data.status = VFONT_TO_CURVE_INIT;
1998
1999 do {
2000 data.ok &= vfont_to_curve(
2001 ob, cu, mode, &data, nullptr, r_nubase, r_text, r_text_len, r_text_free, r_chartransdata);
2002 } while (data.ok && ELEM(data.status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT));
2003
2004 return data.ok;
2005}
2006
2007int BKE_vfont_cursor_to_text_index(Object *ob, const float cursor_location[2])
2008{
2009 Curve *cu = (Curve *)ob->data;
2010 ListBase *r_nubase = &cu->nurb;
2011
2012 /* TODO: iterating to calculate the scale can be avoided. */
2013 VFontToCurveIter data = {};
2015 data.scale_to_fit = 1.0f;
2016 data.word_wrap = true;
2017 data.ok = true;
2018 data.status = VFONT_TO_CURVE_INIT;
2019
2020 VFontCursor_Params cursor_params = {};
2021 cursor_params.cursor_location[0] = cursor_location[0];
2022 cursor_params.cursor_location[1] = cursor_location[1];
2023 cursor_params.r_string_offset = -1;
2024
2025 do {
2026 data.ok &= vfont_to_curve(
2027 ob, cu, FO_CURS, &data, &cursor_params, r_nubase, nullptr, nullptr, nullptr, nullptr);
2028 } while (data.ok && ELEM(data.status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT));
2029
2030 return cursor_params.r_string_offset;
2031}
2032
2033#undef FONT_TO_CURVE_SCALE_ITERATIONS
2034#undef FONT_TO_CURVE_SCALE_THRESHOLD
2035
2037{
2038 BLI_assert(ob->type == OB_FONT);
2039
2040 return BKE_vfont_to_curve_ex(
2041 ob, static_cast<Curve *>(ob->data), mode, r_nubase, nullptr, nullptr, nullptr, nullptr);
2042}
2043
2045{
2046 Curve *cu = static_cast<Curve *>(ob->data);
2047
2048 return BKE_vfont_to_curve_ex(
2049 ob, static_cast<Curve *>(ob->data), mode, &cu->nurb, nullptr, nullptr, nullptr, nullptr);
2050}
2051
2052/* -------------------------------------------------------------------- */
2056static struct {
2057 char32_t *text_buffer;
2060 size_t len_utf8;
2061} g_vfont_clipboard = {nullptr};
2062
2064{
2065 MEM_SAFE_FREE(g_vfont_clipboard.text_buffer);
2066 MEM_SAFE_FREE(g_vfont_clipboard.info_buffer);
2067 g_vfont_clipboard.len_utf32 = 0;
2068 g_vfont_clipboard.len_utf8 = 0;
2069}
2070
2071void BKE_vfont_clipboard_set(const char32_t *text_buf, const CharInfo *info_buf, const size_t len)
2072{
2073 char32_t *text;
2074 CharInfo *info;
2075
2076 /* Clean previous buffers. */
2078
2079 text = static_cast<char32_t *>(MEM_malloc_arrayN((len + 1), sizeof(*text), __func__));
2080 if (text == nullptr) {
2081 return;
2082 }
2083
2084 info = static_cast<CharInfo *>(MEM_malloc_arrayN(len, sizeof(CharInfo), __func__));
2085 if (info == nullptr) {
2086 MEM_freeN(text);
2087 return;
2088 }
2089
2090 memcpy(text, text_buf, len * sizeof(*text));
2091 text[len] = '\0';
2092 memcpy(info, info_buf, len * sizeof(CharInfo));
2093
2094 /* store new buffers */
2095 g_vfont_clipboard.text_buffer = text;
2096 g_vfont_clipboard.info_buffer = info;
2098 g_vfont_clipboard.len_utf32 = len;
2099}
2100
2101void BKE_vfont_clipboard_get(char32_t **r_text_buf,
2102 CharInfo **r_info_buf,
2103 size_t *r_len_utf8,
2104 size_t *r_len_utf32)
2105{
2106 if (r_text_buf) {
2107 *r_text_buf = g_vfont_clipboard.text_buffer;
2108 }
2109
2110 if (r_info_buf) {
2111 *r_info_buf = g_vfont_clipboard.info_buffer;
2112 }
2113
2114 if (r_len_utf32) {
2115 *r_len_utf32 = g_vfont_clipboard.len_utf32;
2116 }
2117
2118 if (r_len_utf8) {
2119 *r_len_utf8 = g_vfont_clipboard.len_utf8;
2120 }
2121}
2122
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
@ 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
@ LIB_ID_CREATE_NO_USER_REFCOUNT
void id_us_plus(ID *id)
Definition lib_id.cc:351
void id_us_min(ID *id)
Definition lib_id.cc:359
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_SMOOTH
@ CU_OVERFLOW_SCALE
@ CU_OVERFLOW_TRUNCATE
@ CU_OVERFLOW_NONE
@ CU_ALIGN_Y_TOP
@ CU_ALIGN_Y_BOTTOM_BASELINE
@ CU_ALIGN_Y_CENTER
@ CU_ALIGN_Y_BOTTOM
@ CU_ALIGN_Y_TOP_BASELINE
#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_CHINFO_WRAP
@ CU_CHINFO_UNDERLINE
@ CU_CHINFO_BOLD
@ CU_CHINFO_ITALIC
@ CU_CHINFO_SMALLCAPS_CHECK
@ CU_CHINFO_SMALLCAPS
@ CU_CHINFO_OVERFLOW
@ CU_NURB_CYCLIC
@ OB_MODE_EDIT
Object is a sort of wrapper for general info.
@ OB_FONT
@ OB_CURVES_LEGACY
struct VFont VFont
#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
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::@101 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 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:2058
void BKE_vfont_select_clamp(Object *ob)
Definition vfont.cc:670
static float vfont_descent(const VFontData *vfd)
Definition vfont.cc:792
@ 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
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:2044
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
bool BKE_vfont_is_builtin(const VFont *vfont)
Definition vfont.cc:232
const void * builtin_font_data
Definition vfont.cc:63
static struct @100 g_vfont_clipboard
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:2036
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:2057
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:2071
static VChar * find_vfont_char(const VFontData *vfd, uint character)
Definition vfont.cc:438
#define FONT_TO_CURVE_SCALE_THRESHOLD
Definition vfont.cc:769
IDTypeInfo IDType_ID_VF
Definition vfont.cc:168
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:2101
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:1983
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:2059
static CLG_LogRef LOG
Definition vfont.cc:54
#define MARGIN_X_MIN
int BKE_vfont_cursor_to_text_index(Object *ob, const float cursor_location[2])
Definition vfont.cc:2007
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:2060
void BKE_vfont_free_data(VFont *vfont)
Definition vfont.cc:200
void BKE_vfont_clipboard_free()
Definition vfont.cc:2063
uint8_t flag
Definition wm_window.cc:138