BLF: Refactor of blf_font_boundbox_foreach_glyph

Refactor of `BLF_boundbox_foreach_glyph` and simplification of its
usage by only passing translated glyph bounds to callbacks.

See D15765 for more details.

Differential Revision: https://developer.blender.org/D15765

Reviewed by Campbell Barton
This commit is contained in:
2022-09-25 11:25:31 -07:00
parent c8ee70c962
commit b3714b1e85
6 changed files with 150 additions and 149 deletions

View File

@@ -118,10 +118,7 @@ int BLF_draw_mono(int fontid, const char *str, size_t str_len, int cwidth) ATTR_
typedef bool (*BLF_GlyphBoundsFn)(const char *str,
size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
int glyph_advance_x,
const struct rcti *glyph_bounds,
const int glyph_bearing[2],
const struct rcti *bounds,
void *user_data);
/**
@@ -132,18 +129,28 @@ typedef bool (*BLF_GlyphBoundsFn)(const char *str,
*
* \note The font position, clipping, matrix and rotation are not applied.
*/
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
BLF_GlyphBoundsFn user_fn,
void *user_data,
struct ResultBLF *r_info) ATTR_NONNULL(2);
void BLF_boundbox_foreach_glyph(int fontid,
const char *str,
size_t str_len,
BLF_GlyphBoundsFn user_fn,
void *user_data) ATTR_NONNULL(2);
/**
* Get the byte offset within a string, selected by mouse at a horizontal location.
*/
size_t BLF_str_offset_from_cursor_position(int fontid,
const char *str,
size_t str_len,
int location_x);
/**
* Return bounds of the glyph rect at the string offset.
*/
bool BLF_str_offset_to_glyph_bounds(int fontid,
const char *str,
size_t str_offset,
struct rcti *glyph_bounds);
/**
* Get the string byte offset that fits within a given width.
*/

View File

@@ -563,32 +563,45 @@ int BLF_draw_mono(int fontid, const char *str, const size_t str_len, int cwidth)
return columns;
}
void BLF_boundbox_foreach_glyph_ex(int fontid,
const char *str,
size_t str_len,
BLF_GlyphBoundsFn user_fn,
void *user_data,
struct ResultBLF *r_info)
void BLF_boundbox_foreach_glyph(
int fontid, const char *str, size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data)
{
FontBLF *font = blf_get(fontid);
BLF_RESULT_CHECK_INIT(r_info);
if (font) {
if (font->flags & BLF_WORD_WRAP) {
/* TODO: word-wrap support. */
BLI_assert(0);
}
else {
blf_font_boundbox_foreach_glyph(font, str, str_len, user_fn, user_data, r_info);
blf_font_boundbox_foreach_glyph(font, str, str_len, user_fn, user_data);
}
}
}
void BLF_boundbox_foreach_glyph(
int fontid, const char *str, const size_t str_len, BLF_GlyphBoundsFn user_fn, void *user_data)
size_t BLF_str_offset_from_cursor_position(int fontid,
const char *str,
size_t str_len,
int location_x)
{
BLF_boundbox_foreach_glyph_ex(fontid, str, str_len, user_fn, user_data, NULL);
FontBLF *font = blf_get(fontid);
if (font) {
return blf_str_offset_from_cursor_position(font, str, str_len, location_x);
}
return 0;
}
bool BLF_str_offset_to_glyph_bounds(int fontid,
const char *str,
size_t str_offset,
rcti *glyph_bounds)
{
FontBLF *font = blf_get(fontid);
if (font) {
blf_str_offset_to_glyph_bounds(font, str, str_offset, glyph_bounds);
return true;
}
return false;
}
size_t BLF_width_to_strlen(

View File

@@ -901,25 +901,23 @@ float blf_font_fixed_width(FontBLF *font)
return width;
}
static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
GlyphCacheBLF *gc,
const char *str,
const size_t str_len,
BLF_GlyphBoundsFn user_fn,
void *user_data,
struct ResultBLF *r_info,
ft_pix pen_y)
void blf_font_boundbox_foreach_glyph(FontBLF *font,
const char *str,
const size_t str_len,
BLF_GlyphBoundsFn user_fn,
void *user_data)
{
GlyphBLF *g, *g_prev = NULL;
ft_pix pen_x = 0;
size_t i = 0, i_curr;
rcti gbox_px;
if (str_len == 0 || str[0] == 0) {
/* early output. */
return;
}
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
while ((i < str_len) && str[i]) {
i_curr = i;
g = blf_glyph_from_utf8_and_step(font, gc, str, str_len, &i);
@@ -928,46 +926,90 @@ static void blf_font_boundbox_foreach_glyph_ex(FontBLF *font,
continue;
}
pen_x += blf_kerning(font, g_prev, g);
const ft_pix pen_x_next = ft_pix_round_advance(pen_x, g->advance_x);
gbox_px.xmin = ft_pix_to_int_floor(pen_x);
gbox_px.xmax = ft_pix_to_int_ceil(pen_x_next);
gbox_px.ymin = ft_pix_to_int_floor(pen_y);
gbox_px.ymax = gbox_px.ymin - g->dims[1];
const int advance_x_px = gbox_px.xmax - gbox_px.xmin;
rcti bounds;
bounds.xmin = ft_pix_to_int_floor(pen_x) + ft_pix_to_int_floor(g->box_xmin);
bounds.xmax = ft_pix_to_int_floor(pen_x) + ft_pix_to_int_ceil(g->box_xmax);
bounds.ymin = ft_pix_to_int_floor(g->box_ymin);
bounds.ymax = ft_pix_to_int_ceil(g->box_ymax);
pen_x = pen_x_next;
rcti box_px;
box_px.xmin = ft_pix_to_int_floor(g->box_xmin);
box_px.xmax = ft_pix_to_int_ceil(g->box_xmax);
box_px.ymin = ft_pix_to_int_floor(g->box_ymin);
box_px.ymax = ft_pix_to_int_ceil(g->box_ymax);
if (user_fn(str, i_curr, &gbox_px, advance_x_px, &box_px, g->pos, user_data) == false) {
if (user_fn(str, i_curr, &bounds, user_data) == false) {
break;
}
pen_x = ft_pix_round_advance(pen_x, g->advance_x);
g_prev = g;
}
if (r_info) {
r_info->lines = 1;
r_info->width = ft_pix_to_int(pen_x);
}
}
void blf_font_boundbox_foreach_glyph(FontBLF *font,
const char *str,
const size_t str_len,
BLF_GlyphBoundsFn user_fn,
void *user_data,
struct ResultBLF *r_info)
{
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
blf_font_boundbox_foreach_glyph_ex(font, gc, str, str_len, user_fn, user_data, r_info, 0);
blf_glyph_cache_release(font);
}
typedef struct CursorPositionForeachGlyph_Data {
/** Horizontal position to test. */
int location_x;
/** Write the character offset here. */
size_t r_offset;
} CursorPositionForeachGlyph_Data;
static bool blf_cursor_position_foreach_glyph(const char *UNUSED(str),
const size_t str_step_ofs,
const rcti *bounds,
void *user_data)
{
CursorPositionForeachGlyph_Data *data = user_data;
if (data->location_x < (bounds->xmin + bounds->xmax) / 2) {
data->r_offset = str_step_ofs;
return false;
}
return true;
}
size_t blf_str_offset_from_cursor_position(struct FontBLF *font,
const char *str,
size_t str_len,
int location_x)
{
CursorPositionForeachGlyph_Data data = {
.location_x = location_x,
.r_offset = (size_t)-1,
};
blf_font_boundbox_foreach_glyph(font, str, str_len, blf_cursor_position_foreach_glyph, &data);
if (data.r_offset == (size_t)-1) {
data.r_offset = BLI_strnlen(str, str_len);
}
return data.r_offset;
}
typedef struct StrOffsetToGlyphBounds_Data {
size_t str_offset;
rcti bounds;
} StrOffsetToGlyphBounds_Data;
static bool blf_str_offset_foreach_glyph(const char *UNUSED(str),
const size_t str_step_ofs,
const rcti *bounds,
void *user_data)
{
StrOffsetToGlyphBounds_Data *data = user_data;
if (data->str_offset == str_step_ofs) {
data->bounds = *bounds;
return false;
}
return true;
}
void blf_str_offset_to_glyph_bounds(struct FontBLF *font,
const char *str,
size_t str_offset,
rcti *glyph_bounds)
{
StrOffsetToGlyphBounds_Data data = {
.str_offset = str_offset,
.bounds = {0},
};
blf_font_boundbox_foreach_glyph(font, str, str_offset + 1, blf_str_offset_foreach_glyph, &data);
*glyph_bounds = data.bounds;
}
/** \} */
/* -------------------------------------------------------------------- */

View File

@@ -141,13 +141,19 @@ void blf_font_boundbox_foreach_glyph(struct FontBLF *font,
size_t str_len,
bool (*user_fn)(const char *str,
size_t str_step_ofs,
const struct rcti *glyph_step_bounds,
int glyph_advance_x,
const struct rcti *glyph_bounds,
const int glyph_bearing[2],
const struct rcti *bounds,
void *user_data),
void *user_data,
struct ResultBLF *r_info);
void *user_data);
size_t blf_str_offset_from_cursor_position(struct FontBLF *font,
const char *str,
size_t str_len,
int location_x);
void blf_str_offset_to_glyph_bounds(struct FontBLF *font,
const char *str,
size_t str_offset,
struct rcti *glyph_bounds);
void blf_font_free(struct FontBLF *font);

View File

@@ -3017,23 +3017,6 @@ static bool ui_textedit_delete_selection(uiBut *but, uiHandleButtonData *data)
return changed;
}
static bool ui_textedit_set_cursor_pos_foreach_glyph(const char *UNUSED(str),
const size_t str_step_ofs,
const rcti *glyph_step_bounds,
const int UNUSED(glyph_advance_x),
const rcti *glyph_bounds,
const int UNUSED(glyph_bearing[2]),
void *user_data)
{
int *cursor_data = user_data;
const int center = glyph_step_bounds->xmin + (BLI_rcti_size_x(glyph_bounds) / 2.0f);
if (cursor_data[0] < center) {
cursor_data[1] = str_step_ofs;
return false;
}
return true;
}
/**
* \param x: Screen space cursor location - #wmEvent.x
*
@@ -3064,7 +3047,7 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
startx += UI_DPI_ICON_SIZE / aspect;
}
}
startx += (UI_TEXT_MARGIN_X * U.widget_unit) / aspect;
startx += (UI_TEXT_MARGIN_X * U.widget_unit - U.pixelsize) / aspect;
/* mouse dragged outside the widget to the left */
if (x < startx) {
@@ -3088,23 +3071,8 @@ static void ui_textedit_set_cursor_pos(uiBut *but, uiHandleButtonData *data, con
}
/* mouse inside the widget, mouse coords mapped in widget space */
else {
str_last = &str[but->ofs];
const int str_last_len = strlen(str_last);
const int x_pos = (int)(x - startx);
int glyph_data[2] = {
x_pos, /* horizontal position to test. */
-1, /* Write the character offset here. */
};
BLF_boundbox_foreach_glyph(fstyle.uifont_id,
str + but->ofs,
INT_MAX,
ui_textedit_set_cursor_pos_foreach_glyph,
glyph_data);
/* If value untouched then we are to the right. */
if (glyph_data[1] == -1) {
glyph_data[1] = str_last_len;
}
but->pos = glyph_data[1] + but->ofs;
but->pos = but->ofs + BLF_str_offset_from_cursor_position(
fstyle.uifont_id, str + but->ofs, INT_MAX, (int)(x - startx));
}
ui_but_text_password_hide(password_str, but, true);

View File

@@ -1858,33 +1858,6 @@ static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
}
#endif /* WITH_INPUT_IME */
struct UnderlineData {
size_t str_offset; /* The string offset of the underlined character. */
int width_px; /* The underline width in pixels. */
int r_offset_px[2]; /* Write the X,Y offset here. */
};
static bool widget_draw_text_underline_calc_position(const char *UNUSED(str),
const size_t str_step_ofs,
const rcti *glyph_step_bounds,
const int UNUSED(glyph_advance_x),
const rcti *glyph_bounds,
const int UNUSED(glyph_bearing[2]),
void *user_data)
{
struct UnderlineData *ul_data = user_data;
if (ul_data->str_offset == str_step_ofs) {
/* Full width of this glyph including both bearings. */
const int width = glyph_bounds->xmin + BLI_rcti_size_x(glyph_bounds) + glyph_bounds->xmin;
ul_data->r_offset_px[0] = glyph_step_bounds->xmin + ((width - ul_data->width_px) / 2);
/* One line-width below the lower glyph bounds. */
ul_data->r_offset_px[1] = glyph_bounds->ymin - U.pixelsize;
/* Early exit. */
return false;
}
return true;
}
static void widget_draw_text(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
uiBut *but,
@@ -2150,26 +2123,18 @@ static void widget_draw_text(const uiFontStyle *fstyle,
}
if (ul_index != -1) {
int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2));
struct UnderlineData ul_data = {
.str_offset = ul_index,
.width_px = ul_width,
};
BLF_boundbox_foreach_glyph(fstyle->uifont_id,
drawstr_ofs,
ul_index + 1,
widget_draw_text_underline_calc_position,
&ul_data);
const int pos_x = rect->xmin + font_xofs + ul_data.r_offset_px[0];
const int pos_y = rect->ymin + font_yofs + ul_data.r_offset_px[1];
/* Use text output because direct drawing doesn't always work. See T89246. */
BLF_position(fstyle->uifont_id, pos_x, pos_y, 0.0f);
BLF_color4ubv(fstyle->uifont_id, wcol->text);
BLF_draw(fstyle->uifont_id, "_", 2);
rcti bounds;
if (BLF_str_offset_to_glyph_bounds(fstyle->uifont_id, drawstr_ofs, ul_index, &bounds) &&
!BLI_rcti_is_empty(&bounds)) {
int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2));
int pos_x = rect->xmin + font_xofs + bounds.xmin +
(bounds.xmax - bounds.xmin - ul_width) / 2;
int pos_y = rect->ymin + font_yofs + bounds.ymin - U.pixelsize;
/* Use text output because direct drawing doesn't always work. See T89246. */
BLF_position(fstyle->uifont_id, (float)pos_x, pos_y, 0.0f);
BLF_color4ubv(fstyle->uifont_id, wcol->text);
BLF_draw(fstyle->uifont_id, "_", 2);
}
}
}
}