Refactor: move run-time flags from CharInfo::flag to CharTrans
The Curve, Curve::strinfo & EditFont::textbufinfo are now read-only during evaluation. CharTrans is now used to store some evaluation options such as wrap/overflow/smallcaps. Since it's no longer possible to inspect evaluation flags from operators without evaluating the curve, line beginning/end functionality has been moved from the operator into vfont_to_curve.
This commit is contained in:
@@ -20,7 +20,11 @@ struct CharTrans {
|
||||
float xof, yof;
|
||||
float rot;
|
||||
short linenr, charnr;
|
||||
char dobreak;
|
||||
|
||||
uint dobreak : 1;
|
||||
uint is_overflow : 1;
|
||||
uint is_wrap : 1;
|
||||
uint is_smallcaps : 1;
|
||||
};
|
||||
|
||||
struct EditFontSelBox {
|
||||
@@ -77,11 +81,14 @@ enum eEditFontMode {
|
||||
FO_DUPLI = 4,
|
||||
FO_PAGEUP = 8,
|
||||
FO_PAGEDOWN = 9,
|
||||
FO_SELCHANGE = 10,
|
||||
FO_LINE_BEGIN = 10,
|
||||
FO_LINE_END = 11,
|
||||
FO_SELCHANGE = 12,
|
||||
};
|
||||
|
||||
/** #BKE_vfont_to_curve will move the cursor in these cases. */
|
||||
#define FO_CURS_IS_MOTION(mode) (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN))
|
||||
#define FO_CURS_IS_MOTION(mode) \
|
||||
(ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN, FO_LINE_BEGIN, FO_LINE_END))
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name VFont API
|
||||
@@ -132,6 +139,7 @@ void BKE_vfont_char_build(Curve *cu,
|
||||
ListBase *nubase,
|
||||
unsigned int charcode,
|
||||
const CharInfo *info,
|
||||
bool is_smallcaps,
|
||||
float ofsx,
|
||||
float ofsy,
|
||||
float rot,
|
||||
|
||||
@@ -297,7 +297,7 @@ static VChar *vfont_char_find_or_placeholder(const VFontData *vfd,
|
||||
* \return The shape used for the underline which may be passed in
|
||||
* as the `ul_prev_nu` in future calls to this function.
|
||||
*/
|
||||
static Nurb *build_underline(Curve *cu,
|
||||
static Nurb *build_underline(const Curve *cu,
|
||||
ListBase *nubase,
|
||||
const rctf *rect,
|
||||
float yofs,
|
||||
@@ -371,10 +371,11 @@ static Nurb *build_underline(Curve *cu,
|
||||
return nu;
|
||||
}
|
||||
|
||||
static void vfont_char_build_impl(Curve *cu,
|
||||
static void vfont_char_build_impl(const Curve *cu,
|
||||
ListBase *nubase,
|
||||
const VChar *che,
|
||||
const CharInfo *info,
|
||||
const bool is_smallcaps,
|
||||
float ofsx,
|
||||
float ofsy,
|
||||
float rot,
|
||||
@@ -452,7 +453,7 @@ static void vfont_char_build_impl(Curve *cu,
|
||||
}
|
||||
bezt = nu->bezt;
|
||||
|
||||
if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
|
||||
if (is_smallcaps) {
|
||||
const float sca = cu->smallcaps_scale;
|
||||
for (int i = nu->pntsu; i > 0; i--) {
|
||||
float *fp = bezt->vec[0];
|
||||
@@ -489,6 +490,7 @@ void BKE_vfont_char_build(Curve *cu,
|
||||
ListBase *nubase,
|
||||
uint charcode,
|
||||
const CharInfo *info,
|
||||
const bool is_smallcaps,
|
||||
float ofsx,
|
||||
float ofsy,
|
||||
float rot,
|
||||
@@ -501,25 +503,25 @@ void BKE_vfont_char_build(Curve *cu,
|
||||
}
|
||||
VChar *che;
|
||||
vfont_char_find(vfd, charcode, &che);
|
||||
vfont_char_build_impl(cu, nubase, che, info, ofsx, ofsy, rot, charidx, fsize);
|
||||
vfont_char_build_impl(cu, nubase, che, info, is_smallcaps, ofsx, ofsy, rot, charidx, fsize);
|
||||
}
|
||||
|
||||
static float vfont_char_width(Curve *cu, VChar *che, const CharInfo *info)
|
||||
static float vfont_char_width(const Curve *cu, VChar *che, const bool is_smallcaps)
|
||||
{
|
||||
/* The character wasn't found, probably `charcode = 0`, then the width shall be 0 as well. */
|
||||
if (che == nullptr) {
|
||||
return 0.0f;
|
||||
}
|
||||
if (info->flag & CU_CHINFO_SMALLCAPS_CHECK) {
|
||||
if (is_smallcaps) {
|
||||
return che->width * cu->smallcaps_scale;
|
||||
}
|
||||
|
||||
return che->width;
|
||||
}
|
||||
|
||||
static char32_t vfont_char_apply_smallcaps(char32_t charcode, const CharInfo *info)
|
||||
static char32_t vfont_char_apply_smallcaps(char32_t charcode, const bool is_smallcaps)
|
||||
{
|
||||
if (UNLIKELY(info->flag & CU_CHINFO_SMALLCAPS_CHECK)) {
|
||||
if (UNLIKELY(is_smallcaps)) {
|
||||
return toupper(charcode);
|
||||
}
|
||||
return charcode;
|
||||
@@ -666,7 +668,7 @@ struct TempLineInfo {
|
||||
* with font styles, text boxes as well as text cursor placement.
|
||||
*/
|
||||
static bool vfont_to_curve(Object *ob,
|
||||
Curve *cu,
|
||||
const Curve *cu,
|
||||
const eEditFontMode mode,
|
||||
VFontToCurveIter *iter_data,
|
||||
VFontCursor_Params *cursor_params,
|
||||
@@ -679,7 +681,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
{
|
||||
EditFont *ef = cu->editfont;
|
||||
EditFontSelBox *selboxes = nullptr;
|
||||
CharInfo *info = nullptr, *custrinfo;
|
||||
const CharInfo *info = nullptr, *custrinfo;
|
||||
TextBox tb_scale;
|
||||
bool use_textbox;
|
||||
VChar *che;
|
||||
@@ -693,6 +695,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
int selstart = 0, selend = 0;
|
||||
int cnr = 0, lnr = 0, wsnr = 0;
|
||||
const char32_t *mem = nullptr;
|
||||
bool mem_alloc = false;
|
||||
const float font_size = cu->fsize * iter_data->scale_to_fit;
|
||||
/* Shift down vertically to be 25% below & 75% above baseline (before font scale is applied). */
|
||||
const float font_select_y_offset = 0.25;
|
||||
@@ -761,6 +764,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
BLI_str_utf8_as_utf32(mem_tmp, cu->str, slen + 1);
|
||||
|
||||
mem = mem_tmp;
|
||||
mem_alloc = true;
|
||||
custrinfo = cu->strinfo;
|
||||
}
|
||||
|
||||
@@ -798,10 +802,6 @@ static bool vfont_to_curve(Object *ob,
|
||||
|
||||
xtrax = 0.5f * cu->spacing - 0.5f;
|
||||
|
||||
for (i = 0; i < slen; i++) {
|
||||
custrinfo[i].flag &= ~(CU_CHINFO_WRAP | CU_CHINFO_SMALLCAPS_CHECK | CU_CHINFO_OVERFLOW);
|
||||
}
|
||||
|
||||
TextBoxBounds_ForCursor *tb_bounds_for_cursor = nullptr;
|
||||
if (cursor_params != nullptr) {
|
||||
if (cu->textoncurve == nullptr && (cu->totbox > 1) && (slen > 0)) {
|
||||
@@ -827,7 +827,8 @@ static bool vfont_to_curve(Object *ob,
|
||||
if (info->flag & CU_CHINFO_SMALLCAPS) {
|
||||
charcode = towupper(charcode);
|
||||
if (mem[i] != charcode) {
|
||||
info->flag |= CU_CHINFO_SMALLCAPS_CHECK;
|
||||
BLI_assert(ct == &chartransdata[i]);
|
||||
ct->is_smallcaps = true;
|
||||
}
|
||||
}
|
||||
/* The #vfont_char_apply_smallcaps function can be used from now on. */
|
||||
@@ -844,7 +845,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
che = nullptr;
|
||||
}
|
||||
|
||||
twidth = vfont_char_width(cu, che, info);
|
||||
twidth = vfont_char_width(cu, che, ct->is_smallcaps);
|
||||
|
||||
/* Calculate positions. */
|
||||
|
||||
@@ -893,8 +894,9 @@ static bool vfont_to_curve(Object *ob,
|
||||
}
|
||||
i = j - 1;
|
||||
xof = ct->xof;
|
||||
BLI_assert(&ct[1] == &chartransdata[i + 1]);
|
||||
ct[1].dobreak = 1;
|
||||
custrinfo[i + 1].flag |= CU_CHINFO_WRAP;
|
||||
ct[1].is_wrap = 1;
|
||||
dobreak = true;
|
||||
break;
|
||||
}
|
||||
@@ -904,7 +906,8 @@ static bool vfont_to_curve(Object *ob,
|
||||
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;
|
||||
BLI_assert(&chartransdata[i + 1] == &ct[1]);
|
||||
ct[1].is_overflow = 1;
|
||||
}
|
||||
/* Since a break was added, re-run this loop with `i` at it's new value. */
|
||||
continue;
|
||||
@@ -940,7 +943,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
}
|
||||
else if (last_line == -1) {
|
||||
last_line = lnr + 1;
|
||||
info->flag |= CU_CHINFO_OVERFLOW;
|
||||
ct->is_overflow = 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -995,7 +998,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
}
|
||||
|
||||
/* Set the width of the character. */
|
||||
twidth = vfont_char_width(cu, che, info);
|
||||
twidth = vfont_char_width(cu, che, ct->is_smallcaps);
|
||||
|
||||
xof += (twidth * wsfac * (1.0f + (info->kern / 40.0f))) + xtrax;
|
||||
|
||||
@@ -1296,12 +1299,13 @@ static bool vfont_to_curve(Object *ob,
|
||||
|
||||
/* Rotate around center character. */
|
||||
info = &custrinfo[i];
|
||||
const char32_t charcode = vfont_char_apply_smallcaps(mem[i], info);
|
||||
BLI_assert(ct == &chartransdata[i]);
|
||||
const char32_t charcode = vfont_char_apply_smallcaps(mem[i], ct->is_smallcaps);
|
||||
|
||||
vfont_info_context_update(&vfinfo_ctx, cu, info);
|
||||
che = vfont_char_find_or_placeholder(vfinfo_ctx.vfd, charcode, che_placeholder);
|
||||
|
||||
twidth = vfont_char_width(cu, che, info);
|
||||
twidth = vfont_char_width(cu, che, ct->is_smallcaps);
|
||||
|
||||
dtime = distfac * 0.5f * twidth;
|
||||
|
||||
@@ -1356,7 +1360,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
}
|
||||
}
|
||||
|
||||
if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN) &&
|
||||
if (ELEM(mode, FO_CURSUP, FO_CURSDOWN, FO_PAGEUP, FO_PAGEDOWN, FO_LINE_BEGIN, FO_LINE_END) &&
|
||||
iter_data->status == VFONT_TO_CURVE_INIT)
|
||||
{
|
||||
ct = &chartransdata[ef->pos];
|
||||
@@ -1367,6 +1371,18 @@ static bool vfont_to_curve(Object *ob,
|
||||
else if (ELEM(mode, FO_CURSDOWN, FO_PAGEDOWN) && ct->linenr == lnr) {
|
||||
/* Pass. */
|
||||
}
|
||||
else if (mode == FO_LINE_BEGIN) {
|
||||
/* Line wrap aware line beginning. */
|
||||
while ((ef->pos > 0) && (chartransdata[ef->pos - 1].linenr == ct->linenr)) {
|
||||
ef->pos -= 1;
|
||||
}
|
||||
}
|
||||
else if (mode == FO_LINE_END) {
|
||||
/* Line wrap aware line end. */
|
||||
while ((ef->pos + 1 < slen) && (chartransdata[ef->pos + 1].linenr == ct->linenr)) {
|
||||
ef->pos += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
switch (mode) {
|
||||
case FO_CURSUP:
|
||||
@@ -1386,6 +1402,8 @@ static bool vfont_to_curve(Object *ob,
|
||||
case FO_CURS:
|
||||
case FO_DUPLI:
|
||||
case FO_SELCHANGE:
|
||||
case FO_LINE_BEGIN:
|
||||
case FO_LINE_END:
|
||||
break;
|
||||
}
|
||||
cnr = ct->charnr;
|
||||
@@ -1478,16 +1496,15 @@ static bool vfont_to_curve(Object *ob,
|
||||
|
||||
ct = chartransdata;
|
||||
for (i = 0; i < slen; i++) {
|
||||
info = &(custrinfo[i]);
|
||||
|
||||
if ((cu->overflow == CU_OVERFLOW_TRUNCATE) && (ob && ob->mode != OB_MODE_EDIT) &&
|
||||
(info->flag & CU_CHINFO_OVERFLOW))
|
||||
ct->is_overflow)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
const char32_t charcode = vfont_char_apply_smallcaps(mem[i], info);
|
||||
|
||||
info = &(custrinfo[i]);
|
||||
const char32_t charcode = vfont_char_apply_smallcaps(mem[i], ct->is_smallcaps);
|
||||
/* We don't want to see any character for `\n`. */
|
||||
if (charcode != '\n') {
|
||||
|
||||
@@ -1495,20 +1512,22 @@ static bool vfont_to_curve(Object *ob,
|
||||
/* Find the character, the characters has to be in the memory already
|
||||
* since character checking has been done earlier already. */
|
||||
che = vfont_char_find_or_placeholder(vfinfo_ctx.vfd, charcode, che_placeholder);
|
||||
vfont_char_build_impl(cu, r_nubase, che, info, ct->xof, ct->yof, ct->rot, i, font_size);
|
||||
vfont_char_build_impl(
|
||||
cu, r_nubase, che, info, ct->is_smallcaps, ct->xof, ct->yof, ct->rot, i, font_size);
|
||||
|
||||
if (info->flag & CU_CHINFO_UNDERLINE) {
|
||||
float ulwidth, uloverlap = 0.0f;
|
||||
rctf rect;
|
||||
|
||||
BLI_assert(&ct[1] == &chartransdata[i + 1]);
|
||||
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))
|
||||
((ct[1].is_wrap) == 0))
|
||||
{
|
||||
uloverlap = xtrax;
|
||||
}
|
||||
|
||||
twidth = vfont_char_width(cu, che, info);
|
||||
twidth = vfont_char_width(cu, che, ct->is_smallcaps);
|
||||
ulwidth = (twidth * (1.0f + (info->kern / 40.0f))) + uloverlap;
|
||||
|
||||
rect.xmin = ct->xof;
|
||||
@@ -1757,7 +1776,7 @@ static bool vfont_to_curve(Object *ob,
|
||||
MEM_freeN(chartransdata);
|
||||
}
|
||||
|
||||
if (ef == nullptr) {
|
||||
if (mem_alloc) {
|
||||
MEM_freeN(mem);
|
||||
}
|
||||
return true;
|
||||
@@ -1766,10 +1785,10 @@ static bool vfont_to_curve(Object *ob,
|
||||
if (r_text) {
|
||||
*r_text = mem;
|
||||
*r_text_len = slen;
|
||||
*r_text_free = (ef == nullptr);
|
||||
*r_text_free = mem_alloc;
|
||||
}
|
||||
else {
|
||||
if (ef == nullptr) {
|
||||
if (mem_alloc) {
|
||||
MEM_freeN(mem);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1350,32 +1350,10 @@ static wmOperatorStatus move_cursor(bContext *C, int type, const bool select)
|
||||
|
||||
switch (type) {
|
||||
case LINE_BEGIN:
|
||||
while (ef->pos > 0) {
|
||||
if (ef->textbuf[ef->pos - 1] == '\n') {
|
||||
break;
|
||||
}
|
||||
if (ef->textbufinfo[ef->pos - 1].flag & CU_CHINFO_WRAP) {
|
||||
break;
|
||||
}
|
||||
ef->pos--;
|
||||
}
|
||||
cursmove = FO_CURS;
|
||||
cursmove = FO_LINE_BEGIN;
|
||||
break;
|
||||
|
||||
case LINE_END:
|
||||
while (ef->pos < ef->len) {
|
||||
if (ef->textbuf[ef->pos] == 0) {
|
||||
break;
|
||||
}
|
||||
if (ef->textbuf[ef->pos] == '\n') {
|
||||
break;
|
||||
}
|
||||
if (ef->textbufinfo[ef->pos].flag & CU_CHINFO_WRAP) {
|
||||
break;
|
||||
}
|
||||
ef->pos++;
|
||||
}
|
||||
cursmove = FO_CURS;
|
||||
cursmove = FO_LINE_END;
|
||||
break;
|
||||
|
||||
case TEXT_BEGIN:
|
||||
|
||||
@@ -213,19 +213,20 @@ typedef enum eBezTriple_KeyframeType {
|
||||
|
||||
/* *************** CHARINFO **************** */
|
||||
|
||||
/** #CharInfo.flag */
|
||||
/**
|
||||
* #CharInfo.flag
|
||||
*
|
||||
* \note This must *not* be used for run-time / evaluation flags.
|
||||
* If this is needed, see: #CharTrans.
|
||||
*/
|
||||
enum {
|
||||
/* NOTE: CU_CHINFO_WRAP, CU_CHINFO_SMALLCAPS_TEST and CU_CHINFO_TRUNCATE are set dynamically. */
|
||||
CU_CHINFO_BOLD = 1 << 0,
|
||||
CU_CHINFO_ITALIC = 1 << 1,
|
||||
CU_CHINFO_UNDERLINE = 1 << 2,
|
||||
/** Word-wrap occurred here. */
|
||||
CU_CHINFO_WRAP = 1 << 3,
|
||||
CU_CHINFO_UNUSED_3 = 1 << 3, /* Dirty. */
|
||||
CU_CHINFO_SMALLCAPS = 1 << 4,
|
||||
/** Set at runtime, checks if case switching is needed. */
|
||||
CU_CHINFO_SMALLCAPS_CHECK = 1 << 5,
|
||||
/** Set at runtime, indicates char that doesn't fit in text boxes. */
|
||||
CU_CHINFO_OVERFLOW = 1 << 6,
|
||||
CU_CHINFO_UNUSED_5 = 1 << 5, /* Dirty. */
|
||||
CU_CHINFO_UNUSED_6 = 1 << 6, /* Dirty. */
|
||||
};
|
||||
|
||||
/** User adjustable as styles (not relating to run-time layout calculation). */
|
||||
|
||||
@@ -306,7 +306,14 @@ typedef struct Curve {
|
||||
float bevfac1, bevfac2;
|
||||
char bevfac1_mapping, bevfac2_mapping;
|
||||
|
||||
char _pad2[2];
|
||||
char _pad2[1];
|
||||
|
||||
/**
|
||||
* If non-zero, the #editfont and #editnurb pointers are not owned by this #Curve. That means
|
||||
* this curve is a container for the result of object geometry evaluation. This only works
|
||||
* because evaluated object data never outlives original data.
|
||||
*/
|
||||
char edit_data_from_original;
|
||||
|
||||
/**
|
||||
* A pointer to curve data from evaluation. Owned by the object's #geometry_set_eval, either as a
|
||||
@@ -316,13 +323,6 @@ typedef struct Curve {
|
||||
* original object data.
|
||||
*/
|
||||
const struct Curves *curve_eval;
|
||||
/**
|
||||
* If non-zero, the #editfont and #editnurb pointers are not owned by this #Curve. That means
|
||||
* this curve is a container for the result of object geometry evaluation. This only works
|
||||
* because evaluated object data never outlives original data.
|
||||
*/
|
||||
char edit_data_from_original;
|
||||
char _pad3[7];
|
||||
|
||||
void *batch_cache;
|
||||
|
||||
|
||||
@@ -228,7 +228,7 @@ static std::optional<TextLayout> get_text_layout(GeoNodeExecParams ¶ms)
|
||||
CharTrans &ct = chartransdata[i];
|
||||
layout.positions.append(float2(ct.xof, ct.yof) * layout.final_font_size);
|
||||
|
||||
if ((info[i].flag & CU_CHINFO_OVERFLOW) && (cu.overflow == CU_OVERFLOW_TRUNCATE)) {
|
||||
if (ct.is_overflow && (cu.overflow == CU_OVERFLOW_TRUNCATE)) {
|
||||
const int offset = BLI_str_utf8_offset_from_index(
|
||||
layout.text.c_str(), layout.text.size(), i + 1);
|
||||
layout.truncated_text = layout.text.substr(offset);
|
||||
@@ -279,7 +279,7 @@ static Map<int, int> create_curve_instances(GeoNodeExecParams ¶ms,
|
||||
CharInfo charinfo = {0};
|
||||
charinfo.mat_nr = 1;
|
||||
|
||||
BKE_vfont_char_build(&cu, &cu.nurb, layout.char_codes[i], &charinfo, 0, 0, 0, i, 1);
|
||||
BKE_vfont_char_build(&cu, &cu.nurb, layout.char_codes[i], &charinfo, false, 0, 0, 0, i, 1);
|
||||
Curves *curves_id = bke::curve_legacy_to_curves(cu);
|
||||
if (curves_id == nullptr) {
|
||||
if (pivot_required) {
|
||||
|
||||
Reference in New Issue
Block a user