diff options
Diffstat (limited to 'source/blender/blenkernel/intern/font.c')
-rw-r--r-- | source/blender/blenkernel/intern/font.c | 114 |
1 files changed, 79 insertions, 35 deletions
diff --git a/source/blender/blenkernel/intern/font.c b/source/blender/blenkernel/intern/font.c index e51b10a97a4..8632e575813 100644 --- a/source/blender/blenkernel/intern/font.c +++ b/source/blender/blenkernel/intern/font.c @@ -635,6 +635,22 @@ struct TempLineInfo { int wspace_nr; /* number of whitespaces of line */ }; +/** + * 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)) + 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) @@ -648,8 +664,6 @@ 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; @@ -663,6 +677,10 @@ bool BKE_vfont_to_curve_ex(Object *ob, Curve *cu, int mode, ListBase *r_nubase, const float xof_scale = cu->xof / cu->fsize; const float yof_scale = cu->yof / cu->fsize; + /* 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) @@ -862,9 +880,9 @@ makebreak: (cu->totbox > (curbox + 1)) && ((-(yof - tb_scale.y)) > (tb_scale.h - linedist) - yof_scale)) { - i_textbox = i + 1; maxlen = 0; curbox++; + i_textbox_array[curbox] = i + 1; textbox_scale(&tb_scale, &cu->tb[curbox], 1.0f / cu->fsize); @@ -1019,50 +1037,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 / cu->fsize); + /* The initial Y origin of the textbox is harcoded to 1.0f * text scale. */ + const float textbox_y_origin = 1.0f; + float yoff; - 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; + /* Non text-box case handled separately. */ float yoff; - 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++; @@ -1071,12 +1112,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->path) { float distfac, imat[4][4], imat3[3][3], cmat[3][3]; float minx, maxx, miny, maxy; float timeofs, sizefac; @@ -1106,7 +1148,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) { @@ -1339,6 +1381,8 @@ finally: #undef MARGIN_Y_MIN } +#undef DESCENT +#undef ASCENT bool BKE_vfont_to_curve_nubase(Object *ob, int mode, ListBase *r_nubase) { |