Blender V5.0
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 <cstdio>
10#include <cstdlib>
11#include <cstring>
12#include <cwctype>
13#include <optional>
14
15#include "CLG_log.h"
16
17#include "MEM_guardedalloc.h"
18
19#include "BLI_ghash.h"
20#include "BLI_listbase.h"
21#include "BLI_path_utils.hh"
22#include "BLI_string.h"
23#include "BLI_string_utf8.h"
24#include "BLI_utildefines.h"
25
26#include "BLT_translation.hh"
27
28#include "DNA_curve_types.h"
29#include "DNA_object_types.h"
31#include "DNA_vfont_types.h"
32
33#include "BKE_bpath.hh"
34#include "BKE_curve.hh"
35#include "BKE_global.hh"
36#include "BKE_idtype.hh"
37#include "BKE_lib_id.hh"
38#include "BKE_library.hh"
39#include "BKE_main.hh"
40#include "BKE_packedFile.hh"
41#include "BKE_vfont.hh"
42#include "BKE_vfontdata.hh"
43
44#include "BLO_read_write.hh"
45
46static CLG_LogRef LOG = {"geom.vfont"};
47
48/* -------------------------------------------------------------------- */
51
53
55
56/* -------------------------------------------------------------------- */
59
60const void *builtin_font_data = nullptr;
62
63static void vfont_init_data(ID *id)
64{
65 VFont *vfont = (VFont *)id;
67
68 if (pf) {
69 VFontData *vfd;
70
72 if (vfd) {
73 vfont->data = vfd;
74
76 }
77
78 /* Free the packed file */
80 }
81}
82
83static void vfont_copy_data(Main * /*bmain*/,
84 std::optional<Library *> /*owner_library*/,
85 ID *id_dst,
86 const ID * /*id_src*/,
87 const int flag)
88{
89 VFont *vfont_dst = (VFont *)id_dst;
90
91 /* We never handle user-count here for own data. */
92 const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
93
94 /* Just to be sure, should not have any value actually after reading time. */
95 vfont_dst->temp_pf = nullptr;
96
97 if (vfont_dst->packedfile) {
98 vfont_dst->packedfile = BKE_packedfile_duplicate(vfont_dst->packedfile);
99 }
100
101 if (vfont_dst->data) {
102 vfont_dst->data = BKE_vfontdata_copy(vfont_dst->data, flag_subdata);
103 }
104}
105
107static void vfont_free_data(ID *id)
108{
109 VFont *vfont = (VFont *)id;
110 BKE_vfont_data_free(vfont);
111
112 if (vfont->packedfile) {
114 vfont->packedfile = nullptr;
115 }
116}
117
118static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
119{
120 VFont *vfont = (VFont *)id;
121
122 if ((vfont->packedfile != nullptr) &&
123 (bpath_data->flag & BKE_BPATH_FOREACH_PATH_SKIP_PACKED) != 0)
124 {
125 return;
126 }
127
128 if (BKE_vfont_is_builtin(vfont)) {
129 return;
130 }
131
132 BKE_bpath_foreach_path_fixed_process(bpath_data, vfont->filepath, sizeof(vfont->filepath));
133}
134
135static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
136{
137 VFont *vf = (VFont *)id;
138 const bool is_undo = BLO_write_is_undo(writer);
139
140 /* Clean up, important in undo case to reduce false detection of changed datablocks. */
141 vf->data = nullptr;
142 vf->temp_pf = nullptr;
143
144 /* Do not store packed files in case this is a library override ID. */
145 if (ID_IS_OVERRIDE_LIBRARY(vf) && !is_undo) {
146 vf->packedfile = nullptr;
147 }
148
149 /* write LibData */
150 BLO_write_id_struct(writer, VFont, id_address, &vf->id);
151 BKE_id_blend_write(writer, &vf->id);
152
153 /* direct data */
155}
156
157static void vfont_blend_read_data(BlendDataReader *reader, ID *id)
158{
159 VFont *vf = (VFont *)id;
160 vf->data = nullptr;
161 vf->temp_pf = nullptr;
163}
164
166 /*id_code*/ VFont::id_type,
167 /*id_filter*/ FILTER_ID_VF,
168 /*dependencies_id_types*/ 0,
169 /*main_listbase_index*/ INDEX_ID_VF,
170 /*struct_size*/ sizeof(VFont),
171 /*name*/ "Font",
172 /*name_plural*/ N_("fonts"),
173 /*translation_context*/ BLT_I18NCONTEXT_ID_VFONT,
175 /*asset_type_info*/ nullptr,
176
177 /*init_data*/ vfont_init_data,
178 /*copy_data*/ vfont_copy_data,
179 /*free_data*/ vfont_free_data,
180 /*make_local*/ nullptr,
181 /*foreach_id*/ nullptr,
182 /*foreach_cache*/ nullptr,
183 /*foreach_path*/ vfont_foreach_path,
184 /*foreach_working_space_color*/ nullptr,
185 /*owner_pointer_get*/ nullptr,
186
187 /*blend_write*/ vfont_blend_write,
188 /*blend_read_data*/ vfont_blend_read_data,
189 /*blend_read_after_liblink*/ nullptr,
190
191 /*blend_read_undo_preserve*/ nullptr,
192
193 /*lib_override_apply_post*/ nullptr,
194};
195
197
198/* -------------------------------------------------------------------- */
201
203{
204 PackedFile *pf;
205 if (BKE_vfont_is_builtin(vfont)) {
207 }
208 else {
209 if (vfont->packedfile) {
210 pf = vfont->packedfile;
211
212 /* We need to copy a temporary font to memory unless it is already there. */
213 if (vfont->temp_pf == nullptr) {
215 }
216 }
217 else {
218 pf = BKE_packedfile_new(nullptr, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
219
220 if (vfont->temp_pf == nullptr) {
222 nullptr, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id));
223 }
224 }
225 if (!pf) {
226 CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->filepath);
227
228 /* NOTE(@ideasman42): Don't attempt to find a fallback.
229 * If the font requested by the user doesn't load, font rendering will display
230 * placeholder characters instead. */
231 }
232 }
233
234 if (pf) {
236 if (pf != vfont->packedfile) {
238 }
239 }
240}
241
243{
244 if (vfont->data) {
245 if (vfont->data->characters) {
246 GHashIterator gh_iter;
247 GHASH_ITER (gh_iter, vfont->data->characters) {
248 VChar *che = static_cast<VChar *>(BLI_ghashIterator_getValue(&gh_iter));
249 if (che == nullptr) {
250 continue;
251 }
252
253 while (che->nurbsbase.first) {
254 Nurb *nu = static_cast<Nurb *>(che->nurbsbase.first);
255 if (nu->bezt) {
256 MEM_freeN(nu->bezt);
257 }
258 BLI_freelinkN(&che->nurbsbase, nu);
259 }
260
261 MEM_freeN(che);
262 }
263
264 BLI_ghash_free(vfont->data->characters, nullptr, nullptr);
265 }
266
267 MEM_freeN(vfont->data);
268 vfont->data = nullptr;
269 }
270
271 if (vfont->temp_pf) {
272 BKE_packedfile_free(vfont->temp_pf); /* Null when the font file can't be found on disk. */
273 vfont->temp_pf = nullptr;
274 }
275}
276
277bool BKE_vfont_is_builtin(const VFont *vfont)
278{
279 return STREQ(vfont->filepath, FO_BUILTIN_NAME);
280}
281
282void BKE_vfont_builtin_register(const void *mem, int size)
283{
284 builtin_font_data = mem;
286}
287
289{
290 if (!builtin_font_data) {
291 CLOG_ERROR(&LOG, "Internal error, builtin font not loaded");
292
293 return nullptr;
294 }
295
296 void *mem = MEM_mallocN(builtin_font_size, "vfd_builtin");
297
299
301}
302
303VFont *BKE_vfont_load(Main *bmain, const char *filepath)
304{
305 char filename[FILE_MAXFILE];
306 VFont *vfont = nullptr;
307 PackedFile *pf;
308 bool is_builtin;
309
310 if (STREQ(filepath, FO_BUILTIN_NAME)) {
311 STRNCPY(filename, filepath);
312
314 is_builtin = true;
315 }
316 else {
317 BLI_path_split_file_part(filepath, filename, sizeof(filename));
318 pf = BKE_packedfile_new(nullptr, filepath, BKE_main_blendfile_path(bmain));
319
320 is_builtin = false;
321 }
322
323 if (pf) {
324 VFontData *vfd;
325
327 if (vfd) {
328 /* If there's a font name, use it for the ID name. */
329 vfont = static_cast<VFont *>(
330 BKE_libblock_alloc(bmain, ID_VF, vfd->name[0] ? vfd->name : filename, 0));
331 vfont->data = vfd;
332 STRNCPY(vfont->filepath, filepath);
333
334 /* if auto-pack is on store the packed-file in de font structure */
335 if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) {
336 vfont->packedfile = pf;
337 }
338
339 /* Do not add #FO_BUILTIN_NAME to temporary list-base. */
340 if (!STREQ(filename, FO_BUILTIN_NAME)) {
341 vfont->temp_pf = BKE_packedfile_new(nullptr, filepath, BKE_main_blendfile_path(bmain));
342 }
343 }
344
345 /* Free the packed file */
346 if (!vfont || vfont->packedfile != pf) {
348 }
349 }
350
351 return vfont;
352}
353
354VFont *BKE_vfont_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
355{
356 char filepath_abs[FILE_MAX], filepath_test[FILE_MAX];
357
358 STRNCPY(filepath_abs, filepath);
359 BLI_path_abs(filepath_abs, BKE_main_blendfile_path(bmain));
360
361 /* first search an identical filepath */
362 LISTBASE_FOREACH (VFont *, vfont, &bmain->fonts) {
363 STRNCPY(filepath_test, vfont->filepath);
364 BLI_path_abs(filepath_test, ID_BLEND_PATH(bmain, &vfont->id));
365
366 if (BLI_path_cmp(filepath_test, filepath_abs) == 0) {
367 id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */
368 if (r_exists) {
369 *r_exists = true;
370 }
371 return vfont;
372 }
373 }
374
375 if (r_exists) {
376 *r_exists = false;
377 }
378 return BKE_vfont_load(bmain, filepath);
379}
380
381VFont *BKE_vfont_load_exists(Main *bmain, const char *filepath)
382{
383 return BKE_vfont_load_exists_ex(bmain, filepath, nullptr);
384}
385
387{
388 LISTBASE_FOREACH (VFont *, vfont, &G_MAIN->fonts) {
389 if (BKE_vfont_is_builtin(vfont)) {
390 return vfont;
391 }
392 }
393
394 /* Newly loaded ID's have a user by default, in this case the caller is responsible
395 * for assigning a user, otherwise an additional user would be added, see: #100819. */
397 id_us_min(&vfont->id);
398 BLI_assert(vfont->id.us == 0);
399 return vfont;
400}
401
403
404/* -------------------------------------------------------------------- */
407
408int BKE_vfont_select_get(const Curve *cu, int *r_start, int *r_end)
409{
410 EditFont *ef = cu->editfont;
411 int start, end, direction;
412
413 if (ef == nullptr || (cu->ob_type != OB_FONT)) {
414 return 0;
415 }
416
417 BLI_assert(ef->len >= 0);
418 BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1);
419 BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1);
420 BLI_assert(ef->pos >= 0 && ef->pos <= ef->len);
421
422 if (ef->selstart == 0) {
423 return 0;
424 }
425
426 if (ef->selstart <= ef->selend) {
427 start = ef->selstart - 1;
428 end = ef->selend - 1;
429 direction = 1;
430 }
431 else {
432 start = ef->selend;
433 end = ef->selstart - 2;
434 direction = -1;
435 }
436
437 if (start == end + 1) {
438 return 0;
439 }
440
441 BLI_assert(start < end + 1);
442 *r_start = start;
443 *r_end = end;
444 return direction;
445}
446
448{
449 EditFont *ef = cu->editfont;
450
451 BLI_assert((cu->ob_type == OB_FONT) && ef);
452
453 CLAMP_MAX(ef->pos, ef->len);
454 CLAMP_MAX(ef->selstart, ef->len + 1);
455 CLAMP_MAX(ef->selend, ef->len);
456}
457
459
460/* -------------------------------------------------------------------- */
463
464static struct {
465 char32_t *text_buffer;
467 size_t len_utf32;
468 size_t len_utf8;
469} g_vfont_clipboard = {nullptr};
470
472{
473 MEM_SAFE_FREE(g_vfont_clipboard.text_buffer);
474 MEM_SAFE_FREE(g_vfont_clipboard.info_buffer);
475 g_vfont_clipboard.len_utf32 = 0;
476 g_vfont_clipboard.len_utf8 = 0;
477}
478
479void BKE_vfont_clipboard_set(const char32_t *text_buf, const CharInfo *info_buf, const size_t len)
480{
481 char32_t *text;
482 CharInfo *info;
483
484 /* Clean previous buffers. */
486
487 text = MEM_malloc_arrayN<char32_t>((len + 1), __func__);
488 if (text == nullptr) {
489 return;
490 }
491
492 info = MEM_malloc_arrayN<CharInfo>(len, __func__);
493 if (info == nullptr) {
494 MEM_freeN(text);
495 return;
496 }
497
498 memcpy(text, text_buf, len * sizeof(*text));
499 text[len] = '\0';
500 memcpy(info, info_buf, len * sizeof(CharInfo));
501
502 /* store new buffers */
503 g_vfont_clipboard.text_buffer = text;
504 g_vfont_clipboard.info_buffer = info;
506 g_vfont_clipboard.len_utf32 = len;
507}
508
509void BKE_vfont_clipboard_get(char32_t **r_text_buf,
510 CharInfo **r_info_buf,
511 size_t *r_len_utf8,
512 size_t *r_len_utf32)
513{
514 if (r_text_buf) {
515 *r_text_buf = g_vfont_clipboard.text_buffer;
516 }
517
518 if (r_info_buf) {
519 *r_info_buf = g_vfont_clipboard.info_buffer;
520 }
521
522 if (r_len_utf32) {
523 *r_len_utf32 = g_vfont_clipboard.len_utf32;
524 }
525
526 if (r_len_utf8) {
527 *r_len_utf8 = g_vfont_clipboard.len_utf8;
528 }
529}
530
bool BKE_bpath_foreach_path_fixed_process(BPathForeachPathData *bpath_data, char *path, size_t path_maxncpy)
Definition bpath.cc:125
@ BKE_BPATH_FOREACH_PATH_SKIP_PACKED
Definition BKE_bpath.hh:42
#define G_MAIN
@ G_FILE_AUTOPACK
@ IDTYPE_FLAGS_APPEND_IS_REUSABLE
Definition BKE_idtype.hh:47
@ IDTYPE_FLAGS_NO_ANIMDATA
Definition BKE_idtype.hh:49
IDTypeInfo IDType_ID_VF
Definition vfont.cc:165
void * BKE_libblock_alloc(Main *bmain, short type, const char *name, int flag) ATTR_WARN_UNUSED_RESULT
Definition lib_id.cc:1447
void id_us_plus(ID *id)
Definition lib_id.cc:358
@ LIB_ID_CREATE_NO_USER_REFCOUNT
void id_us_min(ID *id)
Definition lib_id.cc:366
void BKE_id_blend_write(BlendWriter *writer, ID *id)
Definition lib_id.cc:2631
const char * BKE_main_blendfile_path(const Main *bmain) ATTR_NONNULL()
Definition main.cc:887
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)
A structure to represent vector fonts, and to load them from PostScript fonts.
VFontData * BKE_vfontdata_copy(const VFontData *vfont_src, int flag)
VFontData * BKE_vfontdata_from_freetypefont(PackedFile *pf)
#define BLI_assert(a)
Definition BLI_assert.h:46
BLI_INLINE void * BLI_ghashIterator_getValue(GHashIterator *ghi) ATTR_WARN_UNUSED_RESULT
Definition BLI_ghash.h:299
#define GHASH_ITER(gh_iter_, ghash_)
Definition BLI_ghash.h:318
void BLI_ghash_free(GHash *gh, GHashKeyFreeFP keyfreefp, GHashValFreeFP valfreefp)
Definition BLI_ghash.cc:860
#define LISTBASE_FOREACH(type, var, list)
void BLI_freelinkN(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
Definition listbase.cc:270
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
char * STRNCPY(char(&dst)[N], const char *src)
Definition BLI_string.h:693
size_t BLI_str_utf32_as_utf8_len(const char32_t *src) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
#define CLAMP_MAX(a, c)
#define STREQ(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:188
#define CLOG_WARN(clg_ref,...)
Definition CLG_log.h:189
#define FILTER_ID_VF
Definition DNA_ID.h:1222
#define ID_BLEND_PATH_FROM_GLOBAL(_id)
Definition DNA_ID.h:688
#define ID_BLEND_PATH(_bmain, _id)
Definition DNA_ID.h:685
@ INDEX_ID_VF
Definition DNA_ID.h:1300
#define ID_IS_OVERRIDE_LIBRARY(_id)
Definition DNA_ID.h:730
@ ID_VF
Object is a sort of wrapper for general info.
@ OB_FONT
#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
#define pf(_x, _i)
Prefetch 64.
Definition gim_memory.h:48
#define LOG(level)
Definition log.h:97
void * MEM_mallocN(size_t len, const char *str)
Definition mallocn.cc:128
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
Definition mallocn.cc:133
void MEM_freeN(void *vmemh)
Definition mallocn.cc:113
#define G(x, y, z)
eBPathForeachFlag flag
Definition BKE_bpath.hh:102
struct EditFont * editfont
short ob_type
int selend
Definition BKE_vfont.hh:61
int selstart
Definition BKE_vfont.hh:61
Definition DNA_ID.h:414
int us
Definition DNA_ID.h:443
void * first
ListBase fonts
Definition BKE_main.hh:293
BezTriple * bezt
ListBase nurbsbase
GHash * characters
char name[128]
struct VFontData * data
char filepath[1024]
struct PackedFile * temp_pf
struct PackedFile * packedfile
uint len
#define N_(msgid)
void BKE_vfont_data_ensure(VFont *vfont)
Definition vfont.cc:202
int BKE_vfont_select_get(const Curve *cu, int *r_start, int *r_end)
Definition vfont.cc:408
static void vfont_init_data(ID *id)
Definition vfont.cc:63
void BKE_vfont_data_free(VFont *vfont)
Definition vfont.cc:242
static PackedFile * packedfile_new_from_builtin()
Definition vfont.cc:288
CharInfo * info_buffer
Definition vfont.cc:466
int builtin_font_size
Definition vfont.cc:61
VFont * BKE_vfont_load(Main *bmain, const char *filepath)
Definition vfont.cc:303
static void vfont_blend_read_data(BlendDataReader *reader, ID *id)
Definition vfont.cc:157
bool BKE_vfont_is_builtin(const VFont *vfont)
Definition vfont.cc:277
static struct @272305335305122222244222001073371210147151061163 g_vfont_clipboard
const void * builtin_font_data
Definition vfont.cc:60
static void vfont_copy_data(Main *, std::optional< Library * >, ID *id_dst, const ID *, const int flag)
Definition vfont.cc:83
static void vfont_foreach_path(ID *id, BPathForeachPathData *bpath_data)
Definition vfont.cc:118
void BKE_vfont_select_clamp(Curve *cu)
Definition vfont.cc:447
VFont * BKE_vfont_load_exists_ex(Main *bmain, const char *filepath, bool *r_exists)
Definition vfont.cc:354
char32_t * text_buffer
Definition vfont.cc:465
void BKE_vfont_clipboard_set(const char32_t *text_buf, const CharInfo *info_buf, const size_t len)
Definition vfont.cc:479
static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address)
Definition vfont.cc:135
VFont * BKE_vfont_load_exists(Main *bmain, const char *filepath)
Definition vfont.cc:381
void BKE_vfont_builtin_register(const void *mem, int size)
Definition vfont.cc:282
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:509
VFont * BKE_vfont_builtin_ensure()
Definition vfont.cc:386
size_t len_utf32
Definition vfont.cc:467
static void vfont_free_data(ID *id)
Definition vfont.cc:107
size_t len_utf8
Definition vfont.cc:468
void BKE_vfont_clipboard_free()
Definition vfont.cc:471
uint8_t flag
Definition wm_window.cc:145