diff options
author | Campbell Barton <ideasman42@gmail.com> | 2021-10-06 03:15:53 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2021-10-06 03:18:16 +0300 |
commit | b93e947306517a5b6ab879aab35c8fdccff8887e (patch) | |
tree | a3869ea689ed7bc6f710078f4e444e7d3b7f7690 /source/blender/blenkernel/intern/font.c | |
parent | dcac86f4f11fb4e464a8f2dc3f2ef69eff4f4f21 (diff) |
Cleanup: rename BKE_font.h -> BKE_vfont.h
Match API naming prefix (BKE_vfont_*) and DNA_vfont_types.h.
Diffstat (limited to 'source/blender/blenkernel/intern/font.c')
-rw-r--r-- | source/blender/blenkernel/intern/font.c | 1828 |
1 files changed, 0 insertions, 1828 deletions
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c deleted file mode 100644 index d749237971a..00000000000 --- a/source/blender/blenkernel/intern/font.c +++ /dev/null @@ -1,1828 +0,0 @@ -/* - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software Foundation, - * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - * - * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. - * All rights reserved. - */ - -/** \file - * \ingroup bke - */ - -#include <math.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <wctype.h> - -#include "CLG_log.h" - -#include "MEM_guardedalloc.h" - -#include "BLI_ghash.h" -#include "BLI_listbase.h" -#include "BLI_math.h" -#include "BLI_math_base_safe.h" -#include "BLI_path_util.h" -#include "BLI_string.h" -#include "BLI_string_utf8.h" -#include "BLI_threads.h" -#include "BLI_utildefines.h" - -#include "BLT_translation.h" - -#include "DNA_curve_types.h" -#include "DNA_object_types.h" -#include "DNA_packedFile_types.h" -#include "DNA_vfont_types.h" - -#include "BKE_anim_path.h" -#include "BKE_curve.h" -#include "BKE_font.h" -#include "BKE_global.h" -#include "BKE_idtype.h" -#include "BKE_lib_id.h" -#include "BKE_main.h" -#include "BKE_packedFile.h" -#include "BKE_vfontdata.h" - -#include "BLO_read_write.h" - -static CLG_LogRef LOG = {"bke.data_transfer"}; -static ThreadRWMutex vfont_rwlock = BLI_RWLOCK_INITIALIZER; - -/**************************** Prototypes **************************/ - -static PackedFile *get_builtin_packedfile(void); - -/****************************** VFont Datablock ************************/ - -static void vfont_init_data(ID *id) -{ - VFont *vfont = (VFont *)id; - PackedFile *pf = get_builtin_packedfile(); - - if (pf) { - VFontData *vfd; - - vfd = BKE_vfontdata_from_freetypefont(pf); - if (vfd) { - vfont->data = vfd; - - BLI_strncpy(vfont->filepath, FO_BUILTIN_NAME, sizeof(vfont->filepath)); - } - - /* Free the packed file */ - BKE_packedfile_free(pf); - } -} - -static void vfont_copy_data(Main *UNUSED(bmain), - ID *id_dst, - const ID *UNUSED(id_src), - const int flag) -{ - VFont *vfont_dst = (VFont *)id_dst; - - /* We never handle usercount here for own data. */ - const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT; - - /* Just to be sure, should not have any value actually after reading time. */ - vfont_dst->temp_pf = NULL; - - if (vfont_dst->packedfile) { - vfont_dst->packedfile = BKE_packedfile_duplicate(vfont_dst->packedfile); - } - - if (vfont_dst->data) { - vfont_dst->data = BKE_vfontdata_copy(vfont_dst->data, flag_subdata); - } -} - -/** Free (or release) any data used by this font (does not free the font itself). */ -static void vfont_free_data(ID *id) -{ - VFont *vfont = (VFont *)id; - BKE_vfont_free_data(vfont); - - if (vfont->packedfile) { - BKE_packedfile_free(vfont->packedfile); - vfont->packedfile = NULL; - } -} - -static void vfont_blend_write(BlendWriter *writer, ID *id, const void *id_address) -{ - VFont *vf = (VFont *)id; - const bool is_undo = BLO_write_is_undo(writer); - - /* Clean up, important in undo case to reduce false detection of changed datablocks. */ - vf->data = NULL; - vf->temp_pf = NULL; - - /* Do not store packed files in case this is a library override ID. */ - if (ID_IS_OVERRIDE_LIBRARY(vf) && !is_undo) { - vf->packedfile = NULL; - } - - /* write LibData */ - BLO_write_id_struct(writer, VFont, id_address, &vf->id); - BKE_id_blend_write(writer, &vf->id); - - /* direct data */ - BKE_packedfile_blend_write(writer, vf->packedfile); -} - -static void vfont_blend_read_data(BlendDataReader *reader, ID *id) -{ - VFont *vf = (VFont *)id; - vf->data = NULL; - vf->temp_pf = NULL; - BKE_packedfile_blend_read(reader, &vf->packedfile); -} - -IDTypeInfo IDType_ID_VF = { - .id_code = ID_VF, - .id_filter = FILTER_ID_VF, - .main_listbase_index = INDEX_ID_VF, - .struct_size = sizeof(VFont), - .name = "Font", - .name_plural = "fonts", - .translation_context = BLT_I18NCONTEXT_ID_VFONT, - .flags = IDTYPE_FLAGS_NO_ANIMDATA | IDTYPE_FLAGS_APPEND_IS_REUSABLE, - - .init_data = vfont_init_data, - .copy_data = vfont_copy_data, - .free_data = vfont_free_data, - .make_local = NULL, - .foreach_id = NULL, - .foreach_cache = NULL, - .owner_get = NULL, - - .blend_write = vfont_blend_write, - .blend_read_data = vfont_blend_read_data, - .blend_read_lib = NULL, - .blend_read_expand = NULL, - - .blend_read_undo_preserve = NULL, - - .lib_override_apply_post = NULL, -}; - -/***************************** VFont *******************************/ - -/* The vfont code */ -void BKE_vfont_free_data(struct VFont *vfont) -{ - if (vfont->data) { - if (vfont->data->characters) { - GHashIterator gh_iter; - GHASH_ITER (gh_iter, vfont->data->characters) { - VChar *che = BLI_ghashIterator_getValue(&gh_iter); - - while (che->nurbsbase.first) { - Nurb *nu = che->nurbsbase.first; - if (nu->bezt) { - MEM_freeN(nu->bezt); - } - BLI_freelinkN(&che->nurbsbase, nu); - } - - MEM_freeN(che); - } - - BLI_ghash_free(vfont->data->characters, NULL, NULL); - } - - MEM_freeN(vfont->data); - vfont->data = NULL; - } - - if (vfont->temp_pf) { - BKE_packedfile_free(vfont->temp_pf); /* NULL when the font file can't be found on disk */ - vfont->temp_pf = NULL; - } -} - -static const void *builtin_font_data = NULL; -static int builtin_font_size = 0; - -bool BKE_vfont_is_builtin(const struct VFont *vfont) -{ - return STREQ(vfont->filepath, FO_BUILTIN_NAME); -} - -void BKE_vfont_builtin_register(const void *mem, int size) -{ - builtin_font_data = mem; - builtin_font_size = size; -} - -static PackedFile *get_builtin_packedfile(void) -{ - if (!builtin_font_data) { - CLOG_ERROR(&LOG, "Internal error, builtin font not loaded"); - - return NULL; - } - - void *mem = MEM_mallocN(builtin_font_size, "vfd_builtin"); - - memcpy(mem, builtin_font_data, builtin_font_size); - - return BKE_packedfile_new_from_memory(mem, builtin_font_size); -} - -static VFontData *vfont_get_data(VFont *vfont) -{ - if (vfont == NULL) { - return NULL; - } - - /* And then set the data */ - if (!vfont->data) { - PackedFile *pf; - - BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE); - - if (vfont->data) { - /* Check data again, since it might have been already - * initialized from other thread (previous check is - * not accurate or threading, just prevents unneeded - * lock if all the data is here for sure). - */ - BLI_rw_mutex_unlock(&vfont_rwlock); - return vfont->data; - } - - if (BKE_vfont_is_builtin(vfont)) { - pf = get_builtin_packedfile(); - } - else { - if (vfont->packedfile) { - pf = vfont->packedfile; - - /* We need to copy a tmp font to memory unless it is already there */ - if (vfont->temp_pf == NULL) { - vfont->temp_pf = BKE_packedfile_duplicate(pf); - } - } - else { - pf = BKE_packedfile_new(NULL, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); - - if (vfont->temp_pf == NULL) { - vfont->temp_pf = BKE_packedfile_new( - NULL, vfont->filepath, ID_BLEND_PATH_FROM_GLOBAL(&vfont->id)); - } - } - if (!pf) { - CLOG_WARN(&LOG, "Font file doesn't exist: %s", vfont->filepath); - - /* DON'T DO THIS - * missing file shouldn't modify path! - campbell */ -#if 0 - strcpy(vfont->filepath, FO_BUILTIN_NAME); -#endif - pf = get_builtin_packedfile(); - } - } - - if (pf) { - vfont->data = BKE_vfontdata_from_freetypefont(pf); - if (pf != vfont->packedfile) { - BKE_packedfile_free(pf); - } - } - - BLI_rw_mutex_unlock(&vfont_rwlock); - } - - return vfont->data; -} - -VFont *BKE_vfont_load(Main *bmain, const char *filepath) -{ - char filename[FILE_MAXFILE]; - VFont *vfont = NULL; - PackedFile *pf; - bool is_builtin; - - if (STREQ(filepath, FO_BUILTIN_NAME)) { - BLI_strncpy(filename, filepath, sizeof(filename)); - - pf = get_builtin_packedfile(); - is_builtin = true; - } - else { - BLI_split_file_part(filepath, filename, sizeof(filename)); - pf = BKE_packedfile_new(NULL, filepath, BKE_main_blendfile_path(bmain)); - - is_builtin = false; - } - - if (pf) { - VFontData *vfd; - - vfd = BKE_vfontdata_from_freetypefont(pf); - if (vfd) { - /* If there's a font name, use it for the ID name. */ - vfont = BKE_libblock_alloc(bmain, ID_VF, vfd->name[0] ? vfd->name : filename, 0); - vfont->data = vfd; - BLI_strncpy(vfont->filepath, filepath, sizeof(vfont->filepath)); - - /* if autopack is on store the packedfile in de font structure */ - if (!is_builtin && (G.fileflags & G_FILE_AUTOPACK)) { - vfont->packedfile = pf; - } - - /* Do not add FO_BUILTIN_NAME to temporary listbase */ - if (!STREQ(filename, FO_BUILTIN_NAME)) { - vfont->temp_pf = BKE_packedfile_new(NULL, filepath, BKE_main_blendfile_path(bmain)); - } - } - - /* Free the packed file */ - if (!vfont || vfont->packedfile != pf) { - BKE_packedfile_free(pf); - } - } - - return vfont; -} - -VFont *BKE_vfont_load_exists_ex(struct Main *bmain, const char *filepath, bool *r_exists) -{ - VFont *vfont; - char str[FILE_MAX], strtest[FILE_MAX]; - - BLI_strncpy(str, filepath, sizeof(str)); - BLI_path_abs(str, BKE_main_blendfile_path(bmain)); - - /* first search an identical filepath */ - for (vfont = bmain->fonts.first; vfont; vfont = vfont->id.next) { - BLI_strncpy(strtest, vfont->filepath, sizeof(vfont->filepath)); - BLI_path_abs(strtest, ID_BLEND_PATH(bmain, &vfont->id)); - - if (BLI_path_cmp(strtest, str) == 0) { - id_us_plus(&vfont->id); /* officially should not, it doesn't link here! */ - if (r_exists) { - *r_exists = true; - } - return vfont; - } - } - - if (r_exists) { - *r_exists = false; - } - return BKE_vfont_load(bmain, filepath); -} - -VFont *BKE_vfont_load_exists(struct Main *bmain, const char *filepath) -{ - return BKE_vfont_load_exists_ex(bmain, filepath, NULL); -} - -static VFont *which_vfont(Curve *cu, CharInfo *info) -{ - switch (info->flag & (CU_CHINFO_BOLD | CU_CHINFO_ITALIC)) { - case CU_CHINFO_BOLD: - return cu->vfontb ? cu->vfontb : cu->vfont; - case CU_CHINFO_ITALIC: - return cu->vfonti ? cu->vfonti : cu->vfont; - case (CU_CHINFO_BOLD | CU_CHINFO_ITALIC): - return cu->vfontbi ? cu->vfontbi : cu->vfont; - default: - return cu->vfont; - } -} - -VFont *BKE_vfont_builtin_get(void) -{ - VFont *vfont; - - for (vfont = G_MAIN->fonts.first; vfont; vfont = vfont->id.next) { - if (BKE_vfont_is_builtin(vfont)) { - return vfont; - } - } - - return BKE_vfont_load(G_MAIN, FO_BUILTIN_NAME); -} - -static VChar *find_vfont_char(VFontData *vfd, unsigned int character) -{ - return BLI_ghash_lookup(vfd->characters, POINTER_FROM_UINT(character)); -} - -static void build_underline(Curve *cu, - ListBase *nubase, - const rctf *rect, - float yofs, - float rot, - int charidx, - short mat_nr, - const float font_size) -{ - Nurb *nu2; - BPoint *bp; - - nu2 = (Nurb *)MEM_callocN(sizeof(Nurb), "underline_nurb"); - nu2->resolu = cu->resolu; - nu2->bezt = NULL; - nu2->knotsu = nu2->knotsv = NULL; - nu2->charidx = charidx + 1000; - if (mat_nr > 0) { - nu2->mat_nr = mat_nr - 1; - } - nu2->pntsu = 4; - nu2->pntsv = 1; - nu2->orderu = 4; - nu2->orderv = 1; - nu2->flagu = CU_NURB_CYCLIC; - - bp = (BPoint *)MEM_calloc_arrayN(4, sizeof(BPoint), "underline_bp"); - - copy_v4_fl4(bp[0].vec, rect->xmin, (rect->ymax + yofs), 0.0f, 1.0f); - copy_v4_fl4(bp[1].vec, rect->xmax, (rect->ymax + yofs), 0.0f, 1.0f); - copy_v4_fl4(bp[2].vec, rect->xmax, (rect->ymin + yofs), 0.0f, 1.0f); - copy_v4_fl4(bp[3].vec, rect->xmin, (rect->ymin + yofs), 0.0f, 1.0f); - - /* Used by curve extrusion. */ - bp[0].radius = bp[1].radius = bp[2].radius = bp[3].radius = 1.0f; - - nu2->bp = bp; - BLI_addtail(nubase, nu2); - - if (rot != 0.0f) { - float si = sinf(rot); - float co = cosf(rot); - - for (int i = nu2->pntsu; i > 0; i--) { - float *fp = bp->vec; - - float x = fp[0] - rect->xmin; - float y = fp[1] - rect->ymin; - - fp[0] = (+co * x + si * y) + rect->xmin; - fp[1] = (-si * x + co * y) + rect->ymin; - - bp++; - } - - bp = nu2->bp; - } - - mul_v2_fl(bp[0].vec, font_size); - mul_v2_fl(bp[1].vec, font_size); - mul_v2_fl(bp[2].vec, font_size); - mul_v2_fl(bp[3].vec, font_size); -} - -void BKE_vfont_build_char(Curve *cu, - ListBase *nubase, - unsigned int character, - CharInfo *info, - float ofsx, - float ofsy, - float rot, - int charidx, - const float fsize) -{ - VFontData *vfd = vfont_get_data(which_vfont(cu, info)); - if (!vfd) { - return; - } - - /* make a copy at distance ofsx, ofsy with shear */ - float shear = cu->shear; - float si = sinf(rot); - float co = cosf(rot); - - VChar *che = find_vfont_char(vfd, character); - - /* Select the glyph data */ - Nurb *nu1 = NULL; - if (che) { - nu1 = che->nurbsbase.first; - } - - /* Create the character */ - while (nu1) { - BezTriple *bezt1 = nu1->bezt; - if (bezt1) { - Nurb *nu2 = (Nurb *)MEM_mallocN(sizeof(Nurb), "duplichar_nurb"); - if (nu2 == NULL) { - break; - } - memcpy(nu2, nu1, sizeof(struct Nurb)); - nu2->resolu = cu->resolu; - nu2->bp = NULL; - nu2->knotsu = nu2->knotsv = NULL; - nu2->flag = CU_SMOOTH; - nu2->charidx = charidx; - if (info->mat_nr > 0) { - nu2->mat_nr = info->mat_nr - 1; - } - else { - nu2->mat_nr = 0; - } - /* nu2->trim.first = 0; */ - /* nu2->trim.last = 0; */ - int u = nu2->pntsu; - - BezTriple *bezt2 = (BezTriple *)MEM_malloc_arrayN(u, sizeof(BezTriple), "duplichar_bezt2"); - if (bezt2 == NULL) { - MEM_freeN(nu2); - break; - } - memcpy(bezt2, bezt1, u * sizeof(struct BezTriple)); - nu2->bezt = bezt2; - - if (shear != 0.0f) { - bezt2 = nu2->bezt; - - for (int i = nu2->pntsu; i > 0; i--) { - bezt2->vec[0][0] += shear * bezt2->vec[0][1]; - bezt2->vec[1][0] += shear * bezt2->vec[1][1]; - bezt2->vec[2][0] += shear * bezt2->vec[2][1]; - bezt2++; - } - } - if (rot != 0.0f) { - bezt2 = nu2->bezt; - for (int i = nu2->pntsu; i > 0; i--) { - float *fp = bezt2->vec[0]; - - float x = fp[0]; - fp[0] = co * x + si * fp[1]; - fp[1] = -si * x + co * fp[1]; - x = fp[3]; - fp[3] = co * x + si * fp[4]; - fp[4] = -si * x + co * fp[4]; - x = fp[6]; - fp[6] = co * x + si * fp[7]; - fp[7] = -si * x + co * fp[7]; - - bezt2++; - } - } - bezt2 = nu2->bezt; - - if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) { - const float sca = cu->smallcaps_scale; - for (int i = nu2->pntsu; i > 0; i--) { - float *fp = bezt2->vec[0]; - fp[0] *= sca; - fp[1] *= sca; - fp[3] *= sca; - fp[4] *= sca; - fp[6] *= sca; - fp[7] *= sca; - bezt2++; - } - } - bezt2 = nu2->bezt; - - for (int i = nu2->pntsu; i > 0; i--) { - float *fp = bezt2->vec[0]; - fp[0] = (fp[0] + ofsx) * fsize; - fp[1] = (fp[1] + ofsy) * fsize; - fp[3] = (fp[3] + ofsx) * fsize; - fp[4] = (fp[4] + ofsy) * fsize; - fp[6] = (fp[6] + ofsx) * fsize; - fp[7] = (fp[7] + ofsy) * fsize; - bezt2++; - } - - BLI_addtail(nubase, nu2); - } - - nu1 = nu1->next; - } -} - -int BKE_vfont_select_get(Object *ob, int *r_start, int *r_end) -{ - Curve *cu = ob->data; - EditFont *ef = cu->editfont; - int start, end, direction; - - if ((ob->type != OB_FONT) || (ef == NULL)) { - return 0; - } - - BLI_assert(ef->len >= 0); - BLI_assert(ef->selstart >= 0 && ef->selstart <= ef->len + 1); - BLI_assert(ef->selend >= 0 && ef->selend <= ef->len + 1); - BLI_assert(ef->pos >= 0 && ef->pos <= ef->len); - - if (ef->selstart == 0) { - return 0; - } - - if (ef->selstart <= ef->selend) { - start = ef->selstart - 1; - end = ef->selend - 1; - direction = 1; - } - else { - start = ef->selend; - end = ef->selstart - 2; - direction = -1; - } - - if (start == end + 1) { - return 0; - } - - BLI_assert(start < end + 1); - *r_start = start; - *r_end = end; - return direction; -} - -void BKE_vfont_select_clamp(Object *ob) -{ - Curve *cu = ob->data; - EditFont *ef = cu->editfont; - - BLI_assert((ob->type == OB_FONT) && ef); - - CLAMP_MAX(ef->pos, ef->len); - CLAMP_MAX(ef->selstart, ef->len + 1); - CLAMP_MAX(ef->selend, ef->len); -} - -static float char_width(Curve *cu, VChar *che, CharInfo *info) -{ - /* The character wasn't found, probably ascii = 0, then the width shall be 0 as well */ - if (che == NULL) { - return 0.0f; - } - if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) { - return che->width * cu->smallcaps_scale; - } - - return che->width; -} - -static void textbox_scale(TextBox *tb_dst, const TextBox *tb_src, float scale) -{ - tb_dst->x = tb_src->x * scale; - tb_dst->y = tb_src->y * scale; - tb_dst->w = tb_src->w * scale; - tb_dst->h = tb_src->h * scale; -} - -/** - * Used for storing per-line data for alignment & wrapping. - */ -struct TempLineInfo { - float x_min; /* left margin */ - float x_max; /* right margin */ - int char_nr; /* number of characters */ - int wspace_nr; /* number of whitespaces of line */ -}; - -/* -------------------------------------------------------------------- */ -/** \name VFont Scale Overflow - * - * Scale the font to fit inside #TextBox bounds. - * - * - Scale horizontally when #TextBox.h is zero, - * otherwise scale vertically, allowing the text to wrap horizontally. - * - Never increase scale to fit, only ever scale on overflow. - * \{ */ - -typedef struct VFontToCurveIter { - int iteraction; - float scale_to_fit; - struct { - float min; - float max; - } bisect; - bool ok; - /** - * Wrap words that extends beyond the text-box width (enabled by default). - * - * Currently only disabled when scale-to-fit is enabled, - * so floating-point error doesn't cause unexpected wrapping, see T89241. - * - * \note This should only be set once, in the #VFONT_TO_CURVE_INIT pass - * otherwise iterations wont behave predictably, see T91401. - */ - bool word_wrap; - int status; -} VFontToCurveIter; - -enum { - VFONT_TO_CURVE_INIT = 0, - VFONT_TO_CURVE_BISECT, - VFONT_TO_CURVE_SCALE_ONCE, - VFONT_TO_CURVE_DONE, -}; - -#define FONT_TO_CURVE_SCALE_ITERATIONS 20 -#define FONT_TO_CURVE_SCALE_THRESHOLD 0.0001f - -/** \} */ - -/** - * Font metric values explained: - * - * Baseline: Line where the text "rests", used as the origin vertical position for the glyphs. - * Em height: Space most glyphs should fit within. - * Ascent: the recommended distance above the baseline to fit most characters. - * Descent: the recommended distance below the baseline to fit most characters. - * - * We obtain ascent and descent from the font itself (FT_Face->ascender / face->height). - * And in some cases it is even the same value as FT_Face->bbox.yMax/yMin - * (font top and bottom respectively). - * - * The em_height here is relative to FT_Face->bbox. - */ - -static float vfont_ascent(const VFontData *vfd) -{ - return vfd->ascender * vfd->em_height; -} -static float vfont_descent(const VFontData *vfd) -{ - return vfd->em_height - vfont_ascent(vfd); -} - -static bool vfont_to_curve(Object *ob, - Curve *cu, - int mode, - VFontToCurveIter *iter_data, - ListBase *r_nubase, - const char32_t **r_text, - int *r_text_len, - bool *r_text_free, - struct CharTrans **r_chartransdata) -{ - EditFont *ef = cu->editfont; - EditFontSelBox *selboxes = NULL; - VFont *vfont, *oldvfont; - VFontData *vfd = NULL; - CharInfo *info = NULL, *custrinfo; - TextBox tb_scale; - bool use_textbox; - VChar *che; - struct CharTrans *chartransdata = NULL, *ct; - struct TempLineInfo *lineinfo; - float *f, xof, yof, xtrax, linedist; - float twidth = 0, maxlen = 0; - int i, slen, j; - int curbox; - int selstart = 0, selend = 0; - int cnr = 0, lnr = 0, wsnr = 0; - const char32_t *mem = NULL; - char32_t ascii; - bool ok = false; - const float font_size = cu->fsize * iter_data->scale_to_fit; - const bool word_wrap = iter_data->word_wrap; - const float xof_scale = safe_divide(cu->xof, font_size); - const float yof_scale = safe_divide(cu->yof, font_size); - int last_line = -1; - /* Length of the text disregarding \n breaks. */ - float current_line_length = 0.0f; - float longest_line_length = 0.0f; - - /* Text at the beginning of the last used text-box (use for y-axis alignment). - * We overallocate by one to simplify logic of getting last char. */ - int *i_textbox_array = MEM_callocN(sizeof(*i_textbox_array) * (cu->totbox + 1), - "TextBox initial char index"); - -#define MARGIN_X_MIN (xof_scale + tb_scale.x) -#define MARGIN_Y_MIN (yof_scale + tb_scale.y) - - /* remark: do calculations including the trailing '\0' of a string - * because the cursor can be at that location */ - - BLI_assert(ob == NULL || ob->type == OB_FONT); - - /* Set font data */ - vfont = cu->vfont; - - if (cu->str == NULL) { - return ok; - } - if (vfont == NULL) { - return ok; - } - - vfd = vfont_get_data(vfont); - - /* The VFont Data can not be found */ - if (!vfd) { - return ok; - } - - if (ef) { - slen = ef->len; - mem = ef->textbuf; - custrinfo = ef->textbufinfo; - } - else { - char32_t *mem_tmp; - slen = cu->len_char32; - - /* Create unicode string */ - mem_tmp = MEM_malloc_arrayN((slen + 1), sizeof(*mem_tmp), "convertedmem"); - if (!mem_tmp) { - return ok; - } - - BLI_str_utf8_as_utf32(mem_tmp, cu->str, slen + 1); - - if (cu->strinfo == NULL) { /* old file */ - cu->strinfo = MEM_calloc_arrayN((slen + 4), sizeof(CharInfo), "strinfo compat"); - } - custrinfo = cu->strinfo; - if (!custrinfo) { - return ok; - } - - mem = mem_tmp; - } - - if (cu->tb == NULL) { - cu->tb = MEM_calloc_arrayN(MAXTEXTBOX, sizeof(TextBox), "TextBox compat"); - } - - if (ef != NULL && ob != NULL) { - if (ef->selboxes) { - MEM_freeN(ef->selboxes); - } - - if (BKE_vfont_select_get(ob, &selstart, &selend)) { - ef->selboxes_len = (selend - selstart) + 1; - ef->selboxes = MEM_calloc_arrayN(ef->selboxes_len, sizeof(EditFontSelBox), "font selboxes"); - } - else { - ef->selboxes_len = 0; - ef->selboxes = NULL; - } - - selboxes = ef->selboxes; - } - - /* calc offset and rotation of each char */ - ct = chartransdata = MEM_calloc_arrayN((slen + 1), sizeof(struct CharTrans), "buildtext"); - - /* We assume the worst case: 1 character per line (is freed at end anyway) */ - lineinfo = MEM_malloc_arrayN((slen * 2 + 1), sizeof(*lineinfo), "lineinfo"); - - linedist = cu->linedist; - - curbox = 0; - textbox_scale(&tb_scale, &cu->tb[curbox], safe_divide(1.0f, font_size)); - use_textbox = (tb_scale.w != 0.0f); - - xof = MARGIN_X_MIN; - yof = MARGIN_Y_MIN; - - xtrax = 0.5f * cu->spacing - 0.5f; - - oldvfont = NULL; - - for (i = 0; i < slen; i++) { - custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK | CU_CHINFO_OVERFLOW); - } - - for (i = 0; i <= slen; i++) { - makebreak: - /* Characters in the list */ - info = &custrinfo[i]; - ascii = mem[i]; - if (info->flag & CU_CHINFO_SMALLCAPS) { - ascii = towupper(ascii); - if (mem[i] != ascii) { - info->flag |= CU_CHINFO_SMALLCAPS_CHECK; - } - } - - vfont = which_vfont(cu, info); - - if (vfont == NULL) { - break; - } - - if (vfont != oldvfont) { - vfd = vfont_get_data(vfont); - oldvfont = vfont; - } - - /* VFont Data for VFont couldn't be found */ - if (!vfd) { - MEM_freeN(chartransdata); - chartransdata = NULL; - MEM_freeN(lineinfo); - goto finally; - } - - if (!ELEM(ascii, '\n', '\0')) { - BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_READ); - che = find_vfont_char(vfd, ascii); - BLI_rw_mutex_unlock(&vfont_rwlock); - - /* - * The character wasn't in the current curve base so load it - * But if the font is built-in then do not try loading since - * whole font is in the memory already - */ - if (che == NULL && BKE_vfont_is_builtin(vfont) == false) { - BLI_rw_mutex_lock(&vfont_rwlock, THREAD_LOCK_WRITE); - /* Check it once again, char might have been already load - * between previous BLI_rw_mutex_unlock() and this BLI_rw_mutex_lock(). - * - * Such a check should not be a bottleneck since it wouldn't - * happen often once all the chars are load. - */ - if ((che = find_vfont_char(vfd, ascii)) == NULL) { - che = BKE_vfontdata_char_from_freetypefont(vfont, ascii); - } - BLI_rw_mutex_unlock(&vfont_rwlock); - } - } - else { - che = NULL; - } - - twidth = char_width(cu, che, info); - - /* Calculate positions. */ - - if ((tb_scale.w != 0.0f) && (ct->dobreak == 0)) { /* May need wrapping. */ - const float x_available = xof_scale + tb_scale.w; - const float x_used = (xof - tb_scale.x) + twidth; - - if (word_wrap == false) { - /* When scale to fit is used, don't do any wrapping. - * - * Floating precision error can cause the text to be slightly larger. - * Assert this is a small value as large values indicate incorrect - * calculations with scale-to-fit which shouldn't be ignored. See T89241. */ - if (x_used > x_available) { - BLI_assert_msg(compare_ff_relative(x_used, x_available, FLT_EPSILON, 64), - "VFontToCurveIter.scale_to_fit not set correctly!"); - } - } - else if (x_used > x_available) { - // CLOG_WARN(&LOG, "linewidth exceeded: %c%c%c...", mem[i], mem[i+1], mem[i+2]); - for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) { - bool dobreak = false; - if (ELEM(mem[j], ' ', '-')) { - ct -= (i - (j - 1)); - cnr -= (i - (j - 1)); - if (mem[j] == ' ') { - wsnr--; - } - if (mem[j] == '-') { - wsnr++; - } - i = j - 1; - xof = ct->xof; - ct[1].dobreak = 1; - custrinfo[i + 1].flag |= CU_CHINFO_WRAP; - dobreak = true; - } - else if (chartransdata[j].dobreak) { - // CLOG_WARN(&LOG, "word too long: %c%c%c...", mem[j], mem[j+1], mem[j+2]); - ct->dobreak = 1; - custrinfo[i + 1].flag |= CU_CHINFO_WRAP; - ct -= 1; - cnr -= 1; - i--; - xof = ct->xof; - dobreak = true; - } - if (dobreak) { - if (tb_scale.h == 0.0f) { - /* NOTE: If underlined text is truncated away, the extra space is also truncated. */ - custrinfo[i + 1].flag |= CU_CHINFO_OVERFLOW; - } - goto makebreak; - } - } - } - } - - if (ascii == '\n' || ascii == 0 || ct->dobreak) { - ct->xof = xof; - ct->yof = yof; - ct->linenr = lnr; - ct->charnr = cnr; - - yof -= linedist; - - lineinfo[lnr].x_min = (xof - xtrax) - tb_scale.x; - lineinfo[lnr].x_max = tb_scale.w; - lineinfo[lnr].char_nr = cnr; - lineinfo[lnr].wspace_nr = wsnr; - - CLAMP_MIN(maxlen, lineinfo[lnr].x_min); - - if ((tb_scale.h != 0.0f) && ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale)) { - if (cu->totbox > (curbox + 1)) { - maxlen = 0; - curbox++; - i_textbox_array[curbox] = i + 1; - - textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size); - - yof = MARGIN_Y_MIN; - } - else if (last_line == -1) { - last_line = lnr + 1; - info->flag |= CU_CHINFO_OVERFLOW; - } - } - - current_line_length += xof - MARGIN_X_MIN; - if (ct->dobreak) { - current_line_length += twidth; - } - else { - longest_line_length = MAX2(current_line_length, longest_line_length); - current_line_length = 0.0f; - } - - /* XXX(campbell): has been unused for years, need to check if this is useful, r4613 r5282. */ -#if 0 - if (ascii == '\n') { - xof = xof_scale; - } - else { - xof = MARGIN_X_MIN; - } -#else - xof = MARGIN_X_MIN; -#endif - lnr++; - cnr = 0; - wsnr = 0; - } - else if (ascii == 9) { /* TAB */ - float tabfac; - - ct->xof = xof; - ct->yof = yof; - ct->linenr = lnr; - ct->charnr = cnr++; - - tabfac = (xof - MARGIN_X_MIN + 0.01f); - tabfac = 2.0f * ceilf(tabfac / 2.0f); - xof = MARGIN_X_MIN + tabfac; - } - else { - EditFontSelBox *sb = NULL; - float wsfac; - - ct->xof = xof; - ct->yof = yof; - ct->linenr = lnr; - ct->charnr = cnr++; - - if (selboxes && (i >= selstart) && (i <= selend)) { - sb = &selboxes[i - selstart]; - sb->y = yof * font_size - linedist * font_size * 0.1f; - sb->h = linedist * font_size; - sb->w = xof * font_size; - } - - if (ascii == 32) { - wsfac = cu->wordspace; - wsnr++; - } - else { - wsfac = 1.0f; - } - - /* Set the width of the character */ - twidth = char_width(cu, che, info); - - xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f))) + xtrax; - - if (sb) { - sb->w = (xof * font_size) - sb->w; - } - } - ct++; - } - current_line_length += xof + twidth - MARGIN_X_MIN; - longest_line_length = MAX2(current_line_length, longest_line_length); - - cu->lines = 1; - for (i = 0; i <= slen; i++) { - ascii = mem[i]; - ct = &chartransdata[i]; - if (ascii == '\n' || ct->dobreak) { - cu->lines++; - } - } - - /* linedata is now: width of line */ - - if (cu->spacemode != CU_ALIGN_X_LEFT) { - ct = chartransdata; - - if (cu->spacemode == CU_ALIGN_X_RIGHT) { - struct TempLineInfo *li; - - for (i = 0, li = lineinfo; i < lnr; i++, li++) { - li->x_min = (li->x_max - li->x_min) + xof_scale; - } - - for (i = 0; i <= slen; i++) { - ct->xof += lineinfo[ct->linenr].x_min; - ct++; - } - } - else if (cu->spacemode == CU_ALIGN_X_MIDDLE) { - struct TempLineInfo *li; - - for (i = 0, li = lineinfo; i < lnr; i++, li++) { - li->x_min = ((li->x_max - li->x_min) + xof_scale) / 2.0f; - } - - for (i = 0; i <= slen; i++) { - ct->xof += lineinfo[ct->linenr].x_min; - ct++; - } - } - else if ((cu->spacemode == CU_ALIGN_X_FLUSH) && use_textbox) { - struct TempLineInfo *li; - - for (i = 0, li = lineinfo; i < lnr; i++, li++) { - li->x_min = ((li->x_max - li->x_min) + xof_scale); - - if (li->char_nr > 1) { - li->x_min /= (float)(li->char_nr - 1); - } - } - for (i = 0; i <= slen; i++) { - for (j = i; (!ELEM(mem[j], '\0', '\n')) && (chartransdata[j].dobreak == 0) && (j < slen); - j++) { - /* do nothing */ - } - - // if ((mem[j] != '\n') && (mem[j])) { - ct->xof += ct->charnr * lineinfo[ct->linenr].x_min; - // } - ct++; - } - } - else if ((cu->spacemode == CU_ALIGN_X_JUSTIFY) && use_textbox) { - float curofs = 0.0f; - for (i = 0; i <= slen; i++) { - for (j = i; (mem[j]) && (mem[j] != '\n') && (chartransdata[j].dobreak == 0) && (j < slen); - j++) { - /* pass */ - } - - if ((mem[j] != '\n') && ((chartransdata[j].dobreak != 0))) { - if (mem[i] == ' ') { - struct TempLineInfo *li; - - li = &lineinfo[ct->linenr]; - curofs += ((li->x_max - li->x_min) + xof_scale) / (float)li->wspace_nr; - } - ct->xof += curofs; - } - if (mem[i] == '\n' || chartransdata[i].dobreak) { - curofs = 0; - } - ct++; - } - } - } - - /* top-baseline is default, in this case, do nothing */ - if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) { - if (tb_scale.h != 0.0f) { - /* We need to loop all the text-boxes even the "full" ones. - * This way they all get the same vertical padding. */ - for (int tb_index = 0; tb_index < cu->totbox; tb_index++) { - struct CharTrans *ct_first, *ct_last; - const int i_textbox = i_textbox_array[tb_index]; - const int i_textbox_next = i_textbox_array[tb_index + 1]; - const bool is_last_filled_textbox = ELEM(i_textbox_next, 0, slen + 1); - int lines; - - ct_first = chartransdata + i_textbox; - ct_last = chartransdata + (is_last_filled_textbox ? slen : i_textbox_next - 1); - lines = ct_last->linenr - ct_first->linenr + 1; - - if (cu->overflow == CU_OVERFLOW_TRUNCATE) { - /* Ensure overflow doesn't truncate text, before centering vertically - * giving odd/buggy results, see: T66614. */ - if ((tb_index == cu->totbox - 1) && (last_line != -1)) { - lines = last_line - ct_first->linenr; - } - } - - textbox_scale(&tb_scale, &cu->tb[tb_index], 1.0f / font_size); - /* The initial Y origin of the textbox is hardcoded to 1.0f * text scale. */ - const float textbox_y_origin = 1.0f; - float yoff = 0.0f; - - switch (cu->align_y) { - case CU_ALIGN_Y_TOP_BASELINE: - break; - case CU_ALIGN_Y_TOP: - yoff = textbox_y_origin - vfont_ascent(vfd); - break; - case CU_ALIGN_Y_CENTER: - yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - vfont_ascent(vfd)) - - (tb_scale.h * 0.5f) + textbox_y_origin); - break; - case CU_ALIGN_Y_BOTTOM_BASELINE: - yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h; - break; - case CU_ALIGN_Y_BOTTOM: - yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.h + vfont_descent(vfd); - break; - } - - for (ct = ct_first; ct <= ct_last; ct++) { - ct->yof += yoff; - } - - if (is_last_filled_textbox) { - break; - } - } - } - else { - /* Non text-box case handled separately. */ - float yoff = 0.0f; - - switch (cu->align_y) { - case CU_ALIGN_Y_TOP_BASELINE: - break; - case CU_ALIGN_Y_TOP: - yoff = -vfont_ascent(vfd); - break; - case CU_ALIGN_Y_CENTER: - yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - vfont_ascent(vfd); - break; - case CU_ALIGN_Y_BOTTOM_BASELINE: - yoff = (lnr - 1) * linedist; - break; - case CU_ALIGN_Y_BOTTOM: - yoff = (lnr - 1) * linedist + vfont_descent(vfd); - break; - } - - ct = chartransdata; - for (i = 0; i <= slen; i++) { - ct->yof += yoff; - ct++; - } - } - } - - MEM_freeN(lineinfo); - MEM_freeN(i_textbox_array); - - /* TEXT ON CURVE */ - /* NOTE: Only OB_CURVE objects could have a path. */ - if (cu->textoncurve && cu->textoncurve->type == OB_CURVE) { - BLI_assert(cu->textoncurve->runtime.curve_cache != NULL); - if (cu->textoncurve->runtime.curve_cache != NULL && - cu->textoncurve->runtime.curve_cache->anim_path_accum_length != NULL) { - float distfac, imat[4][4], imat3[3][3], cmat[3][3]; - float minx, maxx; - float timeofs, sizefac; - - if (ob != NULL) { - invert_m4_m4(imat, ob->obmat); - } - else { - unit_m4(imat); - } - copy_m3_m4(imat3, imat); - - copy_m3_m4(cmat, cu->textoncurve->obmat); - mul_m3_m3m3(cmat, cmat, imat3); - sizefac = normalize_v3(cmat[0]) / font_size; - - ct = chartransdata; - minx = maxx = ct->xof; - ct++; - for (i = 1; i <= slen; i++, ct++) { - if (minx > ct->xof) { - minx = ct->xof; - } - if (maxx < ct->xof) { - maxx = ct->xof; - } - } - - /* We put the x-coordinate exact at the curve, the y is rotated. */ - - /* length correction */ - const float chartrans_size_x = maxx - minx; - if (chartrans_size_x != 0.0f) { - const CurveCache *cc = cu->textoncurve->runtime.curve_cache; - const float totdist = BKE_anim_path_get_length(cc); - distfac = (sizefac * totdist) / chartrans_size_x; - distfac = (distfac > 1.0f) ? (1.0f / distfac) : 1.0f; - } - else { - /* Happens when there are no characters, set this value to place the text cursor. */ - distfac = 0.0f; - } - - timeofs = 0.0f; - - if (distfac < 1.0f) { - /* Path longer than text: space-mode is involved. */ - - if (cu->spacemode == CU_ALIGN_X_RIGHT) { - timeofs = 1.0f - distfac; - } - else if (cu->spacemode == CU_ALIGN_X_MIDDLE) { - timeofs = (1.0f - distfac) / 2.0f; - } - else if (cu->spacemode == CU_ALIGN_X_FLUSH) { - distfac = 1.0f; - } - } - - if (chartrans_size_x != 0.0f) { - distfac /= chartrans_size_x; - } - - timeofs += distfac * cu->xof; /* not cyclic */ - - ct = chartransdata; - for (i = 0; i <= slen; i++, ct++) { - float ctime, dtime, vec[4], tvec[4], rotvec[3]; - float si, co; - - /* Rotate around center character. */ - info = &custrinfo[i]; - ascii = mem[i]; - if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) { - ascii = towupper(ascii); - } - - che = find_vfont_char(vfd, ascii); - - twidth = char_width(cu, che, info); - - dtime = distfac * 0.5f * twidth; - - ctime = timeofs + distfac * (ct->xof - minx); - CLAMP(ctime, 0.0f, 1.0f); - - /* calc the right loc AND the right rot separately */ - /* vec, tvec need 4 items */ - BKE_where_on_path(cu->textoncurve, ctime, vec, tvec, NULL, NULL, NULL); - BKE_where_on_path(cu->textoncurve, ctime + dtime, tvec, rotvec, NULL, NULL, NULL); - - mul_v3_fl(vec, sizefac); - - ct->rot = (float)M_PI - atan2f(rotvec[1], rotvec[0]); - - si = sinf(ct->rot); - co = cosf(ct->rot); - - yof = ct->yof; - - ct->xof = vec[0] + si * yof; - ct->yof = vec[1] + co * yof; - - if (selboxes && (i >= selstart) && (i <= selend)) { - EditFontSelBox *sb; - sb = &selboxes[i - selstart]; - sb->rot = -ct->rot; - } - } - } - } - - if (selboxes) { - ct = chartransdata; - for (i = 0; i <= selend; i++, ct++) { - if (i >= selstart) { - selboxes[i - selstart].x = ct->xof * font_size; - selboxes[i - selstart].y = ct->yof * font_size; - } - } - } - - if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) && - iter_data->status == VFONT_TO_CURVE_INIT) { - ct = &chartransdata[ef->pos]; - - if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) { - /* pass */ - } - else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) { - /* pass */ - } - else { - switch (mode) { - case FO_CURSUP: - lnr = ct->linenr - 1; - break; - case FO_CURSDOWN: - lnr = ct->linenr + 1; - break; - case FO_PAGEUP: - lnr = ct->linenr - 10; - break; - case FO_PAGEDOWN: - lnr = ct->linenr + 10; - break; - } - cnr = ct->charnr; - /* seek for char with lnr en cnr */ - ef->pos = 0; - ct = chartransdata; - for (i = 0; i < slen; i++) { - if (ct->linenr == lnr) { - if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) { - break; - } - } - else if (ct->linenr > lnr) { - break; - } - ef->pos++; - ct++; - } - } - } - - /* cursor first */ - if (ef) { - float si, co; - - ct = &chartransdata[ef->pos]; - si = sinf(ct->rot); - co = cosf(ct->rot); - - f = ef->textcurs[0]; - - f[0] = font_size * (-0.1f * co + ct->xof); - f[1] = font_size * (0.1f * si + ct->yof); - - f[2] = font_size * (0.1f * co + ct->xof); - f[3] = font_size * (-0.1f * si + ct->yof); - - f[4] = font_size * (0.1f * co + 0.8f * si + ct->xof); - f[5] = font_size * (-0.1f * si + 0.8f * co + ct->yof); - - f[6] = font_size * (-0.1f * co + 0.8f * si + ct->xof); - f[7] = font_size * (0.1f * si + 0.8f * co + ct->yof); - } - - if (mode == FO_SELCHANGE) { - MEM_freeN(chartransdata); - chartransdata = NULL; - } - else if (mode == FO_EDIT) { - /* make nurbdata */ - BKE_nurbList_free(r_nubase); - - ct = chartransdata; - for (i = 0; i < slen; i++) { - unsigned int cha = (unsigned int)mem[i]; - info = &(custrinfo[i]); - - if ((cu->overflow == CU_OVERFLOW_TRUNCATE) && (ob && ob->mode != OB_MODE_EDIT) && - (info->flag & CU_CHINFO_OVERFLOW)) { - break; - } - - if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) { - cha = towupper(cha); - } - - /* Only do that check in case we do have an object, otherwise all materials get erased every - * time that code is called without an object... */ - if (ob != NULL && (info->mat_nr > (ob->totcol))) { - // CLOG_ERROR( - // &LOG, "Illegal material index (%d) in text object, setting to 0", info->mat_nr); - info->mat_nr = 0; - } - /* We do not want to see any character for \n or \r */ - if (cha != '\n') { - BKE_vfont_build_char(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i, font_size); - } - - if ((info->flag & CU_CHINFO_UNDERLINE) && (cha != '\n')) { - float ulwidth, uloverlap = 0.0f; - rctf rect; - - if ((i < (slen - 1)) && (mem[i + 1] != '\n') && - ((mem[i + 1] != ' ') || (custrinfo[i + 1].flag & CU_CHINFO_UNDERLINE)) && - ((custrinfo[i + 1].flag & CU_CHINFO_WRAP) == 0)) { - uloverlap = xtrax + 0.1f; - } - /* Find the character, the characters has to be in the memory already - * since character checking has been done earlier already. */ - che = find_vfont_char(vfd, cha); - - twidth = char_width(cu, che, info); - ulwidth = (twidth * (1.0f + (info->kern / 40.0f))) + uloverlap; - - rect.xmin = ct->xof; - rect.xmax = rect.xmin + ulwidth; - - rect.ymin = ct->yof; - rect.ymax = rect.ymin - cu->ulheight; - - build_underline( - cu, r_nubase, &rect, cu->ulpos - 0.05f, ct->rot, i, info->mat_nr, font_size); - } - ct++; - } - } - - if (iter_data->status == VFONT_TO_CURVE_SCALE_ONCE) { - /* That means we were in a final run, just exit. */ - BLI_assert(cu->overflow == CU_OVERFLOW_SCALE); - iter_data->status = VFONT_TO_CURVE_DONE; - } - else if (cu->overflow == CU_OVERFLOW_NONE) { - /* Do nothing. */ - } - else if ((tb_scale.h == 0.0f) && (tb_scale.w == 0.0f)) { - /* Do nothing. */ - } - else if (cu->overflow == CU_OVERFLOW_SCALE) { - if ((cu->totbox == 1) && ((tb_scale.w == 0.0f) || (tb_scale.h == 0.0f))) { - /* These are special cases, simpler to deal with. */ - if (tb_scale.w == 0.0f) { - /* This is a potential vertical overflow. - * Since there is no width limit, all the new lines are from line breaks. */ - if ((last_line != -1) && (lnr > last_line)) { - const float total_text_height = lnr * linedist; - iter_data->scale_to_fit = tb_scale.h / total_text_height; - iter_data->status = VFONT_TO_CURVE_SCALE_ONCE; - iter_data->word_wrap = false; - } - } - else if (tb_scale.h == 0.0f) { - /* This is a horizontal overflow. */ - if (longest_line_length > tb_scale.w) { - /* We make sure longest line before it broke can fit here. */ - float scale_to_fit = tb_scale.w / longest_line_length; - - iter_data->scale_to_fit = scale_to_fit; - iter_data->status = VFONT_TO_CURVE_SCALE_ONCE; - iter_data->word_wrap = false; - } - } - } - else { - /* This is the really complicated case, the best we can do is to iterate over - * this function a few times until we get an acceptable result. - * - * Keep in mind that there is no single number that will make all fit to the end. - * In a way, our ultimate goal is to get the highest scale that still leads to the - * number of extra lines to zero. - */ - if (iter_data->status == VFONT_TO_CURVE_INIT) { - bool valid = true; - - for (int tb_index = 0; tb_index <= curbox; tb_index++) { - TextBox *tb = &cu->tb[tb_index]; - if ((tb->w == 0.0f) || (tb->h == 0.0f)) { - valid = false; - break; - } - } - - if (valid && (last_line != -1) && (lnr > last_line)) { - const float total_text_height = lnr * linedist; - float scale_to_fit = tb_scale.h / total_text_height; - - iter_data->bisect.max = 1.0f; - iter_data->bisect.min = scale_to_fit; - - iter_data->status = VFONT_TO_CURVE_BISECT; - } - } - else { - BLI_assert(iter_data->status == VFONT_TO_CURVE_BISECT); - /* Try to get the highest scale that gives us the exactly - * number of lines we need. */ - bool valid = false; - - if ((last_line != -1) && (lnr > last_line)) { - /* It is overflowing, scale it down. */ - iter_data->bisect.max = iter_data->scale_to_fit; - } - else { - /* It fits inside the textbox, scale it up. */ - iter_data->bisect.min = iter_data->scale_to_fit; - valid = true; - } - - /* Bisecting to try to find the best fit. */ - iter_data->scale_to_fit = (iter_data->bisect.max + iter_data->bisect.min) * 0.5f; - - /* We iterated enough or got a good enough result. */ - if ((!iter_data->iteraction--) || ((iter_data->bisect.max - iter_data->bisect.min) < - (cu->fsize * FONT_TO_CURVE_SCALE_THRESHOLD))) { - if (valid) { - iter_data->status = VFONT_TO_CURVE_DONE; - } - else { - iter_data->scale_to_fit = iter_data->bisect.min; - iter_data->status = VFONT_TO_CURVE_SCALE_ONCE; - } - } - } - } - } - - /* Scale to fit only works for single text box layouts. */ - if (ELEM(iter_data->status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT)) { - /* Always cleanup before going to the scale-to-fit repetition. */ - if (r_nubase != NULL) { - BKE_nurbList_free(r_nubase); - } - - if (chartransdata != NULL) { - MEM_freeN(chartransdata); - } - - if (ef == NULL) { - MEM_freeN((void *)mem); - } - return true; - } - - ok = true; -finally: - if (r_text) { - *r_text = mem; - *r_text_len = slen; - *r_text_free = (ef == NULL); - } - else { - if (ef == NULL) { - MEM_freeN((void *)mem); - } - } - - if (chartransdata) { - if (ok && r_chartransdata) { - *r_chartransdata = chartransdata; - } - else { - MEM_freeN(chartransdata); - } - } - - /* Store the effective scale, to use for the textbox lines. */ - cu->fsize_realtime = font_size; - - return ok; - -#undef MARGIN_X_MIN -#undef MARGIN_Y_MIN -} - -#undef DESCENT -#undef ASCENT - -bool BKE_vfont_to_curve_ex(Object *ob, - Curve *cu, - int mode, - ListBase *r_nubase, - const char32_t **r_text, - int *r_text_len, - bool *r_text_free, - struct CharTrans **r_chartransdata) -{ - VFontToCurveIter data = { - .iteraction = cu->totbox * FONT_TO_CURVE_SCALE_ITERATIONS, - .scale_to_fit = 1.0f, - .word_wrap = true, - .ok = true, - .status = VFONT_TO_CURVE_INIT, - }; - - do { - data.ok &= vfont_to_curve( - ob, cu, mode, &data, r_nubase, r_text, r_text_len, r_text_free, r_chartransdata); - } while (data.ok && ELEM(data.status, VFONT_TO_CURVE_SCALE_ONCE, VFONT_TO_CURVE_BISECT)); - - return data.ok; -} - -#undef FONT_TO_CURVE_SCALE_ITERATIONS -#undef FONT_TO_CURVE_SCALE_THRESHOLD - -bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase) -{ - BLI_assert(ob->type == OB_FONT); - - return BKE_vfont_to_curve_ex(ob, ob->data, mode, r_nubase, NULL, NULL, NULL, NULL); -} - -/** - * Warning: expects to have access to evaluated data - * (i.e. passed object should be evaluated one...). - */ -bool BKE_vfont_to_curve(Object *ob, int mode) -{ - Curve *cu = ob->data; - - return BKE_vfont_to_curve_ex(ob, ob->data, mode, &cu->nurb, NULL, NULL, NULL, NULL); -} - -/* -------------------------------------------------------------------- */ -/** \name VFont Clipboard - * \{ */ - -static struct { - char32_t *text_buffer; - CharInfo *info_buffer; - size_t len_utf32; - size_t len_utf8; -} g_vfont_clipboard = {NULL}; - -void BKE_vfont_clipboard_free(void) -{ - MEM_SAFE_FREE(g_vfont_clipboard.text_buffer); - MEM_SAFE_FREE(g_vfont_clipboard.info_buffer); - g_vfont_clipboard.len_utf32 = 0; - g_vfont_clipboard.len_utf8 = 0; -} - -void BKE_vfont_clipboard_set(const char32_t *text_buf, const CharInfo *info_buf, const size_t len) -{ - char32_t *text; - CharInfo *info; - - /* Clean previous buffers. */ - BKE_vfont_clipboard_free(); - - text = MEM_malloc_arrayN((len + 1), sizeof(*text), __func__); - if (text == NULL) { - return; - } - - info = MEM_malloc_arrayN(len, sizeof(CharInfo), __func__); - if (info == NULL) { - MEM_freeN(text); - return; - } - - memcpy(text, text_buf, len * sizeof(*text)); - text[len] = '\0'; - memcpy(info, info_buf, len * sizeof(CharInfo)); - - /* store new buffers */ - g_vfont_clipboard.text_buffer = text; - g_vfont_clipboard.info_buffer = info; - g_vfont_clipboard.len_utf8 = BLI_str_utf32_as_utf8_len(text); - g_vfont_clipboard.len_utf32 = len; -} - -void BKE_vfont_clipboard_get(char32_t **r_text_buf, - CharInfo **r_info_buf, - size_t *r_len_utf8, - size_t *r_len_utf32) -{ - if (r_text_buf) { - *r_text_buf = g_vfont_clipboard.text_buffer; - } - - if (r_info_buf) { - *r_info_buf = g_vfont_clipboard.info_buffer; - } - - if (r_len_utf32) { - *r_len_utf32 = g_vfont_clipboard.len_utf32; - } - - if (r_len_utf8) { - *r_len_utf8 = g_vfont_clipboard.len_utf8; - } -} - -/** \} */ |