Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenkernel/intern/font.c')
-rw-r--r--source/blender/blenkernel/intern/font.c437
1 files changed, 346 insertions, 91 deletions
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c
index 6c716e58e23..d796110f185 100644
--- a/source/blender/blenkernel/intern/font.c
+++ b/source/blender/blenkernel/intern/font.c
@@ -362,7 +362,8 @@ static VChar *find_vfont_char(VFontData *vfd, unsigned int character)
}
static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
- float yofs, float rot, int charidx, short mat_nr)
+ float yofs, float rot, int charidx, short mat_nr,
+ const float font_size)
{
Nurb *nu2;
BPoint *bp;
@@ -415,18 +416,19 @@ static void build_underline(Curve *cu, ListBase *nubase, const rctf *rect,
bp = nu2->bp;
}
- mul_v2_fl(bp[0].vec, cu->fsize);
- mul_v2_fl(bp[1].vec, cu->fsize);
- mul_v2_fl(bp[2].vec, cu->fsize);
- mul_v2_fl(bp[3].vec, cu->fsize);
+ 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);
}
static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharInfo *info,
- float ofsx, float ofsy, float rot, int charidx)
+ float ofsx, float ofsy, float rot, int charidx,
+ const float fsize)
{
BezTriple *bezt1, *bezt2;
Nurb *nu1 = NULL, *nu2 = NULL;
- float *fp, fsize, shear, x, si, co;
+ float *fp, shear, x, si, co;
VFontData *vfd = NULL;
VChar *che = NULL;
int i;
@@ -446,7 +448,6 @@ static void buildchar(Curve *cu, ListBase *nubase, unsigned int character, CharI
#endif
/* make a copy at distance ofsx, ofsy with shear */
- fsize = cu->fsize;
shear = cu->shear;
si = sinf(rot);
co = cosf(rot);
@@ -633,7 +634,46 @@ struct TempLineInfo {
int wspace_nr; /* number of whitespaces of line */
};
-bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
+typedef struct VFontToCurveIter {
+ int iteraction;
+ float scale_to_fit;
+ struct {
+ float min;
+ float max;
+ } bisect;
+ bool ok;
+ 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.
+*/
+#define ASCENT(vfd) ((vfd)->ascender * (vfd)->em_height)
+#define DESCENT(vfd) ((vfd)->em_height - ASCENT(vfd))
+
+static bool vfont_to_curve(Object *ob, Curve *cu, int mode,
+ VFontToCurveIter *iter_data,
+ ListBase *r_nubase,
const wchar_t **r_text, int *r_text_len, bool *r_text_free,
struct CharTrans **r_chartransdata)
{
@@ -646,20 +686,27 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
bool use_textbox;
VChar *che;
struct CharTrans *chartransdata = NULL, *ct;
- /* Text at the beginning of the last used text-box (use for y-axis alignment). */
- int i_textbox = 0;
struct TempLineInfo *lineinfo;
float *f, xof, yof, xtrax, linedist;
- float twidth, maxlen = 0;
+ float twidth = 0, maxlen = 0;
int i, slen, j;
int curbox;
int selstart, selend;
int cnr = 0, lnr = 0, wsnr = 0;
- const wchar_t *mem;
+ const wchar_t *mem = NULL;
wchar_t ascii;
bool ok = false;
- const float xof_scale = cu->xof / cu->fsize;
- const float yof_scale = cu->yof / cu->fsize;
+ const float font_size = cu->fsize * iter_data->scale_to_fit;
+ const float xof_scale = cu->xof / font_size;
+ const float yof_scale = 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)
@@ -736,7 +783,7 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
linedist = cu->linedist;
curbox = 0;
- textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
use_textbox = (tb_scale.w != 0.0f);
@@ -748,7 +795,7 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase,
oldvfont = NULL;
for (i = 0; i < slen; i++) {
- custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK);
+ custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK | CU_CHINFO_OVERFLOW);
}
for (i = 0; i <= slen; i++) {
@@ -817,6 +864,7 @@ makebreak:
{
// fprintf(stderr, "linewidth exceeded: %c%c%c...\n", mem[i], mem[i+1], mem[i+2]);
for (j = i; j && (mem[j] != '\n') && (chartransdata[j].dobreak == 0); j--) {
+ bool dobreak = false;
if (mem[j] == ' ' || mem[j] == '-') {
ct -= (i - (j - 1));
cnr -= (i - (j - 1));
@@ -826,9 +874,9 @@ makebreak:
xof = ct->xof;
ct[1].dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
- goto makebreak;
+ dobreak = true;
}
- if (chartransdata[j].dobreak) {
+ else if (chartransdata[j].dobreak) {
// fprintf(stderr, "word too long: %c%c%c...\n", mem[j], mem[j+1], mem[j+2]);
ct->dobreak = 1;
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
@@ -836,6 +884,13 @@ makebreak:
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;
}
}
@@ -857,16 +912,30 @@ makebreak:
CLAMP_MIN(maxlen, lineinfo[lnr].x_min);
if ((tb_scale.h != 0.0f) &&
- (cu->totbox > (curbox + 1)) &&
((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale))
{
- i_textbox = i + 1;
- maxlen = 0;
- curbox++;
+ if (cu->totbox > (curbox + 1)) {
+ maxlen = 0;
+ curbox++;
+ i_textbox_array[curbox] = i + 1;
- textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize);
+ textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / font_size);
- yof = MARGIN_Y_MIN;
+ yof = MARGIN_Y_MIN;
+ }
+ else if (last_line == -1) {
+ last_line = lnr + 1;
+ info->flag |= CU_CHINFO_OVERFLOW;
+ }
+ }
+
+ current_line_length += xof;
+ if (ct->dobreak) {
+ current_line_length += twidth;
+ }
+ else {
+ longest_line_length = MAX2(current_line_length, longest_line_length);
+ current_line_length = 0.0f;
}
/* XXX, has been unused for years, need to check if this is useful, r4613 r5282 - campbell */
@@ -905,9 +974,9 @@ makebreak:
if (selboxes && (i >= selstart) && (i <= selend)) {
sb = &selboxes[i - selstart];
- sb->y = yof * cu->fsize - linedist * cu->fsize * 0.1f;
- sb->h = linedist * cu->fsize;
- sb->w = xof * cu->fsize;
+ sb->y = yof * font_size - linedist * font_size * 0.1f;
+ sb->h = linedist * font_size;
+ sb->w = xof * font_size;
}
if (ascii == 32) {
@@ -924,11 +993,13 @@ makebreak:
xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f)) ) + xtrax;
if (sb) {
- sb->w = (xof * cu->fsize) - sb->w;
+ sb->w = (xof * font_size) - sb->w;
}
}
ct++;
}
+ current_line_length += xof + twidth;
+ longest_line_length = MAX2(current_line_length, longest_line_length);
cu->lines = 1;
for (i = 0; i <= slen; i++) {
@@ -1017,50 +1088,73 @@ makebreak:
/* top-baseline is default, in this case, do nothing */
if (cu->align_y != CU_ALIGN_Y_TOP_BASELINE) {
if (tb_scale.h != 0.0f) {
- /* top and top-baseline are the same when text-boxes are used */
- if (cu->align_y != CU_ALIGN_Y_TOP && i_textbox < slen) {
- /* all previous textboxes are 'full', only align the last used text-box */
- float yoff;
+ /* 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;
- struct CharTrans *ct_last, *ct_textbox;
- ct_last = chartransdata + slen - 1;
- ct_textbox = chartransdata + i_textbox;
+ 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;
- lines = ct_last->linenr - ct_textbox->linenr + 1;
- if (mem[slen - 1] == '\n') {
- lines++;
- }
+ 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;
- if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
- yoff = (lines * linedist) - tb_scale.h;
- }
- else if (cu->align_y == CU_ALIGN_Y_CENTER) {
- yoff = 0.5f * ((lines * linedist) - tb_scale.h);
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = textbox_y_origin - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((((vfd->em_height + (lines - 1) * linedist) * 0.5f) - 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 + DESCENT(vfd);
+ break;
}
- ct = ct_textbox;
- for (i = i_textbox - 1; i < slen; i++) {
+ for (ct = ct_first; ct <= ct_last; ct++) {
ct->yof += yoff;
- ct++;
+ }
+
+ if (is_last_filled_textbox) {
+ break;
}
}
}
else {
- /* non text-box case handled separately */
- ct = chartransdata;
- float yoff;
+ /* Non text-box case handled separately. */
+ float yoff = 0.0f;
- if (cu->align_y == CU_ALIGN_Y_TOP) {
- yoff = -linedist;
- }
- else if (cu->align_y == CU_ALIGN_Y_BOTTOM) {
- yoff = (lnr - 1.0f) * linedist;
- }
- else if (cu->align_y == CU_ALIGN_Y_CENTER) {
- yoff = (lnr - 2.0f) * linedist * 0.5f;
+ switch (cu->align_y) {
+ case CU_ALIGN_Y_TOP_BASELINE:
+ break;
+ case CU_ALIGN_Y_TOP:
+ yoff = -ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_CENTER:
+ yoff = ((vfd->em_height + (lnr - 1) * linedist) * 0.5f) - ASCENT(vfd);
+ break;
+ case CU_ALIGN_Y_BOTTOM_BASELINE:
+ yoff = (lnr - 1) * linedist;
+ break;
+ case CU_ALIGN_Y_BOTTOM:
+ yoff = (lnr - 1) * linedist + DESCENT(vfd);
+ break;
}
+ ct = chartransdata;
for (i = 0; i <= slen; i++) {
ct->yof += yoff;
ct++;
@@ -1069,12 +1163,13 @@ makebreak:
}
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->curve_cache != NULL);
- if (cu->textoncurve->curve_cache->path) {
+ BLI_assert(cu->textoncurve->runtime.curve_cache != NULL);
+ if (cu->textoncurve->runtime.curve_cache != NULL && cu->textoncurve->runtime.curve_cache->path != NULL) {
float distfac, imat[4][4], imat3[3][3], cmat[3][3];
float minx, maxx, miny, maxy;
float timeofs, sizefac;
@@ -1089,7 +1184,7 @@ makebreak:
copy_m3_m4(cmat, cu->textoncurve->obmat);
mul_m3_m3m3(cmat, cmat, imat3);
- sizefac = normalize_v3(cmat[0]) / cu->fsize;
+ sizefac = normalize_v3(cmat[0]) / font_size;
minx = miny = 1.0e20f;
maxx = maxy = -1.0e20f;
@@ -1104,7 +1199,7 @@ makebreak:
/* we put the x-coordinaat exact at the curve, the y is rotated */
/* length correction */
- distfac = sizefac * cu->textoncurve->curve_cache->path->totdist / (maxx - minx);
+ distfac = sizefac * cu->textoncurve->runtime.curve_cache->path->totdist / (maxx - minx);
timeofs = 0.0f;
if (distfac > 1.0f) {
@@ -1182,19 +1277,21 @@ makebreak:
ct = chartransdata;
for (i = 0; i <= selend; i++, ct++) {
if (i >= selstart) {
- selboxes[i - selstart].x = ct->xof * cu->fsize;
- selboxes[i - selstart].y = ct->yof * cu->fsize;
+ selboxes[i - selstart].x = ct->xof * font_size;
+ selboxes[i - selstart].y = ct->yof * font_size;
}
}
}
- if (mode == FO_CURSUP || mode == FO_CURSDOWN || mode == FO_PAGEUP || mode == FO_PAGEDOWN) {
+ if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) &&
+ iter_data->status == VFONT_TO_CURVE_INIT)
+ {
ct = &chartransdata[ef->pos];
- if ((mode == FO_CURSUP || mode == FO_PAGEUP) && ct->linenr == 0) {
+ if (ELEM(mode, FO_CURSUP, FO_PAGEUP) && ct->linenr == 0) {
/* pass */
}
- else if ((mode == FO_CURSDOWN || mode == FO_PAGEDOWN) && ct->linenr == lnr) {
+ else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
/* pass */
}
else {
@@ -1233,27 +1330,25 @@ makebreak:
f = ef->textcurs[0];
- f[0] = cu->fsize * (-0.1f * co + ct->xof);
- f[1] = cu->fsize * ( 0.1f * si + ct->yof);
+ f[0] = font_size * (-0.1f * co + ct->xof);
+ f[1] = font_size * ( 0.1f * si + ct->yof);
- f[2] = cu->fsize * ( 0.1f * co + ct->xof);
- f[3] = cu->fsize * (-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] = cu->fsize * ( 0.1f * co + 0.8f * si + ct->xof);
- f[5] = cu->fsize * (-0.1f * si + 0.8f * co + 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] = cu->fsize * (-0.1f * co + 0.8f * si + ct->xof);
- f[7] = cu->fsize * ( 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;
- goto finally;
}
-
- if (mode == FO_EDIT) {
+ else if (mode == FO_EDIT) {
/* make nurbdata */
BKE_nurbList_free(r_nubase);
@@ -1262,6 +1357,13 @@ makebreak:
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);
}
@@ -1272,7 +1374,7 @@ makebreak:
}
/* We do not want to see any character for \n or \r */
if (cha != '\n')
- buildchar(cu, r_nubase, cha, info, ct->xof, ct->yof, ct->rot, i);
+ buildchar(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;
@@ -1299,17 +1401,134 @@ makebreak:
build_underline(cu, r_nubase,
&rect, cu->ulpos - 0.05f,
- ct->rot, i, info->mat_nr);
+ ct->rot, i, info->mat_nr,
+ font_size);
}
ct++;
}
}
- ok = true;
+ 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;
+ }
+ }
+ else if (tb_scale.h == 0.0f) {
+ /* This is a horizontal overflow. */
+ if (lnr > 1) {
+ /* We make sure longest line before it broke can fit here. */
+ float scale_to_fit = tb_scale.w / (longest_line_length);
+ scale_to_fit -= FLT_EPSILON;
+
+ iter_data->scale_to_fit = scale_to_fit;
+ iter_data->status = VFONT_TO_CURVE_SCALE_ONCE;
+ }
+ }
+ }
+ 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;
+ }
+ }
-finally:
+ 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;
+ }
+ else {
+ ok = true;
+finally:
if (r_text) {
*r_text = mem;
*r_text_len = slen;
@@ -1320,23 +1539,58 @@ finally:
MEM_freeN((void *)mem);
}
}
- }
- if (chartransdata) {
- if (ok && r_chartransdata) {
- *r_chartransdata = chartransdata;
- }
- else {
- MEM_freeN(chartransdata);
+ 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 wchar_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,
+ .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)
{
@@ -1346,6 +1600,7 @@ bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *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;