675 const char32_t **r_text,
679 float *r_font_size_eval)
683 const CharInfo *info =
nullptr, *custrinfo;
688 float xtrax, linedist;
693 int selstart = 0, selend = 0;
694 int cnr = 0, lnr = 0, wsnr = 0;
695 const char32_t *mem =
nullptr;
696 bool mem_alloc =
false;
699 const float font_select_y_offset = 0.25;
700 const bool word_wrap = iter_data.
word_wrap;
707 float current_line_length = 0.0f;
708 float longest_line_length = 0.0f;
714#define MARGIN_X_MIN (cu_offset_scale.x + tb_scale.x)
715#define MARGIN_Y_MIN (cu_offset_scale.y + tb_scale.y)
737 if (vfinfo_ctx.
vfd) {
742 metrics = &_vfont_metrics_default_buf;
821 const bool use_textbox = (tb_scale.
w != 0.0f);
827 xtrax = 0.5f * cu.
spacing - 0.5f;
830 if (cursor_params !=
nullptr) {
833 "TextboxBounds_Cursor");
834 for (curbox = 0; curbox < cu.
totbox; curbox++) {
849 info = &custrinfo[
i];
850 char32_t charcode = mem[
i];
852 charcode = towupper(charcode);
853 if (mem[
i] != charcode) {
855 ct->is_smallcaps =
true;
862 if (!
ELEM(charcode,
'\n',
'\0')) {
864 if (che ==
nullptr) {
876 if ((tb_scale.
w != 0.0f) && (ct->do_break == 0)) {
877 const float x_available = cu_offset_scale.x + tb_scale.
w;
878 const float x_used = (offset.x - tb_scale.
x) + twidth;
880 if (word_wrap ==
false) {
886 if (x_used > x_available) {
888 "VFontToCurveIter.scale_to_fit not set correctly!");
891 else if (x_used > x_available) {
893 bool do_break =
false;
894 for (j =
i; (mem[j] !=
'\n') && (chartransdata[j].
do_break == 0); j--) {
910 if (
ELEM(mem[j],
' ',
'-')) {
912 cnr -= (
i - (j - 1));
920 offset.x = ct->offset.x;
931 if (tb_scale.
h == 0.0f) {
934 ct[1].is_overflow = 1;
942 if (charcode ==
'\n' || charcode == 0 || ct->do_break) {
947 offset.y -= linedist;
949 lineinfo[lnr].
x_min = (offset.x - xtrax) - tb_scale.
x;
950 lineinfo[lnr].
x_max = tb_scale.
w;
954 if (tb_bounds_for_cursor !=
nullptr) {
958 if ((tb_scale.
h != 0.0f) &&
959 (-(offset.y - tb_scale.
y) > (tb_scale.
h - linedist) - cu_offset_scale.y))
961 if (cu.
totbox > (curbox + 1)) {
963 i_textbox_array[curbox] =
i + 1;
969 else if (last_line == -1) {
977 current_line_length += twidth;
980 longest_line_length = std::max(current_line_length, longest_line_length);
981 current_line_length = 0.0f;
989 else if (charcode ==
'\t') {
997 tabfac = 2.0f *
ceilf(tabfac / 2.0f);
1004 ct->offset = offset;
1008 if (selboxes && (
i >= selstart) && (
i <= selend)) {
1009 sb = &selboxes[
i - selstart];
1010 sb->
y = (offset.y - font_select_y_offset) * font_size - linedist * font_size * 0.1f;
1011 sb->
h = linedist * font_size;
1012 sb->
w = offset.x * font_size;
1015 if (charcode ==
' ') {
1026 offset.x += (twidth * wsfac * (1.0f + (info->
kern / 40.0f))) + xtrax;
1029 sb->
w = (offset.x * font_size) - sb->
w;
1036 current_line_length += offset.x + twidth -
MARGIN_X_MIN;
1037 longest_line_length = std::max(current_line_length, longest_line_length);
1039 if (ef && selboxes) {
1044 info = &custrinfo[k];
1055 for (
i = 0, li = lineinfo;
i < lnr;
i++, li++) {
1059 for (
i = 0;
i <= slen;
i++) {
1060 ct->offset.x += lineinfo[ct->linenr].
x_min;
1067 for (
i = 0, li = lineinfo;
i < lnr;
i++, li++) {
1071 for (
i = 0;
i <= slen;
i++) {
1072 ct->offset.x += lineinfo[ct->linenr].
x_min;
1079 for (
i = 0, li = lineinfo;
i < lnr;
i++, li++) {
1086 for (
i = 0;
i <= slen;
i++) {
1087 for (j =
i; !
ELEM(mem[j],
'\0',
'\n') && (chartransdata[j].
do_break == 0) && (j < slen);
1094 ct->offset.x += ct->charnr * lineinfo[ct->linenr].
x_min;
1100 float curofs = 0.0f;
1101 for (
i = 0;
i <= slen;
i++) {
1102 for (j =
i; (mem[j]) && (mem[j] !=
'\n') && (chartransdata[j].
do_break == 0) && (j < slen);
1108 if ((mem[j] !=
'\n') && (chartransdata[j].do_break != 0)) {
1109 if (mem[
i] ==
' ') {
1112 li = &lineinfo[ct->linenr];
1115 ct->offset.x += curofs;
1117 if (mem[
i] ==
'\n' || chartransdata[
i].do_break) {
1127 if (tb_scale.
h != 0.0f) {
1130 for (
int tb_index = 0; tb_index < cu.
totbox; tb_index++) {
1132 const int i_textbox = i_textbox_array[tb_index];
1133 const int i_textbox_next = i_textbox_array[tb_index + 1];
1134 const bool is_last_filled_textbox =
ELEM(i_textbox_next, 0, slen + 1);
1137 ct_first = chartransdata + i_textbox;
1138 ct_last = chartransdata + (is_last_filled_textbox ? slen : i_textbox_next - 1);
1144 if ((tb_index == cu.
totbox - 1) && (last_line != -1)) {
1145 lines = last_line - ct_first->
linenr;
1151 const float textbox_y_origin = 1.0f;
1161 yoff = ((((metrics->
em_ratio + (lines - 1) * linedist) * 0.5f) -
1163 (tb_scale.
h * 0.5f) + textbox_y_origin);
1166 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.
h;
1169 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.
h +
1174 for (ct = ct_first; ct <= ct_last; ct++) {
1175 ct->offset.y += yoff;
1178 if (is_last_filled_textbox) {
1194 yoff = ((metrics->
em_ratio + (lnr - 1) * linedist) * 0.5f) -
1198 yoff = (lnr - 1) * linedist;
1206 for (
i = 0;
i <= slen;
i++) {
1207 ct->offset.y += yoff;
1212 if (tb_bounds_for_cursor !=
nullptr) {
1213 int char_beg_next = 0;
1214 for (curbox = 0; curbox < cu.
totbox; curbox++) {
1219 const int char_beg = char_beg_next;
1223 TempLineInfo *line_end = &lineinfo[chartransdata[char_end].linenr];
1225 int char_idx_offset = char_beg;
1230 bounds->ymax = chartransdata[char_beg].offset.y;
1231 bounds->ymin = chartransdata[char_end].offset.y;
1233 for (
TempLineInfo *line = line_beg; line <= line_end; line++) {
1234 const CharTrans *first_char_line = &chartransdata[char_idx_offset];
1235 const CharTrans *last_char_line = &chartransdata[char_idx_offset + line->char_nr];
1239 char_idx_offset += line->char_nr + 1;
1257 float distfac, imat[4][4], imat3[3][3], cmat[3][3];
1259 float timeofs, sizefac;
1261 if (ob !=
nullptr) {
1274 minx = maxx = ct->
offset.x;
1276 for (
i = 1;
i <= slen;
i++, ct++) {
1277 minx = std::min(minx, ct->offset.x);
1278 maxx = std::max(maxx, ct->offset.x);
1284 const float chartrans_size_x = maxx - minx;
1285 if (chartrans_size_x != 0.0f) {
1288 distfac = (sizefac * totdist) / chartrans_size_x;
1289 distfac = (distfac > 1.0f) ? (1.0f / distfac) : 1.0f;
1298 if (distfac < 1.0f) {
1302 timeofs = 1.0f - distfac;
1305 timeofs = (1.0f - distfac) / 2.0f;
1312 if (chartrans_size_x != 0.0f) {
1313 distfac /= chartrans_size_x;
1316 timeofs += distfac * cu.
xof;
1319 for (
i = 0;
i <= slen;
i++, ct++) {
1320 float ctime, dtime, vec[4], rotvec[3];
1324 info = &custrinfo[
i];
1333 dtime = distfac * 0.5f * twidth;
1335 ctime = timeofs + distfac * (ct->offset.x - minx);
1336 CLAMP(ctime, 0.0f, 1.0f);
1341 cu.
textoncurve, ctime + dtime,
nullptr, rotvec,
nullptr,
nullptr,
nullptr);
1347 si =
sinf(ct->rotate);
1348 co =
cosf(ct->rotate);
1350 offset.y = ct->offset.y;
1353 vec[0] + si * offset.y,
1354 vec[1] + co * offset.y,
1357 if (selboxes && (
i >= selstart) && (
i <= selend)) {
1359 sb = &selboxes[
i - selstart];
1360 sb->
rotate = -ct->rotate;
1368 for (
i = 0;
i <= selend;
i++, ct++) {
1369 if (
i >= selstart) {
1371 sb->
x = ct->offset.x;
1372 sb->
y = ct->offset.y;
1373 if (ct->rotate != 0.0f) {
1374 sb->
x -=
sinf(ct->rotate) * font_select_y_offset;
1375 sb->
y -=
cosf(ct->rotate) * font_select_y_offset;
1379 sb->
y -= font_select_y_offset;
1383 selboxes[
i - selstart].
h = font_size;
1391 ct = &chartransdata[ef->
pos];
1401 while ((ef->
pos > 0) && (chartransdata[ef->
pos - 1].
linenr == ct->linenr)) {
1407 while ((ef->
pos < slen) && (chartransdata[ef->
pos + 1].
linenr == ct->linenr)) {
1414 lnr = ct->linenr - 1;
1417 lnr = ct->linenr + 1;
1420 lnr = ct->linenr - 10;
1423 lnr = ct->linenr + 10;
1438 for (
i = 0;
i < slen;
i++) {
1439 if (ct->linenr == lnr) {
1440 if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) {
1444 else if (ct->linenr > lnr) {
1455 ct = &chartransdata[ef->
pos];
1456 const float cursor_width = 0.04f;
1457 const float cursor_half = 0.02f;
1461 float cursor_left = 0.0f - cursor_half;
1462 float cursor_rotate = ct->
rotate;
1474 cursor_left = 0.0f - cursor_width;
1477 else if ((ef->
pos == ef->
len) && (ef->
len > 0)) {
1479 cursor_rotate = chartransdata[ef->
len - 1].
rotate;
1494 for (
int vert = 0; vert < 4; vert++) {
1498 ef->
textcurs[vert] = font_size * (ct->offset + temp_fl);
1504 chartransdata =
nullptr;
1513 Nurb *ul_prev_nu =
nullptr;
1516 for (
i = 0;
i < slen;
i++) {
1524 info = &(custrinfo[
i]);
1527 if (charcode !=
'\n') {
1534 cu, r_nubase, che, info, ct->is_smallcaps, ct->offset, ct->rotate,
i, font_size);
1537 float ulwidth, uloverlap = 0.0f;
1541 if ((
i < (slen - 1)) && (mem[
i + 1] !=
'\n') &&
1543 ((ct[1].is_wrap) == 0))
1549 ulwidth = (twidth * (1.0f + (info->
kern / 40.0f))) + uloverlap;
1551 rect.
xmin = ct->offset.x;
1554 rect.
ymin = ct->offset.y;
1557 if ((ul_prev_i != -1) &&
1559 ((ul_prev_i + 1 !=
i) ||
1561 (chartransdata[ul_prev_i].linenr != ct->
linenr)))
1563 ul_prev_nu =
nullptr;
1575 ul_prev_i = ul_prev_nu ?
i : -1;
1590 else if ((tb_scale.
h == 0.0f) && (tb_scale.
w == 0.0f)) {
1594 if ((cu.
totbox == 1) && ((tb_scale.
w == 0.0f) || (tb_scale.
h == 0.0f))) {
1596 if (tb_scale.
w == 0.0f) {
1599 if ((last_line != -1) && (lnr > last_line)) {
1600 const float total_text_height = lnr * linedist;
1606 else if (tb_scale.
h == 0.0f) {
1608 if (longest_line_length > tb_scale.
w) {
1610 float scale_to_fit = tb_scale.
w / longest_line_length;
1628 for (
int tb_index = 0; tb_index <= curbox; tb_index++) {
1630 if ((tb->
w == 0.0f) || (tb->
h == 0.0f)) {
1636 if (valid && (last_line != -1) && (lnr > last_line)) {
1637 const float total_text_height = lnr * linedist;
1638 float scale_to_fit = tb_scale.
h / total_text_height;
1652 if ((last_line != -1) && (lnr > last_line)) {
1681 if (cursor_params) {
1689 int closest_char = -1;
1690 float closest_dist_sq =
FLT_MAX;
1692 for (
i = 0;
i <= slen;
i++) {
1695 if (closest_dist_sq > test_dist_sq) {
1697 closest_dist_sq = test_dist_sq;
1706 int char_end = slen;
1708 if (tb_bounds_for_cursor !=
nullptr) {
1710 int closest_box = -1;
1711 float closest_dist_sq =
FLT_MAX;
1712 for (curbox = 0; curbox < cu.
totbox; curbox++) {
1725 cursor_location_clamped);
1726 if (test_dist_sq < closest_dist_sq) {
1727 closest_dist_sq = test_dist_sq;
1728 closest_box = curbox;
1731 if (closest_box != -1) {
1732 if (closest_box != 0) {
1738 tb_bounds_for_cursor =
nullptr;
1740 const float interline_offset = ((linedist - 0.5f) / 2.0f) * font_size;
1742 for (
i = char_beg;
i <= char_end;
i++) {
1743 if (cursor_location.y >= ((chartransdata[
i].
offset.y * font_size) - interline_offset)) {
1749 const float char_yof = chartransdata[
i].
offset.y;
1753 for (;
i >= char_beg + 1 && chartransdata[
i - 1].
offset.y == char_yof;
i--) {
1758 for (;
i <= char_end && char_yof == chartransdata[
i].
offset.y;
i++) {
1759 info = &custrinfo[
i];
1766 const float charhalf = (charwidth / 2.0f);
1767 if (cursor_location.x <= ((chartransdata[
i].
offset.x + charhalf) * font_size)) {
1775 if (
i > char_beg && chartransdata[
i].offset.y != char_yof) {
1787 if (r_nubase !=
nullptr) {
1791 if (chartransdata !=
nullptr) {
1804 *r_text_free = mem_alloc;
1812 if (chartransdata) {
1813 if (r_chartransdata) {
1814 *r_chartransdata = chartransdata;
1822 if (ef !=
nullptr) {
1825 if (r_font_size_eval) {
1826 *r_font_size_eval = font_size;