667 const char32_t **r_text,
671 float *r_font_size_eval)
675 const CharInfo *info =
nullptr, *custrinfo;
681 float xof, yof, xtrax, linedist;
686 int selstart = 0, selend = 0;
687 int cnr = 0, lnr = 0, wsnr = 0;
688 const char32_t *mem =
nullptr;
689 bool mem_alloc =
false;
692 const float font_select_y_offset = 0.25;
693 const bool word_wrap = iter_data->
word_wrap;
698 float current_line_length = 0.0f;
699 float longest_line_length = 0.0f;
705#define MARGIN_X_MIN (xof_scale + tb_scale.x)
706#define MARGIN_Y_MIN (yof_scale + tb_scale.y)
728 if (vfinfo_ctx.
vfd) {
733 metrics = &_vfont_metrics_default_buf;
812 use_textbox = (tb_scale.
w != 0.0f);
817 xtrax = 0.5f * cu->
spacing - 0.5f;
820 if (cursor_params !=
nullptr) {
823 "TextboxBounds_Cursor");
824 for (curbox = 0; curbox < cu->
totbox; curbox++) {
839 info = &custrinfo[
i];
840 char32_t charcode = mem[
i];
842 charcode = towupper(charcode);
843 if (mem[
i] != charcode) {
845 ct->is_smallcaps =
true;
852 if (!
ELEM(charcode,
'\n',
'\0')) {
854 if (che ==
nullptr) {
866 if ((tb_scale.
w != 0.0f) && (ct->dobreak == 0)) {
867 const float x_available = xof_scale + tb_scale.
w;
868 const float x_used = (xof - tb_scale.
x) + twidth;
870 if (word_wrap ==
false) {
876 if (x_used > x_available) {
878 "VFontToCurveIter.scale_to_fit not set correctly!");
881 else if (x_used > x_available) {
883 bool dobreak =
false;
884 for (j =
i; (mem[j] !=
'\n') && (chartransdata[j].
dobreak == 0); j--) {
900 if (
ELEM(mem[j],
' ',
'-')) {
902 cnr -= (
i - (j - 1));
921 if (tb_scale.
h == 0.0f) {
924 ct[1].is_overflow = 1;
932 if (charcode ==
'\n' || charcode == 0 || ct->dobreak) {
940 lineinfo[lnr].
x_min = (xof - xtrax) - tb_scale.
x;
941 lineinfo[lnr].
x_max = tb_scale.
w;
945 if (tb_bounds_for_cursor !=
nullptr) {
949 if ((tb_scale.
h != 0.0f) && (-(yof - tb_scale.
y) > (tb_scale.
h - linedist) - yof_scale)) {
950 if (cu->
totbox > (curbox + 1)) {
952 i_textbox_array[curbox] =
i + 1;
958 else if (last_line == -1) {
966 current_line_length += twidth;
969 longest_line_length = std::max(current_line_length, longest_line_length);
970 current_line_length = 0.0f;
978 else if (charcode ==
'\t') {
987 tabfac = 2.0f *
ceilf(tabfac / 2.0f);
999 if (selboxes && (
i >= selstart) && (
i <= selend)) {
1000 sb = &selboxes[
i - selstart];
1001 sb->
y = (yof - font_select_y_offset) * font_size - linedist * font_size * 0.1f;
1002 sb->
h = linedist * font_size;
1003 sb->
w = xof * font_size;
1006 if (charcode ==
' ') {
1017 xof += (twidth * wsfac * (1.0f + (info->
kern / 40.0f))) + xtrax;
1020 sb->
w = (xof * font_size) - sb->
w;
1028 longest_line_length = std::max(current_line_length, longest_line_length);
1030 if (ef && selboxes) {
1035 info = &custrinfo[k];
1046 for (
i = 0, li = lineinfo;
i < lnr;
i++, li++) {
1050 for (
i = 0;
i <= slen;
i++) {
1051 ct->xof += lineinfo[ct->linenr].
x_min;
1058 for (
i = 0, li = lineinfo;
i < lnr;
i++, li++) {
1062 for (
i = 0;
i <= slen;
i++) {
1063 ct->xof += lineinfo[ct->linenr].
x_min;
1070 for (
i = 0, li = lineinfo;
i < lnr;
i++, li++) {
1077 for (
i = 0;
i <= slen;
i++) {
1078 for (j =
i; !
ELEM(mem[j],
'\0',
'\n') && (chartransdata[j].
dobreak == 0) && (j < slen);
1085 ct->xof += ct->charnr * lineinfo[ct->linenr].
x_min;
1091 float curofs = 0.0f;
1092 for (
i = 0;
i <= slen;
i++) {
1093 for (j =
i; (mem[j]) && (mem[j] !=
'\n') && (chartransdata[j].
dobreak == 0) && (j < slen);
1099 if ((mem[j] !=
'\n') && (chartransdata[j].dobreak != 0)) {
1100 if (mem[
i] ==
' ') {
1103 li = &lineinfo[ct->linenr];
1108 if (mem[
i] ==
'\n' || chartransdata[
i].dobreak) {
1118 if (tb_scale.
h != 0.0f) {
1121 for (
int tb_index = 0; tb_index < cu->
totbox; tb_index++) {
1123 const int i_textbox = i_textbox_array[tb_index];
1124 const int i_textbox_next = i_textbox_array[tb_index + 1];
1125 const bool is_last_filled_textbox =
ELEM(i_textbox_next, 0, slen + 1);
1128 ct_first = chartransdata + i_textbox;
1129 ct_last = chartransdata + (is_last_filled_textbox ? slen : i_textbox_next - 1);
1135 if ((tb_index == cu->
totbox - 1) && (last_line != -1)) {
1136 lines = last_line - ct_first->
linenr;
1142 const float textbox_y_origin = 1.0f;
1152 yoff = ((((metrics->
em_ratio + (lines - 1) * linedist) * 0.5f) -
1154 (tb_scale.
h * 0.5f) + textbox_y_origin);
1157 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.
h;
1160 yoff = textbox_y_origin + ((lines - 1) * linedist) - tb_scale.
h +
1165 for (ct = ct_first; ct <= ct_last; ct++) {
1169 if (is_last_filled_textbox) {
1185 yoff = ((metrics->
em_ratio + (lnr - 1) * linedist) * 0.5f) -
1189 yoff = (lnr - 1) * linedist;
1197 for (
i = 0;
i <= slen;
i++) {
1203 if (tb_bounds_for_cursor !=
nullptr) {
1204 int char_beg_next = 0;
1205 for (curbox = 0; curbox < cu->
totbox; curbox++) {
1210 const int char_beg = char_beg_next;
1214 TempLineInfo *line_end = &lineinfo[chartransdata[char_end].linenr];
1216 int char_idx_offset = char_beg;
1221 bounds->ymax = chartransdata[char_beg].yof;
1222 bounds->ymin = chartransdata[char_end].yof;
1224 for (
TempLineInfo *line = line_beg; line <= line_end; line++) {
1225 const CharTrans *first_char_line = &chartransdata[char_idx_offset];
1226 const CharTrans *last_char_line = &chartransdata[char_idx_offset + line->char_nr];
1230 char_idx_offset += line->char_nr + 1;
1248 float distfac, imat[4][4], imat3[3][3], cmat[3][3];
1250 float timeofs, sizefac;
1252 if (ob !=
nullptr) {
1265 minx = maxx = ct->
xof;
1267 for (
i = 1;
i <= slen;
i++, ct++) {
1268 minx = std::min(minx, ct->xof);
1269 maxx = std::max(maxx, ct->xof);
1275 const float chartrans_size_x = maxx - minx;
1276 if (chartrans_size_x != 0.0f) {
1279 distfac = (sizefac * totdist) / chartrans_size_x;
1280 distfac = (distfac > 1.0f) ? (1.0f / distfac) : 1.0f;
1289 if (distfac < 1.0f) {
1293 timeofs = 1.0f - distfac;
1296 timeofs = (1.0f - distfac) / 2.0f;
1303 if (chartrans_size_x != 0.0f) {
1304 distfac /= chartrans_size_x;
1307 timeofs += distfac * cu->
xof;
1310 for (
i = 0;
i <= slen;
i++, ct++) {
1311 float ctime, dtime, vec[4], rotvec[3];
1315 info = &custrinfo[
i];
1324 dtime = distfac * 0.5f * twidth;
1326 ctime = timeofs + distfac * (ct->xof - minx);
1327 CLAMP(ctime, 0.0f, 1.0f);
1332 cu->
textoncurve, ctime + dtime,
nullptr, rotvec,
nullptr,
nullptr,
nullptr);
1336 ct->rot = float(
M_PI) -
atan2f(rotvec[1], rotvec[0]);
1343 ct->xof = vec[0] + si * yof;
1344 ct->yof = vec[1] + co * yof;
1346 if (selboxes && (
i >= selstart) && (
i <= selend)) {
1348 sb = &selboxes[
i - selstart];
1357 for (
i = 0;
i <= selend;
i++, ct++) {
1358 if (
i >= selstart) {
1362 if (ct->rot != 0.0f) {
1363 sb->
x -=
sinf(ct->rot) * font_select_y_offset;
1364 sb->
y -=
cosf(ct->rot) * font_select_y_offset;
1368 sb->
y -= font_select_y_offset;
1372 selboxes[
i - selstart].
h = font_size;
1380 ct = &chartransdata[ef->
pos];
1390 while ((ef->
pos > 0) && (chartransdata[ef->
pos - 1].
linenr == ct->linenr)) {
1396 while ((ef->
pos < slen) && (chartransdata[ef->
pos + 1].
linenr == ct->linenr)) {
1403 lnr = ct->linenr - 1;
1406 lnr = ct->linenr + 1;
1409 lnr = ct->linenr - 10;
1412 lnr = ct->linenr + 10;
1427 for (
i = 0;
i < slen;
i++) {
1428 if (ct->linenr == lnr) {
1429 if ((ct->charnr == cnr) || ((ct + 1)->charnr == 0)) {
1433 else if (ct->linenr > lnr) {
1444 ct = &chartransdata[ef->
pos];
1445 const float cursor_width = 0.04f;
1446 const float cursor_half = 0.02f;
1447 const float xoffset = ct->
xof;
1448 const float yoffset = ct->yof;
1452 float cursor_left = 0.0f - cursor_half;
1453 float rotation = ct->rot;
1465 cursor_left = 0.0f - cursor_width;
1468 else if ((ef->
pos == ef->
len) && (ef->
len > 0)) {
1470 rotation = chartransdata[ef->
len - 1].
rot;
1478 ef->
textcurs[0][1] = 0.0f - font_select_y_offset;
1480 ef->
textcurs[1][0] = cursor_left + cursor_width;
1481 ef->
textcurs[1][1] = 0.0f - font_select_y_offset;
1484 ef->
textcurs[3][1] = 1.0f - font_select_y_offset;
1486 ef->
textcurs[2][0] = cursor_left + cursor_width;
1487 ef->
textcurs[2][1] = 1.0f - font_select_y_offset;
1489 for (
int vert = 0; vert < 4; vert++) {
1493 ef->
textcurs[vert][0] = font_size * (xoffset + temp_fl[0]);
1494 ef->
textcurs[vert][1] = font_size * (yoffset + temp_fl[1]);
1500 chartransdata =
nullptr;
1509 Nurb *ul_prev_nu =
nullptr;
1512 for (
i = 0;
i < slen;
i++) {
1520 info = &(custrinfo[
i]);
1523 if (charcode !=
'\n') {
1530 cu, r_nubase, che, info, ct->is_smallcaps, ct->xof, ct->yof, ct->rot,
i, font_size);
1533 float ulwidth, uloverlap = 0.0f;
1537 if ((
i < (slen - 1)) && (mem[
i + 1] !=
'\n') &&
1539 ((ct[1].is_wrap) == 0))
1545 ulwidth = (twidth * (1.0f + (info->
kern / 40.0f))) + uloverlap;
1547 rect.
xmin = ct->xof;
1550 rect.
ymin = ct->yof;
1553 if ((ul_prev_i != -1) &&
1555 ((ul_prev_i + 1 !=
i) ||
1557 (chartransdata[ul_prev_i].linenr != ct->
linenr)))
1559 ul_prev_nu =
nullptr;
1571 ul_prev_i = ul_prev_nu ?
i : -1;
1586 else if ((tb_scale.
h == 0.0f) && (tb_scale.
w == 0.0f)) {
1590 if ((cu->
totbox == 1) && ((tb_scale.
w == 0.0f) || (tb_scale.
h == 0.0f))) {
1592 if (tb_scale.
w == 0.0f) {
1595 if ((last_line != -1) && (lnr > last_line)) {
1596 const float total_text_height = lnr * linedist;
1602 else if (tb_scale.
h == 0.0f) {
1604 if (longest_line_length > tb_scale.
w) {
1606 float scale_to_fit = tb_scale.
w / longest_line_length;
1624 for (
int tb_index = 0; tb_index <= curbox; tb_index++) {
1626 if ((tb->
w == 0.0f) || (tb->
h == 0.0f)) {
1632 if (valid && (last_line != -1) && (lnr > last_line)) {
1633 const float total_text_height = lnr * linedist;
1634 float scale_to_fit = tb_scale.
h / total_text_height;
1648 if ((last_line != -1) && (lnr > last_line)) {
1677 if (cursor_params) {
1685 int closest_char = -1;
1686 float closest_dist_sq =
FLT_MAX;
1688 for (
i = 0;
i <= slen;
i++) {
1689 const float char_location[2] = {
1690 chartransdata[
i].
xof * font_size,
1691 chartransdata[
i].
yof * font_size,
1693 const float test_dist_sq =
len_squared_v2v2(cursor_location, char_location);
1694 if (closest_dist_sq > test_dist_sq) {
1696 closest_dist_sq = test_dist_sq;
1705 int char_end = slen;
1707 if (tb_bounds_for_cursor !=
nullptr) {
1709 int closest_box = -1;
1710 float closest_dist_sq =
FLT_MAX;
1711 for (curbox = 0; curbox < cu->
totbox; curbox++) {
1718 const float cursor_location_clamped[2] = {
1723 const float test_dist_sq =
len_squared_v2v2(cursor_location, cursor_location_clamped);
1724 if (test_dist_sq < closest_dist_sq) {
1725 closest_dist_sq = test_dist_sq;
1726 closest_box = curbox;
1729 if (closest_box != -1) {
1730 if (closest_box != 0) {
1736 tb_bounds_for_cursor =
nullptr;
1738 const float interline_offset = ((linedist - 0.5f) / 2.0f) * font_size;
1740 for (
i = char_beg;
i <= char_end;
i++) {
1741 if (cursor_location[1] >= ((chartransdata[
i].yof * font_size) - interline_offset)) {
1747 const float char_yof = chartransdata[
i].
yof;
1751 for (;
i >= char_beg + 1 && chartransdata[
i - 1].
yof == char_yof;
i--) {
1756 for (;
i <= char_end && char_yof == chartransdata[
i].
yof;
i++) {
1757 info = &custrinfo[
i];
1764 const float charhalf = (charwidth / 2.0f);
1765 if (cursor_location[0] <= ((chartransdata[
i].xof + charhalf) * font_size)) {
1773 if (
i > char_beg && chartransdata[
i].yof != char_yof) {
1785 if (r_nubase !=
nullptr) {
1789 if (chartransdata !=
nullptr) {
1802 *r_text_free = mem_alloc;
1810 if (chartransdata) {
1811 if (r_chartransdata) {
1812 *r_chartransdata = chartransdata;
1820 if (ef !=
nullptr) {
1823 if (r_font_size_eval) {
1824 *r_font_size_eval = font_size;